212 lines
8.7 KiB
C++
212 lines
8.7 KiB
C++
/**
|
||
**************************************************************************
|
||
* @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; }
|