modbus tcp fix uid settings

This commit is contained in:
Alex Lisitsyn
2023-02-28 16:29:12 +08:00
parent cea014cad1
commit 2db0cfcf69
17 changed files with 71 additions and 29 deletions

10
Kconfig
View File

@ -16,7 +16,7 @@ menu "Modbus configuration"
config FMB_TCP_PORT_MAX_CONN
int "Maximum allowed connections for TCP stack"
range 1 6
range 1 8
default 5
depends on FMB_COMM_MODE_TCP_EN
help
@ -34,6 +34,14 @@ menu "Modbus configuration"
Modbus TCP connection timeout in seconds.
Once expired the current connection with the client will be closed
and Modbus slave will be waiting for new connection to accept.
config FMB_TCP_UID_ENABLED
bool "Modbus TCP enable UID (Unit Identifier) support"
default n
depends on FMB_COMM_MODE_TCP_EN
help
If this option is set the Modbus stack uses UID (Unit Identifier) field in MBAP frame.
Else the UID is ignored by master and slave.
config FMB_COMM_MODE_RTU_EN
bool "Enable Modbus stack support for RTU mode"

View File

@ -143,6 +143,7 @@ typedef union {
// TCP/UDP communication structure
struct {
mb_mode_type_t ip_mode; /*!< Modbus communication mode */
uint8_t slave_uid; /*!< Modbus slave address field for UID */
uint16_t ip_port; /*!< Modbus port */
mb_tcp_addr_type_t ip_addr_type; /*!< Modbus address type */
void* ip_addr; /*!< Modbus address table for connection */

View File

@ -165,6 +165,7 @@ eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
* frame processing is still disabled until eMBEnable( ) is called.
*
* \param usTCPPort The TCP port to listen on.
* \param ucSlaveUid The UID field for slave to listen on.
* \return If the protocol stack has been initialized correctly the function
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
* codes is returned:
@ -172,7 +173,7 @@ eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
* slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/
eMBErrorCode eMBTCPInit( USHORT usTCPPort );
eMBErrorCode eMBTCPInit( UCHAR ucSlaveUid, USHORT usTCPPort );
/*! \ingroup modbus
* \brief Release resources used by the protocol stack.

View File

@ -86,6 +86,10 @@ PR_BEGIN_EXTERN_C
#endif
/*! \brief The option is required for support of RTU over TCP.
*/
#define MB_TCP_UID_ENABLED ( CONFIG_FMB_TCP_UID_ENABLED )
/*! \brief This option defines the number of data bits per ASCII character.
*
* A parity bit is added before the stop bit which keeps the actual byte size at 10 bits.

View File

@ -202,11 +202,16 @@ eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eM
#if MB_TCP_ENABLED > 0
eMBErrorCode
eMBTCPInit( USHORT ucTCPPort )
eMBTCPInit( UCHAR ucSlaveUid, USHORT ucTCPPort )
{
eMBErrorCode eStatus = MB_ENOERR;
if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
/* Check preconditions */
if( ucSlaveUid > MB_ADDRESS_MAX )
{
eStatus = MB_EINVAL;
}
else if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
{
eMBState = STATE_DISABLED;
}
@ -222,7 +227,7 @@ eMBTCPInit( USHORT ucTCPPort )
peMBFrameReceiveCur = eMBTCPReceive;
peMBFrameSendCur = eMBTCPSend;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
ucMBAddress = ucSlaveUid;
eMBCurrentMode = MB_TCP;
eMBState = STATE_DISABLED;
}
@ -371,7 +376,8 @@ eMBPoll( void )
if( eStatus == MB_ENOERR )
{
/* Check if the frame is for us. If not ignore the frame. */
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST )
|| ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS ) )
{
( void )xMBPortEventPost( EV_EXECUTE );
ESP_LOG_BUFFER_HEX_LEVEL(MB_PORT_TAG, &ucMBFrame[MB_PDU_FUNC_OFF], usLength, ESP_LOG_DEBUG);
@ -401,8 +407,8 @@ eMBPoll( void )
}
/* If the request was not sent to the broadcast address we
* return a reply. */
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
* return a reply. In case of TCP the slave answers to broadcast address. */
if( ( ucRcvAddress != MB_ADDRESS_BROADCAST ) || ( eMBCurrentMode == MB_TCP ) )
{
if( eException != MB_EX_NONE )
{

View File

@ -124,10 +124,14 @@ eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLength )
*pusLength = usLength - MB_TCP_FUNC;
eStatus = MB_ENOERR;
/* Modbus TCP does not use any addresses. Fake the source address such
* that the processing part deals with this frame.
/* The regular Modbus TCP does not use any addresses. Fake the MBAP UID in this case.
* The MBAP UID field support is used for RTU over TCP option if enabled.
*/
#if MB_TCP_UID_ENABLED
*pucRcvAddress = pucMBTCPFrame[MB_TCP_UID];
#else
*pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
#endif
}
}
else
@ -152,6 +156,7 @@ eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
*/
pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
if( xMBTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE )
{
eStatus = MB_EIO;

View File

@ -123,10 +123,14 @@ eMBMasterTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLeng
*pusLength = usLength - MB_TCP_FUNC;
eStatus = MB_ENOERR;
/* Modbus TCP does not use any addresses. Fake the source address such
* that the processing part deals with this frame.
/* Get MBAP UID field if its support is enabled.
* Otherwise just ignore this field.
*/
#if MB_TCP_UID_ENABLED
*pucRcvAddress = pucMBTCPFrame[MB_TCP_UID];
#else
*pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
#endif
}
}
else
@ -137,20 +141,27 @@ eMBMasterTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLeng
}
eMBErrorCode
eMBMasterTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
eMBMasterTCPSend( UCHAR ucAddress, const UCHAR * pucFrame, USHORT usLength )
{
eMBErrorCode eStatus = MB_ENOERR;
UCHAR *pucMBTCPFrame = ( UCHAR * ) pucFrame - MB_TCP_FUNC;
USHORT usTCPLength = usLength + MB_TCP_FUNC;
/* The MBAP header is already initialized because the caller calls this
* function with the buffer returned by the previous call. Therefore we
* only have to update the length in the header. Note that the length
* header includes the size of the Modbus PDU and the UID Byte. Therefore
* the length is usLength plus one.
/* Note that the length in the MBAP header includes the size of the Modbus PDU
* and the UID Byte. Therefore the length is usLength plus one.
*/
pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
/* Set UID field in the MBAP if it is supported.
* If the RTU over TCP is not supported, the UID = 0 or 0xFF.
*/
#if MB_TCP_UID_ENABLED
pucMBTCPFrame[MB_TCP_UID] = ucAddress;
#else
pucMBTCPFrame[MB_TCP_UID] = 0x00;
#endif
if( xMBMasterTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE )
{
eStatus = MB_EIO;

View File

@ -50,7 +50,7 @@ void eMBMasterTCPStart( void );
void eMBMasterTCPStop( void );
eMBErrorCode eMBMasterTCPReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
USHORT * pusLength );
eMBErrorCode eMBMasterTCPSend( UCHAR _unused, const UCHAR * pucFrame,
eMBErrorCode eMBMasterTCPSend( UCHAR ucAddress, const UCHAR * pucFrame,
USHORT usLength );
BOOL xMBMasterTCPTimerExpired(void);

View File

@ -989,6 +989,7 @@ xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
// 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);
if (xRes < 0) {
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),

View File

@ -72,7 +72,7 @@ static esp_err_t mbc_tcp_slave_start(void)
eMBErrorCode status = MB_EIO;
// Initialize Modbus stack using mbcontroller parameters
status = eMBTCPInit((USHORT)mbs_opts->mbs_comm.ip_port);
status = eMBTCPInit((UCHAR)mbs_opts->mbs_comm.slave_uid, (USHORT)mbs_opts->mbs_comm.ip_port);
MB_SLAVE_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack initialization failure, eMBInit() returns (0x%x).", status);

View File

@ -106,8 +106,9 @@ static void* vxMBTCPPortRespQueueRecv(QueueHandle_t xRespQueueHandle)
BaseType_t xStatus = xQueueReceive(xRespQueueHandle,
(void*)&pvResp,
pdMS_TO_TICKS(MB_TCP_RESP_TIMEOUT_MS));
MB_PORT_CHECK((xStatus == pdTRUE), NULL, "Could not get respond confirmation.");
MB_PORT_CHECK((pvResp), NULL, "Incorrect response processing.");
if (xStatus != pdTRUE) {
ESP_LOGD(TAG, "Could not get respond confirmation.");
}
return pvResp;
}
@ -599,7 +600,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
// Wait while response is not processed by stack by timeout
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
if (pucSentBuffer == NULL) {
ESP_LOGE(TAG, "Response time exceeds configured %d [ms], ignore packet.",
ESP_LOGD(TAG, "Response is ignored, time exceeds configured %d [ms].",
MB_TCP_RESP_TIMEOUT_MS);
} else {
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);

View File

@ -1,4 +1,4 @@
version: "1.0.8"
version: "1.0.9"
description: ESP-MODBUS is the official Modbus library for Espressif SoCs.
url: https://github.com/espressif/esp-modbus
dependencies:

View File

@ -73,7 +73,7 @@ static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
enum {
MB_DEVICE_ADDR1 = 1, // Slave address 1
MB_DEVICE_ADDR1 = 1, // Slave UID = 1
MB_DEVICE_ADDR2 = 200,
MB_DEVICE_ADDR3 = 35
};
@ -750,7 +750,6 @@ void app_main(void)
comm_info.ip_netif_ptr = (void*)get_example_netif();
ESP_ERROR_CHECK(master_init(&comm_info));
vTaskDelay(50);
master_operation_func(NULL);
ESP_ERROR_CHECK(master_destroy());

View File

@ -8,6 +8,7 @@ CONFIG_FMB_COMM_MODE_ASCII_EN=n
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=3000
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
CONFIG_FMB_TIMER_PORT_ENABLED=y
CONFIG_FMB_TCP_UID_ENABLED=n
CONFIG_MB_MDNS_IP_RESOLVER=n
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
CONFIG_EXAMPLE_CONNECT_IPV6=n

View File

@ -13,6 +13,7 @@ CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
CONFIG_FMB_TIMER_PORT_ENABLED=y
CONFIG_FMB_TIMER_ISR_IN_IRAM=y
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
CONFIG_FMB_TCP_UID_ENABLED=n
CONFIG_MB_MDNS_IP_RESOLVER=n
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
CONFIG_MB_SLAVE_ADDR=1

View File

@ -2,7 +2,8 @@ menu "Modbus Example Configuration"
config MB_SLAVE_ADDR
int "Modbus slave address"
range 1 255
range 1 247 if !FMB_TCP_UID_ENABLED
range 0 247 if FMB_TCP_UID_ENABLED
default 1
help
This is the Modbus slave address in the network.

View File

@ -52,6 +52,8 @@
| MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
static const char *TAG = "SLAVE_TEST";
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
@ -69,8 +71,6 @@ static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
#define MB_DEVICE_ID (uint32_t)CONFIG_FMB_CONTROLLER_SLAVE_ID
#endif
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
#define MB_MDNS_INSTANCE(pref) pref"mb_slave_tcp"
// convert mac from binary format to string
@ -315,6 +315,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
comm_info->ip_addr = NULL; // Bind to any address
comm_info->ip_netif_ptr = (void*)get_example_netif();
comm_info->slave_uid = MB_SLAVE_ADDR;
// Setup communication parameters and start stack
err = mbc_slave_setup((void*)comm_info);
@ -423,6 +424,7 @@ void app_main(void)
ESP_ERROR_CHECK(init_services());
// Set UART log level
esp_log_level_set(TAG, ESP_LOG_INFO);
mb_communication_info_t comm_info = { 0 };