diff --git a/freemodbus/common/include/esp_modbus_master.h b/freemodbus/common/include/esp_modbus_master.h index 9b874a0..d11ade7 100644 --- a/freemodbus/common/include/esp_modbus_master.h +++ b/freemodbus/common/include/esp_modbus_master.h @@ -9,6 +9,7 @@ #include // for standard int types definition #include // for NULL and std defines +#include "soc/soc.h" // for BITN definitions #include "esp_modbus_common.h" // for common types #ifdef __cplusplus diff --git a/freemodbus/common/include/esp_modbus_slave.h b/freemodbus/common/include/esp_modbus_slave.h index 962dbda..7d79b51 100644 --- a/freemodbus/common/include/esp_modbus_slave.h +++ b/freemodbus/common/include/esp_modbus_slave.h @@ -10,6 +10,7 @@ // Public interface header for slave #include // for standard int types definition #include // for NULL and std defines +#include "soc/soc.h" // for BITN definitions #include "freertos/FreeRTOS.h" // for task creation and queues access #include "freertos/event_groups.h" // for event groups #include "esp_modbus_common.h" // for common types diff --git a/freemodbus/modbus/ascii/mbascii.c b/freemodbus/modbus/ascii/mbascii.c index 462a641..4400c25 100644 --- a/freemodbus/modbus/ascii/mbascii.c +++ b/freemodbus/modbus/ascii/mbascii.c @@ -151,26 +151,33 @@ eMBErrorCode eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ) { eMBErrorCode eStatus = MB_ENOERR; + UCHAR *pucMBASCIIFrame = ( UCHAR* ) ucASCIIBuf; + USHORT usFrameLength = usRcvBufferPos; + if( xMBSerialPortGetRequest( &pucMBASCIIFrame, &usFrameLength ) == FALSE ) + { + return MB_EIO; + } + ENTER_CRITICAL_SECTION( ); - assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX ); + assert( usFrameLength < MB_SER_PDU_SIZE_MAX ); /* Length and CRC check */ - if( ( usRcvBufferPos >= MB_ASCII_SER_PDU_SIZE_MIN ) - && ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) ) + if( ( usFrameLength >= MB_ASCII_SER_PDU_SIZE_MIN ) + && ( prvucMBLRC( ( UCHAR * ) pucMBASCIIFrame, usFrameLength ) == 0 ) ) { /* Save the address field. All frames are passed to the upper layed * and the decision if a frame is used is done there. */ - *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF]; + *pucRcvAddress = pucMBASCIIFrame[MB_SER_PDU_ADDR_OFF]; /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus * size of address field and CRC checksum. */ - *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC ); + *pusLength = ( USHORT )( usFrameLength - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC ); /* Return the start of the Modbus PDU to the caller. */ - *pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF]; + *pucFrame = ( UCHAR * ) & pucMBASCIIFrame[MB_SER_PDU_PDU_OFF]; } else { @@ -186,13 +193,14 @@ eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) eMBErrorCode eStatus = MB_ENOERR; UCHAR usLRC; - ENTER_CRITICAL_SECTION( ); + /* Check if the receiver is still in idle state. If not we where too * slow with processing the received frame and the master sent another * frame on the network. We have to abort sending the frame. */ if( eRcvState == STATE_RX_IDLE ) { + ENTER_CRITICAL_SECTION( ); /* First byte before the Modbus-PDU is the slave address. */ pucSndBufferCur = ( UCHAR * ) pucFrame - 1; usSndBufferCount = 1; @@ -207,6 +215,13 @@ eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) /* Activate the transmitter. */ eSndState = STATE_TX_START; + EXIT_CRITICAL_SECTION( ); + + if ( xMBSerialPortSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE ) + { + eStatus = MB_EIO; + } + vMBPortSerialEnable( FALSE, TRUE ); } else diff --git a/freemodbus/modbus/ascii/mbascii_m.c b/freemodbus/modbus/ascii/mbascii_m.c index 8106598..849ab65 100644 --- a/freemodbus/modbus/ascii/mbascii_m.c +++ b/freemodbus/modbus/ascii/mbascii_m.c @@ -154,29 +154,34 @@ eMBErrorCode eMBMasterASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ) { eMBErrorCode eStatus = MB_ENOERR; + UCHAR *pucMBASCIIFrame = ( UCHAR* ) ucMasterASCIIRcvBuf; + USHORT usFrameLength = usMasterRcvBufferPos; + if( xMBMasterSerialPortGetResponse( &pucMBASCIIFrame, &usFrameLength ) == FALSE ) + { + return MB_EIO; + } ENTER_CRITICAL_SECTION( ); - assert( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX ); + assert( usFrameLength < MB_SER_PDU_SIZE_MAX ); + assert( pucMBASCIIFrame ); /* Length and CRC check */ - if( ( usMasterRcvBufferPos >= MB_ASCII_SER_PDU_SIZE_MIN ) - && ( prvucMBLRC( ( UCHAR * ) ucMasterASCIIRcvBuf, usMasterRcvBufferPos ) == 0 ) ) + if( ( usFrameLength >= MB_ASCII_SER_PDU_SIZE_MIN ) + && ( prvucMBLRC( ( UCHAR * ) pucMBASCIIFrame, usFrameLength ) == 0 ) ) { /* Save the address field. All frames are passed to the upper layed - * and the decision if a frame is used is done there. - */ - *pucRcvAddress = ucMasterASCIIRcvBuf[MB_SER_PDU_ADDR_OFF]; + * and the decision if a frame is used is done there. + */ + *pucRcvAddress = pucMBASCIIFrame[MB_SER_PDU_ADDR_OFF]; - /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus - * size of address field and CRC checksum. - */ - *pusLength = ( USHORT )( usMasterRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC ); + /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus + * size of address field and CRC checksum. + */ + *pusLength = ( USHORT )( usFrameLength - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC ); - /* Return the start of the Modbus PDU to the caller. */ - *pucFrame = ( UCHAR * ) & ucMasterASCIIRcvBuf[MB_SER_PDU_PDU_OFF]; - } - else - { + /* Return the start of the Modbus PDU to the caller. */ + *pucFrame = ( UCHAR * ) & pucMBASCIIFrame[MB_SER_PDU_PDU_OFF]; + } else { eStatus = MB_EIO; } EXIT_CRITICAL_SECTION( ); @@ -191,13 +196,13 @@ eMBMasterASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLengt if ( ucSlaveAddress > MB_MASTER_TOTAL_SLAVE_NUM ) return MB_EINVAL; - ENTER_CRITICAL_SECTION( ); /* Check if the receiver is still in idle state. If not we where too * slow with processing the received frame and the master sent another * frame on the network. We have to abort sending the frame. */ if(eRcvState == STATE_M_RX_IDLE) { + ENTER_CRITICAL_SECTION( ); /* First byte before the Modbus-PDU is the slave address. */ pucMasterSndBufferCur = ( UCHAR * ) pucFrame - 1; usMasterSndBufferCount = 1; @@ -208,17 +213,22 @@ eMBMasterASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLengt /* Calculate LRC checksum for Modbus-Serial-Line-PDU. */ usLRC = prvucMBLRC( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ); - ucMasterASCIISndBuf[usMasterSndBufferCount++] = usLRC; + pucMasterSndBufferCur[usMasterSndBufferCount++] = usLRC; /* Activate the transmitter. */ eSndState = STATE_M_TX_START; + EXIT_CRITICAL_SECTION( ); + + if ( xMBMasterSerialPortSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE ) + { + eStatus = MB_EIO; + } vMBMasterPortSerialEnable( FALSE, TRUE ); } else { eStatus = MB_EIO; } - EXIT_CRITICAL_SECTION( ); return eStatus; } @@ -447,7 +457,7 @@ xMBMasterASCIITransmitFSM( void ) return xNeedPoll; } -BOOL +BOOL MB_PORT_ISR_ATTR xMBMasterASCIITimerT1SExpired( void ) { BOOL xNeedPoll = FALSE; @@ -457,7 +467,6 @@ xMBMasterASCIITimerT1SExpired( void ) /* Timer t35 expired. Startup phase is finished. */ case STATE_M_RX_INIT: xNeedPoll = xMBMasterPortEventPost(EV_MASTER_READY); - ESP_EARLY_LOGI("xMBMasterASCIITimerT1SExpired", "RX_INIT_EXPIRED"); break; /* Start of message is not received during respond timeout. diff --git a/freemodbus/modbus/include/mbconfig.h b/freemodbus/modbus/include/mbconfig.h index 897cc6c..268b748 100644 --- a/freemodbus/modbus/include/mbconfig.h +++ b/freemodbus/modbus/include/mbconfig.h @@ -41,6 +41,10 @@ #include "sdkconfig.h" // for KConfig options +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#endif + #ifdef __cplusplus PR_BEGIN_EXTERN_C #endif @@ -73,6 +77,15 @@ PR_BEGIN_EXTERN_C #error "None of Modbus communication mode is enabled. Please enable one of (ASCII, RTU, TCP) mode in Kconfig." #endif +#ifdef ESP_IDF_VERSION + +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) +// Features supported from 4.4 +#define MB_TIMER_SUPPORTS_ISR_DISPATCH_METHOD 1 +#endif + +#endif + /*! \brief This option defines the number of data bits per ASCII character. * * A parity bit is added before the stop bit which keeps the actual byte size at 10 bits. diff --git a/freemodbus/modbus/include/mbport.h b/freemodbus/modbus/include/mbport.h index 42773be..acaf908 100644 --- a/freemodbus/modbus/include/mbport.h +++ b/freemodbus/modbus/include/mbport.h @@ -145,6 +145,10 @@ BOOL xMBPortSerialGetByte( CHAR * pucByte ); BOOL xMBPortSerialPutByte( CHAR ucByte ); +BOOL xMBSerialPortGetRequest( UCHAR **ppucMBSerialFrame, USHORT * pusSerialLength ) __attribute__ ((weak)); + +BOOL xMBSerialPortSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) __attribute__ ((weak)); + #if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ); @@ -158,6 +162,11 @@ void vMBMasterPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ); BOOL xMBMasterPortSerialGetByte( CHAR * pucByte ); BOOL xMBMasterPortSerialPutByte( CHAR ucByte ); + +BOOL xMBMasterSerialPortGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ); + +BOOL xMBMasterSerialPortSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength ); + #endif /* ----------------------- Timers functions ---------------------------------*/ diff --git a/freemodbus/modbus/mb_m.c b/freemodbus/modbus/mb_m.c index aa5922a..1f13b9a 100644 --- a/freemodbus/modbus/mb_m.c +++ b/freemodbus/modbus/mb_m.c @@ -70,18 +70,18 @@ /* ----------------------- Static variables ---------------------------------*/ -static UCHAR ucMBMasterDestAddress; -static BOOL xMBRunInMasterMode = FALSE; +static UCHAR ucMBMasterDestAddress; +static BOOL xMBRunInMasterMode = FALSE; static volatile eMBMasterErrorEventType eMBMasterCurErrorType; -static volatile USHORT usMasterSendPDULength; +static volatile USHORT usMasterSendPDULength; static volatile eMBMode eMBMasterCurrentMode; /*------------------------ Shared variables ---------------------------------*/ -volatile UCHAR ucMasterSndBuf[MB_SERIAL_BUF_SIZE]; -volatile UCHAR ucMasterRcvBuf[MB_SERIAL_BUF_SIZE]; +volatile UCHAR ucMasterSndBuf[MB_SERIAL_BUF_SIZE]; +volatile UCHAR ucMasterRcvBuf[MB_SERIAL_BUF_SIZE]; volatile eMBMasterTimerMode eMasterCurTimerMode; -volatile BOOL xFrameIsBroadcast = FALSE; +volatile BOOL xFrameIsBroadcast = FALSE; static enum { @@ -152,7 +152,7 @@ static xMBFunctionHandler xMasterFuncHandlers[MB_FUNC_HANDLERS_MAX] = { }; /* ----------------------- Start implementation -----------------------------*/ -#if MB_MASTER_TCP_ENABLED > 0 +#if MB_MASTER_TCP_ENABLED eMBErrorCode eMBMasterTCPInit( USHORT ucTCPPort ) { diff --git a/freemodbus/modbus/rtu/mbcrc.c b/freemodbus/modbus/rtu/mbcrc.c index c46e7d1..f413453 100644 --- a/freemodbus/modbus/rtu/mbcrc.c +++ b/freemodbus/modbus/rtu/mbcrc.c @@ -39,7 +39,7 @@ #include "port.h" #include "mbconfig.h" -#if MB_MASTER_RTU_ENABLED || MB_SLAVE_RTU_ENABLED +#if (MB_MASTER_RTU_ENABLED || MB_SLAVE_RTU_ENABLED || CONFIG_MB_UTEST) static const UCHAR aucCRCHi[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, diff --git a/freemodbus/modbus/rtu/mbrtu.c b/freemodbus/modbus/rtu/mbrtu.c index 180bde2..144e208 100644 --- a/freemodbus/modbus/rtu/mbrtu.c +++ b/freemodbus/modbus/rtu/mbrtu.c @@ -155,26 +155,33 @@ eMBErrorCode eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ) { eMBErrorCode eStatus = MB_ENOERR; + UCHAR *pucMBRTUFrame = ( UCHAR* ) ucRTUBuf; + USHORT usFrameLength = usRcvBufferPos; + + if( xMBSerialPortGetRequest( &pucMBRTUFrame, &usFrameLength ) == FALSE ) + { + return MB_EIO; + } ENTER_CRITICAL_SECTION( ); - assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX ); + assert( usFrameLength < MB_SER_PDU_SIZE_MAX ); /* Length and CRC check */ - if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN ) - && ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) ) + if( ( usFrameLength >= MB_SER_PDU_SIZE_MIN ) + && ( usMBCRC16( ( UCHAR * ) pucMBRTUFrame, usFrameLength ) == 0 ) ) { /* Save the address field. All frames are passed to the upper layed * and the decision if a frame is used is done there. */ - *pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF]; + *pucRcvAddress = pucMBRTUFrame[MB_SER_PDU_ADDR_OFF]; /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus * size of address field and CRC checksum. */ - *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC ); + *pusLength = ( USHORT )( usFrameLength - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC ); /* Return the start of the Modbus PDU to the caller. */ - *pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF]; + *pucFrame = ( UCHAR * ) & pucMBRTUFrame[MB_SER_PDU_PDU_OFF]; } else { @@ -191,14 +198,13 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) eMBErrorCode eStatus = MB_ENOERR; USHORT usCRC16; - ENTER_CRITICAL_SECTION( ); - /* Check if the receiver is still in idle state. If not we where to * slow with processing the received frame and the master sent another * frame on the network. We have to abort sending the frame. */ if( eRcvState == STATE_RX_IDLE ) { + ENTER_CRITICAL_SECTION( ); /* First byte before the Modbus-PDU is the slave address. */ pucSndBufferCur = ( UCHAR * ) pucFrame - 1; usSndBufferCount = 1; @@ -214,13 +220,19 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) /* Activate the transmitter. */ eSndState = STATE_TX_XMIT; + EXIT_CRITICAL_SECTION( ); + + if( xMBSerialPortSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE ) + { + eStatus = MB_EIO; + } + vMBPortSerialEnable( FALSE, TRUE ); } else { eStatus = MB_EIO; } - EXIT_CRITICAL_SECTION( ); return eStatus; } @@ -272,7 +284,7 @@ xMBRTUReceiveFSM( void ) case STATE_RX_RCV: if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX ) { - if ( xStatus ) { + if( xStatus ) { ucRTUBuf[usRcvBufferPos++] = ucByte; } } diff --git a/freemodbus/modbus/rtu/mbrtu_m.c b/freemodbus/modbus/rtu/mbrtu_m.c index 47a5513..65ac4b7 100644 --- a/freemodbus/modbus/rtu/mbrtu_m.c +++ b/freemodbus/modbus/rtu/mbrtu_m.c @@ -161,26 +161,34 @@ eMBErrorCode eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ) { eMBErrorCode eStatus = MB_ENOERR; + UCHAR *pucMBRTUFrame = ( UCHAR* ) ucMasterRTURcvBuf; + USHORT usFrameLength = usMasterRcvBufferPos; + + if( xMBMasterSerialPortGetResponse( &pucMBRTUFrame, &usFrameLength ) == FALSE ) + { + return MB_EIO; + } ENTER_CRITICAL_SECTION( ); - assert( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX ); + assert( usFrameLength < MB_SER_PDU_SIZE_MAX ); + assert( pucMBRTUFrame ); /* Length and CRC check */ - if( ( usMasterRcvBufferPos >= MB_RTU_SER_PDU_SIZE_MIN ) - && ( usMBCRC16( ( UCHAR * ) ucMasterRTURcvBuf, usMasterRcvBufferPos ) == 0 ) ) + if( ( usFrameLength >= MB_RTU_SER_PDU_SIZE_MIN ) + && ( usMBCRC16( ( UCHAR * ) pucMBRTUFrame, usFrameLength ) == 0 ) ) { - /* Save the address field. All frames are passed to the upper layed + /* Save the address field. All frames are passed to the upper layer * and the decision if a frame is used is done there. */ - *pucRcvAddress = ucMasterRTURcvBuf[MB_SER_PDU_ADDR_OFF]; + *pucRcvAddress = pucMBRTUFrame[MB_SER_PDU_ADDR_OFF]; /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus * size of address field and CRC checksum. */ - *pusLength = ( USHORT )( usMasterRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC ); + *pusLength = ( USHORT )( usFrameLength - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC ); /* Return the start of the Modbus PDU to the caller. */ - *pucFrame = ( UCHAR * ) & ucMasterRTURcvBuf[MB_SER_PDU_PDU_OFF]; + *pucFrame = ( UCHAR * ) & pucMBRTUFrame[MB_SER_PDU_PDU_OFF]; } else { @@ -199,14 +207,13 @@ eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength if ( ucSlaveAddress > MB_MASTER_TOTAL_SLAVE_NUM ) return MB_EINVAL; - ENTER_CRITICAL_SECTION( ); - /* Check if the receiver is still in idle state. If not we where to * slow with processing the received frame and the master sent another * frame on the network. We have to abort sending the frame. */ if( eRcvState == STATE_M_RX_IDLE ) { + ENTER_CRITICAL_SECTION( ); /* First byte before the Modbus-PDU is the slave address. */ pucMasterSndBufferCur = ( UCHAR * ) pucFrame - 1; usMasterSndBufferCount = 1; @@ -217,11 +224,18 @@ eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */ usCRC16 = usMBCRC16( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ); - ucMasterRTUSndBuf[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF ); - ucMasterRTUSndBuf[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 ); + pucMasterSndBufferCur[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF ); + pucMasterSndBufferCur[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 ); + EXIT_CRITICAL_SECTION( ); /* Activate the transmitter. */ eSndState = STATE_M_TX_XMIT; + + if ( xMBMasterSerialPortSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE ) + { + eStatus = MB_EIO; + } + // The place to enable RS485 driver vMBMasterPortSerialEnable( FALSE, TRUE ); } @@ -229,7 +243,6 @@ eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength { eStatus = MB_EIO; } - EXIT_CRITICAL_SECTION( ); return eStatus; } @@ -273,11 +286,15 @@ xMBMasterRTUReceiveFSM( void ) eSndState = STATE_M_TX_IDLE; usMasterRcvBufferPos = 0; - ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte; - eRcvState = STATE_M_RX_RCV; + if( xStatus && ucByte ) { + ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte; + eRcvState = STATE_M_RX_RCV; + } /* Enable t3.5 timers. */ +#if CONFIG_FMB_TIMER_PORT_ENABLED vMBMasterPortTimersT35Enable( ); +#endif break; /* We are currently receiving a frame. Reset the timer after @@ -296,7 +313,9 @@ xMBMasterRTUReceiveFSM( void ) { eRcvState = STATE_M_RX_ERROR; } +#if CONFIG_FMB_TIMER_PORT_ENABLED vMBMasterPortTimersT35Enable( ); +#endif break; } return xStatus; diff --git a/freemodbus/port/port.c b/freemodbus/port/port.c index 1959104..4f672a9 100644 --- a/freemodbus/port/port.c +++ b/freemodbus/port/port.c @@ -38,6 +38,7 @@ /* ----------------------- Modbus includes ----------------------------------*/ #include "freertos/FreeRTOS.h" +#include "freertos/queue.h" #include "sys/lock.h" #include "port.h" @@ -72,6 +73,13 @@ vMBPortSetMode( UCHAR ucMode ) EXIT_CRITICAL_SECTION(); } +BOOL xMBPortSerialWaitEvent(QueueHandle_t xMbUartQueue, uart_event_t* pxEvent, ULONG xTimeout) +{ + BOOL xResult = (BaseType_t)xQueueReceive(xMbUartQueue, (void*)pxEvent, (TickType_t) xTimeout); + ESP_LOGD(__func__, "UART event: %d ", pxEvent->type); + return xResult; +} + #if MB_TCP_DEBUG // This function is kept to realize legacy freemodbus frame logging functionality diff --git a/freemodbus/port/port.h b/freemodbus/port/port.h index 42ae780..b5d8858 100644 --- a/freemodbus/port/port.h +++ b/freemodbus/port/port.h @@ -38,8 +38,18 @@ #define PORT_COMMON_H_ #include "freertos/FreeRTOS.h" +#include "freertos/queue.h" // for queue + #include "esp_log.h" // for ESP_LOGE macro #include "esp_timer.h" +#include "driver/uart.h" // for uart_event_t + +#if __has_include("driver/gptimer.h") +#include "driver/gptimer.h" +#else +#include "driver/timer.h" +#endif + #include "mbconfig.h" #define INLINE inline @@ -174,6 +184,8 @@ void prvvMBTCPLogFrame( const CHAR * pucMsg, UCHAR * pucFrame, USHORT usFrameLen void vMBPortSetMode( UCHAR ucMode ); UCHAR ucMBPortGetMode( void ); +BOOL xMBPortSerialWaitEvent(QueueHandle_t xMbUartQueue, uart_event_t* pxEvent, ULONG xTimeout); + #ifdef __cplusplus PR_END_EXTERN_C #endif /* __cplusplus */ diff --git a/freemodbus/port/portserial.c b/freemodbus/port/portserial.c index a57a6c6..aae45d9 100644 --- a/freemodbus/port/portserial.c +++ b/freemodbus/port/portserial.c @@ -33,6 +33,8 @@ * * File: $Id: portother.c,v 1.1 2010/06/06 13:07:20 wolti Exp $ */ + +#include "driver/uart.h" #include "port.h" #include "driver/uart.h" #include "freertos/queue.h" // for queue support @@ -85,15 +87,14 @@ static USHORT usMBPortSerialRxPoll(size_t xEventSize) if (bRxStateEnabled) { // Get received packet into Rx buffer - while(xReadStatus && (usCnt++ <= MB_SERIAL_BUF_SIZE)) { + while(xReadStatus && (usCnt++ <= xEventSize)) { // Call the Modbus stack callback function and let it fill the buffers. xReadStatus = pxMBFrameCBByteReceived(); // callback to execute receive FSM } uart_flush_input(ucUartNumber); // Send event EV_FRAME_RECEIVED to allow stack process packet #if !CONFIG_FMB_TIMER_PORT_ENABLED - // Let the stack know that T3.5 time is expired and data is received - (void)pxMBPortCBTimerExpired(); // calls callback xMBRTUTimerT35Expired(); + pxMBPortCBTimerExpired(); #endif ESP_LOGD(TAG, "RX: %d bytes\n", usCnt); } @@ -126,7 +127,7 @@ static void vUartTask(void *pvParameters) uart_event_t xEvent; USHORT usResult = 0; for(;;) { - if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { + if (xMBPortSerialWaitEvent(xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) { ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); switch(xEvent.type) { //Event of UART receving data @@ -135,6 +136,8 @@ static void vUartTask(void *pvParameters) // This flag set in the event means that no more // data received during configured timeout and UART TOUT feature is triggered if (xEvent.timeout_flag) { + // Get buffered data length + ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); // Read received data and send it to modbus stack usResult = usMBPortSerialRxPoll(xEvent.size); ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); @@ -219,7 +222,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .rx_flow_ctrl_thresh = 2, - .source_clk = UART_SCLK_APB, + .source_clk = UART_SCLK_APB }; // Set UART config xErr = uart_param_config(ucUartNumber, &xUartConfig); @@ -257,6 +260,17 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, return TRUE; } +BOOL xMBSerialPortGetRequest( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ) +{ + BOOL eStatus = TRUE; + return eStatus; +} + +BOOL xMBSerialPortSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) +{ + return TRUE; +} + void vMBPortSerialClose(void) { (void)vTaskSuspend(xMbTaskHandle); diff --git a/freemodbus/port/portserial_m.c b/freemodbus/port/portserial_m.c index b0324e3..777eee8 100644 --- a/freemodbus/port/portserial_m.c +++ b/freemodbus/port/portserial_m.c @@ -89,7 +89,7 @@ static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize) USHORT usCnt = 0; if (bRxStateEnabled) { - while(xReadStatus && (usCnt++ <= MB_SERIAL_BUF_SIZE)) { + while(xReadStatus && (usCnt++ <= xEventSize)) { // Call the Modbus stack callback function and let it fill the stack buffers. xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM } @@ -134,7 +134,7 @@ static void vUartTask(void* pvParameters) uart_event_t xEvent; USHORT usResult = 0; for(;;) { - if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { + if (xMBPortSerialWaitEvent(xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) { ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); switch(xEvent.type) { //Event of UART receiving data @@ -143,6 +143,8 @@ static void vUartTask(void* pvParameters) // This flag set in the event means that no more // data received during configured timeout and UART TOUT feature is triggered if (xEvent.timeout_flag) { + // Get buffered data length + ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); // Read received data and send it to modbus stack usResult = usMBMasterPortSerialRxPoll(xEvent.size); ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); @@ -266,6 +268,24 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, return TRUE; } +/* + * The function is called from ASCII/RTU module to get processed data buffer. Sets the + * received buffer and its length using parameters. + */ +BOOL xMBMasterSerialPortGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ) +{ + return TRUE; +} + +/* + * The function is called from ASCII/RTU module to set processed data buffer + * to be sent in transmitter state machine. + */ +BOOL xMBMasterSerialPortSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) +{ + return TRUE; +} + void vMBMasterPortSerialClose(void) { (void)vTaskDelete(xMbTaskHandle); diff --git a/freemodbus/port/porttimer.c b/freemodbus/port/porttimer.c index 9e2673f..4fbfbfd 100644 --- a/freemodbus/port/porttimer.c +++ b/freemodbus/port/porttimer.c @@ -74,7 +74,7 @@ BOOL xMBPortTimersInit(USHORT usTimeOut50us) esp_timer_create_args_t xTimerConf = { .callback = vTimerAlarmCBHandler, .arg = NULL, -#if CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD +#if (MB_TIMER_SUPPORTS_ISR_DISPATCH_METHOD && CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD) .dispatch_method = ESP_TIMER_ISR, #else .dispatch_method = ESP_TIMER_TASK, diff --git a/freemodbus/port/porttimer_m.c b/freemodbus/port/porttimer_m.c index 3982f27..f1595a6 100644 --- a/freemodbus/port/porttimer_m.c +++ b/freemodbus/port/porttimer_m.c @@ -71,7 +71,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) esp_timer_create_args_t xTimerConf = { .callback = vTimerAlarmCBHandler, .arg = NULL, -#if CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD +#if (MB_TIMER_SUPPORTS_ISR_DISPATCH_METHOD && CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD) .dispatch_method = ESP_TIMER_ISR, #else .dispatch_method = ESP_TIMER_TASK, diff --git a/freemodbus/serial_master/modbus_controller/mbc_serial_master.c b/freemodbus/serial_master/modbus_controller/mbc_serial_master.c index 3a3f2da..94bec3f 100644 --- a/freemodbus/serial_master/modbus_controller/mbc_serial_master.c +++ b/freemodbus/serial_master/modbus_controller/mbc_serial_master.c @@ -30,7 +30,7 @@ extern BOOL xMBMasterPortSerialTxPoll(void); #define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + 10) -static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst; +static mb_master_interface_t* mbm_interface_ptr = NULL; static const char *TAG = "MB_CONTROLLER_MASTER"; // Modbus event processing task @@ -101,7 +101,7 @@ static esp_err_t mbc_serial_master_start(void) "mb stack initialization failure, eMBInit() returns (0x%x).", status); status = eMBMasterEnable(); MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE, - "mb stack set slave ID failure, eMBEnable() returned (0x%x).", (uint32_t)status); + "mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status); // Set the mbcontroller start flag EventBits_t flag = xEventGroupSetBits(mbm_opts->mbm_event_group, (EventBits_t)MB_EVENT_STACK_STARTED); diff --git a/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c b/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c index bdcfe14..f1f3916 100644 --- a/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c +++ b/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c @@ -159,7 +159,7 @@ static esp_err_t mbc_tcp_master_start(void) status = eMBMasterEnable(); MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE, - "mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status); + "mb stack enable failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status); // Add slave IP address for each slave to initialize connection mb_slave_addr_entry_t *p_slave_info; @@ -172,13 +172,12 @@ static esp_err_t mbc_tcp_master_start(void) // Add end of list condition (void)xMBTCPPortMasterAddSlaveIp(0xFF, NULL, 0xFF); - // Wait for connection done event bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, - (EventBits_t)MB_EVENT_STACK_STARTED, MB_TCP_CONNECTION_TOUT); + (EventBits_t)MB_EVENT_STACK_STARTED, MB_TCP_CONNECTION_TOUT); MB_MASTER_CHECK((start), ESP_ERR_INVALID_STATE, - "mb stack could not connect to slaves for %d seconds.", - CONFIG_FMB_TCP_CONNECTION_TOUT_SEC); + "mb stack could not connect to slaves for %d seconds.", + CONFIG_FMB_TCP_CONNECTION_TOUT_SEC); return ESP_OK; } diff --git a/freemodbus/tcp_slave/port/port_tcp_slave.c b/freemodbus/tcp_slave/port/port_tcp_slave.c index e7046d6..c5eee09 100644 --- a/freemodbus/tcp_slave/port/port_tcp_slave.c +++ b/freemodbus/tcp_slave/port/port_tcp_slave.c @@ -560,6 +560,12 @@ static void vMBTCPPortServerTask(void *pvParameters) pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr); break; } + + if (xShutdownSemaphore) { + xSemaphoreGive(xShutdownSemaphore); + vTaskDelete(NULL); + } + // Close client connection xMBTCPPortCloseConnection(pxClientInfo); diff --git a/idf_component.yml b/idf_component.yml index 6af0316..a9cfdef 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,5 +1,10 @@ -version: "0.1.0" +version: "0.0.2" description: ESP-MODBUS is the official Modbus library for Espressif SoCs. dependencies: idf: ">=4.1" - +files: + exclude: + - "docs/_build/**/*" + - "docs/_build" + - "test/**/build/**/*" + - "test/**/build" diff --git a/test/README.md b/test/README.md index eef0cb2..e8931d4 100644 --- a/test/README.md +++ b/test/README.md @@ -1,7 +1,9 @@ -# Test Apps +# Test implementation This directory contains a set of ESP-IDF projects to be used as tests only, which aim to exercise various configuration of components to check completely arbitrary functionality should it be building only, executing under various conditions or combination with other components, including custom test frameworks. -The test apps are not intended to demonstrate the ESP-IDF functionality in any way. +The tests in this folder are not intended to demonstrate the ESP-IDF functionality in any way. + +The examples can be found here: https://github.com/espressif/esp-idf/tree/master/examples/protocols/modbus diff --git a/test/mb_example_common/CMakeLists.txt b/test/mb_example_common/CMakeLists.txt index bbd076e..c4854e9 100644 --- a/test/mb_example_common/CMakeLists.txt +++ b/test/mb_example_common/CMakeLists.txt @@ -2,5 +2,4 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) idf_component_register(SRCS "modbus_params.c" - INCLUDE_DIRS "include" - PRIV_REQUIRES esp-modbus) + INCLUDE_DIRS "include") diff --git a/test/serial/mb_serial_master/sdkconfig.defaults b/test/serial/mb_serial_master/sdkconfig.defaults index 4773f5b..3c9c6de 100644 --- a/test/serial/mb_serial_master/sdkconfig.defaults +++ b/test/serial/mb_serial_master/sdkconfig.defaults @@ -3,10 +3,8 @@ # CONFIG_MB_COMM_MODE_ASCII=y CONFIG_MB_UART_BAUD_RATE=115200 -CONFIG_FMB_TIMER_PORT_ENABLED=y -CONFIG_FMB_TIMER_GROUP=0 -CONFIG_FMB_TIMER_INDEX=0 +CONFIG_FMB_TIMER_PORT_ENABLED=n CONFIG_FMB_TIMER_ISR_IN_IRAM=y CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 -CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=400 CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y diff --git a/test/serial/mb_serial_slave/dependencies.lock b/test/serial/mb_serial_slave/dependencies.lock deleted file mode 100644 index ce2bede..0000000 --- a/test/serial/mb_serial_slave/dependencies.lock +++ /dev/null @@ -1,9 +0,0 @@ -dependencies: - idf: - component_hash: null - source: - type: idf - version: 5.0.0 -manifest_hash: ef92ef397dcb09fa7a851b483306296fee18dfca839e1a68e8190dad2ed66a64 -target: esp32 -version: 1.0.0 diff --git a/test/serial/mb_serial_slave/sdkconfig.defaults b/test/serial/mb_serial_slave/sdkconfig.defaults index 6507dfa..14806eb 100644 --- a/test/serial/mb_serial_slave/sdkconfig.defaults +++ b/test/serial/mb_serial_slave/sdkconfig.defaults @@ -4,8 +4,6 @@ CONFIG_MB_COMM_MODE_ASCII=y CONFIG_MB_SLAVE_ADDR=1 CONFIG_MB_UART_BAUD_RATE=115200 -CONFIG_FMB_TIMER_PORT_ENABLED=y -CONFIG_FMB_TIMER_GROUP=0 -CONFIG_FMB_TIMER_INDEX=0 +CONFIG_FMB_TIMER_PORT_ENABLED=n CONFIG_FMB_TIMER_ISR_IN_IRAM=y CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y