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 config FMB_TCP_PORT_MAX_CONN
int "Maximum allowed connections for TCP stack" int "Maximum allowed connections for TCP stack"
range 1 6 range 1 8
default 5 default 5
depends on FMB_COMM_MODE_TCP_EN depends on FMB_COMM_MODE_TCP_EN
help help
@ -34,6 +34,14 @@ menu "Modbus configuration"
Modbus TCP connection timeout in seconds. Modbus TCP connection timeout in seconds.
Once expired the current connection with the client will be closed Once expired the current connection with the client will be closed
and Modbus slave will be waiting for new connection to accept. 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 config FMB_COMM_MODE_RTU_EN
bool "Enable Modbus stack support for RTU mode" bool "Enable Modbus stack support for RTU mode"

View File

@ -143,6 +143,7 @@ typedef union {
// TCP/UDP communication structure // TCP/UDP communication structure
struct { struct {
mb_mode_type_t ip_mode; /*!< Modbus communication mode */ 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 */ uint16_t ip_port; /*!< Modbus port */
mb_tcp_addr_type_t ip_addr_type; /*!< Modbus address type */ mb_tcp_addr_type_t ip_addr_type; /*!< Modbus address type */
void* ip_addr; /*!< Modbus address table for connection */ 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. * frame processing is still disabled until eMBEnable( ) is called.
* *
* \param usTCPPort The TCP port to listen on. * \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 * \return If the protocol stack has been initialized correctly the function
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error * returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
* codes is returned: * codes is returned:
@ -172,7 +173,7 @@ eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
* slave addresses are in the range 1 - 247. * slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error. * - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/ */
eMBErrorCode eMBTCPInit( USHORT usTCPPort ); eMBErrorCode eMBTCPInit( UCHAR ucSlaveUid, USHORT usTCPPort );
/*! \ingroup modbus /*! \ingroup modbus
* \brief Release resources used by the protocol stack. * \brief Release resources used by the protocol stack.

View File

@ -86,6 +86,10 @@ PR_BEGIN_EXTERN_C
#endif #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. /*! \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. * 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 #if MB_TCP_ENABLED > 0
eMBErrorCode eMBErrorCode
eMBTCPInit( USHORT ucTCPPort ) eMBTCPInit( UCHAR ucSlaveUid, USHORT ucTCPPort )
{ {
eMBErrorCode eStatus = MB_ENOERR; 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; eMBState = STATE_DISABLED;
} }
@ -222,7 +227,7 @@ eMBTCPInit( USHORT ucTCPPort )
peMBFrameReceiveCur = eMBTCPReceive; peMBFrameReceiveCur = eMBTCPReceive;
peMBFrameSendCur = eMBTCPSend; peMBFrameSendCur = eMBTCPSend;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL; pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
ucMBAddress = MB_TCP_PSEUDO_ADDRESS; ucMBAddress = ucSlaveUid;
eMBCurrentMode = MB_TCP; eMBCurrentMode = MB_TCP;
eMBState = STATE_DISABLED; eMBState = STATE_DISABLED;
} }
@ -371,7 +376,8 @@ eMBPoll( void )
if( eStatus == MB_ENOERR ) if( eStatus == MB_ENOERR )
{ {
/* Check if the frame is for us. If not ignore the frame. */ /* 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 ); ( void )xMBPortEventPost( EV_EXECUTE );
ESP_LOG_BUFFER_HEX_LEVEL(MB_PORT_TAG, &ucMBFrame[MB_PDU_FUNC_OFF], usLength, ESP_LOG_DEBUG); 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 /* If the request was not sent to the broadcast address we
* return a reply. */ * return a reply. In case of TCP the slave answers to broadcast address. */
if( ucRcvAddress != MB_ADDRESS_BROADCAST ) if( ( ucRcvAddress != MB_ADDRESS_BROADCAST ) || ( eMBCurrentMode == MB_TCP ) )
{ {
if( eException != MB_EX_NONE ) if( eException != MB_EX_NONE )
{ {

View File

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

View File

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

View File

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

View File

@ -989,6 +989,7 @@ xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
// Apply TID field to the frame before send // Apply TID field to the frame before send
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U); pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF); pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS); int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
if (xRes < 0) { if (xRes < 0) {
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."), 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; eMBErrorCode status = MB_EIO;
// Initialize Modbus stack using mbcontroller parameters // 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_SLAVE_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack initialization failure, eMBInit() returns (0x%x).", status); "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, BaseType_t xStatus = xQueueReceive(xRespQueueHandle,
(void*)&pvResp, (void*)&pvResp,
pdMS_TO_TICKS(MB_TCP_RESP_TIMEOUT_MS)); pdMS_TO_TICKS(MB_TCP_RESP_TIMEOUT_MS));
MB_PORT_CHECK((xStatus == pdTRUE), NULL, "Could not get respond confirmation."); if (xStatus != pdTRUE) {
MB_PORT_CHECK((pvResp), NULL, "Incorrect response processing."); ESP_LOGD(TAG, "Could not get respond confirmation.");
}
return pvResp; return pvResp;
} }
@ -599,7 +600,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
// Wait while response is not processed by stack by timeout // Wait while response is not processed by stack by timeout
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle); UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
if (pucSentBuffer == NULL) { 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); MB_TCP_RESP_TIMEOUT_MS);
} else { } else {
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID); 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. description: ESP-MODBUS is the official Modbus library for Espressif SoCs.
url: https://github.com/espressif/esp-modbus url: https://github.com/espressif/esp-modbus
dependencies: dependencies:

View File

@ -73,7 +73,7 @@ static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device // 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 // Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
enum { enum {
MB_DEVICE_ADDR1 = 1, // Slave address 1 MB_DEVICE_ADDR1 = 1, // Slave UID = 1
MB_DEVICE_ADDR2 = 200, MB_DEVICE_ADDR2 = 200,
MB_DEVICE_ADDR3 = 35 MB_DEVICE_ADDR3 = 35
}; };
@ -750,7 +750,6 @@ void app_main(void)
comm_info.ip_netif_ptr = (void*)get_example_netif(); comm_info.ip_netif_ptr = (void*)get_example_netif();
ESP_ERROR_CHECK(master_init(&comm_info)); ESP_ERROR_CHECK(master_init(&comm_info));
vTaskDelay(50);
master_operation_func(NULL); master_operation_func(NULL);
ESP_ERROR_CHECK(master_destroy()); 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_TIMEOUT_MS_RESPOND=3000
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300 CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
CONFIG_FMB_TIMER_PORT_ENABLED=y CONFIG_FMB_TIMER_PORT_ENABLED=y
CONFIG_FMB_TCP_UID_ENABLED=n
CONFIG_MB_MDNS_IP_RESOLVER=n CONFIG_MB_MDNS_IP_RESOLVER=n
CONFIG_MB_SLAVE_IP_FROM_STDIN=y CONFIG_MB_SLAVE_IP_FROM_STDIN=y
CONFIG_EXAMPLE_CONNECT_IPV6=n 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_PORT_ENABLED=y
CONFIG_FMB_TIMER_ISR_IN_IRAM=y CONFIG_FMB_TIMER_ISR_IN_IRAM=y
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
CONFIG_FMB_TCP_UID_ENABLED=n
CONFIG_MB_MDNS_IP_RESOLVER=n CONFIG_MB_MDNS_IP_RESOLVER=n
CONFIG_MB_SLAVE_IP_FROM_STDIN=y CONFIG_MB_SLAVE_IP_FROM_STDIN=y
CONFIG_MB_SLAVE_ADDR=1 CONFIG_MB_SLAVE_ADDR=1

View File

@ -2,7 +2,8 @@ menu "Modbus Example Configuration"
config MB_SLAVE_ADDR config MB_SLAVE_ADDR
int "Modbus slave address" 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 default 1
help help
This is the Modbus slave address in the network. This is the Modbus slave address in the network.

View File

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