Arduino_Modbus/rs_message.cpp

212 lines
8.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
**************************************************************************
* @file rs_message.c
* @brief Модуль для реализации протоколов по RS/UART.
**************************************************************************\
* @details
* Данный модуль реализует основные функции для приема и передачи сообщений
* по протоколу RS через UART в режиме прерываний. Реализована обработка
* приема и передачи данных, управление состояниями RS, а также функции для
* инициализации и управления периферией.
*
* Реализованы следующие функции:
* - 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_Buffer[] для хранения принимаемых/передаваемых данных.
*
* @note
* Для корректной работы модуля предполагается использование соответствующих
* обработчиков прерываний UART и таймера (RS_UART_Handler(), RS_TIM_Handler()),
* которые надо вызывать с обработчиках используемой периферии
@verbatim
//-------------------Функции-------------------//
Functions: users
- 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
@endverbatim
*************************************************************************/
#include "rs_message.h"
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
//-------------------------------------------------------------------
//-------------------------GENERAL FUNCTIONS-------------------------
/**
* @brief Initialize UART and handle RS stucture.
* @param hRS - указатель на хендлер RS.
* @param suart - указатель на структуру с настройками UART.
* @param stim - указатель на структуру с настройками таймера.
* @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");
return RS_ERR;
}
hRS->huart = SerialPort;
hRS->pBufferPtr = pRS_BufferPtr ? pRS_BufferPtr : RS_Buffer;
hRS->RS_STATUS = RS_OK;
RS_Set_Free(hRS);
RS_Reset_RX_Flags(hRS);
RS_Reset_TX_Flags(hRS);
hRS->f.RX_Half = 0;
hRS->lastByteTime = 0;
Serial.println("[RS] Initialized successfully");
return RS_OK;
}
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) {
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);
}
RS_Set_Free(hRS);
hRS->RS_STATUS = RS_ABORTED;
return RS_ABORTED;
}
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");
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;
}
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;
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;
}
}
}
}
// weak functions
__attribute__((weak)) RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { return RS_ERR; }
__attribute__((weak)) RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; }
__attribute__((weak)) RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { return RS_ERR; }
__attribute__((weak)) RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) { return RS_ERR; }