freemodbus: fix nvs access failure

place timer handler functions into IRAM
update timer port handlers
fix communication issues
fix offset issue in example
add kconfig option to place handlers into IRAM
This commit is contained in:
Alex Lisitsyn 2019-11-08 16:55:42 +08:00 committed by Angus Gratton
parent ba72de2099
commit 1ab9e81729
18 changed files with 187 additions and 160 deletions

View file

@ -113,7 +113,7 @@ menu "Modbus configuration"
range 0 1 range 0 1
default 0 default 0
help help
Modbus Timer group number that is used for timeout measurement. Modbus Timer group number that is used for timeout measurement.
config FMB_TIMER_INDEX config FMB_TIMER_INDEX
int "Modbus Timer index in the group" int "Modbus Timer index in the group"
@ -122,4 +122,14 @@ menu "Modbus configuration"
help help
Modbus Timer Index in the group that is used for timeout measurement. Modbus Timer Index in the group that is used for timeout measurement.
config FMB_ISR_IN_IRAM
bool "Place interrupt handlers into IRAM"
default y
select UART_ISR_IN_IRAM
help
This option places Modbus IRQ handlers into IRAM.
This allows to avoid delays related to processing of non-IRAM-safe interrupts
during a flash write operation (NVS updating a value, or some other
flash API which has to perform an read/write operation and disable CPU cache).
endmenu endmenu

View file

@ -45,7 +45,7 @@ esp_err_t mbc_master_init(mb_port_type_t port_type, void** handler)
MB_MASTER_CHECK((port_handler != NULL), MB_MASTER_CHECK((port_handler != NULL),
ESP_ERR_INVALID_STATE, ESP_ERR_INVALID_STATE,
"Master interface initialization failure, error=(0x%x), port type=(0x%x).", "Master interface initialization failure, error=(0x%x), port type=(0x%x).",
(uint16_t)error, (uint16_t)port_type); error, (uint16_t)port_type);
if ((port_handler != NULL) && (error == ESP_OK)) { if ((port_handler != NULL) && (error == ESP_OK)) {
master_interface_ptr = (mb_master_interface_t*) port_handler; master_interface_ptr = (mb_master_interface_t*) port_handler;
@ -106,9 +106,9 @@ esp_err_t mbc_master_get_parameter(uint16_t cid, char* name, uint8_t* value, uin
"Master interface is not correctly initialized."); "Master interface is not correctly initialized.");
error = master_interface_ptr->get_parameter(cid, name, value, type); error = master_interface_ptr->get_parameter(cid, name, value, type);
MB_MASTER_CHECK((error == ESP_OK), MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE, error,
"SERIAL master get parameter failure error=(0x%x).", "SERIAL master get parameter failure error=(0x%x) (%s).",
(uint16_t)error); error, esp_err_to_name(error));
return error; return error;
} }
@ -126,10 +126,10 @@ esp_err_t mbc_master_send_request(mb_param_request_t* request, void* data_ptr)
"Master interface is not correctly initialized."); "Master interface is not correctly initialized.");
error = master_interface_ptr->send_request(request, data_ptr); error = master_interface_ptr->send_request(request, data_ptr);
MB_MASTER_CHECK((error == ESP_OK), MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE, error,
"SERIAL master get parameter failure error=(0x%x).", "SERIAL master send request failure error=(0x%x) (%s).",
(uint16_t)error); error, esp_err_to_name(error));
return error; return ESP_OK;
} }
/** /**
@ -146,10 +146,10 @@ esp_err_t mbc_master_set_descriptor(const mb_parameter_descriptor_t* descriptor,
"Master interface is not correctly initialized."); "Master interface is not correctly initialized.");
error = master_interface_ptr->set_descriptor(descriptor, num_elements); error = master_interface_ptr->set_descriptor(descriptor, num_elements);
MB_MASTER_CHECK((error == ESP_OK), MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE, error,
"SERIAL master set descriptor failure error=(0x%x).", "SERIAL master set descriptor failure error=(0x%x) (%s).",
(uint16_t)error); error, esp_err_to_name(error));
return error; return ESP_OK;
} }
/** /**
@ -166,10 +166,10 @@ esp_err_t mbc_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uin
"Master interface is not correctly initialized."); "Master interface is not correctly initialized.");
error = master_interface_ptr->set_parameter(cid, name, value, type); error = master_interface_ptr->set_parameter(cid, name, value, type);
MB_MASTER_CHECK((error == ESP_OK), MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE, error,
"SERIAL master set parameter failure error=(0x%x).", "SERIAL master set parameter failure error=(0x%x) (%s).",
(uint16_t)error); error, esp_err_to_name(error));
return error; return ESP_OK;
} }
/** /**
@ -186,10 +186,10 @@ esp_err_t mbc_master_setup(void* comm_info)
"Master interface is not correctly initialized."); "Master interface is not correctly initialized.");
error = master_interface_ptr->setup(comm_info); error = master_interface_ptr->setup(comm_info);
MB_MASTER_CHECK((error == ESP_OK), MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE, error,
"SERIAL master setup failure error=(0x%x).", "SERIAL master setup failure error=(0x%x) (%s).",
(uint16_t)error); error, esp_err_to_name(error));
return error; return ESP_OK;
} }
/** /**
@ -206,10 +206,10 @@ esp_err_t mbc_master_start(void)
"Master interface is not correctly initialized."); "Master interface is not correctly initialized.");
error = master_interface_ptr->start(); error = master_interface_ptr->start();
MB_MASTER_CHECK((error == ESP_OK), MB_MASTER_CHECK((error == ESP_OK),
ESP_ERR_INVALID_STATE, error,
"SERIAL master start failure error=(0x%x).", "SERIAL master start failure error=(0x%x) (%s).",
(uint16_t)error); error, esp_err_to_name(error));
return error; return ESP_OK;
} }
eMBErrorCode eMBMasterRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBMasterRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress,

View file

@ -113,7 +113,7 @@ eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eP
ENTER_CRITICAL_SECTION( ); ENTER_CRITICAL_SECTION( );
ucMBLFCharacter = MB_ASCII_DEFAULT_LF; ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE ) if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
{ {
eStatus = MB_EPORTERR; eStatus = MB_EPORTERR;
} }
@ -388,27 +388,21 @@ xMBASCIITransmitFSM( void )
* been sent. */ * been sent. */
case STATE_TX_NOTIFY: case STATE_TX_NOTIFY:
eSndState = STATE_TX_IDLE; eSndState = STATE_TX_IDLE;
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT ); xMBPortEventPost( EV_FRAME_SENT );
xNeedPoll = TRUE;
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBPortSerialEnable( TRUE, FALSE );
eSndState = STATE_TX_IDLE;
break; break;
/* We should not get a transmitter event if the transmitter is in /* We should not get a transmitter event if the transmitter is in
* idle state. */ * idle state. */
case STATE_TX_IDLE: case STATE_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBPortSerialEnable( TRUE, FALSE );
break; break;
} }
return xNeedPoll; return xNeedPoll;
} }
BOOL BOOL MB_PORT_ISR_ATTR xMBASCIITimerT1SExpired( void )
xMBASCIITimerT1SExpired( void )
{ {
switch ( eRcvState ) switch ( eRcvState )
{ {
@ -421,7 +415,8 @@ xMBASCIITimerT1SExpired( void )
break; break;
default: default:
assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) ); assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF )
|| (eRcvState == STATE_RX_IDLE ));
break; break;
} }
vMBPortTimersDisable( ); vMBPortTimersDisable( );

View file

@ -130,6 +130,9 @@ PR_BEGIN_EXTERN_C
/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */ /*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 ) #define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
/*! \brief Check the option to place handlers into IRAM */
#define MB_ISR_IN_IRAM ( CONFIG_FMB_ISR_IN_IRAM )
/*! @} */ /*! @} */
#ifdef __cplusplus #ifdef __cplusplus
PR_END_EXTERN_C PR_END_EXTERN_C

View file

@ -37,6 +37,20 @@
PR_BEGIN_EXTERN_C PR_BEGIN_EXTERN_C
#endif #endif
#if CONFIG_UART_ISR_IN_IRAM
#define MB_PORT_SERIAL_ISR_FLAG ESP_INTR_FLAG_IRAM
#else
#define MB_PORT_SERIAL_ISR_FLAG ESP_INTR_FLAG_LOWMED
#endif
#if MB_ISR_IN_IRAM
#define MB_PORT_ISR_ATTR IRAM_ATTR
#define MB_PORT_TIMER_ISR_FLAG ESP_INTR_FLAG_IRAM
#else
#define MB_PORT_ISR_ATTR
#define MB_PORT_TIMER_ISR_FLAG ESP_INTR_FLAG_LOWMED
#endif
/* ----------------------- Type definitions ---------------------------------*/ /* ----------------------- Type definitions ---------------------------------*/
typedef enum typedef enum
@ -47,7 +61,7 @@ typedef enum
EV_FRAME_SENT = 0x08 /*!< Frame sent. */ EV_FRAME_SENT = 0x08 /*!< Frame sent. */
} eMBEventType; } eMBEventType;
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 #if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED
typedef enum { typedef enum {
EV_MASTER_NO_EVENT = 0x0000, EV_MASTER_NO_EVENT = 0x0000,
EV_MASTER_READY = 0x0001, /*!< Startup finished. */ EV_MASTER_READY = 0x0001, /*!< Startup finished. */

View file

@ -48,7 +48,7 @@
#include "mbrtu.h" #include "mbrtu.h"
#endif #endif
#if MB_MASTER_ASCII_ENABLED == 1 #if MB_MASTER_ASCII_ENABLED == 1
#include "mbascii.h" #include "mbascii_m.h"
#endif #endif
#if MB_MASTER_TCP_ENABLED == 1 #if MB_MASTER_TCP_ENABLED == 1
#include "mbtcp.h" #include "mbtcp.h"
@ -56,7 +56,6 @@
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 #if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#ifndef MB_PORT_HAS_CLOSE #ifndef MB_PORT_HAS_CLOSE
#define MB_PORT_HAS_CLOSE 1 #define MB_PORT_HAS_CLOSE 1
#endif #endif
@ -269,15 +268,13 @@ eMBMasterPoll( void )
eMBMasterErrorEventType errorType; eMBMasterErrorEventType errorType;
/* Check if the protocol stack is ready. */ /* Check if the protocol stack is ready. */
if( eMBState != STATE_ENABLED ) if( eMBState != STATE_ENABLED ) {
{
return MB_EILLSTATE; return MB_EILLSTATE;
} }
/* Check if there is a event available. If not return control to caller. /* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */ * Otherwise we will handle the event. */
if( xMBMasterPortEventGet( &eEvent ) == TRUE ) if( xMBMasterPortEventGet( &eEvent ) == TRUE ) {
{
switch ( eEvent ) switch ( eEvent )
{ {
case EV_MASTER_NO_EVENT: case EV_MASTER_NO_EVENT:
@ -303,13 +300,10 @@ eMBMasterPoll( void )
case EV_MASTER_FRAME_RECEIVED: case EV_MASTER_FRAME_RECEIVED:
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength ); eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
// 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 ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) ) {
{
ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, eStatus); ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, eStatus);
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE ); ( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
} } else {
else
{
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
ESP_LOGD(MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).", __func__, ucRcvAddress, eStatus); ESP_LOGD(MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).", __func__, ucRcvAddress, eStatus);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
@ -322,13 +316,10 @@ eMBMasterPoll( void )
/* 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 >> 7) { if(ucFunctionCode >> 7) {
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF]; eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
} } else {
else for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++) {
{
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
{
/* No more function handlers registered. Abort. */ /* No more function handlers registered. Abort. */
if (xMasterFuncHandlers[i].ucFunctionCode == 0) { if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
break; break;
} }
else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) { else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
@ -342,8 +333,7 @@ eMBMasterPoll( void )
vMBMasterSetDestAddress(j); vMBMasterSetDestAddress(j);
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength); eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
} }
} } else {
else {
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength); eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
} }
vMBMasterSetCBRunInMasterMode(FALSE); vMBMasterSetCBRunInMasterMode(FALSE);
@ -355,8 +345,7 @@ eMBMasterPoll( void )
if (eException != MB_EX_NONE) { if (eException != MB_EX_NONE) {
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION); vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
} } else {
else {
vMBMasterCBRequestSuccess( ); vMBMasterCBRequestSuccess( );
vMBMasterRunResRelease( ); vMBMasterRunResRelease( );
} }
@ -366,8 +355,7 @@ eMBMasterPoll( void )
/* Master is busy now. */ /* Master is busy now. */
vMBMasterGetPDUSndBuf( &ucMBFrame ); vMBMasterGetPDUSndBuf( &ucMBFrame );
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() ); eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
if (eStatus != MB_ENOERR) if (eStatus != MB_ENOERR) {
{
ESP_LOGD(MB_PORT_TAG, "%s:Frame send error. %d", __func__, eStatus); ESP_LOGD(MB_PORT_TAG, "%s:Frame send error. %d", __func__, eStatus);
} }
@ -438,7 +426,7 @@ eMBMasterErrorEventType eMBMasterGetErrorType( void )
} }
// Set Modbus Master current error event type. // Set Modbus Master current error event type.
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType ) void IRAM_ATTR vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
{ {
eMBMasterCurErrorType = errorType; eMBMasterCurErrorType = errorType;
} }

View file

@ -249,7 +249,7 @@ xMBRTUReceiveFSM( void )
/* In the idle state we wait for a new character. If a character /* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the * is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE. * receiver is in the state STATE_RX_RCV.
*/ */
case STATE_RX_IDLE: case STATE_RX_IDLE:
usRcvBufferPos = 0; usRcvBufferPos = 0;
@ -292,8 +292,6 @@ xMBRTUTransmitFSM( void )
/* We should not get a transmitter event if the transmitter is in /* We should not get a transmitter event if the transmitter is in
* idle state. */ * idle state. */
case STATE_TX_IDLE: case STATE_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBPortSerialEnable( TRUE, FALSE );
break; break;
case STATE_TX_XMIT: case STATE_TX_XMIT:
@ -306,11 +304,10 @@ xMBRTUTransmitFSM( void )
} }
else else
{ {
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT ); xMBPortEventPost( EV_FRAME_SENT );
/* Disable transmitter. This prevents another transmit buffer xNeedPoll = TRUE;
* empty interrupt. */
vMBPortSerialEnable( TRUE, FALSE );
eSndState = STATE_TX_IDLE; eSndState = STATE_TX_IDLE;
vMBPortTimersEnable( );
} }
break; break;
} }
@ -318,7 +315,7 @@ xMBRTUTransmitFSM( void )
return xNeedPoll; return xNeedPoll;
} }
BOOL BOOL MB_PORT_ISR_ATTR
xMBRTUTimerT35Expired( void ) xMBRTUTimerT35Expired( void )
{ {
BOOL xNeedPoll = FALSE; BOOL xNeedPoll = FALSE;
@ -342,8 +339,7 @@ xMBRTUTimerT35Expired( void )
/* Function called in an illegal state. */ /* Function called in an illegal state. */
default: default:
assert( ( eRcvState == STATE_RX_INIT ) || assert( ( eRcvState == STATE_RX_IDLE ) || ( eRcvState == STATE_RX_ERROR ) );
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
} }
vMBPortTimersDisable( ); vMBPortTimersDisable( );

View file

@ -69,12 +69,15 @@ typedef enum
STATE_M_TX_XFWR, /*!< Transmitter is in transfer finish and wait receive state. */ STATE_M_TX_XFWR, /*!< Transmitter is in transfer finish and wait receive state. */
} eMBMasterSndState; } eMBMasterSndState;
/*------------------------ Shared variables ---------------------------------*/
volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
/* ----------------------- Static variables ---------------------------------*/ /* ----------------------- Static variables ---------------------------------*/
static volatile eMBMasterSndState eSndState; static volatile eMBMasterSndState eSndState;
static volatile eMBMasterRcvState eRcvState; static volatile eMBMasterRcvState eRcvState;
static volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
static volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
static volatile USHORT usMasterSendPDULength; static volatile USHORT usMasterSendPDULength;
static volatile UCHAR *pucMasterSndBufferCur; static volatile UCHAR *pucMasterSndBufferCur;
@ -260,7 +263,7 @@ xMBMasterRTUReceiveFSM( void )
/* In the idle state we wait for a new character. If a character /* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the * is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE and disable early * receiver is in the state STATE_M_RX_RCV and disable early
* the timer of respond timeout . * the timer of respond timeout .
*/ */
case STATE_M_RX_IDLE: case STATE_M_RX_IDLE:
@ -310,11 +313,10 @@ xMBMasterRTUTransmitFSM( void )
/* We should not get a transmitter event if the transmitter is in /* We should not get a transmitter event if the transmitter is in
* idle state. */ * idle state. */
case STATE_M_TX_XFWR: case STATE_M_TX_XFWR:
xNeedPoll = TRUE;
break; break;
case STATE_M_TX_IDLE: case STATE_M_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBMasterPortSerialEnable( TRUE, FALSE );
break; break;
case STATE_M_TX_XMIT: case STATE_M_TX_XMIT:
@ -328,9 +330,6 @@ xMBMasterRTUTransmitFSM( void )
else else
{ {
xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE; xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBMasterPortSerialEnable( TRUE, FALSE );
eSndState = STATE_M_TX_XFWR; eSndState = STATE_M_TX_XFWR;
/* If the frame is broadcast ,master will enable timer of convert delay, /* If the frame is broadcast ,master will enable timer of convert delay,
* else master will enable timer of respond timeout. */ * else master will enable timer of respond timeout. */
@ -342,7 +341,6 @@ xMBMasterRTUTransmitFSM( void )
{ {
vMBMasterPortTimersRespondTimeoutEnable( ); vMBMasterPortTimersRespondTimeoutEnable( );
} }
xNeedPoll = TRUE;
} }
break; break;
} }
@ -350,8 +348,7 @@ xMBMasterRTUTransmitFSM( void )
return xNeedPoll; return xNeedPoll;
} }
BOOL BOOL MB_PORT_ISR_ATTR xMBMasterRTUTimerExpired(void)
xMBMasterRTUTimerExpired(void)
{ {
BOOL xNeedPoll = FALSE; BOOL xNeedPoll = FALSE;
@ -395,8 +392,7 @@ xMBMasterRTUTimerExpired(void)
break; break;
/* Function called in an illegal state. */ /* Function called in an illegal state. */
default: default:
assert( assert(( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
break; break;
} }
eSndState = STATE_M_TX_IDLE; eSndState = STATE_M_TX_IDLE;

View file

@ -30,7 +30,7 @@
#define MB_PORT_CHECK(a, ret_val, str, ...) \ #define MB_PORT_CHECK(a, ret_val, str, ...) \
if (!(a)) { \ if (!(a)) { \
ESP_LOGE(MB_PORT_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ ESP_LOGE(MB_PORT_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \ return ret_val; \
} }
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -56,7 +56,7 @@
/* ----------------------- Variables ----------------------------------------*/ /* ----------------------- Variables ----------------------------------------*/
static xQueueHandle xQueueHdl; static xQueueHandle xQueueHdl;
#define MB_EVENT_QUEUE_SIZE (1) #define MB_EVENT_QUEUE_SIZE (6)
#define MB_EVENT_QUEUE_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_EVENT_QUEUE_TIMEOUT)) #define MB_EVENT_QUEUE_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_EVENT_QUEUE_TIMEOUT))
/* ----------------------- Start implementation -----------------------------*/ /* ----------------------- Start implementation -----------------------------*/
@ -82,21 +82,27 @@ vMBPortEventClose( void )
} }
} }
BOOL BOOL MB_PORT_ISR_ATTR
xMBPortEventPost( eMBEventType eEvent ) xMBPortEventPost( eMBEventType eEvent )
{ {
BOOL bStatus = TRUE; BaseType_t xStatus, xHigherPriorityTaskWoken = pdFALSE;
assert(xQueueHdl != NULL); assert(xQueueHdl != NULL);
if( (BOOL)xPortInIsrContext() == TRUE ) if( (BOOL)xPortInIsrContext() == TRUE )
{ {
xQueueSendFromISR(xQueueHdl, (const void*)&eEvent, pdFALSE); xStatus = xQueueSendFromISR(xQueueHdl, (const void*)&eEvent, &xHigherPriorityTaskWoken);
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "%s: Post message failure.", __func__);
if ( xHigherPriorityTaskWoken )
{
portYIELD_FROM_ISR();
}
} }
else else
{ {
xQueueSend(xQueueHdl, (const void*)&eEvent, MB_EVENT_QUEUE_TIMEOUT); xStatus = xQueueSend(xQueueHdl, (const void*)&eEvent, MB_EVENT_QUEUE_TIMEOUT);
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "%s: Post message failure.", __func__);
} }
return bStatus; return TRUE;
} }
BOOL BOOL

View file

@ -79,7 +79,7 @@ xMBMasterPortEventInit( void )
return TRUE; return TRUE;
} }
BOOL BOOL MB_PORT_ISR_ATTR
xMBMasterPortEventPost( eMBMasterEventType eEvent ) xMBMasterPortEventPost( eMBMasterEventType eEvent )
{ {
BOOL bStatus = FALSE; BOOL bStatus = FALSE;
@ -140,10 +140,7 @@ xMBMasterPortEventGet( eMBMasterEventType * eEvent)
void vMBMasterOsResInit( void ) void vMBMasterOsResInit( void )
{ {
xSemaphorMasterHdl = xSemaphoreCreateBinary(); xSemaphorMasterHdl = xSemaphoreCreateBinary();
if (xSemaphorMasterHdl == NULL) MB_PORT_CHECK((xSemaphorMasterHdl != NULL), ; , "%s: OS semaphore create error.", __func__);
{
ESP_LOGE(MB_PORT_TAG,"%s: OS semaphore create error.", __func__);
}
} }
/** /**
@ -156,15 +153,13 @@ void vMBMasterOsResInit( void )
*/ */
BOOL xMBMasterRunResTake( LONG lTimeOut ) BOOL xMBMasterRunResTake( LONG lTimeOut )
{ {
BOOL xResult = FALSE;
BaseType_t xStatus = pdTRUE; BaseType_t xStatus = pdTRUE;
// If waiting time is -1. It will wait forever // If waiting time is -1. It will wait forever
xStatus = xSemaphoreTake(xSemaphorMasterHdl, lTimeOut ); xStatus = xSemaphoreTake(xSemaphorMasterHdl, lTimeOut );
if (xStatus == pdTRUE) { MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s:Take resource failure.", __func__);
xResult = TRUE; ESP_LOGV(MB_PORT_TAG,"%s:Take resource (%lu ticks).", __func__, lTimeOut);
} return TRUE;
return xResult;
} }
/** /**
@ -173,11 +168,9 @@ BOOL xMBMasterRunResTake( LONG lTimeOut )
*/ */
void vMBMasterRunResRelease( void ) void vMBMasterRunResRelease( void )
{ {
BaseType_t xStatus = pdTRUE; BaseType_t xStatus = pdFALSE;
xStatus = xSemaphoreGive(xSemaphorMasterHdl); xStatus = xSemaphoreGive(xSemaphorMasterHdl);
if (xStatus != pdTRUE) { MB_PORT_CHECK((xStatus == pdTRUE), ; , "%s: resource release failure.", __func__);
ESP_LOGE(MB_PORT_TAG,"%s: resource release failure.", __func__);
}
} }
/** /**
@ -192,9 +185,7 @@ void vMBMasterRunResRelease( void )
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength) void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{ {
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT); BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT);
if(ret != TRUE) { MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RESPOND_TIMEOUT' failed!", __func__);
ESP_LOGE(MB_PORT_TAG, "Post event 'EV_MASTER_ERROR_RESPOND_TIMEOUT' failed!!!");
}
ESP_LOGD(MB_PORT_TAG,"%s:Callback respond timeout.", __func__); ESP_LOGD(MB_PORT_TAG,"%s:Callback respond timeout.", __func__);
} }
@ -209,9 +200,7 @@ void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength) void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{ {
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA); BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA);
if(ret != TRUE) { MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RECEIVE_DATA' failed!", __func__);
ESP_LOGE(MB_PORT_TAG,"xMBMasterPortEventPost event 'EV_MASTER_ERROR_RECEIVE_DATA' failed!!!");
}
ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data timeout failure.", __func__); ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data timeout failure.", __func__);
} }
@ -228,9 +217,8 @@ void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, U
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength) void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{ {
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION); BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION);
if(ret != TRUE) { MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!", __func__);
ESP_LOGE(MB_PORT_TAG,"xMBMasterPortEventPost event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!!!"); ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data timeout failure.", __func__);
}
} }
/** /**
@ -244,9 +232,8 @@ void vMBMasterCBRequestSuccess( void ) {
* If you don't use OS, you can change it. * If you don't use OS, you can change it.
*/ */
BOOL ret = xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCCESS); BOOL ret = xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCCESS);
if (ret != TRUE) { MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_PROCESS_SUCCESS' failed!", __func__);
ESP_LOGE(MB_PORT_TAG,"xMBMasterPortEventPost event 'EV_MASTER_PROCESS_SUCCESS' failed!!!"); ESP_LOGD(MB_PORT_TAG,"%s: Callback request success.", __func__);
}
} }
/** /**
@ -284,7 +271,7 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eErrStatus = MB_MRE_EXE_FUN; eErrStatus = MB_MRE_EXE_FUN;
} }
} else { } else {
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, xRecvedEvent); ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, uxBits);
assert(0); assert(0);
} }
return eErrStatus; return eErrStatus;

View file

@ -67,6 +67,8 @@
#define MB_SERIAL_TASK_STACK_SIZE (CONFIG_FMB_SERIAL_TASK_STACK_SIZE) #define MB_SERIAL_TASK_STACK_SIZE (CONFIG_FMB_SERIAL_TASK_STACK_SIZE)
#define MB_SERIAL_TOUT (3) // 3.5*8 = 28 ticks, TOUT=3 -> ~24..33 ticks #define MB_SERIAL_TOUT (3) // 3.5*8 = 28 ticks, TOUT=3 -> ~24..33 ticks
#define MB_SERIAL_TX_TOUT_MS (100)
#define MB_SERIAL_TX_TOUT_TICKS pdMS_TO_TICKS(MB_SERIAL_TX_TOUT_MS) // timeout for transmission
// Set buffer size for transmission // Set buffer size for transmission
#define MB_SERIAL_BUF_SIZE (CONFIG_FMB_SERIAL_BUF_SIZE) #define MB_SERIAL_BUF_SIZE (CONFIG_FMB_SERIAL_BUF_SIZE)
@ -125,14 +127,13 @@ static void vMBPortSerialRxPoll(size_t xEventSize)
// Let the stack know that T3.5 time is expired and data is received // Let the stack know that T3.5 time is expired and data is received
(void)pxMBPortCBTimerExpired(); // calls callback xMBRTUTimerT35Expired(); (void)pxMBPortCBTimerExpired(); // calls callback xMBRTUTimerT35Expired();
#endif #endif
ESP_LOGD(TAG, "RX_T35_timeout: %d(bytes in buffer)\n", (uint32_t)usLength); ESP_LOGD(TAG, "Receive: %d(bytes in buffer)\n", (uint32_t)usLength);
} }
} }
} }
BOOL xMBPortSerialTxPoll(void) BOOL xMBPortSerialTxPoll(void)
{ {
BOOL bStatus = FALSE;
USHORT usCount = 0; USHORT usCount = 0;
BOOL bNeedPoll = FALSE; BOOL bNeedPoll = FALSE;
@ -142,10 +143,14 @@ BOOL xMBPortSerialTxPoll(void)
// Calls the modbus stack callback function to let it fill the UART transmit buffer. // Calls the modbus stack callback function to let it fill the UART transmit buffer.
bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // calls callback xMBRTUTransmitFSM(); bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // calls callback xMBRTUTransmitFSM();
} }
ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes\n", (uint16_t)usCount); ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount);
bStatus = TRUE; // Waits while UART sending the packet
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
vMBPortSerialEnable(TRUE, FALSE);
MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure.");
return TRUE;
} }
return bStatus; return FALSE;
} }
static void vUartTask(void *pvParameters) static void vUartTask(void *pvParameters)
@ -154,7 +159,6 @@ static void vUartTask(void *pvParameters)
for(;;) { for(;;) {
if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) {
ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber);
//vMBPortTimersEnable();
switch(xEvent.type) { switch(xEvent.type) {
//Event of UART receving data //Event of UART receving data
case UART_DATA: case UART_DATA:
@ -246,7 +250,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
FALSE, "mb config failure, uart_param_config() returned (0x%x).", (uint32_t)xErr); FALSE, "mb config failure, uart_param_config() returned (0x%x).", (uint32_t)xErr);
// Install UART driver, and get the queue. // Install UART driver, and get the queue.
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE, xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
MB_QUEUE_LENGTH, &xMbUartQueue, ESP_INTR_FLAG_LEVEL3); MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial driver failure, uart_driver_install() returned (0x%x).", (uint32_t)xErr); "mb serial driver failure, uart_driver_install() returned (0x%x).", (uint32_t)xErr);
#ifndef MB_TIMER_PORT_ENABLED #ifndef MB_TIMER_PORT_ENABLED

View file

@ -114,7 +114,7 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize)
} }
// The buffer is transferred into Modbus stack and is not needed here any more // The buffer is transferred into Modbus stack and is not needed here any more
uart_flush_input(ucUartNumber); uart_flush_input(ucUartNumber);
ESP_LOGD(TAG, "RX_T35_timeout: %d(bytes in buffer)\n", (uint32_t)usLength); ESP_LOGD(TAG, "Receive: %d(bytes in buffer)\n", (uint32_t)usLength);
} }
} else { } else {
ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%d bytes) received. ", __func__, (uint16_t)xEventSize); ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%d bytes) received. ", __func__, (uint16_t)xEventSize);
@ -123,7 +123,6 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize)
BOOL xMBMasterPortSerialTxPoll(void) BOOL xMBMasterPortSerialTxPoll(void)
{ {
BOOL bStatus = FALSE;
USHORT usCount = 0; USHORT usCount = 0;
BOOL bNeedPoll = FALSE; BOOL bNeedPoll = FALSE;
@ -137,10 +136,11 @@ BOOL xMBMasterPortSerialTxPoll(void)
// Waits while UART sending the packet // Waits while UART sending the packet
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS); esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
bTxStateEnabled = FALSE; bTxStateEnabled = FALSE;
vMBMasterPortSerialEnable( TRUE, FALSE );
MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure."); MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure.");
bStatus = TRUE; return TRUE;
} }
return bStatus; return FALSE;
} }
// UART receive event task // UART receive event task
@ -241,7 +241,7 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
FALSE, "mb config failure, uart_param_config() returned (0x%x).", (uint32_t)xErr); FALSE, "mb config failure, uart_param_config() returned (0x%x).", (uint32_t)xErr);
// Install UART driver, and get the queue. // Install UART driver, and get the queue.
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE, xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
MB_QUEUE_LENGTH, &xMbUartQueue, ESP_INTR_FLAG_LEVEL3); MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial driver failure, uart_driver_install() returned (0x%x).", (uint32_t)xErr); "mb serial driver failure, uart_driver_install() returned (0x%x).", (uint32_t)xErr);
// Set timeout for TOUT interrupt (T3.5 modbus time) // Set timeout for TOUT interrupt (T3.5 modbus time)

View file

@ -112,7 +112,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
(uint32_t)xErr); (uint32_t)xErr);
// Register ISR for timer // Register ISR for timer
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr,
(void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_LOWMED, &xTimerIntHandle); (void*)(uint32_t)usTimerIndex, MB_PORT_TIMER_ISR_FLAG, &xTimerIntHandle);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer set value failure, timer_isr_register() returned (0x%x).", "timer set value failure, timer_isr_register() returned (0x%x).",
(uint32_t)xErr); (uint32_t)xErr);
@ -130,13 +130,18 @@ void vMBPortTimersEnable(void)
#endif #endif
} }
void vMBPortTimersDisable(void) void MB_PORT_ISR_ATTR
vMBPortTimersDisable(void)
{ {
#ifdef CONFIG_FMB_TIMER_PORT_ENABLED #ifdef CONFIG_FMB_TIMER_PORT_ENABLED
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex)); if( (BOOL)xPortInIsrContext() ) {
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL)); timer_group_set_counter_enable_in_isr(usTimerGroupIndex, usTimerIndex, TIMER_PAUSE);
// Disable timer interrupt } else {
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex)); ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL));
// Disable timer interrupt
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
}
#endif #endif
} }

View file

@ -109,7 +109,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
(uint32_t)xErr); (uint32_t)xErr);
// Register ISR for timer // Register ISR for timer
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex,
vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_LOWMED, &xTimerIntHandle); vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, MB_PORT_TIMER_ISR_FLAG, &xTimerIntHandle);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer set value failure, timer_isr_register() returned (0x%x).", "timer set value failure, timer_isr_register() returned (0x%x).",
(uint32_t)xErr); (uint32_t)xErr);
@ -179,13 +179,18 @@ void vMBMasterPortTimersRespondTimeoutEnable(void)
(void)xMBMasterPortTimersEnable(usTimerTicks); (void)xMBMasterPortTimersEnable(usTimerTicks);
} }
void vMBMasterPortTimersDisable(void) void MB_PORT_ISR_ATTR
vMBMasterPortTimersDisable()
{ {
// Stop timer and then reload timer counter value if( (BOOL)xPortInIsrContext() ) {
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex)); timer_group_set_counter_enable_in_isr(usTimerGroupIndex, usTimerIndex, TIMER_PAUSE);
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL)); } else {
// Disable timer interrupt // Stop timer and then reload timer counter value
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex)); ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL));
// Disable timer interrupt
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
}
} }
void vMBMasterPortTimerClose(void) void vMBMasterPortTimerClose(void)

View file

@ -36,10 +36,17 @@
extern BOOL xMBMasterPortSerialTxPoll(void); extern BOOL xMBMasterPortSerialTxPoll(void);
/*-----------------------Master mode use these variables----------------------*/ /*-----------------------Master mode use these variables----------------------*/
#define MODE_RTU
#ifdef MODE_RTU
#define MB_DT_SIZE(size) ((size << 1) + 8)
#else
#define MB_DT_SIZE(size) ((size << 2) + 20)
#endif
// The response time is average processing time + data transmission (higher on lower speeds) // The response time is average processing time + data transmission (higher on lower speeds)
// ~resp_time_ms = min_pcocessing_time_ms + ((2 packets * (header_size + packet_bytes)) * 11 bits in byte * 1000 ms_in_sec) / transmit_speed)) // ~resp_time_ms = min_pcocessing_time_ms + ((2 packets * (header_size + packet_bytes)) * 11 bits in byte * 1000 ms_in_sec) / transmit_speed))
#define MB_RESPONSE_TIMEOUT(size) pdMS_TO_TICKS(30 + (2 * ((size << 1) + 8) * 11 * 1000 / mb_speed)) #define MB_RESPONSE_TIMEOUT(mb_speed, size) pdMS_TO_TICKS( 30 + (2 * MB_DT_SIZE(size) * 11 * 1000 / mb_speed))
#define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst; static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
@ -190,8 +197,8 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
uint16_t mb_size = request->reg_size; uint16_t mb_size = request->reg_size;
uint32_t mb_speed = mbm_opts->mbm_comm.baudrate; uint32_t mb_speed = mbm_opts->mbm_comm.baudrate;
// Timeout value for packet processing // Timeout value for last processed packet
uint32_t timeout = 0; static uint32_t timeout = MB_RESPONSE_TICS;
size_t pack_length = 0; size_t pack_length = 0;
// Set the buffer for callback function processing of received data // Set the buffer for callback function processing of received data
@ -203,53 +210,53 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
{ {
case MB_FUNC_READ_COILS: case MB_FUNC_READ_COILS:
pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1; pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1;
timeout = MB_RESPONSE_TIMEOUT(pack_length); timeout = MB_RESPONSE_TIMEOUT(mb_speed, pack_length);
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size , (LONG)timeout ); (USHORT)mb_size , (LONG)timeout );
break; break;
case MB_FUNC_WRITE_SINGLE_COIL: case MB_FUNC_WRITE_SINGLE_COIL:
timeout = MB_RESPONSE_TIMEOUT(1); timeout = MB_RESPONSE_TIMEOUT(mb_speed, 1);
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
*(USHORT*)data_ptr, (LONG)timeout ); *(USHORT*)data_ptr, (LONG)timeout );
break; break;
case MB_FUNC_WRITE_MULTIPLE_COILS: case MB_FUNC_WRITE_MULTIPLE_COILS:
pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1; pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1;
timeout = MB_RESPONSE_TIMEOUT(pack_length); timeout = MB_RESPONSE_TIMEOUT(mb_speed, pack_length);
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (UCHAR*)data_ptr, (LONG)timeout); (USHORT)mb_size, (UCHAR*)data_ptr, (LONG)timeout);
break; break;
case MB_FUNC_READ_DISCRETE_INPUTS: case MB_FUNC_READ_DISCRETE_INPUTS:
pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1; pack_length = (mb_size >= 8) ? (mb_size >> 3) : 1;
timeout = MB_RESPONSE_TIMEOUT(pack_length); timeout = MB_RESPONSE_TIMEOUT(mb_speed, pack_length);
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (LONG)timeout ); (USHORT)mb_size, (LONG)timeout );
break; break;
case MB_FUNC_READ_HOLDING_REGISTER: case MB_FUNC_READ_HOLDING_REGISTER:
timeout = MB_RESPONSE_TIMEOUT(mb_size); timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size);
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (LONG)timeout ); (USHORT)mb_size, (LONG)timeout );
break; break;
case MB_FUNC_WRITE_REGISTER: case MB_FUNC_WRITE_REGISTER:
timeout = MB_RESPONSE_TIMEOUT(1); timeout = MB_RESPONSE_TIMEOUT(mb_speed, 1);
mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
*(USHORT*)data_ptr, (LONG)timeout ); *(USHORT*)data_ptr, (LONG)timeout );
break; break;
case MB_FUNC_WRITE_MULTIPLE_REGISTERS: case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
timeout = MB_RESPONSE_TIMEOUT(mb_size); timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size);
mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
(USHORT)mb_offset, (USHORT)mb_size, (USHORT)mb_offset, (USHORT)mb_size,
(USHORT*)data_ptr, (LONG)timeout ); (USHORT*)data_ptr, (LONG)timeout );
break; break;
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS: case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
timeout = MB_RESPONSE_TIMEOUT(mb_size << 1); timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size << 1);
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (USHORT*)data_ptr, (USHORT)mb_size, (USHORT*)data_ptr,
(USHORT)mb_offset, (USHORT)mb_size, (USHORT)mb_offset, (USHORT)mb_size,
(LONG)timeout ); (LONG)timeout );
break; break;
case MB_FUNC_READ_INPUT_REGISTER: case MB_FUNC_READ_INPUT_REGISTER:
timeout = MB_RESPONSE_TIMEOUT(mb_size); timeout = MB_RESPONSE_TIMEOUT(mb_speed, mb_size);
mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset, mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (LONG) timeout ); (USHORT)mb_size, (LONG) timeout );
break; break;
@ -268,18 +275,25 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
break; break;
case MB_MRE_NO_REG: case MB_MRE_NO_REG:
error = ESP_ERR_NOT_SUPPORTED; error = ESP_ERR_NOT_SUPPORTED; // Invalid register request
break; break;
case MB_MRE_TIMEDOUT: case MB_MRE_TIMEDOUT:
error = ESP_ERR_TIMEOUT; error = ESP_ERR_TIMEOUT; // Slave did not send response
break; break;
case MB_MRE_EXE_FUN: case MB_MRE_EXE_FUN:
case MB_MRE_REV_DATA: case MB_MRE_REV_DATA:
error = ESP_ERR_INVALID_RESPONSE; error = ESP_ERR_INVALID_RESPONSE; // Invalid response from slave
break; break;
case MB_MRE_MASTER_BUSY:
error = ESP_ERR_INVALID_STATE; // Master is busy (previous request is pending
break;
default: default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
__FUNCTION__, mb_error);
error = ESP_FAIL; error = ESP_FAIL;
break; break;
} }

View file

@ -55,7 +55,7 @@
#ifdef __cplusplus #ifdef __cplusplus
PR_BEGIN_EXTERN_C PR_BEGIN_EXTERN_C
#endif /* __cplusplus */ #endif /* __cplusplus */
void vMBPortSetMode( UCHAR ucMode ); void vMBPortSetMode( UCHAR ucMode );
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -48,7 +48,11 @@ static void modbus_slave_task(void *pvParameters)
// Check if stack started then poll for data // Check if stack started then poll for data
if (status & MB_EVENT_STACK_STARTED) { if (status & MB_EVENT_STACK_STARTED) {
(void)eMBPoll(); // allow stack to process data (void)eMBPoll(); // allow stack to process data
(void)xMBPortSerialTxPoll(); // Send response buffer if ready // Send response buffer
BOOL xSentState = xMBPortSerialTxPoll();
if (xSentState) {
(void)xMBPortEventPost( EV_FRAME_SENT );
}
} }
} }
} }