add the function to expose the transaction info

This commit is contained in:
aleks
2024-05-14 16:12:16 +02:00
parent 17de1dd9dd
commit f50e220dae
8 changed files with 138 additions and 48 deletions

View File

@@ -237,6 +237,24 @@ eMBErrorCode eMBMasterRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress,
return error; return error;
} }
/**
* Helper function to get current transaction info
*/
esp_err_t mbc_master_get_transaction_info(mb_trans_info_t *ptinfo)
{
mb_trans_info_t tinfo = {0};
MB_MASTER_CHECK((ptinfo),
ESP_ERR_INVALID_ARG,
"Wrong argument.");
MB_MASTER_CHECK(xMBMasterGetLastTransactionInfo(&tinfo.trans_id, &tinfo.dest_addr,
&tinfo.func_code, &tinfo.exception,
&tinfo.err_type),
ESP_ERR_INVALID_STATE,
"Master can not get transaction info.");
*ptinfo = tinfo;
return ESP_OK;
}
// Helper function to set parameter buffer according to its type // Helper function to set parameter buffer according to its type
esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size) esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size)
{ {

View File

@@ -150,6 +150,17 @@ typedef struct {
uint16_t reg_size; /*!< Modbus number of registers */ uint16_t reg_size; /*!< Modbus number of registers */
} mb_param_request_t; } mb_param_request_t;
/**
* @brief Modbus transacion info structure
*/
typedef struct {
uint64_t trans_id; /*!< Modbus unique transaction identificator */
uint8_t dest_addr; /*!< Modbus destination short address (or UID) */
uint8_t func_code; /*!< Modbus last transaction function code */
uint8_t exception; /*!< Modbus last transaction exception code returned by slave */
uint16_t err_type; /*!< Modbus last transaction error type */
} mb_trans_info_t;
/** /**
* @brief Initialize Modbus controller and stack for TCP port * @brief Initialize Modbus controller and stack for TCP port
* *
@@ -321,6 +332,18 @@ esp_err_t mbc_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uin
*/ */
esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size); esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size);
/**
* @brief The helper function to expose transaction info from modbus layer
*
* @param[in] ptinfo the pointer to transaction info structure
*
* @return
* - esp_err_t ESP_OK - the transaction info is saved in the appropriate parameter structure
* - esp_err_t ESP_ERR_INVALID_ARG - invalid argument of function or parameter descriptor
* - esp_err_t ESP_ERR_INVALID_STATE - invalid state during data processing or allocation failure
*/
esp_err_t mbc_master_get_transaction_info(mb_trans_info_t *ptinfo);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -18,6 +18,7 @@
#include "esp_modbus_common.h" // for common types #include "esp_modbus_common.h" // for common types
#include "esp_modbus_master.h" // for public master types #include "esp_modbus_master.h" // for public master types
#include "esp_modbus_callbacks.h" #include "esp_modbus_callbacks.h"
#include "mb_m.h" // this is required to expose current transaction info
/* ----------------------- Defines ------------------------------------------*/ /* ----------------------- Defines ------------------------------------------*/

View File

@@ -409,6 +409,9 @@ eMBMasterErrorEventType eMBMasterGetErrorType( void );
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType ); void vMBMasterSetErrorType( eMBMasterErrorEventType errorType );
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ); eMBMasterReqErrCode eMBMasterWaitRequestFinish( void );
eMBMode ucMBMasterGetCommMode( void ); eMBMode ucMBMasterGetCommMode( void );
BOOL xMBMasterGetLastTransactionInfo( uint64_t *pxTransId, UCHAR *pucDestAddress,
UCHAR *pucFunctionCode, UCHAR *pucException,
USHORT *pusErrorType );
/* ----------------------- Callback -----------------------------------------*/ /* ----------------------- Callback -----------------------------------------*/

View File

@@ -71,12 +71,21 @@
/* ----------------------- Static variables ---------------------------------*/ /* ----------------------- Static variables ---------------------------------*/
static UCHAR ucMBMasterDestAddress; static UCHAR ucMBMasterDestAddress = 0;
static BOOL xMBRunInMasterMode = FALSE; static BOOL xMBRunInMasterMode = FALSE;
static volatile eMBMasterErrorEventType eMBMasterCurErrorType; static volatile eMBMasterErrorEventType eMBMasterCurErrorType = EV_ERROR_INIT;
static volatile USHORT usMasterSendPDULength; static volatile USHORT usMasterSendPDULength;
static volatile eMBMode eMBMasterCurrentMode; static volatile eMBMode eMBMasterCurrentMode;
static UCHAR *pucMBSendFrame = NULL;
static UCHAR *pucMBRecvFrame = NULL;
static UCHAR ucRecvAddress = 0;
static UCHAR ucLastFunctionCode = 0;
static UCHAR usLastFrameError = 0;
static eMBException eLastException = MB_EX_NONE;
static uint64_t xLastTransactionId = 0;
static uint64_t xCurTransactionId = 0;
/*------------------------ Shared variables ---------------------------------*/ /*------------------------ Shared variables ---------------------------------*/
volatile UCHAR ucMasterSndBuf[MB_SERIAL_BUF_SIZE]; volatile UCHAR ucMasterSndBuf[MB_SERIAL_BUF_SIZE];
@@ -182,7 +191,13 @@ eMBMasterTCPInit( USHORT ucTCPPort )
{ {
eStatus = MB_EPORTERR; eStatus = MB_EPORTERR;
} }
/* initialize the state values. */
ucRecvAddress = 0;
ucLastFunctionCode = 0;
usLastFrameError = 0;
eLastException = MB_EX_NONE;
xCurTransactionId = 0;
eMBMasterCurErrorType = EV_ERROR_INIT;
} }
return eStatus; return eStatus;
} }
@@ -240,6 +255,13 @@ eMBMasterSerialInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eP
else else
{ {
eMBState = STATE_DISABLED; eMBState = STATE_DISABLED;
/* initialize the state values. */
ucRecvAddress = 0;
ucLastFunctionCode = 0;
usLastFrameError = 0;
eLastException = MB_EX_NONE;
xCurTransactionId = 0;
eMBMasterCurErrorType = EV_ERROR_INIT;
} }
/* initialize the OS resource for modbus master. */ /* initialize the OS resource for modbus master. */
vMBMasterOsResInit(); vMBMasterOsResInit();
@@ -311,18 +333,14 @@ eMBMasterDisable( void )
eMBErrorCode eMBErrorCode
eMBMasterPoll( void ) eMBMasterPoll( void )
{ {
static UCHAR *pucMBSendFrame = NULL;
static UCHAR *pucMBRecvFrame = NULL;
static UCHAR ucRcvAddress;
static UCHAR ucFunctionCode;
static USHORT usLength;
static eMBException eException;
static uint64_t xCurTransactionId = 0;
int i; int i;
int j; int j;
eMBErrorCode eStatus = MB_ENOERR; eMBErrorCode eStatus = MB_ENOERR;
xMBMasterEventType xEvent; xMBMasterEventType xEvent;
eMBMasterErrorEventType errorType; eMBMasterErrorEventType errorType;
eMBException eException = MB_EX_NONE;
UCHAR ucFunctionCode = 0;
static USHORT usRecvLength = 0;
/* Check if the protocol stack is ready. */ /* Check if the protocol stack is ready. */
if( eMBState != STATE_ENABLED ) { if( eMBState != STATE_ENABLED ) {
@@ -352,6 +370,7 @@ eMBMasterPoll( void )
ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Frame send error = %d", xEvent.xTransactionId, (unsigned)eStatus ); ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Frame send error = %d", xEvent.xTransactionId, (unsigned)eStatus );
} }
xCurTransactionId = xEvent.xTransactionId; xCurTransactionId = xEvent.xTransactionId;
atomic_store(&(xLastTransactionId), xCurTransactionId);
break; break;
case EV_MASTER_FRAME_SENT: case EV_MASTER_FRAME_SENT:
if (xCurTransactionId == xEvent.xTransactionId) { if (xCurTransactionId == xEvent.xTransactionId) {
@@ -361,15 +380,15 @@ eMBMasterPoll( void )
break; break;
case EV_MASTER_FRAME_RECEIVED: case EV_MASTER_FRAME_RECEIVED:
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_RECEIVED", xEvent.xTransactionId ); ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_RECEIVED", xEvent.xTransactionId );
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &pucMBRecvFrame, &usLength); eStatus = peMBMasterFrameReceiveCur( &ucRecvAddress, &pucMBRecvFrame, &usRecvLength);
if (xCurTransactionId == xEvent.xTransactionId) { if (xCurTransactionId == xEvent.xTransactionId) {
MB_PORT_CHECK(pucMBSendFrame, MB_EILLSTATE, "Send buffer initialization fail."); MB_PORT_CHECK(pucMBSendFrame, MB_EILLSTATE, "Send buffer initialization fail.");
// Check if the frame is for us. If not ,send an error process event. // Check if the frame is for us. If not ,send an error process event.
if ( ( eStatus == MB_ENOERR ) && ( ( ucRcvAddress == ucMBMasterGetDestAddress() ) if ( ( eStatus == MB_ENOERR ) && ( ( ucRecvAddress == ucMBMasterGetDestAddress() )
|| ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS) ) ) { || ( ucRecvAddress == MB_TCP_PSEUDO_ADDRESS) ) ) {
if ( ( pucMBRecvFrame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR ) == ( pucMBSendFrame[MB_PDU_FUNC_OFF] ) ) { if ( ( pucMBRecvFrame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR ) == ( pucMBSendFrame[MB_PDU_FUNC_OFF] ) ) {
ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ": Packet data received successfully (%u).", xEvent.xTransactionId, (unsigned)eStatus); ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ": Packet data received successfully (%u).", xEvent.xTransactionId, (unsigned)eStatus);
ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)pucMBRecvFrame, (uint16_t)usLength, ESP_LOG_DEBUG); ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)pucMBRecvFrame, (uint16_t)usRecvLength, ESP_LOG_DEBUG);
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE ); ( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
} else { } else {
ESP_LOGE( MB_PORT_TAG, "Drop incorrect frame, receive_func(%u) != send_func(%u)", ESP_LOGE( MB_PORT_TAG, "Drop incorrect frame, receive_func(%u) != send_func(%u)",
@@ -381,7 +400,7 @@ eMBMasterPoll( void )
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ": Packet data receive failed (addr=%u)(%u).", ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ": Packet data receive failed (addr=%u)(%u).",
xEvent.xTransactionId, (unsigned)ucRcvAddress, (unsigned)eStatus); xEvent.xTransactionId, (unsigned)ucRecvAddress, (unsigned)eStatus);
} }
} else { } else {
// Ignore the `EV_MASTER_FRAME_RECEIVED` event because the respond timeout occurred // Ignore the `EV_MASTER_FRAME_RECEIVED` event because the respond timeout occurred
@@ -398,6 +417,7 @@ eMBMasterPoll( void )
MB_PORT_CHECK(pucMBRecvFrame, MB_EILLSTATE, "receive buffer initialization fail."); MB_PORT_CHECK(pucMBRecvFrame, MB_EILLSTATE, "receive buffer initialization fail.");
ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_EXECUTE", xEvent.xTransactionId); ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_EXECUTE", xEvent.xTransactionId);
ucFunctionCode = pucMBRecvFrame[MB_PDU_FUNC_OFF]; ucFunctionCode = pucMBRecvFrame[MB_PDU_FUNC_OFF];
atomic_store(&(ucLastFunctionCode), ucFunctionCode);
eException = MB_EX_ILLEGAL_FUNCTION; eException = MB_EX_ILLEGAL_FUNCTION;
/* If receive frame has exception. The receive function code highest bit is 1.*/ /* If receive frame has exception. The receive function code highest bit is 1.*/
if (ucFunctionCode & MB_FUNC_ERROR) { if (ucFunctionCode & MB_FUNC_ERROR) {
@@ -415,20 +435,21 @@ eMBMasterPoll( void )
* the master need execute function for all slave. * the master need execute function for all slave.
*/ */
if ( xMBMasterRequestIsBroadcast() ) { if ( xMBMasterRequestIsBroadcast() ) {
usLength = usMBMasterGetPDUSndLength(); USHORT usLength = usMBMasterGetPDUSndLength();
for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++) for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++)
{ {
vMBMasterSetDestAddress(j); vMBMasterSetDestAddress(j);
eException = xMasterFuncHandlers[i].pxHandler(pucMBRecvFrame, &usLength); eException = xMasterFuncHandlers[i].pxHandler(pucMBRecvFrame, &usLength);
} }
} else { } else {
eException = xMasterFuncHandlers[i].pxHandler( pucMBRecvFrame, &usLength ); eException = xMasterFuncHandlers[i].pxHandler(pucMBRecvFrame, &usRecvLength);
} }
vMBMasterSetCBRunInMasterMode( FALSE ); vMBMasterSetCBRunInMasterMode( FALSE );
break; break;
} }
} }
} }
atomic_store(&(eLastException), eException);
/* If master has exception, will send error process event. Otherwise the master is idle.*/ /* If master has exception, will send error process event. Otherwise the master is idle.*/
if ( eException != MB_EX_NONE ) { if ( eException != MB_EX_NONE ) {
vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION ); vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION );
@@ -456,24 +477,28 @@ eMBMasterPoll( void )
vMBMasterErrorCBRespondTimeout( xEvent.xTransactionId, vMBMasterErrorCBRespondTimeout( xEvent.xTransactionId,
ucMBMasterGetDestAddress( ), ucMBMasterGetDestAddress( ),
pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); pucMBSendFrame, usMBMasterGetPDUSndLength( ) );
atomic_store(&(usLastFrameError), ( UCHAR )errorType);
break; break;
case EV_ERROR_RECEIVE_DATA: case EV_ERROR_RECEIVE_DATA:
vMBMasterErrorCBReceiveData( xEvent.xTransactionId, vMBMasterErrorCBReceiveData( xEvent.xTransactionId,
ucMBMasterGetDestAddress( ), ucMBMasterGetDestAddress( ),
pucMBRecvFrame, usLength, pucMBRecvFrame, usRecvLength,
pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); pucMBSendFrame, usMBMasterGetPDUSndLength( ) );
atomic_store(&(usLastFrameError), ( UCHAR )errorType);
break; break;
case EV_ERROR_EXECUTE_FUNCTION: case EV_ERROR_EXECUTE_FUNCTION:
vMBMasterErrorCBExecuteFunction( xEvent.xTransactionId, vMBMasterErrorCBExecuteFunction( xEvent.xTransactionId,
ucMBMasterGetDestAddress( ), ucMBMasterGetDestAddress( ),
pucMBRecvFrame, usLength, pucMBRecvFrame, usRecvLength,
pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); pucMBSendFrame, usMBMasterGetPDUSndLength( ) );
atomic_store(&(usLastFrameError), ( UCHAR )errorType);
break; break;
case EV_ERROR_OK: case EV_ERROR_OK:
vMBMasterCBRequestSuccess( xEvent.xTransactionId, vMBMasterCBRequestSuccess( xEvent.xTransactionId,
ucMBMasterGetDestAddress( ), ucMBMasterGetDestAddress( ),
pucMBRecvFrame, usLength, pucMBRecvFrame, usRecvLength,
pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); pucMBSendFrame, usMBMasterGetPDUSndLength( ) );
atomic_store(&(usLastFrameError), ( UCHAR )errorType);
break; break;
default: default:
ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":incorrect error type = %d.", xEvent.xTransactionId, (int)errorType); ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":incorrect error type = %d.", xEvent.xTransactionId, (int)errorType);
@@ -583,4 +608,21 @@ eMBMode ucMBMasterGetCommMode(void)
return eMBMasterCurrentMode; return eMBMasterCurrentMode;
} }
/* Get current transaction information */
BOOL xMBMasterGetLastTransactionInfo( uint64_t *pxTransId, UCHAR *pucDestAddress,
UCHAR *pucFunctionCode, UCHAR *pucException,
USHORT *pusErrorType )
{
BOOL xState = (eMBState == STATE_ENABLED);
if (xState && pxTransId && pucDestAddress && pucFunctionCode
&& pucException && pusErrorType) {
*pxTransId = atomic_load(&xLastTransactionId);
*pucDestAddress = ucMBMasterGetDestAddress();
*pucFunctionCode = atomic_load(&ucLastFunctionCode);
*pucException = (UCHAR) atomic_load(&eLastException);
*pusErrorType = atomic_load(&usLastFrameError);
}
return xState;
}
#endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED #endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED

View File

@@ -392,6 +392,13 @@ static void master_operation_func(void *arg)
alarm_state = true; alarm_state = true;
break; break;
} }
mb_trans_info_t tinfo = {0};
if (mbc_master_get_transaction_info(&tinfo) == ESP_OK) {
ESP_LOGI("TRANS_INFO", "Id: %" PRIu64 ", Addr: %x, FC: %x, Exp: %u, Err: %x",
(uint64_t)tinfo.trans_id, (int)tinfo.dest_addr,
(unsigned)tinfo.func_code, (unsigned)tinfo.exception,
(int)tinfo.err_type);
}
} else if ((cid >= CID_RELAY_P1) && (cid <= CID_DISCR_P1)) { } else if ((cid >= CID_RELAY_P1) && (cid <= CID_DISCR_P1)) {
if (TEST_VERIFY_VALUES(param_descriptor, (uint8_t *)temp_data_ptr) == ESP_OK) { if (TEST_VERIFY_VALUES(param_descriptor, (uint8_t *)temp_data_ptr) == ESP_OK) {
uint8_t state = *(uint8_t *)temp_data_ptr; uint8_t state = *(uint8_t *)temp_data_ptr;
@@ -483,26 +490,22 @@ static esp_err_t master_init(void)
return err; return err;
} }
#ifndef UCHAR
#define UCHAR uint8_t
#define USHORT uint16_t
#define MB_PDU_DATA_OFF 1 #define MB_PDU_DATA_OFF 1
#endif
#define EV_ERROR_EXECUTE_FUNCTION 3 #define EV_ERROR_EXECUTE_FUNCTION 3
void vMBMasterErrorCBUserHandler( uint64_t xTransId, USHORT usError, UCHAR ucDestAddress, const UCHAR* pucRecvData, USHORT ucRecvLength, void vMBMasterErrorCBUserHandler( uint64_t xTransId, uint16_t usError, uint8_t ucDestAddress, const uint8_t *pucRecvData, uint16_t ucRecvLength,
const UCHAR* pucSendData, USHORT ucSendLength ) const uint8_t *pucSendData, uint16_t ucSendLength )
{ {
ESP_LOGW("USER_ERR_CB", "The transaction error type: %u", usError); ESP_LOGW("USER_ERR_CB", "The transaction %" PRIu64 ", error type: %u", xTransId, usError);
if ((usError == EV_ERROR_EXECUTE_FUNCTION) && pucRecvData && ucRecvLength) { if ((usError == EV_ERROR_EXECUTE_FUNCTION) && pucRecvData && ucRecvLength) {
ESP_LOGW("USER_ERR_CB", "The command is unsupported or an exception on slave happened: %x", (int)pucRecvData[1]); ESP_LOGW("USER_ERR_CB", "The command is unsupported or an exception on slave happened: %x", (int)pucRecvData[MB_PDU_DATA_OFF]);
} }
if (pucRecvData && ucRecvLength) { if (pucRecvData && ucRecvLength) {
ESP_LOG_BUFFER_HEX_LEVEL("Received buffer", (void *)pucRecvData, (USHORT)ucRecvLength, ESP_LOG_WARN); ESP_LOG_BUFFER_HEX_LEVEL("Received buffer", (void *)pucRecvData, (uint16_t)ucRecvLength, ESP_LOG_WARN);
} }
if (pucSendData && ucSendLength) { if (pucSendData && ucSendLength) {
ESP_LOG_BUFFER_HEX_LEVEL("Sent buffer", (void *)pucSendData, (USHORT)ucSendLength, ESP_LOG_WARN); ESP_LOG_BUFFER_HEX_LEVEL("Sent buffer", (void *)pucSendData, (uint16_t)ucSendLength, ESP_LOG_WARN);
} }
} }