/** ************************************************************************** * @file rs_message.c * @brief Модуль для реализации протоколов по RS/UART. ************************************************************************** @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 Functions: uart initialize (это было в отдельных файлах, мб надо обратно разнести) - UART_Base_Init Инициализация UART для RS - RS_UART_GPIO_Init Инициализация GPIO для RS - UART_DMA_Init Инициализация DMA для RS - UART_MspInit Аналог HAL_MspInit для RS - UART_MspDeInit Аналог HAL_MspDeInit для RS @endverbatim *************************************************************************/ #include "rs_message.h" uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer #ifndef INCLUDE_GENERAL_PERIPH_LIBS extern void RS_UART_Init(void); extern void RS_UART_DeInit(UART_HandleTypeDef *huart); extern void RS_TIM_Init(void); extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim); #endif //------------------------------------------------------------------- //-------------------------GENERAL FUNCTIONS------------------------- /** * @brief Start receive IT. * @param hRS - указатель на хендлер RS. * @param RS_msg - указатель на структуру сообщения. * @return RS_RES - статус о состоянии RS после инициализации приема. */ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { RS_StatusTypeDef RS_RES = 0; HAL_StatusTypeDef uart_res = 0; //-------------CHECK RS LINE---------------- // check that receive isnt busy if( RS_Is_RX_Busy(hRS) ) // if tx busy - return busy status return RS_BUSY; //-----------INITIALIZE RECEIVE------------- // if all OK: start receiving RS_EnableReceive(); RS_Set_Busy(hRS); // set RS busy RS_Set_RX_Flags(hRS); // initialize flags for receive hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions // start receiving uart_res = HAL_UART_Receive_IT(hRS->huart, hRS->pBufferPtr, RX_FIRST_PART_SIZE); // receive until ByteCnt+1 byte, // then in Callback restart receive for rest bytes // if receive isnt started - abort RS if(uart_res != HAL_OK) { RS_RES = RS_Abort(hRS, ABORT_RS); printf_rs_err("\n%d: Error RS: Failed to start RS receiving...", uwTick); TrackerCnt_Err(hRS->rs_err); } else { RS_RES = RS_OK; printf_rs("\n%d: RS: Start Receiving...", uwTick); TrackerCnt_Ok(hRS->rs_err); } hRS->RS_STATUS = RS_RES; return RS_RES; // returns result of receive init } /** * @brief Start transmit IT. * @param hRS - указатель на хендлер RS. * @param RS_msg - указатель на структуру сообщения. * @return RS_RES - статус о состоянии RS после инициализации передачи. */ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { RS_StatusTypeDef RS_RES = 0; HAL_StatusTypeDef uart_res = 0; //-------------CHECK RS LINE---------------- // check that transmit isnt busy if( RS_Is_TX_Busy(hRS) ) // if tx busy - return busy status return RS_BUSY; // check receive line //------------COLLECT MESSAGE--------------- RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES {// need collect message status, so doesnt write abort to RS_RES RS_Abort(hRS, ABORT_RS); RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // restart receive } else // if collect successful { //----------INITIALIZE TRANSMIT------------- RS_EnableTransmit(); // for(int i = 0; i < hRS->sRS_Timeout; i++); RS_Set_Busy(hRS); // set RS busy RS_Set_TX_Flags(hRS); // initialize flags for transmit IT hRS->pMessagePtr = RS_msg; // set pointer for filling given structure from UARTHandler fucntion // if all OK: start transmitting uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size); // if transmit isnt started - abort RS if(uart_res != HAL_OK) { RS_RES = RS_Abort(hRS, ABORT_RS); printf_rs_err("\n%d: Error RS: Failed to start RS transmitting...", uwTick); TrackerCnt_Err(hRS->rs_err); } else { RS_RES = RS_OK; printf_rs("\n%d: RS: Start Transmitting...", uwTick); TrackerCnt_Ok(hRS->rs_err); } } hRS->RS_STATUS = RS_RES; return RS_RES; // returns result of transmit init } /** * @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. */ #ifdef INCLUDE_GENERAL_PERIPH_LIBS RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_SettingsTypeDef *suart, TIM_SettingsTypeDef *stim, uint8_t *pRS_BufferPtr) #else RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr) #endif { // check that hRS is defined if (hRS == NULL) return RS_ERR; #ifdef INCLUDE_GENERAL_PERIPH_LIBS // check that huart is defined if ((suart->huart.Instance == NULL) || (suart->huart.Init.BaudRate == NULL)) return RS_ERR; #else // check that huart is defined if (huart == NULL) return RS_ERR; #endif // init uart #ifdef INCLUDE_GENERAL_PERIPH_LIBS UART_Base_Init(suart); hRS->huart = &suart->huart; #else // RS_UART_Init(); hRS->huart = huart; #endif #ifdef INCLUDE_GENERAL_PERIPH_LIBS // check that timeout in interrupt needed if (hRS->sRS_Timeout) { if (stim->htim.Instance == NULL) // check is timer defined return RS_ERR; // calc frequency corresponding to timeout and tims 1ms tickbase stim->sTickBaseUS = TIM_TickBase_1MS; stim->htim.Init.Period = hRS->sRS_Timeout; TIM_Base_Init(stim); hRS->htim = &stim->htim; } #else // RS_TIM_Init(); hRS->htim = htim; #endif if (hRS->sRS_RX_Size_Mode == NULL) return RS_ERR; // check that buffer is defined if (hRS->pBufferPtr == NULL) { hRS->pBufferPtr = RS_Buffer; // if no - set default } else hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user return RS_OK; } /** * @brief ReInitialize UART and RS receive. * @param hRS - указатель на хендлер RS. * @param suart - указатель на структуру с настройками UART. * @return RS_RES - статус о состоянии RS после инициализации. * @note Реинициализация UART и приема по RS. */ #ifdef INCLUDE_GENERAL_PERIPH_LIBS HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_SettingsTypeDef *suart) #else HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart) #endif { HAL_StatusTypeDef RS_RES; hRS->f.ReInit_UART = 0; #ifdef INCLUDE_GENERAL_PERIPH_LIBS // check is settings are valid if(Check_UART_Init_Struct(suart) != HAL_OK) return HAL_ERROR; RS_Abort(hRS, ABORT_RS); UART_MspDeInit(&suart->huart); RS_RES = UART_Base_Init(suart); #else // // check is settings are valid // if(Check_UART_Init_Struct(suart) != HAL_OK) // return HAL_ERROR; RS_Abort(hRS, ABORT_RS); RS_UART_DeInit(huart); RS_UART_Init(); #endif RS_Receive_IT(hRS, hRS->pMessagePtr); return RS_RES; } /** * @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 Отмена работы UART в целом или отмена приема/передачи RS. Также очищается хендл hRS. */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { HAL_StatusTypeDef uart_res = 0; hRS->htim->Instance->CNT = 0; if(hRS->sRS_Timeout) // if timeout setted { TIM14->DIER &= ~(TIM_IT_UPDATE); /* Disable the Peripheral */ TIM14->CR1 &= ~(TIM_CR1_CEN); } if((AbortMode&ABORT_RS) == 0x00) { if((AbortMode&ABORT_RX) == ABORT_RX) { uart_res = HAL_UART_AbortReceive(hRS->huart); // abort receive RS_Reset_RX_Flags(hRS); } if((AbortMode&ABORT_TX) == ABORT_TX) { uart_res = HAL_UART_AbortTransmit(hRS->huart); // abort transmit RS_Reset_TX_Flags(hRS); } } else { uart_res = HAL_UART_Abort(hRS->huart); RS_Clear_All(hRS); } hRS->RS_STATUS = RS_ABORTED; return RS_ABORTED; } //-------------------------GENERAL FUNCTIONS------------------------- //------------------------------------------------------------------- //------------------------------------------------------------------- //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- /** * @brief Handle for starting receive. * @param hRS - указатель на хендлер RS. * @param RS_msg - указатель на структуру сообщения. * @return RS_RES - статус о состоянии RS после инициализации приема или окончания общения. * @note Определяет начинать прием команды/ответа или нет. */ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { RS_StatusTypeDef RS_RES = 0; switch(hRS->sRS_Mode) { case SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again case SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request) RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy) } if(RS_RES != RS_OK) { TrackerCnt_Err(hRS->rs_err); } return RS_RES; } /** * @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) { RS_StatusTypeDef RS_RES = 0; switch(hRS->sRS_Mode) { case SLAVE_ALWAYS_WAIT: // in slave mode always response case SLAVE_TIMEOUT_WAIT: // transmit response RS_RES = RS_Transmit_IT(hRS, RS_msg); break; } if(RS_RES != RS_OK) { TrackerCnt_Err(hRS->rs_err); } return RS_RES; } /** * @brief UART RX Callback: define behaviour after receiving parts of message. * @param hRS - указатель на хендлер RS. * @return RS_RES - статус о состоянии RS после обработки приема. * @note Контролирует прием сообщения: определяет размер принимаемой посылки и обрабатывает его. */ RS_StatusTypeDef RS_UART_RxCpltCallback(RS_HandleTypeDef *hRS) { RS_StatusTypeDef RS_RES = 0; HAL_StatusTypeDef uart_res = 0; // if we had received bytes before ByteCnt if((hRS->sRS_RX_Size_Mode == RS_RX_Size_NotConst) && (hRS->f.RX_Half == 0)) // if data size isnt constant and its first half, and { // First receive part of message, then define size of rest of message, and start receive it hRS->f.RX_Half = 1; //---------------FIND DATA SIZE----------------- uint32_t NuRS_of_Rest_Bytes = 0xFFFF; RS_RES = RS_Define_Size_of_RX_Message(hRS, &NuRS_of_Rest_Bytes); // if we need to skip this message - restart receive if(RS_RES == RS_SKIP || NuRS_of_Rest_Bytes == 0xFFFF) { TrackerCnt_Err(hRS->rs_err); RS_Abort(hRS, ABORT_RX); RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); return RS_RES; } // if there is no bytes to receive if(NuRS_of_Rest_Bytes == 0) { hRS->f.RX_Half = 0; //---------PROCESS DATA & ENDING RECEIVING-------- RS_Set_RX_End(hRS); if(hRS->sRS_Timeout) // if timeout setted { TIM14->DIER &= ~(TIM_IT_UPDATE); /* Disable the Peripheral */ TIM14->CR1 &= ~(TIM_CR1_CEN); } // parse received data RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message // RESPONSE RS_RES = RS_Response(hRS, hRS->pMessagePtr); return RS_RES; } //-------------START UART RECEIVE--------------- uart_res = HAL_UART_Receive_IT(hRS->huart, (hRS->pBufferPtr + RX_FIRST_PART_SIZE), NuRS_of_Rest_Bytes); if(uart_res != HAL_OK) {// need uart status, so doesnt write abort to RS_RES TrackerCnt_Err(hRS->rs_err); RS_RES = RS_Abort(hRS, ABORT_RS); } else RS_RES = RS_OK; } else // if we had received whole message { hRS->f.RX_Half = 0; //---------PROCESS DATA & ENDING RECEIVING-------- RS_Set_RX_End(hRS); if(hRS->sRS_Timeout) // if timeout setted { TIM14->DIER &= ~(TIM_IT_UPDATE); /* Disable the Peripheral */ TIM14->CR1 &= ~(TIM_CR1_CEN); } // parse received data RS_RES = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); // parse message // RESPONSE RS_RES = RS_Response(hRS, hRS->pMessagePtr); } return RS_RES; } /** * @brief UART TX Callback: define behaviour after transmiting message. * @param hRS - указатель на хендлер RS. * @return RS_RES - статус о состоянии RS после обработки приема. * @note Определяет поведение RS после передачи сообщения. */ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS) { RS_StatusTypeDef RS_RES = RS_OK; HAL_StatusTypeDef uart_res = 0; //--------------ENDING TRANSMITTING------------- RS_Set_TX_End(hRS); RS_EnableReceive(); // for(int i = 0; i < hRS->sRS_Timeout; i++); //-----------START RECEIVING or END RS---------- RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); return RS_RES; } /** * @brief Handler for UART. * @param hRS - указатель на хендлер RS. * @note Обрабатывает ошибки если есть и вызывает RS Коллбеки. * Добавить вызов этой функции в UARTx_IRQHandler(). */ void RS_UART_Handler(RS_HandleTypeDef *hRS) { HAL_UART_IRQHandler(hRS->huart); //-------------CALL RS CALLBACKS------------ /* IF NO ERROR OCCURS */ if(hRS->huart->ErrorCode == 0) { hRS->htim->Instance->CNT = 0; // reset cnt; /* Start timeout */ if(hRS->sRS_Timeout) // if timeout setted if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active { TIM14->DIER |= (TIM_IT_UPDATE); /* Disable the Peripheral */ TIM14->CR1 |= (TIM_CR1_CEN); RS_Set_RX_Active_Flags(hRS); } /* RX Callback */ if (( hRS->huart->RxXferCount == 0U) && RS_Is_RX_Busy(hRS) && // if all bytes are received and receive is active hRS->huart->RxState != HAL_UART_STATE_BUSY_RX) // also check that receive "REALLY" isnt busy RS_UART_RxCpltCallback(hRS); /* TX Callback */ if (( hRS->huart->TxXferCount == 0U) && RS_Is_TX_Busy(hRS) && // if all bytes are transmited and transmit is active hRS->huart->gState != HAL_UART_STATE_BUSY_TX) // also check that receive "REALLY" isnt busy RS_UART_TxCpltCallback(hRS); } //----------------ERRORS HANDLER---------------- else { TrackerCnt_Err(hRS->rs_err); /* de-init uart transfer */ RS_Abort(hRS, ABORT_RS); RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // later, maybe, will be added specific handlers for err } } /** * @brief Handler for TIM. * @param hRS - указатель на хендлер RS. * @note Попадание сюда = таймаут и перезапуск RS приема * Добавить вызов этой функции в TIMx_IRQHandler(). */ void RS_TIM_Handler(RS_HandleTypeDef *hRS) { TIM14->SR = ~(TIM_IT_UPDATE); /* Disable the TIM Update interrupt */ TIM14->DIER &= ~(TIM_IT_UPDATE); /* Disable the Peripheral */ TIM14->CR1 &= ~(TIM_CR1_CEN); RS_Abort(hRS, ABORT_RS); RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); } //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- //------------------------------------------------------------------- //------------------------------------------------------------------- //--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- /** * @brief Respond accord to received message. * @param hRS - указатель на хендлер RS. * @param RS_msg - указатель на структуру сообщения. * @return RS_RES - статус о результате ответа на комманду. * @note Обработка принятой комманды и ответ на неё. */ __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { /* Redefine function for user purposes */ 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 из структуры сообщения. */ __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { /* Redefine function for user purposes */ 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. */ __weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { /* Redefine function for user purposes */ 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 Определение сколько байтов надо принять по протоколу. */ __weak RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size) { /* Redefine function for user purposes */ return RS_ERR; } //--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE--------------- //-------------------------------------------------------------------