/** ******************************************************************************* * @file rs_message.h * @brief Библиотека обмена сообщениями по RS-интерфейсу ******************************************************************************* @defgroup RS_TOOLS RS Tools @brief Всякое для работы по UART/RS @{ ******************************************************************************* * @details Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom) через UART в режиме прерываний с поддержкой таймаутов. @section posibility Основные возможности: - Прием/передача в прерываниях - Обработка IDLE линии для определения конца фрейма - Таймауты приема через TIM - Гибкая настройка размера сообщений @section usage Использование: 1. Определить структуру сообщения и размеры буфера 2. Реализовать weak-функции обработки сообщений 3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания 4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT() @section features Особенности: - Буфер: RS_Buffer[RS_MSG_SIZE_MAX] Общий для приема/передачи - Состояния: отслеживается через флаги в RS_HandleTypeDef - Таймауты: контролируют максимальное время ожидания фрейма ******************************************************************************/ #ifndef __RS_LIB_H_ #define __RS_LIB_H_ #include "modbus_core.h" ///////////////////////////////////////////////////////////////////// ////////////////////////////---DEFINES---//////////////////////////// /* Check that all defines required by RS are defined */ #ifndef RS_MSG_SIZE_MAX #error Define RS_MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. #endif /** * @cond Заглушки и внутренний недокументированный стаф */ /* 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_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0; #define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1 #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; _hRS_->f.RX_Continue = 0; #define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0; #define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 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_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_) /* Clear all RS stuff */ #define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_); //#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX) //#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) #define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1) #define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1) #ifndef RS_USER_VARS_NUMB #define RS_USER_VARS_NUMB 0 #endif #ifndef local_time #define local_time() uwTick #endif /** @endcond */ /** * @addtogroup RS_DEBUG Tools for debug RS/UART/TIM * @ingroup RS_TOOLS * @brief Дефайны для отладки периферии * @{ */ #ifndef RS_USER_VARS_NUMB #define RS_USER_VARS_NUMB 0 ///< Количество переменных в @ref TrackerTypeDef #endif /** * @brief Тип структуры для счетчиков-переменных * @param num_user_vars Есть возмоность добавления num_user_vars количества пользовательскиъх переменных */ #define TrackerTypeDef(num_user_vars) void * /** @brief Инкрементировать переменную - успешных событий */ #define TrackerCnt_Ok(_cntstruct_) /** @brief Инкрементировать переменную - ошибок */ #define TrackerCnt_Err(_cntstruct_) /** @brief Инкрементировать переменную - предупреждений */ #define TrackerCnt_Warn(_cntstruct_) #ifndef printf_rs /** @brief Printf обычных событий RS/UART/TIM */ #define printf_rs(...) #endif #ifndef printf_rs_err /** @brief Printf ошибок RS/UART/TIM */ #define printf_rs_err(...) #endif #ifndef RS_TIM_Handler_ENTER /** @brief Действия при заходе в прерывания таймера */ #define RS_TIM_Handler_ENTER() #endif #ifndef RS_TIM_Handler_EXIT /** @brief Действия при выходе из прерывания таймера */ #define RS_TIM_Handler_EXIT() #endif #ifndef RS_UART_Handler_ENTER /** @brief Действия при заходе в прерывания UART */ #define RS_UART_Handler_ENTER() #endif #ifndef RS_UART_Handler_EXIT /** @brief Действия при выходе из прерывания UART */ #define RS_UART_Handler_EXIT() #endif /** RS_TOOLS * @} */ // направление передачи rs485 #ifndef RS_EnableReceive #define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485 #endif #ifndef RS_EnableTransmit #define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485 #endif ////////////////////////////---DEFINES---//////////////////////////// ///////////////////////////////////////////////////////////////////// ///////////////////////---STRUCTURES & ENUMS---////////////////////// //------------------ENUMERATIONS-------------------- /** @brief Enums for respond CMD about RS status */ typedef enum // RS_StatusTypeDef { /* IN-CODE STATUS (start from 0x01, and goes up)*/ /*0x01*/ RS_OK = 0x01, /*0x02*/ RS_ERR, /*0x03*/ RS_ABORTED, /*0x04*/ RS_BUSY, /*0x05*/ RS_SKIP, /*0x06*/ RS_TIMEOUT, /*0x07*/ RS_COLLECT_MSG_ERR, /*0x08*/ RS_PARSE_MSG_ERR, // reserved values // /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero) }RS_StatusTypeDef; #define RS_MASTER_MODE_START 0x3 ///< Начало режимов мастера (до него - режим слейв) /** @brief Enums for RS Modes */ typedef enum // RS_ModeTypeDef { RS_SLAVE_ALWAYS_WAIT = 0x01, ///< Слейв в постоянном ожидании RS_RESERVED = 0x02, ///< резерв RS_MASTER_REQUEST = 0x03, ///< Мастер с ручным запросом //RS_MASTER_POLLING = 0x04, ///< Мастер с опросом в фоновом режиме }RS_ModeTypeDef; /** @brief Enums for Abort modes */ typedef enum // RS_AbortTypeDef { ABORT_TX = 0x01, ///< Отменить передачу ABORT_RX = 0x02, ///< Отменить прием ABORT_RX_TX = 0x03, ///< Отменить прием и передачу ABORT_RS = 0x04, ///< Отменить любую работу UART в целом }RS_AbortTypeDef; //-----------STRUCTURE FOR HANDLE RS------------ /** @brief Struct for flags RS */ typedef struct { unsigned RS_Busy:1; ///< 1 - RS занят, 0 - RS свободен unsigned RX_Ongoing:1; ///< 1 - Прием данных в активном состоянии, 0 - Ожидаем начало приема данных unsigned RX_Busy:1; ///< 1 - Режим приема активен, 0 - Прием не активен unsigned TX_Busy:1; ///< 1 - Режим передачи активен, 0 - Прием не активен unsigned RX_Done:1; ///< 1 - Прием закончен, 0 - Прием еще в процессе или не инициализирован unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована // Выставление следующие флагов определяет пользователь unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании unsigned DataUpdated:1; ///< 1 - Данные были обновлены }RS_FlagsTypeDef; /** * @brief Handle for RS communication. * @note Prefixes: h - handle, s - settings, f - flag */ typedef struct // RS_HandleTypeDef { /* MESSAGE */ uint8_t ID; ///< ID хендла RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола uint8_t *pBufferPtr; ///< Указатеь на буфер UART int32_t RS_Message_Size; ///< size of whole message, not only data /* HANDLERS and SETTINGS */ UART_HandleTypeDef *huart; ///< Хендл UART TIM_HandleTypeDef *htim; ///< Хендл TIM RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер /* FLAGS */ RS_FlagsTypeDef f; ///< Флаги для контроля приема/передачи /* RS STATUS */ uint32_t lastPacketTick; ///< Время последнего принятого пакета RS_StatusTypeDef RS_STATUS; ///< Статус RS TrackerTypeDef(RS_USER_VARS_NUMB) rs_err; }RS_HandleTypeDef; extern RS_HandleTypeDef hmodbus1; ///////////////////////---STRUCTURES & ENUMS---////////////////////// ///////////////////////////////////////////////////////////////////// ///////////////////////////---FUNCTIONS---/////////////////////////// //----------------FUNCTIONS FOR PROCESSING MESSAGE------------------- /*--------------------Defined by users purposes--------------------*/ /* Пользовательская функция для ответа на запрос по UART */ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Пользовательская функция для обработки принятого ответа по UART */ __weak RS_StatusTypeDef RS_Response_Callback(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Пользовательская функция для сбора сообщения в буфер UART */ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff); /* Пользовательская функция для парса сообщения из буфера UART */ RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff); //-------------------------GENERAL FUNCTIONS------------------------- /*-----------------Should be called from main code-----------------*/ /* Начать прием по прерываниям */ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Начать передачу по прерываниям */ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Инициалазация структуры @ref RS_HandleTypeDef */ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr); /* Отменить прием/передачу RS/UART */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); //-------------------------GENERAL FUNCTIONS------------------------- //------------------------------------------------------------------- //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- /* Обработчик для начала приема */ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* Обработчик для начала передачи */ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); /* UART TX Callback: коллбек после окончания передачи */ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS); /* Обработчик прерывания UART */ void RS_UART_Handler(RS_HandleTypeDef *hRS); /* Обработчик прерывания TIM */ void RS_TIM_Handler(RS_HandleTypeDef *hRS); /* Запуск таймаута приема. */ RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS); /* Остановка таймаута приема. */ RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS); /* Обновление (сброс) таймаута приема. */ RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS); //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- ///////////////////////////---FUNCTIONS---/////////////////////////// /** RS_TOOLS * @} */ #endif // __RS_LIB_H_