Работает Modbus, проверено на ESP32-S3-Zero

Заготовка для модбас на ИВР
This commit is contained in:
Razvalyaev 2025-08-29 20:23:34 +03:00
parent 51f6216eb7
commit 1c4f4d689a
6 changed files with 235 additions and 87 deletions

View File

@ -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();

View File

@ -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
{
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<MB_FunctonTypeDef>(
static_cast<int>(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<MB_FunctonTypeDef>(
static_cast<int>(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<MB_FunctonTypeDef>(
static_cast<int>(modbus_msg->Func_Code) + ERR_VALUES_START
);

View File

@ -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_

View File

@ -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

View File

@ -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);
Serial.println("[RS] TX finished");
RS_Set_RX_Flags(hRS);
RS_Set_RX_Flags(hRS);
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; }

View File

@ -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_