diff --git a/Arduino_Modbus.ino b/Arduino_Modbus.ino index 4948b75..9d4893c 100644 --- a/Arduino_Modbus.ino +++ b/Arduino_Modbus.ino @@ -15,8 +15,7 @@ void setup() { void loop() { // put your main code here, to run repeatedly: - RS_UART_Handler(&hmodbus1); // нужно вызывать периодически - RS_TIM_Handler(&hmodbus1); // проверка таймаута + RS_Process(&hmodbus1); //delay(500); //Serial.println("start"); //rs_huart.println("start1"); diff --git a/modbus.cpp b/modbus.cpp index 0c180b1..779283f 100644 --- a/modbus.cpp +++ b/modbus.cpp @@ -89,7 +89,7 @@ void MODBUS_FirstInit(void) hmodbus1.sRS_Timeout = MODBUS_TIMEOUT; hmodbus1.sRS_Mode = SLAVE_ALWAYS_WAIT; hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; - + hmodbus1.pMessagePtr = &MODBUS_MSG; // INIT hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, 0); diff --git a/rs_message.cpp b/rs_message.cpp index e95aa44..1037377 100644 --- a/rs_message.cpp +++ b/rs_message.cpp @@ -57,55 +57,6 @@ uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer //------------------------------------------------------------------- //-------------------------GENERAL FUNCTIONS------------------------- -/** - * @brief Start receive IT. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации приема. - */ -RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { - if (hRS->f.RS_Busy || hRS->f.RX_Busy) return RS_BUSY; - - RS_EnableReceive(); - RS_Set_Busy(hRS); - RS_Set_RX_Flags(hRS); - - hRS->pMessagePtr = RS_msg; - hRS->lastByteTime = millis(); - hRS->RS_STATUS = RS_OK; - - return RS_OK; -} - - -/** - * @brief Start transmit IT. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации передачи. - */ -RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { - if (hRS->f.RS_Busy || hRS->f.TX_Busy) return RS_BUSY; - - RS_StatusTypeDef RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); - if (RS_RES != RS_OK) { - RS_Abort(hRS, ABORT_RS); - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - return RS_RES; - } - - RS_EnableTransmit(); - RS_Set_Busy(hRS); - RS_Set_TX_Flags(hRS); - - hRS->pMessagePtr = RS_msg; - hRS->huart->write(hRS->pBufferPtr, hRS->RS_Message_Size); - hRS->lastByteTime = millis(); - - return RS_OK; -} - - /** * @brief Initialize UART and handle RS stucture. * @param hRS - указатель на хендлер RS. @@ -116,7 +67,10 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { * @note Инициализация перефирии и структуры для приема-передачи по RS. */ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8_t *pRS_BufferPtr) { - if (!hRS || !SerialPort) return RS_ERR; + if (!hRS || !SerialPort) { + Serial.println("[RS] Init error: null handler or port"); + return RS_ERR; + } hRS->huart = SerialPort; hRS->pBufferPtr = pRS_BufferPtr ? pRS_BufferPtr : RS_Buffer; @@ -126,29 +80,28 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8 RS_Reset_TX_Flags(hRS); hRS->f.RX_Half = 0; - hRS->lastByteTime = millis(); + hRS->lastByteTime = 0; + Serial.println("[RS] Initialized successfully"); return RS_OK; } - -/** - * @brief Abort RS/UART. - * @param hRS - указатель на хендлер RS. - * @param AbortMode - выбор, что надо отменить. - - ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX, - - ABORT_RX: Отмена приема по ЮАРТ, с очищением флагов RX, - - ABORT_RX_TX: Отмена приема и передачи по ЮАРТ, - - ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры. - * @return RS_RES - статус о состоянии RS после аборта. - * @note Отмена работы UART в целом или отмена приема/передачи RS. - Также очищается хендл hRS. - */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { + if (hRS == nullptr) { + Serial.println("[RS] Abort error: null handler"); + return RS_ERR; + } if ((AbortMode & ABORT_RS) == 0) { - if ((AbortMode & ABORT_RX) == ABORT_RX) RS_Reset_RX_Flags(hRS); - if ((AbortMode & ABORT_TX) == ABORT_TX) RS_Reset_TX_Flags(hRS); + if ((AbortMode & ABORT_RX) == ABORT_RX) { + Serial.println("[RS] Abort RX"); + RS_Reset_RX_Flags(hRS); + } + if ((AbortMode & ABORT_TX) == ABORT_TX) { + Serial.println("[RS] Abort TX"); + RS_Reset_TX_Flags(hRS); + } } else { + Serial.println("[RS] Abort RS (full reset)"); RS_Clear_All(hRS); } @@ -157,179 +110,98 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { return RS_ABORTED; } - -//-------------------------GENERAL FUNCTIONS------------------------- -//------------------------------------------------------------------- - - - -//------------------------------------------------------------------- -//--------------------CALLBACK/HANDLER FUNCTIONS--------------------- -/** - * @brief Handle for starting receive. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации приема или окончания общения. - * @note Определяет начинать прием команды/ответа или нет. - */ -RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) -{ - RS_StatusTypeDef RS_RES = RS_OK; - - switch(hRS->sRS_Mode) - { - case SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting - RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again - case SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request) - RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy) - } - - if(RS_RES != RS_OK) - { - } - - return RS_RES; -} -/** - * @brief Handle for starting transmit. - * @param hRS - указатель на хендлер RS. - * @param RS_msg - указатель на структуру сообщения. - * @return RS_RES - статус о состоянии RS после инициализации передачи. - * @note Определяет отвечать ли на команду или нет. - */ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) -{ - RS_StatusTypeDef RS_RES = RS_OK; - - switch(hRS->sRS_Mode) - { - case SLAVE_ALWAYS_WAIT: // in slave mode always response - case SLAVE_TIMEOUT_WAIT: // transmit response - RS_RES = RS_Transmit_IT(hRS, RS_msg); break; - } - if(RS_RES != RS_OK) - { - } - - return RS_RES; -} -/** - * @brief UART RX Callback: define behaviour after receiving parts of message. - * @param hRS - указатель на хендлер RS. - * @return RS_RES - статус о состоянии RS после обработки приема. - * @note Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его. - */ -RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS) { - if (!hRS->f.RX_Half && hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) { - hRS->f.RX_Half = 1; - uint32_t restSize = 0xFFFF; - RS_StatusTypeDef res = RS_Define_Size_of_RX_Message(hRS, &restSize); - if (res == RS_SKIP || restSize == 0xFFFF) { - RS_Abort(hRS, ABORT_RX); - return RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - } - - // if there is no bytes to receive - if(NuRS_of_Rest_Bytes == 0) - { - hRS->f.RX_Half = 0; - - //---------PROCESS DATA & ENDING RECEIVING-------- - RS_Set_RX_End(hRS); - - // parse received data - RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message - hRS->RS_Message_Size = NuRS_of_Rest_Bytes; - - // RESPONSE - RS_RES = RS_Response(hRS, hRS->pMessagePtr); - return RS_RES; - } - } - else // if we had received whole message - { - hRS->f.RX_Half = 0; - - //---------PROCESS DATA & ENDING RECEIVING-------- - RS_Set_RX_End(hRS); - - // parse received data - RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message - - // RESPONSE - RS_RES = RS_Response(hRS, hRS->pMessagePtr); - } - - return RS_RES; -} - -/** - * @brief UART TX Callback: define behaviour after transmiting message. - * @param hRS - указатель на хендлер RS. - * @return RS_RES - статус о состоянии RS после обработки приема. - * @note Определяет поведение RS после передачи сообщения. - */ -RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS) { - RS_StatusTypeDef RS_RES = RS_OK; - HAL_StatusTypeDef uart_res = 0; - - //--------------ENDING TRANSMITTING------------- - RS_Set_TX_End(hRS); - RS_EnableReceive(); -// for(int i = 0; i < hRS->sRS_Timeout; i++); - - //-----------START RECEIVING or END RS---------- - RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - - return RS_RES; + if (hRS == nullptr || RS_msg == nullptr) { + Serial.println("[RS] TX start error: null ptr"); + return RS_ERR; + } + + if (RS_Is_TX_Busy(hRS)) { + Serial.println("[RS] TX busy, cannot start"); + return RS_BUSY; + } + + RS_StatusTypeDef status = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); + if (status != RS_OK) { + Serial.println("[RS] TX collect message failed"); + return status; + } + + Serial.print("[RS] TX start, size="); + Serial.println(hRS->RS_Message_Size); + + RS_Set_TX_Flags(hRS); + hRS->huart->write(hRS->pBufferPtr, hRS->RS_Message_Size); + RS_Set_TX_End(hRS); + + Serial.println("[RS] TX finished"); + return RS_OK; } -/** - * @brief Handler for UART. - * @param hRS - указатель на хендлер RS. - * @note Обрабатывает ошибки если есть и вызывает RS Коллбеки. - * Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler(). - */ -void RS_UART_Handler(RS_HandleTypeDef *hRS) { - while (hRS->huart->available()) { - uint8_t b = hRS->huart->read(); - hRS->pBufferPtr[hRS->RS_Message_Size++] = b; +void RS_Process(RS_HandleTypeDef *hRS) +{ + if (hRS == nullptr) { + Serial.println("[RS] Process error: null handler"); + return; + } + static uint32_t rx_index = 0; + static uint32_t expected_size = RX_FIRST_PART_SIZE; + + if (hRS->f.RX_Ongoing) { + if (millis() - hRS->lastByteTime > hRS->sRS_Timeout) { + Serial.println("[RS] RX timeout"); + RS_Abort(hRS, ABORT_RX); + return; + } + } + + if (hRS->huart->available()) { + if (!hRS->f.RX_Ongoing) { + Serial.println("[RS] RX start"); + RS_Set_RX_Active_Flags(hRS); + rx_index = 0; + expected_size = RX_FIRST_PART_SIZE; + RS_Clear_Buff(hRS->pBufferPtr); + } + hRS->lastByteTime = millis(); + + while (hRS->huart->available() && rx_index < MSG_SIZE_MAX) { + uint8_t b = hRS->huart->read(); + hRS->pBufferPtr[rx_index++] = b; - if (hRS->f.RX_Busy && (hRS->RS_Message_Size >= RX_FIRST_PART_SIZE) && !hRS->f.RX_Half) - RS_UART_RxCpltCallback(hRS); + Serial.print("[RS] RX byte: 0x"); + Serial.println(b, HEX); + + if (rx_index == RX_FIRST_PART_SIZE && hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) { + uint32_t data_size; + Serial.println("Defining size..."); + RS_Define_Size_of_RX_Message(hRS, &data_size); + expected_size = RX_FIRST_PART_SIZE + data_size; + Serial.print("[RS] RX expected size="); + Serial.println(expected_size); + } + + if (rx_index >= expected_size) { + RS_Set_RX_End(hRS); + Serial.println("[RS] RX complete, parsing..."); + + RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); + + if (hRS->pMessagePtr->MbAddr == hRS->ID) { + Serial.println("[RS] RX for me, sending response"); + RS_Response(hRS, hRS->pMessagePtr); + } else { + Serial.print("[RS] RX not for me, Addr="); + Serial.println(hRS->pMessagePtr->MbAddr); + } + break; + } + } } } -/** - * @brief Handler for TIM (timeout check). - * @param hRS - указатель на хендлер RS. - * @note Проверяет таймаут между байтами. Если превышен, сбрасывает RX и перезапускает прием. - * Вызывать в TIMx_IRQHandler() после HAL_TIM_IRQHandler(). - */ -void RS_TIM_Handler(RS_HandleTypeDef *hRS) { - if (!hRS) return; - - unsigned long now = millis(); - - // Если идет прием данных и есть таймаут - if (hRS->f.RX_Busy && hRS->sRS_Timeout > 0) { - if ((now - hRS->lastByteTime) >= hRS->sRS_Timeout) { - // таймаут истек → abort RX и restart - RS_Abort(hRS, ABORT_RX); - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - } - } - - // Можно также проверять TX, если нужна логика таймаута передачи - if (hRS->f.TX_Busy && hRS->sRS_Timeout > 0) { - if ((now - hRS->lastByteTime) >= hRS->sRS_Timeout) { - RS_Abort(hRS, ABORT_TX); - // TX не рестартим автоматически - } - } -} // weak functions diff --git a/rs_message.h b/rs_message.h index dbced66..5d775ef 100644 --- a/rs_message.h +++ b/rs_message.h @@ -29,69 +29,42 @@ ///////////////////////////////////////////////////////////////////// ////////////////////////////---DEFINES---//////////////////////////// -/* Check that all defines required by RS are defined */ #ifndef MSG_SIZE_MAX -#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. +#error "Define MSG_SIZE_MAX (Maximum size of message)" #endif #ifndef RX_FIRST_PART_SIZE -#error Define RX_FIRST_PART_SIZE (Size of first part of message). This is necessary to receive the first part of the message, from which determine the size of the remaining part of the message. +#error "Define RX_FIRST_PART_SIZE (Size of first part of message)" #endif -/* Clear message-uart buffer */ -#define RS_Clear_Buff(_buff_) for(int i=0; if.RS_Busy = 0) -#define RS_Set_Busy(_hRS_) (_hRS_->f.RS_Busy = 1) +#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy=0 +#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy=1 -#define RS_Set_RX_Flags(_hRS_) do { \ - _hRS_->f.RX_Busy = 1; \ - _hRS_->f.RX_Done = 0; \ - _hRS_->f.RX_Half = 0; \ - } while(0) +#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy=1; _hRS_->f.RX_Done=0; _hRS_->f.RX_Half=0 +#define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing=1 -#define RS_Set_RX_Active_Flags(_hRS_) (_hRS_->f.RX_Ongoing = 1) -#define RS_Set_TX_Flags(_hRS_) do { \ - _hRS_->f.TX_Busy = 1; \ - _hRS_->f.TX_Done = 0; \ - } while(0) +#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy=1; _hRS_->f.TX_Done=0 -#define RS_Reset_RX_Active_Flags(_hRS_) (_hRS_->f.RX_Ongoing = 0) +#define RS_Reset_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing=0 +#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy=0; _hRS_->f.RX_Done=0; _hRS_->f.RX_Half=0 +#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy=0; _hRS_->f.TX_Done=0 -#define RS_Reset_RX_Flags(_hRS_) do { \ - RS_Reset_RX_Active_Flags(_hRS_); \ - _hRS_->f.RX_Busy = 0; \ - _hRS_->f.RX_Done = 0; \ - _hRS_->f.RX_Half = 0; \ - } while(0) +#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done=1 +#define RS_Set_TX_End_Flag(_hRS_) _hRS_->f.TX_Done=1 -#define RS_Reset_TX_Flags(_hRS_) do { \ - _hRS_->f.TX_Busy = 0; \ - _hRS_->f.TX_Done = 0; \ - } while(0) +#define RS_Set_RX_End(_hRS_) RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_) +#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) -#define RS_Set_RX_End_Flag(_hRS_) (_hRS_->f.RX_Done = 1) -#define RS_Set_TX_End_Flag(_hRS_) (_hRS_->f.TX_Done = 1) +#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_) -#define RS_Set_RX_End(_hRS_) do { RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_); } while(0) -#define RS_Set_TX_End(_hRS_) do { RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_); } while(0) +#define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy==1) +#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy==1) -/* Clear all RS stuff */ -#define RS_Clear_All(_hRS_) do { \ - RS_Clear_Buff(_hRS_->pBufferPtr); \ - RS_Reset_RX_Flags(_hRS_); \ - RS_Reset_TX_Flags(_hRS_); \ - } while(0) - -#define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1) -#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1) - -/* For Arduino we can redefine later if needed */ #ifndef RS_EnableReceive -#define RS_EnableReceive() +#define RS_EnableReceive() #endif - #ifndef RS_EnableTransmit #define RS_EnableTransmit() #endif @@ -182,7 +155,6 @@ typedef struct // RS_HandleTypeDef /* HANDLERS and SETTINGS */ HUART_TypeDef *huart; ///< handler for used uart - void *htim; ///< handler for used tim RS_ModeTypeDef sRS_Mode; ///< setting: slave or master @ref RS_ModeTypeDef uint16_t sRS_Timeout; ///< setting: timeout in ms RS_RX_SizeTypeDef sRS_RX_Size_Mode; ///< setting: 1 - not const, 0 - const @@ -217,32 +189,14 @@ RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *r //-------------------------GENERAL FUNCTIONS------------------------- /*-----------------Should be called from main code-----------------*/ +void RS_Process(RS_HandleTypeDef *hRS); /* Initialize UART and handle RS stucture */ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *huart, uint8_t *pRS_BufferPtr); -/* Start receive IT */ -RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); -/* Start transmit IT */ -RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Abort RS/UART */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); -//-------------------------GENERAL FUNCTIONS------------------------- - - -//------------------------------------------------------------------- -//--------------------CALLBACK/HANDLER FUNCTIONS--------------------- -/* Handle for starting receive */ -RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Handle for starting transmit */ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); -/* UART RX Callback: define behaviour after receiving parts of message */ -RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS); -/* UART TX Callback: define behaviour after transmiting message */ -RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS); -/* Handler for UART */ -void RS_UART_Handler(RS_HandleTypeDef *hRS); -/* Handler for TIM */ -void RS_TIM_Handler(RS_HandleTypeDef *hRS); -//--------------------CALLBACK/HANDLER FUNCTIONS--------------------- + ///////////////////////////---FUNCTIONS---///////////////////////////