serial master, slave fix parity check

This commit is contained in:
aleks
2023-02-09 17:40:59 +01:00
parent a854d3b188
commit cc04189b0a
7 changed files with 124 additions and 99 deletions

View File

@ -159,6 +159,17 @@ typedef struct {
BOOL xTimerState; BOOL xTimerState;
} xTimerContext_t; } xTimerContext_t;
typedef struct {
QueueHandle_t xMbUartQueue; /*!< A queue to handle UART event. */
TaskHandle_t xMbTaskHandle; /*!< Serial task handle */
UCHAR ucUartNumber; /*!< The UART hardware port number */
BOOL bRxStateEnabled; /*!< Receiver enabled flag */
BOOL bTxStateEnabled; /*!< Transmitter enabled flag */
SemaphoreHandle_t xRxSemaHandle; /*!< Rx blocking semaphore handle */
ULONG ulParityErrors; /*!< Parity errors counter */
ULONG ulFrameErrors; /*!< Frame errors counter */
} MBMSerialContext_t;
void vMBPortEnterCritical(void); void vMBPortEnterCritical(void);
void vMBPortExitCritical(void); void vMBPortExitCritical(void);

View File

@ -292,12 +292,12 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
xEventGroupSetBits( xEventGroupMasterConfirmHdl, (xRecvedEvent & MB_EVENT_REQ_MASK) ); xEventGroupSetBits( xEventGroupMasterConfirmHdl, (xRecvedEvent & MB_EVENT_REQ_MASK) );
if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_PROCESS_SUCCESS)) { if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_PROCESS_SUCCESS)) {
eErrStatus = MB_MRE_NO_ERR; eErrStatus = MB_MRE_NO_ERR;
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT)) {
eErrStatus = MB_MRE_TIMEDOUT;
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RECEIVE_DATA)) { } else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RECEIVE_DATA)) {
eErrStatus = MB_MRE_REV_DATA; eErrStatus = MB_MRE_REV_DATA;
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION)) { } else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION)) {
eErrStatus = MB_MRE_EXE_FUN; eErrStatus = MB_MRE_EXE_FUN;
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT)) {
eErrStatus = MB_MRE_TIMEDOUT;
} }
} else { } else {
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, uxBits); ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, uxBits);

View File

@ -50,33 +50,34 @@
#include "port_serial_slave.h" #include "port_serial_slave.h"
// Note: This code uses mixed coding standard from legacy IDF code and used freemodbus stack // 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;
static const CHAR *TAG = "MB_SERIAL"; static const CHAR *TAG = "MB_SERIAL";
// The UART hardware port number // Serial communication context structure
static UCHAR ucUartNumber = UART_NUM_MAX - 1; static MBMSerialContext_t xMBSCtx = {
.xMbUartQueue = NULL,
static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag .xMbTaskHandle = NULL,
static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag .ucUartNumber = UART_NUM_MAX - 1,
.xRxSemaHandle = NULL,
.bTxStateEnabled = FALSE,
.bRxStateEnabled = FALSE,
.ulParityErrors = 0
};
void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
{ {
// This function can be called from xMBRTUTransmitFSM() of different task // This function can be called from xMBRTUTransmitFSM() of different task
if (bTxEnable) { if (bTxEnable) {
bTxStateEnabled = TRUE; xMBSCtx.bTxStateEnabled = TRUE;
} else { } else {
bTxStateEnabled = FALSE; xMBSCtx.bTxStateEnabled = FALSE;
} }
if (bRxEnable) { if (bRxEnable) {
//uart_enable_rx_intr(ucUartNumber); //uart_enable_rx_intr(ucUartNumber);
bRxStateEnabled = TRUE; xMBSCtx.bRxStateEnabled = TRUE;
vTaskResume(xMbTaskHandle); // Resume receiver task vTaskResume(xMBSCtx.xMbTaskHandle); // Resume receiver task
} else { } else {
vTaskSuspend(xMbTaskHandle); // Block receiver task vTaskSuspend(xMBSCtx.xMbTaskHandle); // Block receiver task
bRxStateEnabled = FALSE; xMBSCtx.bRxStateEnabled = FALSE;
} }
} }
@ -85,13 +86,13 @@ static USHORT usMBPortSerialRxPoll(size_t xEventSize)
BOOL xReadStatus = TRUE; BOOL xReadStatus = TRUE;
USHORT usCnt = 0; USHORT usCnt = 0;
if (bRxStateEnabled) { if (xMBSCtx.bRxStateEnabled) {
// Get received packet into Rx buffer // Get received packet into Rx buffer
while(xReadStatus && (usCnt++ <= xEventSize)) { while(xReadStatus && (usCnt++ <= xEventSize)) {
// Call the Modbus stack callback function and let it fill the buffers. // Call the Modbus stack callback function and let it fill the buffers.
xReadStatus = pxMBFrameCBByteReceived(); // callback to execute receive FSM xReadStatus = pxMBFrameCBByteReceived(); // callback to execute receive FSM
} }
uart_flush_input(ucUartNumber); uart_flush_input(xMBSCtx.ucUartNumber);
// Send event EV_FRAME_RECEIVED to allow stack process packet // Send event EV_FRAME_RECEIVED to allow stack process packet
#if !CONFIG_FMB_TIMER_PORT_ENABLED #if !CONFIG_FMB_TIMER_PORT_ENABLED
pxMBPortCBTimerExpired(); pxMBPortCBTimerExpired();
@ -106,7 +107,7 @@ BOOL xMBPortSerialTxPoll(void)
USHORT usCount = 0; USHORT usCount = 0;
BOOL bNeedPoll = TRUE; BOOL bNeedPoll = TRUE;
if( bTxStateEnabled ) { if(xMBSCtx.bTxStateEnabled) {
// Continue while all response bytes put in buffer or out of buffer // 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. // Calls the modbus stack callback function to let it fill the UART transmit buffer.
@ -114,7 +115,7 @@ BOOL xMBPortSerialTxPoll(void)
} }
ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount); ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount);
// Waits while UART sending the packet // Waits while UART sending the packet
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS); esp_err_t xTxStatus = uart_wait_tx_done(xMBSCtx.ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
vMBPortSerialEnable(TRUE, FALSE); vMBPortSerialEnable(TRUE, FALSE);
MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure."); MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure.");
return TRUE; return TRUE;
@ -127,8 +128,8 @@ static void vUartTask(void *pvParameters)
uart_event_t xEvent; uart_event_t xEvent;
USHORT usResult = 0; USHORT usResult = 0;
for(;;) { for(;;) {
if (xMBPortSerialWaitEvent(xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) { if (xMBPortSerialWaitEvent(xMBSCtx.xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) {
ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); ESP_LOGD(TAG, "MB_uart[%d] event:", xMBSCtx.ucUartNumber);
switch(xEvent.type) { switch(xEvent.type) {
//Event of UART receving data //Event of UART receving data
case UART_DATA: case UART_DATA:
@ -137,7 +138,7 @@ static void vUartTask(void *pvParameters)
// data received during configured timeout and UART TOUT feature is triggered // data received during configured timeout and UART TOUT feature is triggered
if (xEvent.timeout_flag) { if (xEvent.timeout_flag) {
// Get buffered data length // Get buffered data length
ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); ESP_ERROR_CHECK(uart_get_buffered_data_len(xMBSCtx.ucUartNumber, &xEvent.size));
// Read received data and send it to modbus stack // Read received data and send it to modbus stack
usResult = usMBPortSerialRxPoll(xEvent.size); usResult = usMBPortSerialRxPoll(xEvent.size);
ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult);
@ -146,13 +147,13 @@ static void vUartTask(void *pvParameters)
//Event of HW FIFO overflow detected //Event of HW FIFO overflow detected
case UART_FIFO_OVF: case UART_FIFO_OVF:
ESP_LOGD(TAG, "hw fifo overflow\n"); ESP_LOGD(TAG, "hw fifo overflow\n");
xQueueReset(xMbUartQueue); xQueueReset(xMBSCtx.xMbUartQueue);
break; break;
//Event of UART ring buffer full //Event of UART ring buffer full
case UART_BUFFER_FULL: case UART_BUFFER_FULL:
ESP_LOGD(TAG, "ring buffer full\n"); ESP_LOGD(TAG, "ring buffer full\n");
xQueueReset(xMbUartQueue); xQueueReset(xMBSCtx.xMbUartQueue);
uart_flush_input(ucUartNumber); uart_flush_input(xMBSCtx.ucUartNumber);
break; break;
//Event of UART RX break detected //Event of UART RX break detected
case UART_BREAK: case UART_BREAK:
@ -160,7 +161,10 @@ static void vUartTask(void *pvParameters)
break; break;
//Event of UART parity check error //Event of UART parity check error
case UART_PARITY_ERR: case UART_PARITY_ERR:
ESP_LOGD(TAG, "uart parity error\n"); ESP_LOGD(TAG, "uart parity error, count: %lu.", xMBSCtx.ulParityErrors);
xMBSCtx.ulParityErrors++;
xQueueReset(xMBSCtx.xMbUartQueue);
uart_flush_input(xMBSCtx.ucUartNumber);
break; break;
//Event of UART frame error //Event of UART frame error
case UART_FRAME_ERR: case UART_FRAME_ERR:
@ -180,7 +184,8 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
{ {
esp_err_t xErr = ESP_OK; esp_err_t xErr = ESP_OK;
// Set communication port number // Set communication port number
ucUartNumber = ucPORT; xMBSCtx.ucUartNumber = ucPORT;
xMBSCtx.ulParityErrors = 0;
// Configure serial communication parameters // Configure serial communication parameters
UCHAR ucParity = UART_PARITY_DISABLE; UCHAR ucParity = UART_PARITY_DISABLE;
UCHAR ucData = UART_DATA_8_BITS; UCHAR ucData = UART_DATA_8_BITS;
@ -229,53 +234,53 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
#endif #endif
}; };
// Set UART config // Set UART config
xErr = uart_param_config(ucUartNumber, &xUartConfig); xErr = uart_param_config(xMBSCtx.ucUartNumber, &xUartConfig);
MB_PORT_CHECK((xErr == ESP_OK), MB_PORT_CHECK((xErr == ESP_OK),
FALSE, "mb config failure, uart_param_config() returned (0x%x).", xErr); FALSE, "mb config failure, uart_param_config() returned (0x%x).", xErr);
// Install UART driver, and get the queue. // Install UART driver, and get the queue.
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE, xErr = uart_driver_install(xMBSCtx.ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG); MB_QUEUE_LENGTH, &xMBSCtx.xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial driver failure, uart_driver_install() returned (0x%x).", xErr); "mb serial driver failure, uart_driver_install() returned (0x%x).", xErr);
#if !CONFIG_FMB_TIMER_PORT_ENABLED #if !CONFIG_FMB_TIMER_PORT_ENABLED
// Set timeout for TOUT interrupt (T3.5 modbus time) // Set timeout for TOUT interrupt (T3.5 modbus time)
xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT); xErr = uart_set_rx_timeout(xMBSCtx.ucUartNumber, MB_SERIAL_TOUT);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr); "mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr);
#endif #endif
// Set always timeout flag to trigger timeout interrupt even after rx fifo full // Set always timeout flag to trigger timeout interrupt even after rx fifo full
uart_set_always_rx_timeout(ucUartNumber, true); uart_set_always_rx_timeout(xMBSCtx.ucUartNumber, true);
// Create a task to handle UART events // Create a task to handle UART events
BaseType_t xStatus = xTaskCreatePinnedToCore(vUartTask, "uart_queue_task", BaseType_t xStatus = xTaskCreatePinnedToCore(vUartTask, "uart_queue_task",
MB_SERIAL_TASK_STACK_SIZE, MB_SERIAL_TASK_STACK_SIZE,
NULL, MB_SERIAL_TASK_PRIO, NULL, MB_SERIAL_TASK_PRIO,
&xMbTaskHandle, MB_PORT_TASK_AFFINITY); &xMBSCtx.xMbTaskHandle, MB_PORT_TASK_AFFINITY);
if (xStatus != pdPASS) { if (xStatus != pdPASS) {
vTaskDelete(xMbTaskHandle); vTaskDelete(xMBSCtx.xMbTaskHandle);
// Force exit from function with failure // Force exit from function with failure
MB_PORT_CHECK(FALSE, FALSE, MB_PORT_CHECK(FALSE, FALSE,
"mb stack serial task creation error. xTaskCreate() returned (0x%x).", "mb stack serial task creation error. xTaskCreate() returned (0x%x).",
xStatus); xStatus);
} else { } else {
vTaskSuspend(xMbTaskHandle); // Suspend serial task while stack is not started vTaskSuspend(xMBSCtx.xMbTaskHandle); // Suspend serial task while stack is not started
} }
return TRUE; return TRUE;
} }
void vMBPortSerialClose(void) void vMBPortSerialClose(void)
{ {
(void)vTaskSuspend(xMbTaskHandle); (void)vTaskSuspend(xMBSCtx.xMbTaskHandle);
(void)vTaskDelete(xMbTaskHandle); (void)vTaskDelete(xMBSCtx.xMbTaskHandle);
ESP_ERROR_CHECK(uart_driver_delete(ucUartNumber)); ESP_ERROR_CHECK(uart_driver_delete(xMBSCtx.ucUartNumber));
} }
BOOL xMBPortSerialPutByte(CHAR ucByte) BOOL xMBPortSerialPutByte(CHAR ucByte)
{ {
// Send one byte to UART transmission buffer // Send one byte to UART transmission buffer
// This function is called by Modbus stack // This function is called by Modbus stack
UCHAR ucLength = uart_write_bytes(ucUartNumber, &ucByte, 1); UCHAR ucLength = uart_write_bytes(xMBSCtx.ucUartNumber, &ucByte, 1);
return (ucLength == 1); return (ucLength == 1);
} }
@ -283,6 +288,6 @@ BOOL xMBPortSerialPutByte(CHAR ucByte)
BOOL xMBPortSerialGetByte(CHAR* pucByte) BOOL xMBPortSerialGetByte(CHAR* pucByte)
{ {
assert(pucByte != NULL); assert(pucByte != NULL);
USHORT usLength = uart_read_bytes(ucUartNumber, (uint8_t*)pucByte, 1, MB_SERIAL_RX_TOUT_TICKS); USHORT usLength = uart_read_bytes(xMBSCtx.ucUartNumber, (uint8_t*)pucByte, 1, MB_SERIAL_RX_TOUT_TICKS);
return (usLength == 1); return (usLength == 1);
} }

View File

@ -59,38 +59,40 @@
/* ----------------------- Static variables ---------------------------------*/ /* ----------------------- Static variables ---------------------------------*/
static const CHAR *TAG = "MB_MASTER_SERIAL"; static const CHAR *TAG = "MB_MASTER_SERIAL";
// A queue to handle UART event. // Serial communication context structure
static QueueHandle_t xMbUartQueue; static MBMSerialContext_t xMBMCtx = {
static TaskHandle_t xMbTaskHandle; .xMbUartQueue = NULL,
.xMbTaskHandle = NULL,
// The UART hardware port number .ucUartNumber = UART_NUM_MAX - 1,
static UCHAR ucUartNumber = UART_NUM_MAX - 1; .xRxSemaHandle = NULL,
.bTxStateEnabled = FALSE,
static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag .bRxStateEnabled = FALSE,
static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag .ulParityErrors = 0, // Debug counters, can overrun
.ulFrameErrors = 0
static SemaphoreHandle_t xMasterSemaRxHandle; // Rx blocking semaphore handle };
static BOOL xMBMasterPortRxSemaInit( void ) static BOOL xMBMasterPortRxSemaInit( void )
{ {
xMasterSemaRxHandle = xSemaphoreCreateBinary(); xMBMCtx.xRxSemaHandle = xSemaphoreCreateBinary();
MB_PORT_CHECK((xMasterSemaRxHandle != NULL), FALSE , "%s: RX semaphore create failure.", __func__); MB_PORT_CHECK((xMBMCtx.xRxSemaHandle != NULL), FALSE , "%s: RX semaphore create failure.", __func__);
return TRUE; return TRUE;
} }
static void vMBMasterPortRxSemaClose( void ) static void vMBMasterPortRxSemaClose( void )
{ {
if (xMasterSemaRxHandle) { if (xMBMCtx.xRxSemaHandle) {
vSemaphoreDelete(xMasterSemaRxHandle); vSemaphoreDelete(xMBMCtx.xRxSemaHandle);
xMasterSemaRxHandle = NULL; xMBMCtx.xRxSemaHandle = NULL;
} }
} }
static BOOL xMBMasterPortRxSemaTake( LONG lTimeOut ) static BOOL xMBMasterPortRxSemaTake( LONG lTimeOut )
{ {
BaseType_t xStatus = pdTRUE; BaseType_t xStatus = pdTRUE;
xStatus = xSemaphoreTake(xMasterSemaRxHandle, lTimeOut ); xStatus = xSemaphoreTake(xMBMCtx.xRxSemaHandle, lTimeOut );
MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s: RX semaphore take failure.", __func__); if (xStatus != pdTRUE) {
ESP_LOGD(TAG, "%s: RX semaphore take failure.", __func__);
}
ESP_LOGV(MB_PORT_TAG,"%s:Take RX semaphore (%lu ticks).", __func__, lTimeOut); ESP_LOGV(MB_PORT_TAG,"%s:Take RX semaphore (%lu ticks).", __func__, lTimeOut);
return TRUE; return TRUE;
} }
@ -98,7 +100,7 @@ static BOOL xMBMasterPortRxSemaTake( LONG lTimeOut )
static void vMBMasterRxSemaRelease( void ) static void vMBMasterRxSemaRelease( void )
{ {
BaseType_t xStatus = pdFALSE; BaseType_t xStatus = pdFALSE;
xStatus = xSemaphoreGive(xMasterSemaRxHandle); xStatus = xSemaphoreGive(xMBMCtx.xRxSemaHandle);
if (xStatus != pdTRUE) { if (xStatus != pdTRUE) {
ESP_LOGD(MB_PORT_TAG,"%s:RX semaphore is free.", __func__); ESP_LOGD(MB_PORT_TAG,"%s:RX semaphore is free.", __func__);
} }
@ -107,7 +109,7 @@ static void vMBMasterRxSemaRelease( void )
static BOOL vMBMasterRxSemaIsBusy( void ) static BOOL vMBMasterRxSemaIsBusy( void )
{ {
BaseType_t xStatus = pdFALSE; BaseType_t xStatus = pdFALSE;
xStatus = (uxSemaphoreGetCount(xMasterSemaRxHandle) == 0) ? TRUE : FALSE; xStatus = (uxSemaphoreGetCount(xMBMCtx.xRxSemaHandle) == 0) ? TRUE : FALSE;
return xStatus; return xStatus;
} }
@ -116,11 +118,11 @@ void vMBMasterRxFlush( void )
size_t xSize = 1; size_t xSize = 1;
esp_err_t xErr = ESP_OK; esp_err_t xErr = ESP_OK;
for (int xCount = 0; (xCount < MB_SERIAL_RX_FLUSH_RETRY) && xSize; xCount++) { for (int xCount = 0; (xCount < MB_SERIAL_RX_FLUSH_RETRY) && xSize; xCount++) {
xErr = uart_get_buffered_data_len(ucUartNumber, &xSize); xErr = uart_get_buffered_data_len(xMBMCtx.ucUartNumber, &xSize);
MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", xErr); MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", xErr);
BaseType_t xStatus = xQueueReset(xMbUartQueue); BaseType_t xStatus = xQueueReset(xMBMCtx.xMbUartQueue);
if (xStatus) { if (xStatus) {
xErr = uart_flush_input(ucUartNumber); xErr = uart_flush_input(xMBMCtx.ucUartNumber);
MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", xErr); MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", xErr);
} }
} }
@ -131,17 +133,17 @@ void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
// This function can be called from xMBRTUTransmitFSM() of different task // This function can be called from xMBRTUTransmitFSM() of different task
if (bTxEnable) { if (bTxEnable) {
vMBMasterRxFlush(); vMBMasterRxFlush();
bTxStateEnabled = TRUE; xMBMCtx.bTxStateEnabled = TRUE;
} else { } else {
bTxStateEnabled = FALSE; xMBMCtx.bTxStateEnabled = FALSE;
} }
if (bRxEnable) { if (bRxEnable) {
bRxStateEnabled = TRUE; xMBMCtx.bRxStateEnabled = TRUE;
vMBMasterRxSemaRelease(); vMBMasterRxSemaRelease();
vTaskResume(xMbTaskHandle); // Resume receiver task vTaskResume(xMBMCtx.xMbTaskHandle); // Resume receiver task
} else { } else {
vTaskSuspend(xMbTaskHandle); // Block receiver task vTaskSuspend(xMBMCtx.xMbTaskHandle); // Block receiver task
bRxStateEnabled = FALSE; xMBMCtx.bRxStateEnabled = FALSE;
} }
} }
@ -157,7 +159,7 @@ static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize)
xStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM xStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM
} }
// The buffer is transferred into Modbus stack and is not needed here any more // The buffer is transferred into Modbus stack and is not needed here any more
uart_flush_input(ucUartNumber); uart_flush_input(xMBMCtx.ucUartNumber);
ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt); ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt);
#if !CONFIG_FMB_TIMER_PORT_ENABLED #if !CONFIG_FMB_TIMER_PORT_ENABLED
vMBMasterSetCurTimerMode(MB_TMODE_T35); vMBMasterSetCurTimerMode(MB_TMODE_T35);
@ -178,7 +180,7 @@ BOOL xMBMasterPortSerialTxPoll(void)
USHORT usCount = 0; USHORT usCount = 0;
BOOL bNeedPoll = TRUE; BOOL bNeedPoll = TRUE;
if( bTxStateEnabled ) { if(xMBMCtx.bTxStateEnabled) {
// Continue while all response bytes put in buffer or out of buffer // 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. // Calls the modbus stack callback function to let it fill the UART transmit buffer.
@ -186,7 +188,7 @@ BOOL xMBMasterPortSerialTxPoll(void)
} }
ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes.", (uint16_t)(usCount - 1)); ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes.", (uint16_t)(usCount - 1));
// Waits while UART sending the packet // Waits while UART sending the packet
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS); esp_err_t xTxStatus = uart_wait_tx_done(xMBMCtx.ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
vMBMasterPortSerialEnable(TRUE, FALSE); vMBMasterPortSerialEnable(TRUE, FALSE);
MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure."); MB_PORT_CHECK((xTxStatus == ESP_OK), FALSE, "mb serial sent buffer failure.");
return TRUE; return TRUE;
@ -200,8 +202,8 @@ static void vUartTask(void* pvParameters)
uart_event_t xEvent; uart_event_t xEvent;
USHORT usResult = 0; USHORT usResult = 0;
for(;;) { for(;;) {
if (xMBPortSerialWaitEvent(xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) { if (xMBPortSerialWaitEvent(xMBMCtx.xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) {
ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); ESP_LOGD(TAG, "MB_uart[%d] event:", xMBMCtx.ucUartNumber);
switch(xEvent.type) { switch(xEvent.type) {
//Event of UART receiving data //Event of UART receiving data
case UART_DATA: case UART_DATA:
@ -213,10 +215,12 @@ static void vUartTask(void* pvParameters)
// Do not wait completion of processing and just discard received data as incorrect // Do not wait completion of processing and just discard received data as incorrect
if (vMBMasterRxSemaIsBusy()) { if (vMBMasterRxSemaIsBusy()) {
vMBMasterRxFlush(); vMBMasterRxFlush();
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
break; break;
} }
// Get buffered data length // Get buffered data length
ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); ESP_ERROR_CHECK(uart_get_buffered_data_len(xMBMCtx.ucUartNumber, &xEvent.size));
// Read received data and send it to modbus stack // Read received data and send it to modbus stack
usResult = usMBMasterPortSerialRxPoll(xEvent.size); usResult = usMBMasterPortSerialRxPoll(xEvent.size);
ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult);
@ -225,13 +229,13 @@ static void vUartTask(void* pvParameters)
//Event of HW FIFO overflow detected //Event of HW FIFO overflow detected
case UART_FIFO_OVF: case UART_FIFO_OVF:
ESP_LOGD(TAG, "hw fifo overflow."); ESP_LOGD(TAG, "hw fifo overflow.");
xQueueReset(xMbUartQueue); xQueueReset(xMBMCtx.xMbUartQueue);
break; break;
//Event of UART ring buffer full //Event of UART ring buffer full
case UART_BUFFER_FULL: case UART_BUFFER_FULL:
ESP_LOGD(TAG, "ring buffer full."); ESP_LOGD(TAG, "ring buffer full.");
xQueueReset(xMbUartQueue); xQueueReset(xMBMCtx.xMbUartQueue);
uart_flush_input(ucUartNumber); uart_flush_input(xMBMCtx.ucUartNumber);
break; break;
//Event of UART RX break detected //Event of UART RX break detected
case UART_BREAK: case UART_BREAK:
@ -239,11 +243,15 @@ static void vUartTask(void* pvParameters)
break; break;
//Event of UART parity check error //Event of UART parity check error
case UART_PARITY_ERR: case UART_PARITY_ERR:
ESP_LOGD(TAG, "uart parity error."); ESP_LOGD(TAG, "uart parity error, count: %lu.", xMBMCtx.ulParityErrors);
xMBMasterPortRxSemaTake(0);
xMBMCtx.ulParityErrors++;
break; break;
//Event of UART frame error //Event of UART frame error
case UART_FRAME_ERR: case UART_FRAME_ERR:
ESP_LOGD(TAG, "uart frame error."); ESP_LOGD(TAG, "uart frame error, count: %lu.", xMBMCtx.ulFrameErrors);
xMBMasterPortRxSemaTake(0);
xMBMCtx.ulFrameErrors++;
break; break;
default: default:
ESP_LOGD(TAG, "uart event type: %d.", xEvent.type); ESP_LOGD(TAG, "uart event type: %d.", xEvent.type);
@ -259,7 +267,9 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
{ {
esp_err_t xErr = ESP_OK; esp_err_t xErr = ESP_OK;
// Set communication port number // Set communication port number
ucUartNumber = ucPORT; xMBMCtx.ucUartNumber = ucPORT;
xMBMCtx.ulParityErrors = 0;
xMBMCtx.ulFrameErrors = 0;
// Configure serial communication parameters // Configure serial communication parameters
UCHAR ucParity = UART_PARITY_DISABLE; UCHAR ucParity = UART_PARITY_DISABLE;
UCHAR ucData = UART_DATA_8_BITS; UCHAR ucData = UART_DATA_8_BITS;
@ -308,36 +318,35 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
#endif #endif
}; };
// Set UART config // Set UART config
xErr = uart_param_config(ucUartNumber, &xUartConfig); xErr = uart_param_config(xMBMCtx.ucUartNumber, &xUartConfig);
MB_PORT_CHECK((xErr == ESP_OK), MB_PORT_CHECK((xErr == ESP_OK),
FALSE, "mb config failure, uart_param_config() returned (0x%x).", xErr); FALSE, "mb config failure, uart_param_config() returned (0x%x).", xErr);
// Install UART driver, and get the queue. // Install UART driver, and get the queue.
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE, xErr = uart_driver_install(xMBMCtx.ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG); MB_QUEUE_LENGTH, &xMBMCtx.xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial driver failure, uart_driver_install() returned (0x%x).", xErr); "mb serial driver failure, uart_driver_install() returned (0x%x).", xErr);
// Set timeout for TOUT interrupt (T3.5 modbus time) // Set timeout for TOUT interrupt (T3.5 modbus time)
xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT); xErr = uart_set_rx_timeout(xMBMCtx.ucUartNumber, MB_SERIAL_TOUT);
MB_PORT_CHECK((xErr == ESP_OK), FALSE, MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr); "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 // Set always timeout flag to trigger timeout interrupt even after rx fifo full
uart_set_always_rx_timeout(ucUartNumber, true); uart_set_always_rx_timeout(xMBMCtx.ucUartNumber, true);
MB_PORT_CHECK((xMBMasterPortRxSemaInit()), FALSE, MB_PORT_CHECK((xMBMasterPortRxSemaInit()), FALSE,
"mb serial RX semaphore create fail."); "mb serial RX semaphore create fail.");
// Create a task to handle UART events // Create a task to handle UART events
BaseType_t xStatus = xTaskCreatePinnedToCore(vUartTask, "uart_queue_task", BaseType_t xStatus = xTaskCreatePinnedToCore(vUartTask, "uart_queue_task",
MB_SERIAL_TASK_STACK_SIZE, MB_SERIAL_TASK_STACK_SIZE,
NULL, MB_SERIAL_TASK_PRIO, NULL, MB_SERIAL_TASK_PRIO,
&xMbTaskHandle, MB_PORT_TASK_AFFINITY); &xMBMCtx.xMbTaskHandle, MB_PORT_TASK_AFFINITY);
if (xStatus != pdPASS) { if (xStatus != pdPASS) {
vTaskDelete(xMbTaskHandle); vTaskDelete(xMBMCtx.xMbTaskHandle);
// Force exit from function with failure // Force exit from function with failure
MB_PORT_CHECK(FALSE, FALSE, MB_PORT_CHECK(FALSE, FALSE,
"mb stack serial task creation error. xTaskCreate() returned (0x%x).", "mb stack serial task creation error. xTaskCreate() returned (0x%x).",
xStatus); xStatus);
} else { } else {
vTaskSuspend(xMbTaskHandle); // Suspend serial task while stack is not started vTaskSuspend(xMBMCtx.xMbTaskHandle); // Suspend serial task while stack is not started
} }
ESP_LOGD(MB_PORT_TAG,"%s Init serial.", __func__); ESP_LOGD(MB_PORT_TAG,"%s Init serial.", __func__);
return TRUE; return TRUE;
@ -346,15 +355,15 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
void vMBMasterPortSerialClose(void) void vMBMasterPortSerialClose(void)
{ {
vMBMasterPortRxSemaClose(); vMBMasterPortRxSemaClose();
(void)vTaskDelete(xMbTaskHandle); (void)vTaskDelete(xMBMCtx.xMbTaskHandle);
ESP_ERROR_CHECK(uart_driver_delete(ucUartNumber)); ESP_ERROR_CHECK(uart_driver_delete(xMBMCtx.ucUartNumber));
} }
BOOL xMBMasterPortSerialPutByte(CHAR ucByte) BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{ {
// Send one byte to UART transmission buffer // Send one byte to UART transmission buffer
// This function is called by Modbus stack // This function is called by Modbus stack
UCHAR ucLength = uart_write_bytes(ucUartNumber, &ucByte, 1); UCHAR ucLength = uart_write_bytes(xMBMCtx.ucUartNumber, &ucByte, 1);
return (ucLength == 1); return (ucLength == 1);
} }
@ -362,6 +371,6 @@ BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
BOOL xMBMasterPortSerialGetByte(CHAR* pucByte) BOOL xMBMasterPortSerialGetByte(CHAR* pucByte)
{ {
assert(pucByte != NULL); assert(pucByte != NULL);
USHORT usLength = uart_read_bytes(ucUartNumber, (uint8_t*)pucByte, 1, MB_SERIAL_RX_TOUT_TICKS); USHORT usLength = uart_read_bytes(xMBMCtx.ucUartNumber, (uint8_t*)pucByte, 1, MB_SERIAL_RX_TOUT_TICKS);
return (usLength == 1); return (usLength == 1);
} }

View File

@ -54,4 +54,4 @@ void vMBPortSetMode( UCHAR ucMode );
PR_END_EXTERN_C PR_END_EXTERN_C
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif

View File

@ -256,7 +256,7 @@ static esp_err_t master_init(void)
.mode = MB_MODE_RTU, .mode = MB_MODE_RTU,
#endif #endif
.baudrate = MB_DEV_SPEED, .baudrate = MB_DEV_SPEED,
.parity = MB_PARITY_NONE .parity = UART_PARITY_EVEN
}; };
void* master_handler = NULL; void* master_handler = NULL;

View File

@ -108,7 +108,7 @@ void app_main(void)
comm_info.slave_addr = MB_SLAVE_ADDR; comm_info.slave_addr = MB_SLAVE_ADDR;
comm_info.port = MB_PORT_NUM; comm_info.port = MB_PORT_NUM;
comm_info.baudrate = MB_DEV_SPEED; comm_info.baudrate = MB_DEV_SPEED;
comm_info.parity = MB_PARITY_NONE; comm_info.parity = UART_PARITY_EVEN;
ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info)); ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info));
// The code below initializes Modbus register area descriptors // The code below initializes Modbus register area descriptors