From 3abdd2207d6ddae8876ebbdfc7d3f2d0f2a8ba37 Mon Sep 17 00:00:00 2001 From: Alex Lisitsyn Date: Mon, 30 Mar 2020 22:05:48 +0800 Subject: [PATCH] freemodbus: fix long buffer failure check master read write functions with array of registers) fix master serial processing code and modbus controller to work with register array modbus_master: add reading and writing of test value array (58 registers) to check failure is gone remove parameter temporary buffer from modbus controller to allow more than 24 byte writes driver: fix issue with TOUT feature driver: fix uart_rx_timeout issue driver: fix issue with rxfifo_tout_int_raw not triggered when received fifo_len = 120 byte and all bytes read out of fifo as result of rxfifo_full_int_raw driver: add function uart_internal_set_always_rx_timeout() to always handle tout interrupt examples: call uart_internal_set_always_rx_timeout() to handle tout interrupt correctly examples: update examples to use tout feature driver: reflect changes of uart_set_always_rx_timeout() function, change uart.c driver: change conditions to trigger workaround for tout feature in uart.c driver: change uart_set_always_rx_timeout() freemodbus: fix tabs, remove commented code driver: remove uart_ll_is_rx_idle() --- components/driver/include/driver/uart.h | 17 +++ components/driver/uart.c | 19 ++- components/freemodbus/modbus/ascii/mbascii.c | 2 - .../modbus/functions/mbfuncdisc_m.c | 44 +++--- .../modbus/functions/mbfuncholding_m.c | 136 +++++++++--------- .../modbus/functions/mbfuncinput_m.c | 32 ++--- .../freemodbus/modbus/include/mbframe.h | 6 +- components/freemodbus/modbus/include/mbport.h | 1 + components/freemodbus/modbus/mb.c | 2 +- components/freemodbus/modbus/mb_m.c | 11 +- components/freemodbus/modbus/rtu/mbrtu.c | 4 +- components/freemodbus/modbus/rtu/mbrtu_m.c | 4 +- components/freemodbus/port/port.h | 15 +- components/freemodbus/port/portevent_m.c | 4 +- components/freemodbus/port/portserial.c | 67 ++++----- components/freemodbus/port/portserial_m.c | 64 ++++----- components/freemodbus/port/porttimer.c | 10 +- .../modbus_controller/mbc_serial_master.c | 62 +------- components/soc/include/hal/uart_hal.h | 27 +++- .../soc/src/esp32/include/hal/uart_ll.h | 28 +++- .../soc/src/esp32s2/include/hal/uart_ll.h | 16 +++ components/soc/src/hal/uart_hal_iram.c | 6 +- .../protocols/modbus/serial/example_test.py | 2 +- .../mb_example_common/include/modbus_params.h | 1 + .../modbus/serial/mb_master/main/master.c | 110 +++++++++----- .../modbus/serial/mb_slave/main/slave.c | 2 +- 26 files changed, 387 insertions(+), 305 deletions(-) diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index b0596a8cf..ef7508738 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -70,6 +70,8 @@ typedef enum { typedef struct { uart_event_type_t type; /*!< UART event type */ size_t size; /*!< UART data size for UART_DATA event*/ + bool timeout_flag; /*!< UART data read timeout flag for UART_DATA event (no new data received during configured RX TOUT)*/ + /*!< If the event is caused by FIFO-full interrupt, then there will be no event with the timeout flag before the next byte coming.*/ } uart_event_t; typedef intr_handle_t uart_isr_handle_t; @@ -845,6 +847,21 @@ esp_err_t uart_wait_tx_idle_polling(uart_port_t uart_num); */ esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en); +/** + * @brief Configure behavior of UART RX timeout interrupt. + * + * When always_rx_timeout is true, timeout interrupt is triggered even if FIFO is full. + * This function can cause extra timeout interrupts triggered only to send the timeout event. + * Call this function only if you want to ensure timeout interrupt will always happen after a byte stream. + * + * @param uart_num UART number + * @param always_rx_timeout_en Set to false enable the default behavior of timeout interrupt, + * set it to true to always trigger timeout interrupt. + * + * * @return None + */ +void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout_en); + #ifdef __cplusplus } #endif diff --git a/components/driver/uart.c b/components/driver/uart.c index d04821ca0..195da2eba 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -104,6 +104,7 @@ typedef struct { intr_handle_t intr_handle; /*!< UART interrupt handle*/ uart_mode_t uart_mode; /*!< UART controller actual mode set by uart_set_mode() */ bool coll_det_flg; /*!< UART collision detection flag */ + bool rx_always_timeout_flg; /*!< UART always detect rx timeout flag */ //rx parameters int rx_buffered_len; /*!< UART cached data length */ @@ -808,6 +809,10 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) pat_flg = 0; } if (p_uart->rx_buffer_full_flg == false) { + rx_fifo_len = uart_hal_get_rxfifo_len(&(uart_context[uart_num].hal)); + if ((p_uart_obj[uart_num]->rx_always_timeout_flg) && !(uart_intr_status & UART_INTR_RXFIFO_TOUT)) { + rx_fifo_len--; // leave one byte in the fifo in order to trigger uart_intr_rxfifo_tout + } uart_hal_read_rxfifo(&(uart_context[uart_num].hal), p_uart->rx_data_buf, &rx_fifo_len); uint8_t pat_chr = 0; uint8_t pat_num = 0; @@ -825,6 +830,7 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_FULL); uart_event.type = UART_DATA; uart_event.size = rx_fifo_len; + uart_event.timeout_flag = (uart_intr_status & UART_INTR_RXFIFO_TOUT) ? true : false; UART_ENTER_CRITICAL_ISR(&uart_selectlock); if (p_uart->uart_select_notif_callback) { p_uart->uart_select_notif_callback(uart_num, UART_SELECT_READ_NOTIF, &HPTaskAwoken); @@ -1296,6 +1302,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b p_uart_obj[uart_num]->uart_num = uart_num; p_uart_obj[uart_num]->uart_mode = UART_MODE_UART; p_uart_obj[uart_num]->coll_det_flg = false; + p_uart_obj[uart_num]->rx_always_timeout_flg = false; p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary(); xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary(); @@ -1342,7 +1349,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b .intr_enable_mask = UART_INTR_CONFIG_FLAG, .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT, .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT, - .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT + .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT, }; uart_module_enable(uart_num); uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_MASK); @@ -1549,3 +1556,13 @@ esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en) uart_hal_set_loop_back(&(uart_context[uart_num].hal), loop_back_en); return ESP_OK; } + +void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout) +{ + uint16_t rx_tout = uart_hal_get_rx_tout_thr(&(uart_context[uart_num].hal)); + if (rx_tout) { + p_uart_obj[uart_num]->rx_always_timeout_flg = always_rx_timeout; + } else { + p_uart_obj[uart_num]->rx_always_timeout_flg = false; + } +} diff --git a/components/freemodbus/modbus/ascii/mbascii.c b/components/freemodbus/modbus/ascii/mbascii.c index 0918498bc..71a8c3936 100644 --- a/components/freemodbus/modbus/ascii/mbascii.c +++ b/components/freemodbus/modbus/ascii/mbascii.c @@ -382,8 +382,6 @@ xMBASCIITransmitFSM( void ) eSndState = STATE_TX_IDLE; xMBPortEventPost( EV_FRAME_TRANSMIT ); xNeedPoll = FALSE; - - eSndState = STATE_TX_IDLE; break; /* We should not get a transmitter event if the transmitter is in diff --git a/components/freemodbus/modbus/functions/mbfuncdisc_m.c b/components/freemodbus/modbus/functions/mbfuncdisc_m.c index debc52d38..9e5973e65 100644 --- a/components/freemodbus/modbus/functions/mbfuncdisc_m.c +++ b/components/freemodbus/modbus/functions/mbfuncdisc_m.c @@ -79,16 +79,16 @@ eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT u else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY; else { - vMBMasterGetPDUSndBuf(&ucMBFrame); - vMBMasterSetDestAddress(ucSndAddr); - ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_DISCRETE_INPUTS; - ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usDiscreteAddr >> 8; - ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usDiscreteAddr; - ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8; - ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn; - vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE ); - ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); - eErrStatus = eMBMasterWaitRequestFinish( ); + vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterSetDestAddress(ucSndAddr); + ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_DISCRETE_INPUTS; + ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usDiscreteAddr >> 8; + ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usDiscreteAddr; + ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8; + ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn; + vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE ); + ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); + eErrStatus = eMBMasterWaitRequestFinish( ); } return eErrStatus; } @@ -107,11 +107,11 @@ eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen ) /* If this request is broadcast, and it's read mode. This request don't need execute. */ if ( xMBMasterRequestIsBroadcast() ) { - eStatus = MB_EX_NONE; + eStatus = MB_EX_NONE; } else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN ) { - vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterGetPDUSndBuf(&ucMBFrame); usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 ); usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] ); usRegAddress++; @@ -123,26 +123,26 @@ eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen ) * byte is only partially field with unused coils set to zero. */ if( ( usDiscreteCnt & 0x0007 ) != 0 ) { - ucNBytes = ( UCHAR )( usDiscreteCnt / 8 + 1 ); + ucNBytes = ( UCHAR )( usDiscreteCnt / 8 + 1 ); } else { - ucNBytes = ( UCHAR )( usDiscreteCnt / 8 ); + ucNBytes = ( UCHAR )( usDiscreteCnt / 8 ); } /* Check if the number of registers to read is valid. If not * return Modbus illegal data value exception. */ - if ((usDiscreteCnt >= 1) && ucNBytes == pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF]) + if ((usDiscreteCnt >= 1) && ucNBytes == pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF]) { - /* Make callback to fill the buffer. */ - eRegStatus = eMBMasterRegDiscreteCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usDiscreteCnt ); + /* Make callback to fill the buffer. */ + eRegStatus = eMBMasterRegDiscreteCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usDiscreteCnt ); - /* If an error occured convert it into a Modbus exception. */ - if( eRegStatus != MB_ENOERR ) - { - eStatus = prveMBError2Exception( eRegStatus ); - } + /* If an error occured convert it into a Modbus exception. */ + if( eRegStatus != MB_ENOERR ) + { + eStatus = prveMBError2Exception( eRegStatus ); + } } else { diff --git a/components/freemodbus/modbus/functions/mbfuncholding_m.c b/components/freemodbus/modbus/functions/mbfuncholding_m.c index 1cbd876eb..df1c30505 100644 --- a/components/freemodbus/modbus/functions/mbfuncholding_m.c +++ b/components/freemodbus/modbus/functions/mbfuncholding_m.c @@ -107,16 +107,16 @@ eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRe else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY; else { - vMBMasterGetPDUSndBuf(&ucMBFrame); - vMBMasterSetDestAddress(ucSndAddr); - ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_REGISTER; - ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usRegAddr >> 8; - ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usRegAddr; - ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8; - ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ; - vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE ); - ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); - eErrStatus = eMBMasterWaitRequestFinish( ); + vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterSetDestAddress(ucSndAddr); + ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_REGISTER; + ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usRegAddr >> 8; + ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usRegAddr; + ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8; + ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ; + vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE ); + ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); + eErrStatus = eMBMasterWaitRequestFinish( ); } return eErrStatus; } @@ -168,7 +168,7 @@ eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen ) */ eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, - USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut ) + USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut ) { UCHAR *ucMBFrame; USHORT usRegIndex = 0; @@ -178,23 +178,23 @@ eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY; else { - vMBMasterGetPDUSndBuf(&ucMBFrame); - vMBMasterSetDestAddress(ucSndAddr); - ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_REGISTERS; - ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usRegAddr >> 8; - ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usRegAddr; - ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] = usNRegs >> 8; - ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs ; - ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = usNRegs * 2; - ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF; - while( usNRegs > usRegIndex) - { - *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8; - *ucMBFrame++ = pusDataBuffer[usRegIndex++] ; - } - vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs ); - ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); - eErrStatus = eMBMasterWaitRequestFinish( ); + vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterSetDestAddress(ucSndAddr); + ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_REGISTERS; + ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usRegAddr >> 8; + ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usRegAddr; + ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] = usNRegs >> 8; + ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs ; + ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = usNRegs * 2; + ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF; + while( usNRegs > usRegIndex) + { + *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8; + *ucMBFrame++ = pusDataBuffer[usRegIndex++] ; + } + vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs ); + ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); + eErrStatus = eMBMasterWaitRequestFinish( ); } return eErrStatus; } @@ -213,7 +213,7 @@ eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen ) /* If this request is broadcast, the *usLen is not need check. */ if( ( *usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() ) { - vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterGetPDUSndBuf(&ucMBFrame); usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] << 8 ); usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] ); usRegAddress++; @@ -271,16 +271,16 @@ eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRe else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY; else { - vMBMasterGetPDUSndBuf(&ucMBFrame); - vMBMasterSetDestAddress(ucSndAddr); - ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_HOLDING_REGISTER; - ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8; - ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr; - ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8; - ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs; - vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE ); - ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); - eErrStatus = eMBMasterWaitRequestFinish( ); + vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterSetDestAddress(ucSndAddr); + ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_HOLDING_REGISTER; + ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8; + ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr; + ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8; + ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs; + vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE ); + ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); + eErrStatus = eMBMasterWaitRequestFinish( ); } return eErrStatus; } @@ -298,11 +298,11 @@ eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen ) /* If this request is broadcast, and it's read mode. This request don't need execute. */ if ( xMBMasterRequestIsBroadcast() ) { - eStatus = MB_EX_NONE; + eStatus = MB_EX_NONE; } else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN ) { - vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterGetPDUSndBuf(&ucMBFrame); usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 ); usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] ); usRegAddress++; @@ -355,8 +355,8 @@ eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen ) */ 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 ) { UCHAR *ucMBFrame; USHORT usRegIndex = 0; @@ -366,27 +366,27 @@ eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr, else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY; else { - vMBMasterGetPDUSndBuf(&ucMBFrame); - vMBMasterSetDestAddress(ucSndAddr); - ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READWRITE_MULTIPLE_REGISTERS; - ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] = usReadRegAddr >> 8; - ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] = usReadRegAddr; - ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] = usNReadRegs >> 8; - ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] = usNReadRegs ; - ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] = usWriteRegAddr >> 8; - ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] = usWriteRegAddr; - ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] = usNWriteRegs >> 8; - ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs ; - ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF] = usNWriteRegs * 2; - ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF; - while( usNWriteRegs > usRegIndex) - { - *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8; - *ucMBFrame++ = pusDataBuffer[usRegIndex++] ; - } - vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs ); - ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); - eErrStatus = eMBMasterWaitRequestFinish( ); + vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterSetDestAddress(ucSndAddr); + ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READWRITE_MULTIPLE_REGISTERS; + ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] = usReadRegAddr >> 8; + ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] = usReadRegAddr; + ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] = usNReadRegs >> 8; + ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] = usNReadRegs ; + ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] = usWriteRegAddr >> 8; + ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] = usWriteRegAddr; + ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] = usNWriteRegs >> 8; + ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs ; + ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF] = usNWriteRegs * 2; + ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF; + while( usNWriteRegs > usRegIndex) + { + *ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8; + *ucMBFrame++ = pusDataBuffer[usRegIndex++] ; + } + vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs ); + ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); + eErrStatus = eMBMasterWaitRequestFinish( ); } return eErrStatus; } @@ -406,11 +406,11 @@ eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen /* If this request is broadcast, and it's read mode. This request don't need execute. */ if ( xMBMasterRequestIsBroadcast() ) { - eStatus = MB_EX_NONE; + eStatus = MB_EX_NONE; } else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN ) { - vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterGetPDUSndBuf(&ucMBFrame); usRegReadAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] << 8U ); usRegReadAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] ); usRegReadAddress++; @@ -434,8 +434,8 @@ eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen if( eRegStatus == MB_ENOERR ) { /* Make the read callback. */ - eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF], - usRegReadAddress, usRegReadCount, MB_REG_READ); + eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF], + usRegReadAddress, usRegReadCount, MB_REG_READ); } if( eRegStatus != MB_ENOERR ) { diff --git a/components/freemodbus/modbus/functions/mbfuncinput_m.c b/components/freemodbus/modbus/functions/mbfuncinput_m.c index aeb7bc253..9a6b5677b 100644 --- a/components/freemodbus/modbus/functions/mbfuncinput_m.c +++ b/components/freemodbus/modbus/functions/mbfuncinput_m.c @@ -78,16 +78,16 @@ eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY; else { - vMBMasterGetPDUSndBuf(&ucMBFrame); - vMBMasterSetDestAddress(ucSndAddr); - ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_INPUT_REGISTER; - ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8; - ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr; - ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8; - ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs; - vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE ); - ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); - eErrStatus = eMBMasterWaitRequestFinish( ); + vMBMasterGetPDUSndBuf(&ucMBFrame); + vMBMasterSetDestAddress(ucSndAddr); + ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_INPUT_REGISTER; + ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8; + ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr; + ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8; + ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs; + vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE ); + ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT ); + eErrStatus = eMBMasterWaitRequestFinish( ); } return eErrStatus; } @@ -103,13 +103,13 @@ eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen ) eMBErrorCode eRegStatus; /* If this request is broadcast, and it's read mode. This request don't need execute. */ - if ( xMBMasterRequestIsBroadcast() ) - { - eStatus = MB_EX_NONE; - } - else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN ) + if ( xMBMasterRequestIsBroadcast() ) { - vMBMasterGetPDUSndBuf(&ucMBFrame); + eStatus = MB_EX_NONE; + } + else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN ) + { + vMBMasterGetPDUSndBuf(&ucMBFrame); usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 ); usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] ); usRegAddress++; diff --git a/components/freemodbus/modbus/include/mbframe.h b/components/freemodbus/modbus/include/mbframe.h index 92953adc7..8b48909b4 100644 --- a/components/freemodbus/modbus/include/mbframe.h +++ b/components/freemodbus/modbus/include/mbframe.h @@ -31,6 +31,8 @@ #ifndef _MB_FRAME_H #define _MB_FRAME_H +#include "port.h" + #ifdef __cplusplus PR_BEGIN_EXTERN_C #endif @@ -61,12 +63,12 @@ PR_BEGIN_EXTERN_C */ /* ----------------------- Defines ------------------------------------------*/ -#define MB_PDU_SIZE_MAX 253 /*!< Maximum size of a PDU. */ +#define MB_PDU_SIZE_MAX ( 253 ) /*!< Maximum size of a PDU. */ #define MB_PDU_SIZE_MIN 1 /*!< Function Code */ #define MB_PDU_FUNC_OFF 0 /*!< Offset of function code in PDU. */ #define MB_PDU_DATA_OFF 1 /*!< Offset for response data in PDU. */ -#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus frame. */ +#define MB_SER_PDU_SIZE_MAX ( MB_SERIAL_BUF_SIZE ) /*!< Maximum size of a Modbus frame. */ #define MB_SER_PDU_SIZE_LRC 1 /*!< Size of LRC field in PDU. */ #define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */ #define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */ diff --git a/components/freemodbus/modbus/include/mbport.h b/components/freemodbus/modbus/include/mbport.h index 9b591ce12..2bcd385c0 100644 --- a/components/freemodbus/modbus/include/mbport.h +++ b/components/freemodbus/modbus/include/mbport.h @@ -81,6 +81,7 @@ typedef enum { EV_ERROR_RESPOND_TIMEOUT, /*!< Slave respond timeout. */ EV_ERROR_RECEIVE_DATA, /*!< Receive frame data erroe. */ EV_ERROR_EXECUTE_FUNCTION, /*!< Execute function error. */ + EV_ERROR_OK, /*!< Data processed. */ } eMBMasterErrorEventType; #endif diff --git a/components/freemodbus/modbus/mb.c b/components/freemodbus/modbus/mb.c index d847b97e2..927ba4d05 100644 --- a/components/freemodbus/modbus/mb.c +++ b/components/freemodbus/modbus/mb.c @@ -62,7 +62,7 @@ static UCHAR ucMBAddress; static eMBMode eMBCurrentMode; -volatile UCHAR ucMbSlaveBuf[MB_SER_PDU_SIZE_MAX]; +volatile UCHAR ucMbSlaveBuf[MB_SERIAL_BUF_SIZE]; static enum { diff --git a/components/freemodbus/modbus/mb_m.c b/components/freemodbus/modbus/mb_m.c index cc86f66c9..d7fe5d881 100644 --- a/components/freemodbus/modbus/mb_m.c +++ b/components/freemodbus/modbus/mb_m.c @@ -69,8 +69,8 @@ static volatile USHORT usMasterSendPDULength; /*------------------------ Shared variables ---------------------------------*/ -volatile UCHAR ucMasterSndBuf[MB_PDU_SIZE_MAX]; -volatile UCHAR ucMasterRcvBuf[MB_SER_PDU_SIZE_MAX]; +volatile UCHAR ucMasterSndBuf[MB_SERIAL_BUF_SIZE]; +volatile UCHAR ucMasterRcvBuf[MB_SERIAL_BUF_SIZE]; volatile eMBMasterTimerMode eMasterCurTimerMode; volatile BOOL xFrameIsBroadcast = FALSE; @@ -359,8 +359,8 @@ eMBMasterPoll( void ) } else { - vMBMasterCBRequestSuccess( ); - vMBMasterRunResRelease( ); + vMBMasterSetErrorType(EV_ERROR_OK); + ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); } MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_EXECUTE ); } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_TRANSMIT ) ) { @@ -395,6 +395,9 @@ eMBMasterPoll( void ) vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ), ucMBFrame, usMBMasterGetPDUSndLength( ) ); break; + case EV_ERROR_OK: + vMBMasterCBRequestSuccess( ); + break; default: ESP_LOGE( MB_PORT_TAG, "%s: incorrect error type = %d.", __func__, errorType); break; diff --git a/components/freemodbus/modbus/rtu/mbrtu.c b/components/freemodbus/modbus/rtu/mbrtu.c index 434ac6e7a..066fea3ee 100644 --- a/components/freemodbus/modbus/rtu/mbrtu.c +++ b/components/freemodbus/modbus/rtu/mbrtu.c @@ -265,7 +265,9 @@ xMBRTUReceiveFSM( void ) case STATE_RX_RCV: if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX ) { - ucRTUBuf[usRcvBufferPos++] = ucByte; + if ( xStatus ) { + ucRTUBuf[usRcvBufferPos++] = ucByte; + } } else { diff --git a/components/freemodbus/modbus/rtu/mbrtu_m.c b/components/freemodbus/modbus/rtu/mbrtu_m.c index 07b6d2573..0ab012b5a 100644 --- a/components/freemodbus/modbus/rtu/mbrtu_m.c +++ b/components/freemodbus/modbus/rtu/mbrtu_m.c @@ -281,7 +281,9 @@ xMBMasterRTUReceiveFSM( void ) case STATE_M_RX_RCV: if( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX ) { - ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte; + if ( xStatus ) { + ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte; + } } else { diff --git a/components/freemodbus/port/port.h b/components/freemodbus/port/port.h index 815b2e344..d9e2cb794 100644 --- a/components/freemodbus/port/port.h +++ b/components/freemodbus/port/port.h @@ -19,6 +19,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/xtensa_api.h" #include "esp_log.h" // for ESP_LOGE macro +#include "sdkconfig.h" #define INLINE inline #define PR_BEGIN_EXTERN_C extern "C" { @@ -26,10 +27,22 @@ #define MB_PORT_TAG "MB_PORT_COMMON" +#define MB_BAUD_RATE_DEFAULT (115200) +#define MB_QUEUE_LENGTH (CONFIG_FMB_QUEUE_LENGTH) + +#define MB_SERIAL_TASK_PRIO (CONFIG_FMB_SERIAL_TASK_PRIO) +#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 + +// Set buffer size for transmission +#define MB_SERIAL_BUF_SIZE (CONFIG_FMB_SERIAL_BUF_SIZE) + // common definitions for serial port implementations #define MB_SERIAL_TX_TOUT_MS (100) #define MB_SERIAL_TX_TOUT_TICKS pdMS_TO_TICKS(MB_SERIAL_TX_TOUT_MS) // timeout for transmission -#define MB_SERIAL_RX_TOUT_TICKS pdMS_TO_TICKS(1) // timeout for rx from buffer +#define MB_SERIAL_RX_TOUT_MS (1) +#define MB_SERIAL_RX_TOUT_TICKS pdMS_TO_TICKS(MB_SERIAL_RX_TOUT_MS) // timeout for receive + #define MB_SERIAL_RESP_LEN_MIN (4) #define MB_PORT_CHECK(a, ret_val, str, ...) \ diff --git a/components/freemodbus/port/portevent_m.c b/components/freemodbus/port/portevent_m.c index 2e54c926c..7ad91433f 100644 --- a/components/freemodbus/port/portevent_m.c +++ b/components/freemodbus/port/portevent_m.c @@ -217,7 +217,7 @@ void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUDat { BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION); MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!", __func__); - ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data timeout failure.", __func__); + ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data handler failure.", __func__); } /** @@ -252,7 +252,7 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) { MB_EVENT_REQ_MASK, // The bits within the event group to wait for. pdTRUE, // Masked bits should be cleared before returning. pdFALSE, // Don't wait for both bits, either bit will do. - portMAX_DELAY ); // Wait forever for either bit to be set. + 1000 ); // Wait forever for either bit to be set. //portMAX_DELAY xRecvedEvent = (eMBMasterEventType)(uxBits); if (xRecvedEvent) { ESP_LOGD(MB_PORT_TAG,"%s: returned event = 0x%x", __func__, xRecvedEvent); diff --git a/components/freemodbus/port/portserial.c b/components/freemodbus/port/portserial.c index 4c2eeaa4d..102e47086 100644 --- a/components/freemodbus/port/portserial.c +++ b/components/freemodbus/port/portserial.c @@ -55,25 +55,6 @@ #include "sdkconfig.h" // for KConfig options #include "port_serial_slave.h" -// Definitions of UART default pin numbers -#define MB_UART_RXD (CONFIG_MB_UART_RXD) -#define MB_UART_TXD (CONFIG_MB_UART_TXD) -#define MB_UART_RTS (CONFIG_MB_UART_RTS) - -#define MB_BAUD_RATE_DEFAULT (115200) -#define MB_QUEUE_LENGTH (CONFIG_FMB_QUEUE_LENGTH) - -#define MB_SERIAL_TASK_PRIO (CONFIG_FMB_SERIAL_TASK_PRIO) -#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_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 -#define MB_SERIAL_BUF_SIZE (CONFIG_FMB_SERIAL_BUF_SIZE) - -// Note: This code uses mixed coding standard from legacy IDF code and used freemodbus stack - // A queue to handle UART event. static QueueHandle_t xMbUartQueue; static TaskHandle_t xMbTaskHandle; @@ -103,28 +84,26 @@ void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) } } -static void vMBPortSerialRxPoll(size_t xEventSize) +static USHORT usMBPortSerialRxPoll(size_t xEventSize) { BOOL xReadStatus = TRUE; USHORT usCnt = 0; if (bRxStateEnabled) { - if (xEventSize > MB_SERIAL_RESP_LEN_MIN) { - xEventSize = (xEventSize > MB_SERIAL_BUF_SIZE) ? MB_SERIAL_BUF_SIZE : xEventSize; - // Get received packet into Rx buffer - for(usCnt = 0; xReadStatus && (usCnt < xEventSize); usCnt++ ) { - // Call the Modbus stack callback function and let it fill the buffers. - xReadStatus = pxMBFrameCBByteReceived(); // callback to execute receive FSM state machine - } - uart_flush_input(ucUartNumber); - // Send event EV_FRAME_RECEIVED to allow stack process packet -#ifndef MB_TIMER_PORT_ENABLED - // Let the stack know that T3.5 time is expired and data is received - (void)pxMBPortCBTimerExpired(); // calls callback xMBRTUTimerT35Expired(); -#endif - ESP_LOGD(TAG, "RX: %d bytes\n", usCnt); + // Get received packet into Rx buffer + while(xReadStatus && (usCnt++ <= MB_SERIAL_BUF_SIZE)) { + // 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(); +#endif + ESP_LOGD(TAG, "RX: %d bytes\n", usCnt); } + return usCnt; } BOOL xMBPortSerialTxPoll(void) @@ -136,7 +115,7 @@ BOOL xMBPortSerialTxPoll(void) // Continue while all response bytes put in buffer or out of buffer while((bNeedPoll) && (usCount++ < MB_SERIAL_BUF_SIZE)) { // Calls the modbus stack callback function to let it fill the UART transmit buffer. - bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // callback to transmit FSM state machine + bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // callback to transmit FSM } ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount); // Waits while UART sending the packet @@ -151,15 +130,21 @@ BOOL xMBPortSerialTxPoll(void) static void vUartTask(void *pvParameters) { uart_event_t xEvent; + USHORT usResult = 0; for(;;) { if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); switch(xEvent.type) { //Event of UART receving data case UART_DATA: - ESP_LOGD(TAG,"Receive data, len: %d", xEvent.size); - // Read received data and send it to modbus stack - vMBPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Data event, length: %d", xEvent.size); + // 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) { + // Read received data and send it to modbus stack + usResult = usMBPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); + } break; //Event of HW FIFO overflow detected case UART_FIFO_OVF: @@ -249,12 +234,16 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "mb serial driver failure, uart_driver_install() returned (0x%x).", xErr); -#ifndef MB_TIMER_PORT_ENABLED +#if !CONFIG_FMB_TIMER_PORT_ENABLED // Set timeout for TOUT interrupt (T3.5 modbus time) xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr); #endif + + // Set always timeout flag to trigger timeout interrupt even after rx fifo full + uart_set_always_rx_timeout(ucUartNumber, true); + // Create a task to handle UART events BaseType_t xStatus = xTaskCreate(vUartTask, "uart_queue_task", MB_SERIAL_TASK_STACK_SIZE, NULL, MB_SERIAL_TASK_PRIO, &xMbTaskHandle); diff --git a/components/freemodbus/port/portserial_m.c b/components/freemodbus/port/portserial_m.c index 0359d6fdc..1caa63da0 100644 --- a/components/freemodbus/port/portserial_m.c +++ b/components/freemodbus/port/portserial_m.c @@ -51,18 +51,6 @@ #include "sdkconfig.h" #include "port_serial_master.h" -/* ----------------------- Defines ------------------------------------------*/ - -#define MB_BAUD_RATE_DEFAULT (115200) -#define MB_QUEUE_LENGTH (CONFIG_FMB_QUEUE_LENGTH) - -#define MB_SERIAL_TASK_PRIO (CONFIG_FMB_SERIAL_TASK_PRIO) -#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 - -// Set buffer size for transmission -#define MB_SERIAL_BUF_SIZE (CONFIG_FMB_SERIAL_BUF_SIZE) - /* ----------------------- Static variables ---------------------------------*/ static const CHAR *TAG = "MB_MASTER_SERIAL"; @@ -76,9 +64,6 @@ static UCHAR ucUartNumber = UART_NUM_MAX - 1; static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag -static UCHAR ucBuffer[MB_SERIAL_BUF_SIZE]; // Temporary buffer to transfer received data to modbus stack -static USHORT uiRxBufferPos = 0; // position in the receiver buffer - void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) { // This function can be called from xMBRTUTransmitFSM() of different task @@ -96,28 +81,23 @@ void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) } } -static void vMBMasterPortSerialRxPoll(size_t xEventSize) +static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize) { BOOL xReadStatus = TRUE; USHORT usCnt = 0; if (bRxStateEnabled) { - if (xEventSize > MB_SERIAL_RESP_LEN_MIN) { - xEventSize = (xEventSize > MB_SERIAL_BUF_SIZE) ? MB_SERIAL_BUF_SIZE : xEventSize; - // Get received packet into Rx buffer - USHORT usLength = uart_read_bytes(ucUartNumber, &ucBuffer[0], xEventSize, portMAX_DELAY); - uiRxBufferPos = 0; - for(usCnt = 0; xReadStatus && (usCnt < usLength); usCnt++ ) { - // Call the Modbus stack callback function and let it fill the stack buffers. - xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM state machine - } - // The buffer is transferred into Modbus stack and is not needed here any more - uart_flush_input(ucUartNumber); - ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt); + while(xReadStatus && (usCnt++ <= MB_SERIAL_BUF_SIZE)) { + // Call the Modbus stack callback function and let it fill the stack buffers. + xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM } + // The buffer is transferred into Modbus stack and is not needed here any more + uart_flush_input(ucUartNumber); + ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt); } else { ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%d bytes) received. ", __func__, xEventSize); } + return usCnt; } BOOL xMBMasterPortSerialTxPoll(void) @@ -127,9 +107,9 @@ BOOL xMBMasterPortSerialTxPoll(void) if( bTxStateEnabled ) { // Continue while all response bytes put in buffer or out of buffer - while((bNeedPoll) && (usCount++ < MB_SERIAL_BUF_SIZE)) { + while(bNeedPoll && (usCount++ < MB_SERIAL_BUF_SIZE)) { // Calls the modbus stack callback function to let it fill the UART transmit buffer. - bNeedPoll = pxMBMasterFrameCBTransmitterEmpty( ); // callback to transmit FSM state machine + bNeedPoll = pxMBMasterFrameCBTransmitterEmpty( ); // callback to transmit FSM } ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes.", (uint16_t)(usCount - 1)); // Waits while UART sending the packet @@ -145,15 +125,21 @@ BOOL xMBMasterPortSerialTxPoll(void) static void vUartTask(void* pvParameters) { uart_event_t xEvent; + USHORT usResult = 0; for(;;) { if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); switch(xEvent.type) { //Event of UART receiving data case UART_DATA: - ESP_LOGD(TAG,"Receive data, len: %d.", xEvent.size); - // Read received data and send it to modbus stack - vMBMasterPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Data event, len: %d.", xEvent.size); + // 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) { + // Read received data and send it to modbus stack + usResult = usMBMasterPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); + } break; //Event of HW FIFO overflow detected case UART_FIFO_OVF: @@ -247,6 +233,10 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr); + + // Set always timeout flag to trigger timeout interrupt even after rx fifo full + uart_set_always_rx_timeout(ucUartNumber, true); + // Create a task to handle UART events BaseType_t xStatus = xTaskCreate(vUartTask, "uart_queue_task", MB_SERIAL_TASK_STACK_SIZE, NULL, MB_SERIAL_TASK_PRIO, &xMbTaskHandle); @@ -259,7 +249,6 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, } else { vTaskSuspend(xMbTaskHandle); // Suspend serial task while stack is not started } - uiRxBufferPos = 0; ESP_LOGD(MB_PORT_TAG,"%s Init serial.", __func__); return TRUE; } @@ -282,9 +271,6 @@ BOOL xMBMasterPortSerialPutByte(CHAR ucByte) BOOL xMBMasterPortSerialGetByte(CHAR* pucByte) { assert(pucByte != NULL); - MB_PORT_CHECK((uiRxBufferPos < MB_SERIAL_BUF_SIZE), - FALSE, "mb stack serial get byte failure."); - *pucByte = ucBuffer[uiRxBufferPos]; - uiRxBufferPos++; - return TRUE; + USHORT usLength = uart_read_bytes(ucUartNumber, (uint8_t*)pucByte, 1, MB_SERIAL_RX_TOUT_TICKS); + return (usLength == 1); } diff --git a/components/freemodbus/port/porttimer.c b/components/freemodbus/port/porttimer.c index 246ca335d..4a2af4575 100644 --- a/components/freemodbus/port/porttimer.c +++ b/components/freemodbus/port/porttimer.c @@ -52,7 +52,7 @@ #include "port_serial_slave.h" #include "sdkconfig.h" -#ifdef CONFIG_FMB_TIMER_PORT_ENABLED +#if CONFIG_FMB_TIMER_PORT_ENABLED #define MB_US50_FREQ (20000) // 20kHz 1/20000 = 50mks #define MB_DISCR_TIME_US (50) // 50uS = one discreet for timer @@ -80,7 +80,7 @@ static void IRAM_ATTR vTimerGroupIsr(void *param) BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) { -#ifdef CONFIG_FMB_TIMER_PORT_ENABLED +#if CONFIG_FMB_TIMER_PORT_ENABLED MB_PORT_CHECK((usTim1Timerout50us > 0), FALSE, "Modbus timeout discreet is incorrect."); esp_err_t xErr; @@ -121,7 +121,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us) void vMBPortTimersEnable(void) { -#ifdef CONFIG_FMB_TIMER_PORT_ENABLED +#if CONFIG_FMB_TIMER_PORT_ENABLED ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex)); ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL)); ESP_ERROR_CHECK(timer_enable_intr(usTimerGroupIndex, usTimerIndex)); @@ -132,9 +132,9 @@ void vMBPortTimersEnable(void) void MB_PORT_ISR_ATTR vMBPortTimersDisable(void) { -#ifdef CONFIG_FMB_TIMER_PORT_ENABLED +#if CONFIG_FMB_TIMER_PORT_ENABLED if( (BOOL)xPortInIsrContext() ) { - timer_group_set_counter_enable_in_isr(usTimerGroupIndex, usTimerIndex, TIMER_PAUSE); + timer_group_set_counter_enable_in_isr(usTimerGroupIndex, usTimerIndex, TIMER_PAUSE); } else { ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex)); ESP_ERROR_CHECK(timer_set_counter_value(usTimerGroupIndex, usTimerIndex, 0ULL)); diff --git a/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c b/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c index 66019b3c4..909f932fc 100644 --- a/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c +++ b/components/freemodbus/serial_master/modbus_controller/mbc_serial_master.c @@ -36,7 +36,7 @@ extern BOOL xMBMasterPortSerialTxPoll(void); /*-----------------------Master mode use these variables----------------------*/ -#define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND) +#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; @@ -333,41 +333,6 @@ static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_para return command; } -// Helper function to set parameter buffer according to its type -static esp_err_t mbc_serial_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size) -{ - esp_err_t err = ESP_OK; - MB_MASTER_CHECK((dest != NULL), - ESP_ERR_INVALID_ARG, "incorrect parameter pointer."); - MB_MASTER_CHECK((src != NULL), - ESP_ERR_INVALID_ARG, "incorrect parameter pointer."); - // Transfer parameter data into value of characteristic - switch(param_type) - { - case PARAM_TYPE_U8: - *((uint8_t*)dest) = *((uint8_t*)src); - break; - case PARAM_TYPE_U16: - *((uint16_t*)dest) = *((uint16_t*)src); - break; - case PARAM_TYPE_U32: - *((uint32_t*)dest) = *((uint32_t*)src); - break; - case PARAM_TYPE_FLOAT: - *((float*)dest) = *(float*)src; - break; - case PARAM_TYPE_ASCII: - memcpy((void*)dest, (void*)src, (size_t)param_size); - break; - default: - ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u).", - __FUNCTION__, (uint16_t)param_type); - err = ESP_ERR_NOT_SUPPORTED; - break; - } - return err; -} - // Helper to search parameter by name in the parameter description table // and fills Modbus request fields accordingly static esp_err_t mbc_serial_master_set_request(char* name, mb_param_mode_t mode, @@ -418,7 +383,7 @@ static esp_err_t mbc_serial_master_set_request(char* name, mb_param_mode_t mode, // Get parameter data for corresponding characteristic static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, - uint8_t* value, uint8_t *type) + uint8_t* value_ptr, uint8_t *type) { MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor."); @@ -427,19 +392,12 @@ static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, esp_err_t error = ESP_ERR_INVALID_RESPONSE; mb_param_request_t request ; mb_parameter_descriptor_t reg_info = { 0 }; - uint8_t param_buffer[PARAM_MAX_SIZE] = { 0 }; error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, ®_info); if ((error == ESP_OK) && (cid == reg_info.cid)) { - error = mbc_serial_master_send_request(&request, ¶m_buffer[0]); + // Send request to read characteristic data + error = mbc_serial_master_send_request(&request, value_ptr); if (error == ESP_OK) { - // If data pointer is NULL then we don't need to set value - // (it is still in the cache of cid) - if (value != NULL) { - error = mbc_serial_master_set_param_data((void*)value, (void*)¶m_buffer[0], - reg_info.param_type, reg_info.param_size); - MB_MASTER_CHECK((error == ESP_OK), ESP_ERR_INVALID_STATE, "fail to set parameter data."); - } ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s", __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error)); } else { @@ -457,28 +415,22 @@ static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, // Set parameter value for characteristic selected by name and cid static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name, - uint8_t* value, uint8_t *type) + uint8_t* value_ptr, uint8_t *type) { MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor."); - MB_MASTER_CHECK((value != NULL), + MB_MASTER_CHECK((value_ptr != NULL), ESP_ERR_INVALID_ARG, "value pointer is incorrect."); MB_MASTER_CHECK((type != NULL), ESP_ERR_INVALID_ARG, "type pointer is incorrect."); esp_err_t error = ESP_ERR_INVALID_RESPONSE; mb_param_request_t request ; mb_parameter_descriptor_t reg_info = { 0 }; - uint8_t param_buffer[PARAM_MAX_SIZE] = { 0 }; error = mbc_serial_master_set_request(name, MB_PARAM_WRITE, &request, ®_info); if ((error == ESP_OK) && (cid == reg_info.cid)) { - // Transfer value of characteristic into parameter buffer - error = mbc_serial_master_set_param_data((void*)¶m_buffer[0], (void*)value, - reg_info.param_type, reg_info.param_size); - MB_MASTER_CHECK((error == ESP_OK), - ESP_ERR_INVALID_STATE, "failure to set parameter data."); // Send request to write characteristic data - error = mbc_serial_master_send_request(&request, ¶m_buffer[0]); + error = mbc_serial_master_send_request(&request, value_ptr); if (error == ESP_OK) { ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s", __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error)); diff --git a/components/soc/include/hal/uart_hal.h b/components/soc/include/hal/uart_hal.h index 281d25a83..59ba28d5d 100644 --- a/components/soc/include/hal/uart_hal.h +++ b/components/soc/include/hal/uart_hal.h @@ -127,13 +127,14 @@ typedef struct { /** * @brief Read data from the UART rxfifo * - * @param hal Context of the HAL layer - * @param buf Pointer to the buffer used to store the read data. The buffer size should be large than 128 byts - * @param rd_len The length has been read out from the rxfifo + * @param[in] hal Context of the HAL layer + * @param[in] buf Pointer to the buffer used to store the read data. The buffer size should be large than 128 byte + * @param[inout] inout_rd_len As input, the size of output buffer to read (set to 0 to read all available data). + * As output, returns the actual size written into the output buffer. * * @return None */ -void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *rd_len); +void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *inout_rd_len); /** * @brief Write data into the UART txfifo @@ -448,6 +449,24 @@ uint8_t uart_hal_get_symb_len(uart_hal_context_t *hal); */ uint16_t uart_hal_get_max_rx_timeout_thrd(uart_hal_context_t *hal); +/** + * @brief Get the timeout threshold value set for receiver. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout value. If timeout is disabled then returns 0. + */ +#define uart_hal_get_rx_tout_thr(hal) uart_ll_get_rx_tout_thr((hal)->dev) + +/** + * @brief Get the length of readable data in UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The readable data length in rxfifo. + */ +#define uart_hal_get_rxfifo_len(hal) uart_ll_get_rxfifo_len((hal)->dev) + #ifdef __cplusplus } #endif diff --git a/components/soc/src/esp32/include/hal/uart_ll.h b/components/soc/src/esp32/include/hal/uart_ll.h index f1c7abf3b..dc4a05bff 100644 --- a/components/soc/src/esp32/include/hal/uart_ll.h +++ b/components/soc/src/esp32/include/hal/uart_ll.h @@ -807,6 +807,26 @@ static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thr) } } +/** + * @brief Get the timeout value for receiver receiving a byte. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0. + */ +static inline uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw) +{ + uint16_t tout_thrd = 0; + if (hw->conf1.rx_tout_en > 0) { + if (hw->conf0.tick_ref_always_on == 0) { + tout_thrd = (uint16_t)(hw->conf1.rx_tout_thrhd / UART_LL_TOUT_REF_FACTOR_DEFAULT); + } else { + tout_thrd = (uint16_t)(hw->conf1.rx_tout_thrhd << 3); + } + } + return tout_thrd; +} + /** * @brief Get UART maximum timeout threshold. * @@ -816,13 +836,13 @@ static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thr) */ static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw) { - uint16_t tout_sym = 0; + uint16_t tout_thrd = 0; if (hw->conf0.tick_ref_always_on == 0) { - tout_sym = (uint16_t)(UART_RX_TOUT_THRHD_V / UART_LL_TOUT_REF_FACTOR_DEFAULT); + tout_thrd = (uint16_t)(UART_RX_TOUT_THRHD_V / UART_LL_TOUT_REF_FACTOR_DEFAULT); } else { - tout_sym = (uint16_t)(UART_RX_TOUT_THRHD_V << 3); + tout_thrd = (uint16_t)(UART_RX_TOUT_THRHD_V << 3); } - return tout_sym; + return tout_thrd; } #undef UART_LL_TOUT_REF_FACTOR_DEFAULT diff --git a/components/soc/src/esp32s2/include/hal/uart_ll.h b/components/soc/src/esp32s2/include/hal/uart_ll.h index 3b1c86fa1..9ab67aacf 100644 --- a/components/soc/src/esp32s2/include/hal/uart_ll.h +++ b/components/soc/src/esp32s2/include/hal/uart_ll.h @@ -772,6 +772,22 @@ static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thrd) } } +/** + * @brief Get the timeout value for receiver receiving a byte. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0. + */ +static inline uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw) +{ + uint16_t tout_thrd = 0; + if(hw->conf1.rx_tout_en > 0) { + tout_thrd = hw->mem_conf.rx_tout_thrhd; + } + return tout_thrd; +} + /** * @brief Get UART maximum timeout threshold. * diff --git a/components/soc/src/hal/uart_hal_iram.c b/components/soc/src/hal/uart_hal_iram.c index f13ce4b08..a6da2e4cf 100644 --- a/components/soc/src/hal/uart_hal_iram.c +++ b/components/soc/src/hal/uart_hal_iram.c @@ -40,9 +40,9 @@ void uart_hal_write_txfifo(uart_hal_context_t *hal, const uint8_t *buf, uint32_t uart_ll_write_txfifo(hal->dev, buf, fill_len); } -void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *rd_len) +void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *inout_rd_len) { - uint16_t read_len = uart_ll_get_rxfifo_len(hal->dev); - *rd_len = read_len; + uint16_t read_len = (*inout_rd_len > 0) ? *inout_rd_len : uart_ll_get_rxfifo_len(hal->dev); + *inout_rd_len = read_len; uart_ll_read_rxfifo(hal->dev, buf, read_len); } diff --git a/examples/protocols/modbus/serial/example_test.py b/examples/protocols/modbus/serial/example_test.py index e0e21c3f0..fb9ab2978 100644 --- a/examples/protocols/modbus/serial/example_test.py +++ b/examples/protocols/modbus/serial/example_test.py @@ -41,7 +41,7 @@ expect_dict_master_err = {"READ_PAR_ERR": (u'263', u'ESP_ERR_TIMEOUT'), # The dictionary for regular expression patterns to check in listing pattern_dict_master_ok = {"START": (r'.*I \([0-9]+\) MASTER_TEST: Start modbus test...'), "READ_PAR_OK": (r'.*I\s\([0-9]+\) MASTER_TEST: Characteristic #[0-9]+ [a-zA-Z0-9_]+' - r'\s\([a-zA-Z\%\/]+\) value = [a-zA-Z0-9\.]+ \(0x[a-zA-Z0-9]+\) read successful.'), + r'\s\([a-zA-Z\%\/]+\) value = [a-zA-Z0-9\.\s]*\(0x[a-zA-Z0-9]+\) read successful.'), "ALARM_MSG": (r'.*I \([0-9]*\) MASTER_TEST: Alarm triggered by cid #([0-9]+).')} pattern_dict_master_err = {"READ_PAR_ERR_TOUT": (r'.*E \([0-9]+\) MASTER_TEST: Characteristic #[0-9]+' diff --git a/examples/protocols/modbus/serial/mb_example_common/include/modbus_params.h b/examples/protocols/modbus/serial/mb_example_common/include/modbus_params.h index b6fe9b737..68c6fe573 100644 --- a/examples/protocols/modbus/serial/mb_example_common/include/modbus_params.h +++ b/examples/protocols/modbus/serial/mb_example_common/include/modbus_params.h @@ -49,6 +49,7 @@ typedef struct float holding_data1; float holding_data2; float holding_data3; + uint16_t test_regs[150]; } holding_reg_params_t; #pragma pack(pop) diff --git a/examples/protocols/modbus/serial/mb_master/main/master.c b/examples/protocols/modbus/serial/mb_master/main/master.c index 82e0a4cd4..227785db9 100644 --- a/examples/protocols/modbus/serial/mb_master/main/master.c +++ b/examples/protocols/modbus/serial/mb_master/main/master.c @@ -70,6 +70,7 @@ enum { CID_HOLD_DATA_1, CID_INP_DATA_2, CID_HOLD_DATA_2, + CID_HOLD_TEST_REG, CID_RELAY_P1, CID_RELAY_P2, CID_COUNT @@ -98,6 +99,8 @@ const mb_parameter_descriptor_t device_parameters[] = { INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER }, { CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2, HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER }, + { CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 10, 58, + HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER }, { CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 0, 8, COIL_OFFSET(coils_port0), PARAM_TYPE_U16, 2, OPTS( BIT1, 0, 0 ), PAR_PERMS_READ_WRITE_TRIGGER }, { CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 8, 8, @@ -160,43 +163,83 @@ static void master_operation_func(void *arg) void* temp_data_ptr = master_get_param_data(param_descriptor); assert(temp_data_ptr); uint8_t type = 0; - err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key, - (uint8_t*)&value, &type); - if (err == ESP_OK) { - *(float*)temp_data_ptr = value; - if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) || - (param_descriptor->mb_param_type == MB_PARAM_INPUT)) { - ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.", - param_descriptor->cid, - (char*)param_descriptor->param_key, - (char*)param_descriptor->param_units, - value, - *(uint32_t*)temp_data_ptr); - if (((value > param_descriptor->param_opts.max) || - (value < param_descriptor->param_opts.min))) { - alarm_state = true; - break; + if ((param_descriptor->param_type == PARAM_TYPE_ASCII) && + (param_descriptor->cid == CID_HOLD_TEST_REG)) { + // Check for long array of registers of type PARAM_TYPE_ASCII + err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key, + (uint8_t*)temp_data_ptr, &type); + if (err == ESP_OK) { + ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (char*)param_descriptor->param_units, + *(uint32_t*)temp_data_ptr); + // Initialize data of test array and write to slave + if (*(uint32_t*)temp_data_ptr != 0xAAAAAAAA) { + memset((void*)temp_data_ptr, 0xAA, param_descriptor->param_size); + *(uint32_t*)temp_data_ptr = 0xAAAAAAAA; + err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key, + (uint8_t*)temp_data_ptr, &type); + if (err == ESP_OK) { + ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (char*)param_descriptor->param_units, + *(uint32_t*)temp_data_ptr); + } else { + ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (int)err, + (char*)esp_err_to_name(err)); + } } } else { - uint16_t state = *(uint16_t*)temp_data_ptr; - const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF"; - ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.", - param_descriptor->cid, - (char*)param_descriptor->param_key, - (char*)param_descriptor->param_units, - (const char*)rw_str, - *(uint16_t*)temp_data_ptr); - if (state & param_descriptor->param_opts.opt1) { - alarm_state = true; - break; - } + ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (int)err, + (char*)esp_err_to_name(err)); } } else { - ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = %d (%s).", - param_descriptor->cid, - (char*)param_descriptor->param_key, - (int)err, - (char*)esp_err_to_name(err)); + err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key, + (uint8_t*)&value, &type); + if (err == ESP_OK) { + *(float*)temp_data_ptr = value; + if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) || + (param_descriptor->mb_param_type == MB_PARAM_INPUT)) { + ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (char*)param_descriptor->param_units, + value, + *(uint32_t*)temp_data_ptr); + if (((value > param_descriptor->param_opts.max) || + (value < param_descriptor->param_opts.min))) { + alarm_state = true; + break; + } + } else { + uint16_t state = *(uint16_t*)temp_data_ptr; + const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF"; + ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (char*)param_descriptor->param_units, + (const char*)rw_str, + *(uint16_t*)temp_data_ptr); + if (state & param_descriptor->param_opts.opt1) { + alarm_state = true; + break; + } + } + } else { + ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).", + param_descriptor->cid, + (char*)param_descriptor->param_key, + (int)err, + (char*)esp_err_to_name(err)); + } } vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls } @@ -257,6 +300,7 @@ static esp_err_t master_init(void) err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX); MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE, "mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err); + vTaskDelay(5); err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters); MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE, diff --git a/examples/protocols/modbus/serial/mb_slave/main/slave.c b/examples/protocols/modbus/serial/mb_slave/main/slave.c index 313d45a44..67aed97b1 100644 --- a/examples/protocols/modbus/serial/mb_slave/main/slave.c +++ b/examples/protocols/modbus/serial/mb_slave/main/slave.c @@ -135,7 +135,7 @@ void app_main(void) UART_PIN_NO_CHANGE)); // Set UART driver mode to Half Duplex - ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized."); ESP_LOGI(SLAVE_TAG, "Start modbus test...");