diff --git a/docs/en/master_api_overview.rst b/docs/en/master_api_overview.rst index c10a5e6..777a435 100644 --- a/docs/en/master_api_overview.rst +++ b/docs/en/master_api_overview.rst @@ -9,7 +9,8 @@ The following overview describes how to setup Modbus master communication. The o 2. :ref:`modbus_api_master_configure_descriptor` - Configure data descriptors to access slave parameters. 3. :ref:`modbus_api_master_setup_communication_options` - Allows to setup communication options for selected port. 4. :ref:`modbus_api_master_start_communication` - Start stack and sending / receiving data. -5. :ref:`modbus_api_master_destroy` - Destroy Modbus controller and its resources. +5. :ref:`modbus_api_master_expose_information` - Expose extra information from stack. +6. :ref:`modbus_api_master_destroy` - Destroy Modbus controller and its resources. .. _modbus_api_master_configure_descriptor: @@ -433,6 +434,110 @@ The function writes characteristic's value defined as a name and cid parameter i ESP_LOGE(TAG, "Set data fail, err = 0x%x (%s).", (int)err, (char*)esp_err_to_name(err)); } +.. _modbus_api_master_expose_information: + +Expose Extra Information +^^^^^^^^^^^^^^^^^^^^^^^^ + +In case the does not clarify some information, such as slave exception code returned in the response, the functions below can be useful. + +:cpp:func:`mbc_master_get_transaction_info` + +Allows to return the below information as a :cpp:type:`mb_trans_info_t` structure. + +.. list-table:: Table 4 Transaction extended information + :widths: 2 68 + :header-rows: 1 + + * - Field + - Description + * - uint64_t ``trans_id`` + - The unique transaction identificator stored as uint64_t timestamp. + * - uint8_t ``dest_addr`` + - Destination short address (or UID - Unit Identificator) of the slave being accessed. + * - uint8_t ``func_code`` + - The last transaction function code. + * - uint8_t ``exception`` + - The last transaction exception code returned by slave. :cpp:type:`eMBException`. + * - uint16_t ``err_type`` + - The last transaction error type. + :cpp:enumerator:`EV_ERROR_INIT` = 0, No error, initial state or the request is in progress. + :cpp:enumerator:`EV_ERROR_RESPOND_TIMEOUT` = 1, Slave respond timeout. No response during response timeout. + :cpp:enumerator:`EV_ERROR_RECEIVE_DATA` = 2, Receive frame data error. + :cpp:enumerator:`EV_ERROR_EXECUTE_FUNCTION` = 3, Execute function error. Function is not supported or slave returned an error. + :cpp:enumerator:`EV_ERROR_OK` = 4, No error, processing completed successfully. + +.. warning:: The functionality described in this section is for advanced users and should to be handled correctly. + +.. note:: The above function returns the latest transaction information which may not be actual if another IO call is performed from higher priority task right before the :cpp:func:`mbc_master_get_transaction_info`. In this case the ``trans_id`` field can clarify if the returned information is obsolete. The transaction ID is just a timestamp of type `uint64_t` returned by function `esp_timer_get_time()`. In this case it is possible determining if the information retrieved corresponds to the actual request using timestamp kept before the IO call and transaction identificator. + +.. code:: c + + #define MAX_TRANSACTION_TOUT_US 640000 + + uint64_t start_timestamp = esp_timer_get_time(); // Get current timestamp in microseconds + esp_err_t err = mbc_master_get_parameter(param_descriptor->cid, (char*)param_descriptor->param_key, (uint8_t*)temp_data, &type); + + mb_trans_info_t tinfo = {0}; + if (mbc_master_get_transaction_info(&tinfo) == ESP_OK) { + ESP_LOGI("TRANSACTION_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); + } + + if (tinfo.trans_id >= (start_timestamp + MAX_TRANSACTION_TOUT_US)) { + ESP_LOGI("TRANSACTION_INFO", "Transaction Id: %" PRIu64 " is expired", tinfo.trans_id); + } + +Below is the way to expose the transaction information and request/response buffers defining the user error handling function. This funcion defined as described in the code below will be executed from internal final state machine before returning from blocking :cpp:func:`mbc_master_set_parameter` or :cpp:func:`mbc_master_get_parameter` functions and expose the internal parameters. + +.. code:: c + + #define MB_PDU_DATA_OFF 1 + + #define EV_ERROR_EXECUTE_FUNCTION 3 + + void vMBMasterErrorCBUserHandler( uint64_t trans_id, uint16_t err_type, uint8_t dest_addr, const uint8_t *precv_buf, uint16_t recv_length, + const uint8_t *psent_buf, uint16_t sent_length ) + { + ESP_LOGW("USER_ERR_CB", "The transaction %" PRIu64 ", error type: %u", trans_id, err_type); + if ((err_type == EV_ERROR_EXECUTE_FUNCTION) && precv_buf && recv_length) { + ESP_LOGW("USER_ERR_CB", "The command is unsupported or an exception on slave happened: %x", (int)precv_buf[MB_PDU_DATA_OFF]); + } + if (precv_buf && recv_length) { + ESP_LOG_BUFFER_HEX_LEVEL("Received buffer", (void *)precv_buf, (uint16_t)recv_length, ESP_LOG_WARN); + } + if (psent_buf && sent_length) { + ESP_LOG_BUFFER_HEX_LEVEL("Sent buffer", (void *)psent_buf, (uint16_t)sent_length, ESP_LOG_WARN); + } + } + +.. list-table:: Table 5 Transaction user handler parameters + :widths: 2 68 + :header-rows: 1 + + * - Field + - Description + * - uint64_t ``trans_id``; + - The unique transaction identificator stored as uint64_t timestamp. + * - uint16_t ``err_type``; + - The last transaction error type. + * - uint8_t ``dest_addr``; + - Destination short address (or UID - Unit Identificator) of the slave being accessed. + * - ``precv_buf``; + - The last transaction internal receive buffer pointer that points to the Modbus PDU frame. NULL - not actual. + * - ``recv_length``; + - The last transaction receive buffer length. + * - ``psent_buf``; + - The last transaction internal sent buffer pointer that points to the Modbus PDU frame. NULL - not actual. + * - ``sent_length``; + - The last transaction sent buffer length. + +The user handler function can be useful to check the Modbus frame buffers and expose some information right before returning from the call :cpp:func:`mbc_master_set_parameter` or :cpp:func:`mbc_master_get_parameter` functions. + +.. warning:: The above handler function may prevent the Modbus FSM to work properly! The body of the handler needs to be as short as possible and contain just simple functionality that will not block processing for relatively long time. This is user software responcibility to not break the Modbus functionality using the function. + .. _modbus_api_master_destroy: Modbus Master Teardown diff --git a/freemodbus/common/esp_modbus_master.c b/freemodbus/common/esp_modbus_master.c index 33988a2..a0af76c 100644 --- a/freemodbus/common/esp_modbus_master.c +++ b/freemodbus/common/esp_modbus_master.c @@ -180,7 +180,7 @@ esp_err_t mbc_master_start(void) } eMBErrorCode eMBMasterRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNDiscrete) + USHORT usNDiscrete) { eMBErrorCode error = MB_ENOERR; MB_MASTER_CHECK((master_interface_ptr != NULL), @@ -194,7 +194,7 @@ eMBErrorCode eMBMasterRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress, } eMBErrorCode eMBMasterRegCoilsCB(UCHAR* pucRegBuffer, USHORT usAddress, - USHORT usNCoils, eMBRegisterMode eMode) + USHORT usNCoils, eMBRegisterMode eMode) { eMBErrorCode error = MB_ENOERR; MB_MASTER_CHECK((master_interface_ptr != NULL), @@ -209,7 +209,7 @@ eMBErrorCode eMBMasterRegCoilsCB(UCHAR* pucRegBuffer, USHORT usAddress, } eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs, eMBRegisterMode eMode) + USHORT usNRegs, eMBRegisterMode eMode) { eMBErrorCode error = MB_ENOERR; MB_MASTER_CHECK((master_interface_ptr != NULL), @@ -224,7 +224,7 @@ eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, } eMBErrorCode eMBMasterRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs) + USHORT usNRegs) { eMBErrorCode error = MB_ENOERR; MB_MASTER_CHECK((master_interface_ptr != NULL), @@ -237,6 +237,22 @@ eMBErrorCode eMBMasterRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, return error; } +/** + * Helper function to get current transaction info + */ +esp_err_t mbc_master_get_transaction_info(mb_trans_info_t *ptinfo) +{ + MB_MASTER_CHECK((ptinfo), + ESP_ERR_INVALID_ARG, + "Wrong argument."); + MB_MASTER_CHECK(xMBMasterGetLastTransactionInfo(&ptinfo->trans_id, &ptinfo->dest_addr, + &ptinfo->func_code, &ptinfo->exception, + &ptinfo->err_type), + ESP_ERR_INVALID_STATE, + "Master can not get transaction info."); + return ESP_OK; +} + // 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) { diff --git a/freemodbus/common/include/esp_modbus_master.h b/freemodbus/common/include/esp_modbus_master.h index 463cf0f..7fc9079 100644 --- a/freemodbus/common/include/esp_modbus_master.h +++ b/freemodbus/common/include/esp_modbus_master.h @@ -150,6 +150,17 @@ typedef struct { uint16_t reg_size; /*!< Modbus number of registers */ } mb_param_request_t; +/** + * @brief Modbus transacion info structure + */ +typedef struct { + uint64_t trans_id; /*!< Modbus unique transaction identificator */ + uint16_t err_type; /*!< Modbus last transaction error type */ + 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 */ +} mb_trans_info_t; + /** * @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); +/** + * @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 } #endif diff --git a/freemodbus/common/mbc_master.h b/freemodbus/common/mbc_master.h index 4ffe4ff..a736fab 100644 --- a/freemodbus/common/mbc_master.h +++ b/freemodbus/common/mbc_master.h @@ -18,6 +18,7 @@ #include "esp_modbus_common.h" // for common types #include "esp_modbus_master.h" // for public master types #include "esp_modbus_callbacks.h" +#include "mb_m.h" // this is required to expose current transaction info /* ----------------------- Defines ------------------------------------------*/ diff --git a/freemodbus/modbus/ascii/mbascii_m.c b/freemodbus/modbus/ascii/mbascii_m.c index 99e3bb4..dfc8b53 100644 --- a/freemodbus/modbus/ascii/mbascii_m.c +++ b/freemodbus/modbus/ascii/mbascii_m.c @@ -83,7 +83,7 @@ typedef enum /* These Modbus values are shared in ASCII mode*/ extern volatile UCHAR ucMasterRcvBuf[]; extern volatile UCHAR ucMasterSndBuf[]; -extern volatile eMBMasterTimerMode eMasterCurTimerMode; +//extern volatile eMBMasterTimerMode eMasterCurTimerMode; /* ----------------------- Static functions ---------------------------------*/ static UCHAR prvucMBCHAR2BIN( UCHAR ucCharacter ); diff --git a/freemodbus/modbus/include/mb_m.h b/freemodbus/modbus/include/mb_m.h index 9201dea..3c17169 100644 --- a/freemodbus/modbus/include/mb_m.h +++ b/freemodbus/modbus/include/mb_m.h @@ -100,11 +100,15 @@ typedef enum */ typedef enum { - MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */ - MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */ - MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/ + MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */ + MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */ + MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/ } eMBMasterTimerMode; +extern _lock_t xMBMLock; // Modbus lock object + +#define MB_ATOMIC_SECTION CRITICAL_SECTION(xMBMLock) + /* ----------------------- Function prototypes ------------------------------*/ /*! \ingroup modbus * \brief Initialize the Modbus Master protocol stack. @@ -128,7 +132,7 @@ typedef enum * - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error. */ eMBErrorCode eMBMasterSerialInit( eMBMode eMode, UCHAR ucPort, - ULONG ulBaudRate, eMBParity eParity ); + ULONG ulBaudRate, eMBParity eParity ); /*! \ingroup modbus * \brief Initialize the Modbus Master protocol stack for Modbus TCP. @@ -220,7 +224,7 @@ eMBErrorCode eMBMasterPoll( void ); * valid it returns eMBErrorCode::MB_EINVAL. */ eMBErrorCode eMBMasterRegisterCB( UCHAR ucFunctionCode, - pxMBFunctionHandler pxHandler ); + pxMBFunctionHandler pxHandler ); /* ----------------------- Callback -----------------------------------------*/ @@ -261,7 +265,7 @@ eMBErrorCode eMBMasterRegisterCB( UCHAR ucFunctionCode, * ILLEGAL DATA ADDRESS is sent as a response. */ eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs ); + USHORT usNRegs ); /*! \ingroup modbus_registers * \brief Callback function used if a Holding Register value is @@ -290,7 +294,7 @@ eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, * ILLEGAL DATA ADDRESS is sent as a response. */ eMBErrorCode eMBMasterRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs, eMBRegisterMode eMode ); + USHORT usNRegs, eMBRegisterMode eMode ); /*! \ingroup modbus_registers * \brief Callback function used if a Coil Register value is @@ -319,7 +323,7 @@ eMBErrorCode eMBMasterRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, * ILLEGAL DATA ADDRESS is sent as a response. */ eMBErrorCode eMBMasterRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNCoils, eMBRegisterMode eMode ); + USHORT usNCoils, eMBRegisterMode eMode ); /*! \ingroup modbus_registers * \brief Callback function used if a Input Discrete Register value is @@ -342,7 +346,7 @@ eMBErrorCode eMBMasterRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, * ILLEGAL DATA ADDRESS is sent as a response. */ eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNDiscrete ); + USHORT usNDiscrete ); /*! \ingroup modbus *\brief These Modbus functions are called for user when Modbus run in Master Mode. @@ -353,20 +357,20 @@ eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, - USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut ); + USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr, - USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer, - USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut ); + USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer, + USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr, - USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut ); + USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut ); eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut ); @@ -409,6 +413,9 @@ eMBMasterErrorEventType eMBMasterGetErrorType( void ); void vMBMasterSetErrorType( eMBMasterErrorEventType errorType ); eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ); eMBMode ucMBMasterGetCommMode( void ); +BOOL xMBMasterGetLastTransactionInfo( uint64_t *pxTransId, UCHAR *pucDestAddress, + UCHAR *pucFunctionCode, UCHAR *pucException, + USHORT *pusErrorType ); /* ----------------------- Callback -----------------------------------------*/ diff --git a/freemodbus/modbus/include/mbport.h b/freemodbus/modbus/include/mbport.h index c5e9ff2..d397669 100644 --- a/freemodbus/modbus/include/mbport.h +++ b/freemodbus/modbus/include/mbport.h @@ -40,6 +40,7 @@ #include "mbconfig.h" // for options + #ifdef __cplusplus PR_BEGIN_EXTERN_C #endif @@ -92,10 +93,10 @@ typedef enum { } eMBMasterErrorEventType; typedef struct _MbEventType { - eMBMasterEventEnum eEvent; /*!< event itself. */ - uint64_t xTransactionId; /*!< ID of the transaction */ - uint64_t xPostTimestamp; /*!< timestamp of event posted */ - uint64_t xGetTimestamp; /*!< timestamp of event get */ + eMBMasterEventEnum eEvent; /*!< event itself. */ + uint64_t xTransactionId; /*!< ID of the transaction */ + uint64_t xPostTimestamp; /*!< timestamp of event posted */ + uint64_t xGetTimestamp; /*!< timestamp of event get */ } xMBMasterEventType; #endif @@ -207,16 +208,20 @@ void vMBMasterPortTimersDisable( void ); /* ----------------- Callback for the master error process ------------------*/ -void vMBMasterErrorCBRespondTimeout( UCHAR ucDestAddress, const UCHAR* pucPDUData, - USHORT ucPDULength ); +void vMBMasterErrorCBRespondTimeout( uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucSendData, USHORT ucSendLength ); -void vMBMasterErrorCBReceiveData( UCHAR ucDestAddress, const UCHAR* pucPDUData, - USHORT ucPDULength ); +void vMBMasterErrorCBReceiveData( uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength ); -void vMBMasterErrorCBExecuteFunction( UCHAR ucDestAddress, const UCHAR* pucPDUData, - USHORT ucPDULength ); +void vMBMasterErrorCBExecuteFunction( uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength ); -void vMBMasterCBRequestSuccess( void ); +void vMBMasterCBRequestSuccess( uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength ); #endif /* ----------------------- Callback for the protocol stack ------------------*/ /*! diff --git a/freemodbus/modbus/mb_m.c b/freemodbus/modbus/mb_m.c index df1d07e..b39a155 100644 --- a/freemodbus/modbus/mb_m.c +++ b/freemodbus/modbus/mb_m.c @@ -36,15 +36,14 @@ */ /* ----------------------- System includes ----------------------------------*/ -#include #include #include +#include /* ----------------------- Platform includes --------------------------------*/ #include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ - #include "mb_m.h" #include "mbconfig.h" #include "mbframe.h" @@ -69,20 +68,29 @@ #define MB_PORT_HAS_CLOSE 1 #endif -/* ----------------------- Static variables ---------------------------------*/ - -static UCHAR ucMBMasterDestAddress; -static BOOL xMBRunInMasterMode = FALSE; -static volatile eMBMasterErrorEventType eMBMasterCurErrorType; -static volatile USHORT usMasterSendPDULength; -static volatile eMBMode eMBMasterCurrentMode; - /*------------------------ Shared variables ---------------------------------*/ +_lock_t xMBMLock; // base modbus object lock volatile UCHAR ucMasterSndBuf[MB_SERIAL_BUF_SIZE]; volatile UCHAR ucMasterRcvBuf[MB_SERIAL_BUF_SIZE]; -volatile eMBMasterTimerMode eMasterCurTimerMode; -volatile BOOL xFrameIsBroadcast = FALSE; + +static _Atomic USHORT usMasterSendPDULength = 0; +static _Atomic eMBMasterErrorEventType eMBMasterCurErrorType = EV_ERROR_INIT; +static _Atomic BOOL xMBRunInMasterMode = FALSE; +static _Atomic UCHAR ucMBMasterDestAddress = 0; +static _Atomic UCHAR ucLastFunctionCode = 0; +static _Atomic UCHAR usLastFrameError = 0; +static _Atomic eMBException eLastException = MB_EX_NONE; +static _Atomic uint64_t xLastTransactionId = 0; +static _Atomic BOOL xFrameIsBroadcast = FALSE; +static _Atomic eMBMasterTimerMode eMasterCurTimerMode; + +/* ----------------------- Static variables ---------------------------------*/ +static uint64_t xCurTransactionId = 0; +static UCHAR *pucMBSendFrame = NULL; +static UCHAR *pucMBRecvFrame = NULL; +static UCHAR ucRecvAddress = 0; +static eMBMode eMBMasterCurrentMode; static enum { @@ -172,9 +180,19 @@ eMBMasterTCPInit( USHORT ucTCPPort ) peMBMasterFrameSendCur = eMBMasterTCPSend; pxMBMasterPortCBTimerExpired = xMBMasterTCPTimerExpired; pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterTCPPortClose : NULL; - ucMBMasterDestAddress = MB_TCP_PSEUDO_ADDRESS; eMBMasterCurrentMode = MB_TCP; eMBState = STATE_DISABLED; + ucRecvAddress = MB_TCP_PSEUDO_ADDRESS; + xCurTransactionId = 0; + + /* initialize the state values. */ + atomic_init(&usMasterSendPDULength, 0); + atomic_init(&eMBMasterCurErrorType, EV_ERROR_INIT); + atomic_init(&xMBRunInMasterMode, FALSE); + atomic_init(&ucMBMasterDestAddress, MB_TCP_PSEUDO_ADDRESS); + atomic_init(&ucLastFunctionCode, 0); + atomic_init(&usLastFrameError, 0); + atomic_init(&eLastException, MB_EX_NONE); // initialize the OS resource for modbus master. vMBMasterOsResInit(); @@ -240,6 +258,16 @@ eMBMasterSerialInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eP else { eMBState = STATE_DISABLED; + ucRecvAddress = 0; + xCurTransactionId = 0; + /* initialize the state values. */ + atomic_init(&usMasterSendPDULength, 0); + atomic_init(&eMBMasterCurErrorType, EV_ERROR_INIT); + atomic_init(&xMBRunInMasterMode, FALSE); + atomic_init(&ucMBMasterDestAddress, 0); + atomic_init(&ucLastFunctionCode, 0); + atomic_init(&usLastFrameError, 0); + atomic_init(&eLastException, MB_EX_NONE); } /* initialize the OS resource for modbus master. */ vMBMasterOsResInit(); @@ -311,18 +339,14 @@ eMBMasterDisable( void ) eMBErrorCode eMBMasterPoll( void ) { - static UCHAR *ucMBSendFrame = NULL; - static UCHAR *ucMBRcvFrame = NULL; - static UCHAR ucRcvAddress; - static UCHAR ucFunctionCode; - static USHORT usLength; - static eMBException eException; - static uint64_t xCurTransactionId = 0; - int i; - int j; - eMBErrorCode eStatus = MB_ENOERR; + int i; + int j; + eMBErrorCode eStatus = MB_ENOERR; xMBMasterEventType xEvent; eMBMasterErrorEventType errorType; + eMBException eException = MB_EX_NONE; + UCHAR ucFunctionCode = 0; + static USHORT usRecvLength = 0; /* Check if the protocol stack is ready. */ if( eMBState != STATE_ENABLED ) { @@ -343,37 +367,38 @@ eMBMasterPoll( void ) case EV_MASTER_FRAME_TRANSMIT: ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_TRANSMIT", xEvent.xTransactionId); /* Master is busy now. */ - vMBMasterGetPDUSndBuf( &ucMBSendFrame ); - ESP_LOG_BUFFER_HEX_LEVEL("POLL transmit buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG); - eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBSendFrame, usMBMasterGetPDUSndLength() ); + vMBMasterGetPDUSndBuf( &pucMBSendFrame ); + ESP_LOG_BUFFER_HEX_LEVEL("POLL transmit buffer", (void*)pucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG); + eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), pucMBSendFrame, usMBMasterGetPDUSndLength() ); if (eStatus != MB_ENOERR) { vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Frame send error = %d", xEvent.xTransactionId, (unsigned)eStatus ); } xCurTransactionId = xEvent.xTransactionId; + atomic_store(&(xLastTransactionId), xCurTransactionId); break; case EV_MASTER_FRAME_SENT: if (xCurTransactionId == xEvent.xTransactionId) { ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_SENT", xEvent.xTransactionId ); - ESP_LOG_BUFFER_HEX_LEVEL("POLL sent buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEX_LEVEL("POLL sent buffer", (void*)pucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG); } break; case EV_MASTER_FRAME_RECEIVED: ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_RECEIVED", xEvent.xTransactionId ); - eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBRcvFrame, &usLength); + eStatus = peMBMasterFrameReceiveCur( &ucRecvAddress, &pucMBRecvFrame, &usRecvLength); if (xCurTransactionId == xEvent.xTransactionId) { - MB_PORT_CHECK(ucMBSendFrame, 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. - if ( ( eStatus == MB_ENOERR ) && ( ( ucRcvAddress == ucMBMasterGetDestAddress() ) - || ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS) ) ) { - if ( ( ucMBRcvFrame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR ) == ( ucMBSendFrame[MB_PDU_FUNC_OFF] ) ) { + if ( ( eStatus == MB_ENOERR ) && ( ( ucRecvAddress == ucMBMasterGetDestAddress() ) + || ( ucRecvAddress == MB_TCP_PSEUDO_ADDRESS) ) ) { + 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_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBRcvFrame, (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 ); } else { ESP_LOGE( MB_PORT_TAG, "Drop incorrect frame, receive_func(%u) != send_func(%u)", - ucMBRcvFrame[MB_PDU_FUNC_OFF], ucMBSendFrame[MB_PDU_FUNC_OFF]); + pucMBRecvFrame[MB_PDU_FUNC_OFF], pucMBSendFrame[MB_PDU_FUNC_OFF]); vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); } @@ -381,7 +406,7 @@ eMBMasterPoll( void ) vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); 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 { // Ignore the `EV_MASTER_FRAME_RECEIVED` event because the respond timeout occurred @@ -393,15 +418,16 @@ eMBMasterPoll( void ) if (xCurTransactionId == xEvent.xTransactionId) { if ( xMBMasterRequestIsBroadcast() && (( ucMBMasterGetCommMode() == MB_RTU ) || ( ucMBMasterGetCommMode() == MB_ASCII ) ) ) { - ucMBRcvFrame = ucMBSendFrame; + pucMBRecvFrame = pucMBSendFrame; } - MB_PORT_CHECK(ucMBRcvFrame, 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); - ucFunctionCode = ucMBRcvFrame[MB_PDU_FUNC_OFF]; + ucFunctionCode = pucMBRecvFrame[MB_PDU_FUNC_OFF]; + atomic_store(&(ucLastFunctionCode), ucFunctionCode); eException = MB_EX_ILLEGAL_FUNCTION; /* If receive frame has exception. The receive function code highest bit is 1.*/ if (ucFunctionCode & MB_FUNC_ERROR) { - eException = (eMBException)ucMBRcvFrame[MB_PDU_DATA_OFF]; + eException = (eMBException)pucMBRecvFrame[MB_PDU_DATA_OFF]; } else { for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) { @@ -415,20 +441,21 @@ eMBMasterPoll( void ) * the master need execute function for all slave. */ if ( xMBMasterRequestIsBroadcast() ) { - usLength = usMBMasterGetPDUSndLength(); + USHORT usLength = usMBMasterGetPDUSndLength(); for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++) { vMBMasterSetDestAddress(j); - eException = xMasterFuncHandlers[i].pxHandler(ucMBRcvFrame, &usLength); + eException = xMasterFuncHandlers[i].pxHandler(pucMBRecvFrame, &usLength); } } else { - eException = xMasterFuncHandlers[i].pxHandler( ucMBRcvFrame, &usLength ); + eException = xMasterFuncHandlers[i].pxHandler(pucMBRecvFrame, &usRecvLength); } vMBMasterSetCBRunInMasterMode( FALSE ); break; } } } + atomic_store(&eLastException, eException); /* If master has exception, will send error process event. Otherwise the master is idle.*/ if ( eException != MB_EX_NONE ) { vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION ); @@ -449,23 +476,35 @@ eMBMasterPoll( void ) ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_ERROR_PROCESS", xEvent.xTransactionId); /* Execute specified error process callback function. */ errorType = eMBMasterGetErrorType( ); - vMBMasterGetPDUSndBuf( &ucMBSendFrame ); + vMBMasterGetPDUSndBuf( &pucMBSendFrame ); switch ( errorType ) { case EV_ERROR_RESPOND_TIMEOUT: - vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ), - ucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + vMBMasterErrorCBRespondTimeout( xEvent.xTransactionId, + ucMBMasterGetDestAddress( ), + pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + atomic_store(&usLastFrameError, errorType); break; case EV_ERROR_RECEIVE_DATA: - vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ), - ucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + vMBMasterErrorCBReceiveData( xEvent.xTransactionId, + ucMBMasterGetDestAddress( ), + pucMBRecvFrame, usRecvLength, + pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + atomic_store(&usLastFrameError, errorType); break; case EV_ERROR_EXECUTE_FUNCTION: - vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ), - ucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + vMBMasterErrorCBExecuteFunction( xEvent.xTransactionId, + ucMBMasterGetDestAddress( ), + pucMBRecvFrame, usRecvLength, + pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + atomic_store(&usLastFrameError, errorType); break; case EV_ERROR_OK: - vMBMasterCBRequestSuccess( ); + vMBMasterCBRequestSuccess( xEvent.xTransactionId, + ucMBMasterGetDestAddress( ), + pucMBRecvFrame, usRecvLength, + pucMBSendFrame, usMBMasterGetPDUSndLength( ) ); + atomic_store(&usLastFrameError, errorType); break; default: ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":incorrect error type = %d.", xEvent.xTransactionId, (int)errorType); @@ -500,7 +539,7 @@ BOOL xMBMasterGetCBRunInMasterMode( void ) // Set whether the Modbus Master is run in master mode. void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode ) { - atomic_store(&(xMBRunInMasterMode), IsMasterMode); + atomic_store(&xMBRunInMasterMode, IsMasterMode); } // Get Modbus Master send destination address. @@ -512,7 +551,7 @@ UCHAR ucMBMasterGetDestAddress( void ) // Set Modbus Master send destination address. void vMBMasterSetDestAddress( UCHAR Address ) { - atomic_store(&(ucMBMasterDestAddress), Address); + atomic_store(&ucMBMasterDestAddress, Address); } // Get Modbus Master current error event type. @@ -524,7 +563,7 @@ eMBMasterErrorEventType inline eMBMasterGetErrorType( void ) // Set Modbus Master current error event type. void IRAM_ATTR vMBMasterSetErrorType( eMBMasterErrorEventType errorType ) { - atomic_store(&(eMBMasterCurErrorType), errorType); + atomic_store(&eMBMasterCurErrorType, errorType); } /* Get Modbus Master send PDU's buffer address pointer.*/ @@ -536,7 +575,7 @@ void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame ) /* Set Modbus Master send PDU's buffer length.*/ void vMBMasterSetPDUSndLength( USHORT SendPDULength ) { - atomic_store(&(usMasterSendPDULength), SendPDULength); + atomic_store(&usMasterSendPDULength, SendPDULength); } /* Get Modbus Master send PDU's buffer length.*/ @@ -548,7 +587,7 @@ USHORT usMBMasterGetPDUSndLength( void ) /* Set Modbus Master current timer mode.*/ void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode ) { - atomic_store(&(eMasterCurTimerMode), eMBTimerMode); + atomic_store(&eMasterCurTimerMode, eMBTimerMode); } /* Get Modbus Master current timer mode.*/ @@ -560,13 +599,13 @@ eMBMasterTimerMode MB_PORT_ISR_ATTR xMBMasterGetCurTimerMode( void ) /* The master request is broadcast? */ BOOL MB_PORT_ISR_ATTR xMBMasterRequestIsBroadcast( void ) { - return xFrameIsBroadcast; + return atomic_load(&xFrameIsBroadcast); } /* The master request is broadcast? */ void vMBMasterRequestSetType( BOOL xIsBroadcast ) { - atomic_store(&(xFrameIsBroadcast), xIsBroadcast); + atomic_store(&xFrameIsBroadcast, xIsBroadcast); } // Get Modbus Master communication mode. @@ -575,4 +614,23 @@ eMBMode ucMBMasterGetCommMode(void) 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) { + MB_ATOMIC_SECTION { + *pxTransId = atomic_load(&xLastTransactionId); + *pucDestAddress = atomic_load(&ucMBMasterDestAddress); + *pucFunctionCode = atomic_load(&ucLastFunctionCode); + *pucException = atomic_load(&eLastException); + *pusErrorType = atomic_load(&usLastFrameError); + } + } + return xState; +} + #endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED diff --git a/freemodbus/port/port.c b/freemodbus/port/port.c index e73e81f..e89b50d 100644 --- a/freemodbus/port/port.c +++ b/freemodbus/port/port.c @@ -39,7 +39,6 @@ /* ----------------------- Modbus includes ----------------------------------*/ #include "freertos/FreeRTOS.h" #include "freertos/queue.h" -#include "sys/lock.h" #include "port.h" /* ----------------------- Variables ----------------------------------------*/ @@ -47,13 +46,24 @@ static _lock_t s_port_lock; static UCHAR ucPortMode = 0; /* ----------------------- Start implementation -----------------------------*/ -inline void +INLINE int lock_obj(_lock_t *plock) +{ + _lock_acquire(plock); + return 1; +} + +INLINE void unlock_obj(_lock_t *plock) +{ + _lock_release(plock); +} + +INLINE void vMBPortEnterCritical(void) { _lock_acquire(&s_port_lock); } -inline void +INLINE void vMBPortExitCritical(void) { _lock_release(&s_port_lock); diff --git a/freemodbus/port/port.h b/freemodbus/port/port.h index 418876a..aee2a63 100644 --- a/freemodbus/port/port.h +++ b/freemodbus/port/port.h @@ -37,6 +37,8 @@ #ifndef PORT_COMMON_H_ #define PORT_COMMON_H_ +#include "sys/lock.h" + #include "freertos/FreeRTOS.h" #include "freertos/queue.h" // for queue @@ -52,7 +54,7 @@ #include "mbconfig.h" -#define INLINE inline +#define INLINE inline __attribute__((always_inline)) #define PR_BEGIN_EXTERN_C extern "C" { #define PR_END_EXTERN_C } @@ -105,6 +107,8 @@ #define MB_TCP_DEBUG (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) // Enable legacy debug output in TCP module. +#define MB_ATTR_WEAK __attribute__ ((weak)) + #define MB_TCP_GET_FIELD(buffer, field) ((USHORT)((buffer[field] << 8U) | buffer[field + 1])) #define MB_PORT_CHECK(a, ret_val, str, ...) \ @@ -121,6 +125,35 @@ } \ } while(0) +int lock_obj(_lock_t *plock); +void unlock_obj(_lock_t *plock); + +#define CRITICAL_SECTION_INIT(lock) \ + do \ + { \ + _lock_init((_lock_t *)&lock); \ + } while (0) + +#define CRITICAL_SECTION_CLOSE(lock) \ + do \ + { \ + _lock_close((_lock_t *)&lock); \ + } while (0) + +#define CRITICAL_SECTION_LOCK(lock) \ + do \ + { \ + lock_obj((_lock_t *)&lock); \ + } while (0) + +#define CRITICAL_SECTION_UNLOCK(lock) \ + do \ + { \ + unlock_obj((_lock_t *)&lock); \ + } while (0) + +#define CRITICAL_SECTION(lock) for (int st = lock_obj((_lock_t *)&lock); (st > 0); unlock_obj((_lock_t *)&lock), st = -1) + #ifdef __cplusplus PR_BEGIN_EXTERN_C #endif /* __cplusplus */ @@ -198,6 +231,22 @@ UCHAR ucMBPortGetMode( void ); BOOL xMBPortSerialWaitEvent(QueueHandle_t xMbUartQueue, uart_event_t* pxEvent, ULONG xTimeout); +/** + * This is modbus master user error handling funcion. + * If it is defined in the user application, then helps to handle the errors + * and received/sent buffers to transfer as well as handle the slave exception codes. + * + * @param xTransId - the identification of the trasaction + * @param ucDestAddress destination salve address + * @param usError - the error code, see the enumeration eMBMasterErrorEventType + * @param pucRecvData current receive data pointer + * @param ucRecvLength current length of receive buffer + * @param pucSendData Send buffer data + * @param ucSendLength Send buffer length + */ +void vMBMasterErrorCBUserHandler( uint64_t xTransId, USHORT usError, UCHAR ucDestAddress, const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength ) MB_ATTR_WEAK; + #ifdef __cplusplus PR_END_EXTERN_C #endif /* __cplusplus */ diff --git a/freemodbus/port/portevent_m.c b/freemodbus/port/portevent_m.c index 664371e..ba981d2 100644 --- a/freemodbus/port/portevent_m.c +++ b/freemodbus/port/portevent_m.c @@ -35,7 +35,6 @@ */ /* ----------------------- Modbus includes ----------------------------------*/ - #include #include "freertos/FreeRTOS.h" @@ -66,7 +65,7 @@ static EventGroupHandle_t xEventGroupMasterHdl; static EventGroupHandle_t xEventGroupMasterConfirmHdl; static QueueHandle_t xQueueMasterHdl; -static uint64_t xTransactionID = 0; +static _Atomic uint64_t xTransactionID = 0; /* ----------------------- Start implementation -----------------------------*/ @@ -80,7 +79,7 @@ xMBMasterPortEventInit( void ) xQueueMasterHdl = xQueueCreate(MB_EVENT_QUEUE_SIZE, sizeof(xMBMasterEventType)); MB_PORT_CHECK(xQueueMasterHdl, FALSE, "mb stack event group creation error."); vQueueAddToRegistry(xQueueMasterHdl, "MbMasterPortEventQueue"); - xTransactionID = 0; + atomic_init(&xTransactionID, 0); return TRUE; } @@ -191,30 +190,49 @@ void vMBMasterRunResRelease( void ) * This is modbus master respond timeout error process callback function. * @note There functions will block modbus master poll while execute OS waiting. * + * @param xTransId - the identification of the trasaction * @param ucDestAddress destination salve address - * @param pucPDUData PDU buffer data - * @param ucPDULength PDU buffer length + * @param pucRecvData current receive data pointer + * @param ucRecvLength current length of receive buffer + * @param pucSendData Send buffer data + * @param ucSendLength Send buffer length * */ -void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength) +void vMBMasterErrorCBRespondTimeout(uint64_t xTransId, UCHAR ucDestAddress, const UCHAR* pucSendData, USHORT ucSendLength) { (void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_RESPOND_TIMEOUT ); ESP_LOGD(MB_PORT_TAG,"%s:Callback respond timeout.", __func__); + if (vMBMasterErrorCBUserHandler) { + vMBMasterErrorCBUserHandler( xTransId, + (USHORT)EV_ERROR_RESPOND_TIMEOUT, ucDestAddress, + NULL, 0, + pucSendData, ucSendLength ); + } } /** * This is modbus master receive data error process callback function. * @note There functions will block modbus master poll while execute OS waiting. * + * @param xTransId - the identification of the trasaction * @param ucDestAddress destination salve address - * @param pucPDUData PDU buffer data - * @param ucPDULength PDU buffer length + * @param pucRecvData current receive data pointer + * @param ucRecvLength current length of receive buffer + * @param pucSendData Send buffer data + * @param ucSendLength Send buffer length */ -void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength) +void vMBMasterErrorCBReceiveData(uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength) { (void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_RECEIVE_DATA ); - ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data timeout failure.", __func__); - ESP_LOG_BUFFER_HEX_LEVEL("Err rcv buf", (void *)pucPDUData, (USHORT)ucPDULength, ESP_LOG_DEBUG); + ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data failure.", __func__); + if (vMBMasterErrorCBUserHandler) { + vMBMasterErrorCBUserHandler( xTransId, + (USHORT)EV_ERROR_RECEIVE_DATA, ucDestAddress, + pucRecvData, ucRecvLength, + pucSendData, ucSendLength ); + } } /** @@ -222,27 +240,52 @@ void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, U * @note There functions will block modbus master poll while execute OS waiting. * So,for real-time of system.Do not execute too much waiting process. * + * @param xTransId - the identification of the trasaction * @param ucDestAddress destination salve address - * @param pucPDUData PDU buffer data - * @param ucPDULength PDU buffer length + * @param pucRecvData current receive data pointer + * @param ucRecvLength current length of receive buffer + * @param pucSendData Send buffer data + * @param ucSendLength Send buffer length * */ -void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength) +void vMBMasterErrorCBExecuteFunction(uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength) { xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_EXECUTE_FUNCTION ); ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data handler failure.", __func__); - ESP_LOG_BUFFER_HEX_LEVEL("Exec func buf", (void*)pucPDUData, (USHORT)ucPDULength, ESP_LOG_DEBUG); + if (vMBMasterErrorCBUserHandler) { + vMBMasterErrorCBUserHandler( xTransId, + (USHORT)EV_ERROR_EXECUTE_FUNCTION, ucDestAddress, + pucRecvData, ucRecvLength, + pucSendData, ucSendLength ); + } } /** * This is modbus master request process success callback function. * @note There functions will block modbus master poll while execute OS waiting. * So,for real-time of system. Do not execute too much waiting process. + * + * @param xTransId - the identification of the trasaction + * @param ucDestAddress destination salve address + * @param pucRecvData current receive data pointer + * @param ucRecvLength current length of receive buffer + * @param pucSendData Send buffer data + * @param ucSendLength Send buffer length */ -void vMBMasterCBRequestSuccess( void ) +void vMBMasterCBRequestSuccess(uint64_t xTransId, UCHAR ucDestAddress, + const UCHAR* pucRecvData, USHORT ucRecvLength, + const UCHAR* pucSendData, USHORT ucSendLength) { (void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_PROCESS_SUCCESS ); ESP_LOGD(MB_PORT_TAG,"%s: Callback request success.", __func__); + if (vMBMasterErrorCBUserHandler) { + vMBMasterErrorCBUserHandler( xTransId, + (USHORT)EV_ERROR_OK, ucDestAddress, + pucRecvData, ucRecvLength, + pucSendData, ucSendLength ); + } } /** diff --git a/idf_component.yml b/idf_component.yml index 631ee0e..00296d5 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -9,3 +9,5 @@ files: - "docs" - "test/**/*" - "test" + - "arch" + - "arch/**/*" diff --git a/test/serial/mb_serial_master/main/CMakeLists.txt b/test/serial/mb_serial_master/main/CMakeLists.txt index f9ab7f6..9a6cf30 100644 --- a/test/serial/mb_serial_master/main/CMakeLists.txt +++ b/test/serial/mb_serial_master/main/CMakeLists.txt @@ -2,3 +2,4 @@ set(PROJECT_NAME "modbus_master") idf_component_register(SRCS "master.c" INCLUDE_DIRS ".") + diff --git a/test/serial/mb_serial_master/main/master.c b/test/serial/mb_serial_master/main/master.c index e6e0fd1..63d3e0a 100644 --- a/test/serial/mb_serial_master/main/master.c +++ b/test/serial/mb_serial_master/main/master.c @@ -392,6 +392,13 @@ static void master_operation_func(void *arg) alarm_state = true; 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)) { if (TEST_VERIFY_VALUES(param_descriptor, (uint8_t *)temp_data_ptr) == ESP_OK) { uint8_t state = *(uint8_t *)temp_data_ptr; @@ -483,6 +490,25 @@ static esp_err_t master_init(void) return err; } +#define MB_PDU_DATA_OFF 1 + +#define EV_ERROR_EXECUTE_FUNCTION 3 + +void vMBMasterErrorCBUserHandler( uint64_t xTransId, uint16_t usError, uint8_t ucDestAddress, const uint8_t *pucRecvData, uint16_t ucRecvLength, + const uint8_t *pucSendData, uint16_t ucSendLength ) +{ + ESP_LOGW("USER_ERR_CB", "The transaction %" PRIu64 ", error type: %u", xTransId, usError); + 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[MB_PDU_DATA_OFF]); + } + if (pucRecvData && ucRecvLength) { + ESP_LOG_BUFFER_HEX_LEVEL("Received buffer", (void *)pucRecvData, (uint16_t)ucRecvLength, ESP_LOG_WARN); + } + if (pucSendData && ucSendLength) { + ESP_LOG_BUFFER_HEX_LEVEL("Sent buffer", (void *)pucSendData, (uint16_t)ucSendLength, ESP_LOG_WARN); + } +} + void app_main(void) { // Initialization of device peripheral and objects