diff --git a/Arduino_Modbus.ino b/Arduino_Modbus.ino index 9d4893c..233dacf 100644 --- a/Arduino_Modbus.ino +++ b/Arduino_Modbus.ino @@ -2,9 +2,6 @@ void setup() { // put your setup code here, to run once: - // Пример: RX=16, TX=17, скорость 115200 - rs_huart.begin(115200, SERIAL_8N1, 8, 9); - rs_huart.println("start1"); MODBUS_FirstInit(); diff --git a/modbus.cpp b/modbus.cpp index 779283f..748f005 100644 --- a/modbus.cpp +++ b/modbus.cpp @@ -1,6 +1,6 @@ /** ************************************************************************** -* @file modbus.c +* @file modbus.cpp * @brief Модуль для реализации MODBUS. ************************************************************************** * @details Файл содержит реализацию функций работы с Modbus, включая: @@ -50,16 +50,18 @@ * Таким образом, сами коилы могут представлять собой как массив так и структуру. * * @section Инструкция по подключению -* Для корректной работы надо подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), -* в соответствубщие низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler. После HAL'овского обработчика -* -* Также необходимо в modbus_config.h настроить дефайны для нужной работы UART +* Настройте modbus_config.h дефайны для нужной работы UART +* * После для запуска Modbus: * @verbatim //----------------Прием модбас----------------// #include "rs_message.h" MODBUS_FirstInit(); - RS_Receive_IT(&hmodbus1, &MODBUS_MSG); + + void loop() + { + RS_Process(&hmodbus1);(&hmodbus1, &MODBUS_MSG); + } * @endverbatim * ******************************************************************************/ @@ -73,6 +75,7 @@ MB_DeviceIdentificationTypeDef MB_INFO; MB_DataStructureTypeDef MB_DATA; RS_MsgTypeDef MODBUS_MSG; + //------------------------------------------------------------------- //-----------------------------FOR USER------------------------------ /** @@ -91,6 +94,7 @@ void MODBUS_FirstInit(void) hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; hmodbus1.pMessagePtr = &MODBUS_MSG; // INIT + rs_huart.begin(115200, SERIAL_8N1, 8, 9); hmodbus1.RS_STATUS = RS_Init(&hmodbus1, &rs_huart, 0); RS_EnableReceive(); @@ -188,6 +192,7 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16 // if quantity too big return error if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) { + MB_DEBUG_PRINT("[MB] Illegal Data Address"); return ILLEGAL_DATA_ADDRESS; // return exception code } // if all ok - return no errors @@ -195,7 +200,10 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16 } // if address isnt from this array return error else - return ILLEGAL_DATA_ADDRESS; // return exception code + { + MB_DEBUG_PRINT("[MB] Illegal Data Address"); + return ILLEGAL_DATA_ADDRESS; // return exception code + } } /** * @brief Define Address Origin for Input/Holding Registers @@ -213,6 +221,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u /* check quantity error */ if (Qnt > 125) { + MB_DEBUG_PRINT("[MB] Illegal Data Value"); return ILLEGAL_DATA_VALUE; // return exception code } @@ -226,6 +235,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u // if address doesnt match any array - return illegal data address response else { + MB_DEBUG_PRINT("[MB] Illegal Data Address"); return ILLEGAL_DATA_ADDRESS; } } @@ -239,11 +249,13 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u // if address doesnt match any array - return illegal data address response else { + MB_DEBUG_PRINT("[MB] Illegal Data Address"); return ILLEGAL_DATA_ADDRESS; } } else { + MB_DEBUG_PRINT("[MB] Illegal Function"); return ILLEGAL_FUNCTION; } // if found requeried array return no err @@ -266,6 +278,7 @@ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint /* check quantity error */ if (Qnt > 2000) { + MB_DEBUG_PRINT("[MB] Illegal Data Value"); return ILLEGAL_DATA_VALUE; // return exception code } @@ -277,6 +290,7 @@ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint // if address doesnt match any array - return illegal data address response else { + MB_DEBUG_PRINT("[MB] Illegal Data Address"); return ILLEGAL_DATA_ADDRESS; } @@ -611,20 +625,24 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms { // Read Coils case MB_R_COILS: + MB_DEBUG_PRINT("[MB] Read Coils request"); hmodbus->f.MessageHandled = MB_Read_Coils(hmodbus->pMessagePtr); break; // Read Hodling Registers case MB_R_HOLD_REGS: + MB_DEBUG_PRINT("[MB] Read Hodling Registers request"); hmodbus->f.MessageHandled = MB_Read_Hold_Regs(hmodbus->pMessagePtr); break; case MB_R_IN_REGS: + MB_DEBUG_PRINT("[MB] Read Input Registers request"); hmodbus->f.MessageHandled = MB_Read_Input_Regs(hmodbus->pMessagePtr); break; // Write Single Coils case MB_W_COIL: + MB_DEBUG_PRINT("[MB] Write Single Coil request"); hmodbus->f.MessageHandled = MB_Write_Single_Coil(hmodbus->pMessagePtr); if(hmodbus->f.MessageHandled) { @@ -634,6 +652,7 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms break; case MB_W_HOLD_REG: + MB_DEBUG_PRINT("[MB] Write Single Hodling Register request"); hmodbus->f.MessageHandled = MB_Write_Single_Reg(hmodbus->pMessagePtr); if(hmodbus->f.MessageHandled) { @@ -644,6 +663,7 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms // Write Multiple Coils case MB_W_COILS: + MB_DEBUG_PRINT("[MB] Write Multiple Coils request"); hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr); if(hmodbus->f.MessageHandled) { @@ -654,6 +674,7 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms // Write Multiple Registers case MB_W_HOLD_REGS: + MB_DEBUG_PRINT("[MB] Write Multiple Hodling Registers request"); hmodbus->f.MessageHandled = MB_Write_Miltuple_Regs(hmodbus->pMessagePtr); if(hmodbus->f.MessageHandled) { @@ -663,22 +684,29 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms break; case MB_R_DEVICE_INFO: + MB_DEBUG_PRINT("[MB] Read Device Information request"); hmodbus->f.MessageHandled = MB_Read_Device_Identification(hmodbus->pMessagePtr); break; /* unknown func code */ - default: modbus_msg->Except_Code = ILLEGAL_FUNCTION; /* set exception code: illegal function */ + default: + MB_DEBUG_PRINT("[MB] Illegal function"); + modbus_msg->Except_Code = ILLEGAL_FUNCTION; /* set exception code: illegal function */ } if(hmodbus->f.MessageHandled == 0) { + MB_DEBUG_PRINT("[MB] Function not handled"); modbus_msg->Func_Code = static_cast( static_cast(modbus_msg->Func_Code) + ERR_VALUES_START ); + MB_ERR_DEBUG_PRINT2_HEX("[MB] Function Code:", modbus_msg->Func_Code); + MB_ERR_DEBUG_PRINT2_DEC("[MB] Error Code:", modbus_msg->Except_Code); } else { + MB_DEBUG_PRINT("[MB] Function handled, responsing..."); } @@ -733,6 +761,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE { + MB_DEBUG_PRINT("[MB] Response is invalid (ByteCnt not match DataSize)"); return RS_COLLECT_MSG_ERR; } @@ -754,6 +783,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo modbus_uart_buff[ind++] = modbus_msg->ByteCnt; else // otherwise return data_size err { + MB_DEBUG_PRINT("[MB] Response is invalid (ByteCnt not match DataSize)"); return RS_COLLECT_MSG_ERR; } @@ -844,6 +874,7 @@ RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modb modbus_msg->Func_Code = static_cast( static_cast(modbus_msg->Func_Code) + ERR_VALUES_START ); + MB_DEBUG_PRINT("[MB] Request is invalid (ByteCnt not match DataSize)"); return RS_PARSE_MSG_ERR; } uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; @@ -869,6 +900,9 @@ RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modb // compare crc if (modbus_msg->MB_CRC != CRC_VALUE) { + MB_DEBUG_PRINT("[MB] Request CRC is invalid"); + MB_ERR_DEBUG_PRINT2_HEX("[MB] Request CRC: ", modbus_msg->MB_CRC); + MB_ERR_DEBUG_PRINT2_HEX("[MB] Calced CRC: ", CRC_VALUE); modbus_msg->Func_Code = static_cast( static_cast(modbus_msg->Func_Code) + ERR_VALUES_START ); diff --git a/modbus.h b/modbus.h index 8514eb4..16224a3 100644 --- a/modbus.h +++ b/modbus.h @@ -369,4 +369,33 @@ uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); #define Trace_MB_TIM_Exit() #endif //Trace_MB_TIM_Exit + +#if MODBUS_DEBUG + #define MB_DEBUG_PRINT(msg) Serial.println(msg) + #define MB_DEBUG_PRINT_HEX(val) Serial.println(val, HEX) + #define MB_DEBUG_PRINT_DEC(val) Serial.println(val, DEC) + #define MB_DEBUG_PRINT2_HEX(msg,val) do { Serial.print(msg); Serial.println(val, HEX); } while(0) + #define MB_DEBUG_PRINT2_DEC(msg,val) do { Serial.print(msg); Serial.println(val, DEC); } while(0) +#else + #define MB_DEBUG_PRINT(msg) ((void)0) + #define MB_DEBUG_PRINT_HEX(val) ((void)0) + #define MB_DEBUG_PRINT_DEC(val) ((void)0) + #define MB_DEBUG_PRINT2_HEX(msg,val) ((void)0) + #define MB_DEBUG_PRINT2_DEC(msg,val) ((void)0) +#endif + +#if MODBUS_ERR_DEBUG + #define MB_ERR_DEBUG_PRINT(msg) Serial.println(msg) + #define MB_ERR_DEBUG_PRINT_HEX(val) Serial.println(val, HEX) + #define MB_ERR_DEBUG_PRINT_DEC(val) Serial.println(val, DEC) + #define MB_ERR_DEBUG_PRINT2_HEX(msg,val) do { Serial.print(msg); Serial.println(val, HEX); } while(0) + #define MB_ERR_DEBUG_PRINT2_DEC(msg,val) do { Serial.print(msg); Serial.println(val, DEC); } while(0) +#else + #define MB_ERR_DEBUG_PRINT(msg) ((void)0) + #define MB_ERR_DEBUG_PRINT_HEX(val) ((void)0) + #define MB_ERR_DEBUG_PRINT_DEC(val) ((void)0) + #define MB_ERR_DEBUG_PRINT2_HEX(msg,val) ((void)0) + #define MB_ERR_DEBUG_PRINT2_DEC(msg,val) ((void)0) +#endif + #endif //__MODBUS_H_ diff --git a/modbus_config.h b/modbus_config.h index b173fd9..fa09d76 100644 --- a/modbus_config.h +++ b/modbus_config.h @@ -7,17 +7,22 @@ #ifndef _MODBUS_CONFIG_H_ #define _MODBUS_CONFIG_H_ +// Включить/выключить debug +#define RS_DEBUG 0 ///< Отладка приема/передачи UART +#define MODBUS_DEBUG 0 ///< Отладка обработки запросов Modbus +#define MODBUS_ERR_DEBUG 1 ///< Отладка ошибок по CAN + // MODBUS PARAMS #define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства #define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера // STRING OBJECTS MODBUS -#define MODBUS_VENDOR_NAME "NIO-12" +#define MODBUS_VENDOR_NAME "NIO PRIBOR" #define MODBUS_PRODUCT_CODE "" #define MODBUS_REVISION "Ver. 1.0" #define MODBUS_VENDOR_URL "" #define MODBUS_PRODUCT_NAME "" -#define MODBUS_MODEL_NAME "STM32F103" +#define MODBUS_MODEL_NAME "Arduino" #define MODBUS_USER_APPLICATION_NAME "" // PERIPH FUNCTIONS AND HANDLERS diff --git a/rs_message.cpp b/rs_message.cpp index 1037377..a5bc084 100644 --- a/rs_message.cpp +++ b/rs_message.cpp @@ -1,56 +1,49 @@ /** ************************************************************************** -* @file rs_message.c -* @brief Модуль для реализации протоколов по RS/UART. +* @file rs_message.cpp +* @brief Модуль для реализации протоколов по RS/UART (Arduino). **************************************************************************\ * @details * Данный модуль реализует основные функции для приема и передачи сообщений -* по протоколу RS через UART в режиме прерываний. Реализована обработка -* приема и передачи данных, управление состояниями RS, а также функции для -* инициализации и управления периферией. +* по протоколу RS через UART. Реализована обработка приёма и передачи данных, +* управление состояниями RS, а также функции для инициализации и управления +* периферией Arduino Serial. * * Реализованы следующие функции: -* - RS_Receive_IT() — запуск приема данных в прерывании по UART. -* - RS_Transmit_IT() — запуск передачи данных в прерывании по UART. -* - RS_Init() — инициализация структуры RS и привязка периферии. -* - RS_ReInit_UART() — переинициализация UART и перезапуск приема данных. -* - RS_Abort() — остановка работы RS/UART с очисткой флагов и структур. -* - RS_Handle_Receive_Start() — обработка старта приема данных по RS. +* - RS_Init() — инициализация структуры RS и привязка к Serial-порту. +* - RS_Abort() — остановка работы RS/UART с очисткой флагов и структур. +* - RS_Handle_Transmit_Start() — запуск передачи данных. +* - RS_Process() — обработка входящих данных (вызов в loop()). * -* В модуле также определен буфер RS_Buffer[] для хранения принимаемых/передаваемых данных. +* В модуле также определён буфер RS_Buffer[] для хранения принимаемых/передаваемых данных. +* +* Пользователь должен определить функции: +* - RS_Response() — формирование ответа на принятое сообщение. +* - RS_Collect_Message() — подготовка сообщения для передачи. +* - RS_Parse_Message() — разбор принятого сообщения. +* - RS_Define_Size_of_RX_Message() — определение размера входящих данных. * * @note -* Для корректной работы модуля предполагается использование соответствующих -* обработчиков прерываний UART и таймера (RS_UART_Handler(), RS_TIM_Handler()), -* которые надо вызывать с обработчиках используемой периферии - +* Для корректной работы требуется вызывать RS_Process() в основном цикле программы. +* UART используется через стандартный Arduino Stream API (write(), read(), available()). +* @verbatim //-------------------Функции-------------------// Functions: users - - RS_Parse_Message/RS_Collect_Message Заполнение структуры сообщения и буфера - - RS_Response Ответ на сообщение - - RS_Define_Size_of_RX_Message Определение размера принимаемых данных + - RS_Parse_Message Разбор принятого сообщения + - RS_Collect_Message Заполнение структуры сообщения и буфера + - RS_Response Ответ на сообщение + - RS_Define_Size_of_RX_Message Определение размера принимаемых данных Functions: general - - RS_Receive_IT Ожидание комманды и ответ на неё - - RS_Transmit_IT Отправление комманды и ожидание ответа - - RS_Init Инициализация переферии и структуры для RS - - RS_ReInit_UART Реинициализация UART для RS - - RS_Abort Отмена приема/передачи по ЮАРТ - - RS_Init Инициализация периферии и modbus handler - -Functions: callback/handler - - RS_Handle_Receive_Start Функция для запуска приема или остановки RS - - RS_Handle_Transmit_Start Функция для запуска передачи или остановки RS - - - RS_UART_RxCpltCallback Коллбек при окончании приема или передачи - RS_UART_TxCpltCallback - - - RS_UART_Handler Обработчик прерывания для UART - - RS_TIM_Handler Обработчик прерывания для TIM + - RS_Init Инициализация структуры RS и привязка Serial + - RS_Abort Остановка приёма/передачи + - RS_Handle_Transmit_Start Запуск передачи сообщения + - RS_Process Обработка приёма сообщений (в loop) @endverbatim *************************************************************************/ + #include "rs_message.h" uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer @@ -60,15 +53,14 @@ uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer /** * @brief Initialize UART and handle RS stucture. * @param hRS - указатель на хендлер RS. - * @param suart - указатель на структуру с настройками UART. - * @param stim - указатель на структуру с настройками таймера. + * @param SerialPort - указатель на структуру с настройками UART. * @param pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер. * @return RS_RES - статус о состоянии RS после инициализации. * @note Инициализация перефирии и структуры для приема-передачи по RS. */ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8_t *pRS_BufferPtr) { if (!hRS || !SerialPort) { - Serial.println("[RS] Init error: null handler or port"); + RS_DEBUG_PRINT("[RS] Init error: null handler or port"); return RS_ERR; } @@ -82,26 +74,44 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, HUART_TypeDef *SerialPort, uint8 hRS->f.RX_Half = 0; hRS->lastByteTime = 0; - Serial.println("[RS] Initialized successfully"); + RS_EnableReceive(); + RS_Set_Busy(hRS); + RS_Set_RX_Flags(hRS); + + RS_DEBUG_PRINT("[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 В Arduino аппаратный UART (Serial) не отключается физически, + * т.к. стандартный API HardwareSerial не даёт прямого доступа + * к регистрах UART. RS_Abort лишь очищает внутренние флаги + * и структуры, имитируя "отключение". + */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { if (hRS == nullptr) { - Serial.println("[RS] Abort error: null handler"); + RS_DEBUG_PRINT("[RS] Abort error: null handler"); return RS_ERR; } if ((AbortMode & ABORT_RS) == 0) { if ((AbortMode & ABORT_RX) == ABORT_RX) { - Serial.println("[RS] Abort RX"); + RS_DEBUG_PRINT("[RS] Abort RX"); RS_Reset_RX_Flags(hRS); } if ((AbortMode & ABORT_TX) == ABORT_TX) { - Serial.println("[RS] Abort TX"); + RS_DEBUG_PRINT("[RS] Abort TX"); RS_Reset_TX_Flags(hRS); } } else { - Serial.println("[RS] Abort RS (full reset)"); + RS_DEBUG_PRINT("[RS] Abort RS (full reset)"); RS_Clear_All(hRS); } @@ -110,91 +120,124 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { return RS_ABORTED; } +/** + * @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) { if (hRS == nullptr || RS_msg == nullptr) { - Serial.println("[RS] TX start error: null ptr"); + RS_DEBUG_PRINT("[RS] TX start error: null ptr"); return RS_ERR; } if (RS_Is_TX_Busy(hRS)) { - Serial.println("[RS] TX busy, cannot start"); + RS_DEBUG_PRINT("[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"); + RS_DEBUG_PRINT("[RS] TX collect message failed"); return status; } - Serial.print("[RS] TX start, size="); - Serial.println(hRS->RS_Message_Size); + RS_DEBUG_PRINT2_DEC("[RS] TX start, size=", hRS->RS_Message_Size); + RS_EnableTransmit(); RS_Set_TX_Flags(hRS); hRS->huart->write(hRS->pBufferPtr, hRS->RS_Message_Size); RS_Set_TX_End(hRS); + + RS_Set_RX_Flags(hRS); + RS_Set_RX_Flags(hRS); - Serial.println("[RS] TX finished"); + RS_DEBUG_PRINT("[RS] TX finished"); return RS_OK; } + +/** + * @brief Main RS processing function. + * @param hRS - указатель на хендлер RS. + * @return None. + * @note Функция должна вызываться в основном цикле (loop()). + * Выполняет проверку таймаутов, обработку поступающих байт из UART + * и вызов пользовательских функций: + * - RS_Define_Size_of_RX_Message() для определения размера пакета; + * - RS_Parse_Message() для разбора принятого сообщения; + * - RS_Response() для ответа, если сообщение адресовано текущему устройству. + * В случае таймаута выполняется RS_Abort() с режимом ABORT_RX. + */ 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 == nullptr) { + RS_DEBUG_PRINT("[RS] Process error: null handler"); + return; + } + // Проверка таймаута при активном приёме if (hRS->f.RX_Ongoing) { if (millis() - hRS->lastByteTime > hRS->sRS_Timeout) { - Serial.println("[RS] RX timeout"); + RS_DEBUG_PRINT("[RS] RX timeout"); RS_Abort(hRS, ABORT_RX); return; } } + // Проверка наличия данных в UART if (hRS->huart->available()) { + // Если приём ещё не активен — начинаем новый пакет if (!hRS->f.RX_Ongoing) { - Serial.println("[RS] RX start"); + RS_DEBUG_PRINT("[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(); + // Считываем доступные байты из UART while (hRS->huart->available() && rx_index < MSG_SIZE_MAX) { uint8_t b = hRS->huart->read(); hRS->pBufferPtr[rx_index++] = b; - Serial.print("[RS] RX byte: 0x"); - Serial.println(b, HEX); + RS_DEBUG_PRINT2_HEX("[RS] RX byte: 0x", b); - if (rx_index == RX_FIRST_PART_SIZE && hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) { + // Если достигнут размер первой части пакета — определяем полный размер + if (rx_index == RX_FIRST_PART_SIZE && (hRS->f.RX_Half == 0) && hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) { + hRS->f.RX_Half = 1; uint32_t data_size; - Serial.println("Defining size..."); + RS_DEBUG_PRINT("[RS] 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); + RS_DEBUG_PRINT2_DEC("[RS] RX expected size=", expected_size); } + // Если пакет полностью получен if (rx_index >= expected_size) { + hRS->f.RX_Half = 0; RS_Set_RX_End(hRS); - Serial.println("[RS] RX complete, parsing..."); + RS_DEBUG_PRINT("[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_DEBUG_PRINT("[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); + RS_DEBUG_PRINT2_DEC("[RS] RX not for me, Addr=", hRS->pMessagePtr->MbAddr); } break; } @@ -204,8 +247,43 @@ void RS_Process(RS_HandleTypeDef *hRS) -// weak functions + +//------------------------------------------------------------------- +//--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- +/** + * @brief Respond accord to received message. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @return RS_RES - статус о результате ответа на комманду. + * @note Обработка принятой комманды и ответ на неё. + */ __attribute__((weak)) RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { return RS_ERR; } + +/** + * @brief Collect message in buffer to transmit it. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @param msg_uart_buff - указатель на буффер UART. + * @return RS_RES - статус о результате заполнения буфера. + * @note Заполнение буффера UART из структуры сообщения. + */ __attribute__((weak)) RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; } + +/** + * @brief Parse message from buffer to process it. + * @param hRS - указатель на хендлер RS. + * @param RS_msg - указатель на структуру сообщения. + * @param msg_uart_buff - указатель на буффер UART. + * @return RS_RES - статус о результате заполнения структуры. + * @note Заполнение структуры сообщения из буффера UART. + */ __attribute__((weak)) RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; } + +/** + * @brief Define size of RX Message that need to be received. + * @param hRS - указатель на хендлер RS. + * @param rx_data_size - указатель на переменную для записи кол-ва байт для принятия. + * @return RS_RES - статус о корректности рассчета кол-ва байт для принятия. + * @note Определение сколько байтов надо принять по протоколу. + */ __attribute__((weak)) RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) { return RS_ERR; } diff --git a/rs_message.h b/rs_message.h index 5d775ef..1fbb115 100644 --- a/rs_message.h +++ b/rs_message.h @@ -14,9 +14,6 @@ - Подключить этот файл в раздел rs_message.h. - Определить функции для обработки сообщения: RS_Parse_Message(), RS_Collect_Message(), RS_Response(), RS_Define_Size_of_RX_Message() - - Добавить UART/TIM Handler в Хендлер используемых UART/TIM. - -Так же данный модуль использует счетчики ************************************************************************** @verbatim Визуальное описание. Форматирование сохраняется как в коде. @@ -164,6 +161,7 @@ typedef struct // RS_HandleTypeDef /* RS STATUS */ unsigned long lastByteTime; + unsigned long baudRate; RS_StatusTypeDef RS_STATUS; ///< RS status }RS_HandleTypeDef; extern RS_HandleTypeDef hmodbus1; @@ -200,11 +198,18 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef * ///////////////////////////---FUNCTIONS---/////////////////////////// -#ifndef printf_rs_err -#define printf_rs_err(...) +#if RS_DEBUG + #define RS_DEBUG_PRINT(msg) Serial.println(msg) + #define RS_DEBUG_PRINT_HEX(val) Serial.println(val, HEX) + #define RS_DEBUG_PRINT_DEC(val) Serial.println(val, DEC) + #define RS_DEBUG_PRINT2_HEX(msg,val) do { Serial.print(msg); Serial.println(val, HEX); } while(0) + #define RS_DEBUG_PRINT2_DEC(msg,val) do { Serial.print(msg); Serial.println(val, DEC); } while(0) +#else + #define RS_DEBUG_PRINT(msg) ((void)0) + #define RS_DEBUG_PRINT_HEX(val) ((void)0) + #define RS_DEBUG_PRINT_DEC(val) ((void)0) + #define RS_DEBUG_PRINT2_HEX(msg,val) ((void)0) + #define RS_DEBUG_PRINT2_DEC(msg,val) ((void)0) #endif -#ifndef printf_rs -#define printf_rs(...) -#endif #endif // __RS_LIB_H_