Skip to content

Commit

Permalink
Merge branch 'feature/add_slave_id_command' into 'master'
Browse files Browse the repository at this point in the history
add the command  0x11 - get slave info

Closes IDFGH-13856

See merge request idf/esp-modbus!82
  • Loading branch information
alisitsyn committed Dec 6, 2024
2 parents 5a36ece + db57bd6 commit e8317c2
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 28 deletions.
11 changes: 10 additions & 1 deletion Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ menu "Modbus configuration"
config FMB_MASTER_TIMEOUT_MS_RESPOND
int "Slave respond timeout (Milliseconds)"
default 3000
range 150 15000
range 300 15000
help
If master sends a frame which is not broadcast, it has to wait sometime for slave response.
if slave is not respond in this time, the master will process timeout error.
Expand Down Expand Up @@ -171,6 +171,15 @@ menu "Modbus configuration"
Most significant byte of ID is used as short device ID and
other three bytes used as long ID.

config FMB_CONTROLLER_SLAVE_ID_MAX_SIZE
int "Modbus Slave ID maximum buffer size (bytes)"
range 4 255
default 32
depends on FMB_CONTROLLER_SLAVE_ID_SUPPORT
help
Modbus slave ID buffer size used to store vendor specific ID information
for the <Report Slave ID> command.

config FMB_CONTROLLER_NOTIFY_TIMEOUT
int "Modbus controller notification timeout (ms)"
range 0 200
Expand Down
24 changes: 24 additions & 0 deletions freemodbus/common/esp_modbus_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

#include <sys/param.h>
#include "esp_err.h" // for esp_err_t
#include "mbc_master.h" // for master interface define
#include "esp_modbus_master.h" // for public interface defines
Expand Down Expand Up @@ -237,6 +238,29 @@ eMBErrorCode eMBMasterRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress,
return error;
}

eMBErrorCode eMBMasterRegCommonCB(UCHAR * pucData, USHORT usAddress,
USHORT usBytes)
{
MB_MASTER_CHECK((master_interface_ptr != NULL),
MB_EILLSTATE,
"Master interface is not correctly initialized.");
MB_MASTER_CHECK((master_interface_ptr != NULL),
MB_EILLSTATE,
"Master interface uninitialized.");
MB_MASTER_CHECK(pucData, MB_EINVAL,
"Master stack processing error.");
mb_master_options_t* popts = &master_interface_ptr->opts;
USHORT usRegLen = (USHORT)popts->mbm_reg_buffer_size;
UCHAR* pucParBuffer = (UCHAR*)popts->mbm_reg_buffer_ptr; // Get instance address
eMBErrorCode eStatus = MB_ENOERR;
if (pucParBuffer && !usAddress && (usBytes >= 1) && (((usRegLen << 1) >= usBytes))){
memmove(pucParBuffer, pucData, MIN((usRegLen << 1), usBytes));
} else {
eStatus = MB_ENOREG;
}
return eStatus;
}

/**
* Helper function to get current transaction info
*/
Expand Down
2 changes: 2 additions & 0 deletions freemodbus/common/mbc_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "freertos/FreeRTOS.h" // for task creation and queue access
#include "freertos/task.h" // for task api access
#include "freertos/event_groups.h" // for event groups
#include "freertos/semphr.h" // for semaphore
#include "driver/uart.h" // for UART types
#include "errno.h" // for errno
#include "esp_log.h" // for log write
Expand Down Expand Up @@ -64,6 +65,7 @@ typedef struct {
uint16_t mbm_reg_buffer_size; /*!< Modbus data buffer size */
TaskHandle_t mbm_task_handle; /*!< Modbus task handle */
EventGroupHandle_t mbm_event_group; /*!< Modbus controller event group */
SemaphoreHandle_t mbm_sema; /*!< Modbus controller semaphore */
const mb_parameter_descriptor_t* mbm_param_descriptor_table; /*!< Modbus controller parameter description table */
size_t mbm_param_descriptor_size; /*!< Modbus controller parameter description table size*/
#if MB_MASTER_TCP_ENABLED
Expand Down
59 changes: 56 additions & 3 deletions freemodbus/modbus/functions/mbfuncother.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbconfig.h"
Expand All @@ -52,11 +53,61 @@

#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED

#define MB_PDU_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_DATA_OFF ( MB_PDU_DATA_OFF + 1 )

/* ----------------------- Static variables ---------------------------------*/
static UCHAR ucMBSlaveID[MB_FUNC_OTHER_REP_SLAVEID_BUF];
static UCHAR ucMBSlaveID[MB_FUNC_OTHER_REP_SLAVEID_BUF] = {0};
static USHORT usMBSlaveIDLen;

/* ----------------------- Start implementation -----------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );

eMBMasterReqErrCode
eMBMasterReqReportSlaveID( UCHAR ucSndAddr, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;

if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_OTHER_REPORT_SLAVEID;
vMBMasterSetPDUSndLength( 1 );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}

eMBException
eMBMasterFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen )
{
UCHAR ucByteCount = 0;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;

if( *usLen <= ( MB_FUNC_OTHER_REP_SLAVEID_BUF - 2 ) )
{
ucByteCount = ( UCHAR )( pucFrame[MB_PDU_BYTECNT_OFF] );
// Transfer data from command buffer.
eRegStatus = eMBMasterRegCommonCB( &pucFrame[MB_PDU_FUNC_DATA_OFF], 0, ucByteCount);
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}

eMBErrorCode
eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
Expand Down Expand Up @@ -86,11 +137,13 @@ eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
return eStatus;
}

// pucFrame points to Modbus PDU
eMBException
eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen )
{
memcpy( &pucFrame[MB_PDU_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
*usLen = ( USHORT )( MB_PDU_DATA_OFF + usMBSlaveIDLen );
memcpy( &pucFrame[MB_PDU_FUNC_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
*usLen = ( USHORT )( MB_PDU_FUNC_DATA_OFF + usMBSlaveIDLen );
pucFrame[MB_PDU_BYTECNT_OFF] = usMBSlaveIDLen;
return MB_EX_NONE;
}

Expand Down
26 changes: 23 additions & 3 deletions freemodbus/modbus/include/mb_m.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,24 @@ eMBErrorCode eMBMasterRegisterCB( UCHAR ucFunctionCode,
* to update the application register values.
*/

/*! \ingroup modbus_registers
* \brief The common callback function used to transfer common data as bytes
* from command buffer in little endian format.
*
* \param pucData A pointer to data in command buffer to be transferred.
* \param usAddress Unused for this function == 0.
* \param usBytes Number of bytes the callback function must supply.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG if can not map the data of the registers
* - eMBErrorCode::MB_EILLSTATE if can not procceed with data transfer due to critical error
* - eMBErrorCode::MB_EINVAL if value data can not be transferred
*/
eMBErrorCode eMBMasterRegCommonCB( UCHAR * pucData, USHORT usAddress,
USHORT usBytes );

/*! \ingroup modbus_registers
* \brief Callback function used if the value of a <em>Input Register</em>
* is required by the protocol stack. The starting register address is given
Expand All @@ -273,9 +291,9 @@ eMBErrorCode eMBMasterRegisterCB( UCHAR ucFunctionCode,
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
* - eMBErrorCode::MB_ENOREG if can not map the data of the registers
* - eMBErrorCode::MB_EILLSTATE if can not procceed with data transfer due to critical error
* - eMBErrorCode::MB_EINVAL if value data can not be transferred
*/
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs );
Expand Down Expand Up @@ -365,6 +383,8 @@ eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
*\brief These Modbus functions are called for user when Modbus run in Master Mode.
*/
eMBMasterReqErrCode
eMBMasterReqReportSlaveID( UCHAR ucSndAddr, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut );
Expand Down
2 changes: 1 addition & 1 deletion freemodbus/modbus/include/mbconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ PR_BEGIN_EXTERN_C
* how to set this value. It is only used if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
* is set to <code>1</code>.
*/
#define MB_FUNC_OTHER_REP_SLAVEID_BUF ( 32 )
#define MB_FUNC_OTHER_REP_SLAVEID_BUF ( CONFIG_FMB_CONTROLLER_SLAVE_ID_MAX_SIZE )

/*! \brief If the <em>Report Slave ID</em> function should be enabled. */
#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED ( CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT )
Expand Down
2 changes: 1 addition & 1 deletion freemodbus/modbus/mb_m.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ BOOL( *pxMBMasterFrameCBTransmitFSMCur ) ( void );
*/
static xMBFunctionHandler xMasterFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBMasterFuncReportSlaveID},
#endif
#if MB_FUNC_READ_INPUT_ENABLED > 0
{MB_FUNC_READ_INPUT_REGISTER, eMBMasterFuncReadInputRegister},
Expand Down
28 changes: 19 additions & 9 deletions freemodbus/serial_master/modbus_controller/mbc_serial_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "freertos/task.h" // for task api access
#include "freertos/event_groups.h" // for event groups
#include "freertos/queue.h" // for queue api access
#include "freertos/semphr.h" // for semaphore
#include "mb_m.h" // for modbus stack master types definition
#include "port.h" // for port callback functions
#include "mbutils.h" // for mbutils functions definition for stack callback
Expand All @@ -28,7 +29,7 @@ extern BOOL xMBMasterPortSerialTxPoll(void);

/*-----------------------Master mode use these variables----------------------*/
// Actual wait time depends on the response timer
#define MB_SERIAL_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))
#define MB_SERIAL_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))

static mb_master_interface_t* mbm_interface_ptr = NULL;
static const char *TAG = "MB_CONTROLLER_MASTER";
Expand Down Expand Up @@ -127,6 +128,8 @@ static esp_err_t mbc_serial_master_destroy(void)
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
(void)vTaskDelete(mbm_opts->mbm_task_handle);
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
vSemaphoreDelete(mbm_opts->mbm_sema);
mbm_opts->mbm_sema = NULL;
mb_error = eMBMasterClose();
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack close failure returned (0x%x).", (int)mb_error);
Expand Down Expand Up @@ -176,22 +179,22 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
eMBMasterReqErrCode mb_error = MB_MRE_MASTER_BUSY;
esp_err_t error = ESP_FAIL;

if (xMBMasterRunResTake(MB_SERIAL_API_RESP_TICS)) {

if (xSemaphoreTake(mbm_opts->mbm_sema, MB_SERIAL_API_RESP_TICS) == pdTRUE) {
uint8_t mb_slave_addr = request->slave_addr;
uint8_t mb_command = request->command;
uint16_t mb_offset = request->reg_start;
uint16_t mb_size = request->reg_size;

// Set the buffer for callback function processing of received data
mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
mbm_opts->mbm_reg_buffer_size = mb_size;

vMBMasterRunResRelease();

// Calls appropriate request function to send request and waits response
switch(mb_command)
{
case MB_FUNC_OTHER_REPORT_SLAVEID:
mb_error = eMBMasterReqReportSlaveID((UCHAR)mb_slave_addr, (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_READ_COILS:
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size , (LONG)MB_SERIAL_API_RESP_TICS );
Expand All @@ -216,7 +219,6 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
*(USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
break;

case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
(USHORT)mb_offset, (USHORT)mb_size,
Expand All @@ -237,6 +239,8 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
mb_error = MB_MRE_NO_REG;
break;
}
} else {
ESP_LOGD(TAG, "%s:MBC semaphore take fail.", __func__);
}

// Propagate the Modbus errors to higher level
Expand Down Expand Up @@ -264,11 +268,13 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
break;

default:
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, (int)mb_error);
ESP_LOGE(TAG, "%s: Incorrect return code (0x%x) ", __FUNCTION__, (int)mb_error);
error = ESP_FAIL;
break;
}

(void)xSemaphoreGive( mbm_opts->mbm_sema );

return error;
}

Expand Down Expand Up @@ -508,7 +514,7 @@ eMBErrorCode eMBRegInputCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
// If input or configuration parameters are incorrect then return an error to stack layer
if ((pucInputBuffer != NULL)
&& (usNRegs >= 1)
&& (usRegInputNregs == usRegs)) {
&& ((usRegInputNregs == usRegs) || (!usAddress))) {
while (usRegs > 0) {
_XFER_2_RD(pucInputBuffer, pucRegBuffer);
usRegs -= 1;
Expand Down Expand Up @@ -698,6 +704,10 @@ esp_err_t mbc_serial_master_create(void** handler)
mbm_opts->mbm_event_group = xEventGroupCreate();
MB_MASTER_CHECK((mbm_opts->mbm_event_group != NULL),
ESP_ERR_NO_MEM, "mb event group error.");
mbm_opts->mbm_sema = xSemaphoreCreateBinary();
MB_MASTER_CHECK((mbm_opts->mbm_sema != NULL), ESP_ERR_NO_MEM, "%s: mbm resource create error.", __func__);
(void)xSemaphoreGive( mbm_opts->mbm_sema );

// Create modbus controller task
status = xTaskCreatePinnedToCore((void*)&modbus_master_task,
"modbus_matask",
Expand Down
Loading

0 comments on commit e8317c2

Please sign in to comment.