/**********************************RS***************************************
Данный файл содержит объявления базовых функции и дефайны для реализации 
протоколов по RS/UART.
***************************************************************************/
#ifndef __RS_LIB_H_
#define __RS_LIB_H_

#include "modbus.h" 

#include "periph_general.h"
#include "crc_algs.h"


/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
/* Check that all defines required by RS are defined */
#ifndef MSG_SIZE_MAX
#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
#endif

#ifndef RX_FIRST_PART_SIZE
#error Define RX_FIRST_PART_SIZE (Size of first part of message). This is necessary to receive the first part of the message, from which determine the size of the remaining part of the message.
#endif


/* Clear message-uart buffer */
#define RS_Clear_Buff(_buff_)				for(int i=0; i<MSG_SIZE_MAX;i++)	_buff_[i] = NULL

/* Set/Reset flags */
#define RS_Set_Free(_hRS_)					_hRS_->fRS_Busy = 0
#define RS_Set_Busy(_hRS_)					_hRS_->fRS_Busy = 1

#define RS_Set_RX_Flags(_hRS_)			_hRS_->fRX_Busy = 1; _hRS_->fRX_Done = 0; _hRS_->fRX_Half = 0
#define RS_Set_TX_Flags(_hRS_)			_hRS_->fTX_Busy = 1; _hRS_->fTX_Done = 0

#define RS_Reset_RX_Flags(_hRS_)		_hRS_->fRX_Busy = 0; _hRS_->fRX_Done = 0; _hRS_->fRX_Half = 0
#define RS_Reset_TX_Flags(_hRS_)		_hRS_->fTX_Busy = 0; _hRS_->fTX_Done = 0

#define RS_Set_RX_End_Flag(_hRS_)		_hRS_->fRX_Done = 1
#define RS_Set_TX_End_Flag(_hRS_)		_hRS_->fTX_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_->fRX_Busy == 1)
#define RS_Is_TX_Busy(_hRS_)				(_hRS_->fTX_Busy == 1)
////////////////////////////---DEFINES---////////////////////////////



/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
//------------------ENUMERATIONS--------------------
/* 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_COLLECT_MSG_ERR,
	/*0x07*/	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;


/* Enums for RS Modes */
typedef enum	// RS_ModeTypeDef
{
	SLAVE_ALWAYS_WAIT =				0x01,		// Slave mode with infinity waiting
	SLAVE_TIMEOUT_WAIT = 			0x02,		// Slave mode with waiting with timeout
//	MASTER = 									0x03,		// Master mode
}RS_ModeTypeDef;

/* Enums for RS UART Modes */
typedef enum	// RS_ITModeTypeDef
{
	BLCK_MODE = 		0x00,		// Blocking mode
	IT_MODE = 			0x01,		// Interrupt mode
}RS_ITModeTypeDef;

/* Enums for Abort modes */
typedef enum	// RS_AbortTypeDef
{
	ABORT_TX = 			0x01,		// Abort transmit
	ABORT_RX = 			0x02,		// Abort receive
	ABORT_RX_TX =		0x03,		// Abort receive and transmit
	ABORT_RS = 			0x04,		// Abort uart and reset RS structure
}RS_AbortTypeDef;

/* Enums for RX Size modes */
typedef enum	// RS_RXSizeTypeDef
{
	RS_RX_Size_Const = 			0x01,		// size of receiving message is constant
	RS_RX_Size_NotConst = 	0x02,		// size of receiving message isnt constant
}RS_RXSizeTypeDef;


//-----------STRUCTURE FOR HANDLE RS------------
/** 
	* @brief 	Handle for RS communication.
	* @note 	Prefixes: h - handle, s - settings, f - flag
	*/
typedef struct	// RS_HandleTypeDef
{		
	/* MESSAGE */
	uint8_t										ID;										// ID of RS "channel"
	RS_MsgTypeDef 						*pMessagePtr;					// pointer to message struct
	uint8_t 									*pBufferPtr;					// pointer to message buffer
	uint32_t									RS_Message_Size;			// size of whole message, not only data
	
	/* HANDLERS and SETTINGS */
	UART_HandleTypeDef 				*huart;								// handler for used uart
	TIM_HandleTypeDef 				*htim;								// handler for used tim
	RS_ModeTypeDef						sRS_Mode;							// setting: slave or master @ref RS_ModeTypeDef
	RS_ITModeTypeDef					sRS_IT_Mode;					// setting: 1 - IT mode, 	0 - Blocking mode 
	uint16_t 									sRS_Timeout;					// setting: timeout in ms
	RS_RXSizeTypeDef					sRS_RX_Size_Mode;			// setting: 1 - not const, 0 - const 
	
	/* FLAGS */		
	// These flags for controling receive/transmit
	unsigned 									fRX_Half:1;						// flag: 0 - receiving msg before ByteCnt, 	0 - receiving msg after ByteCnt
	
	unsigned 									fRS_Busy:1;						// flag: 1 - RS is busy, 0 - RS isnt busy		
	unsigned 									fRX_Busy:1;						// flag: 1 - receiving is active, 	0 - receiving isnt active
	unsigned 									fTX_Busy:1;						// flag: 1 - transmiting is active, 0 - transmiting isnt active				
	
	unsigned 									fRX_Done:1;						// flag: 1 - receiving is done, 	0 - receiving isnt done	
	unsigned 									fTX_Done:1;						// flag: 1 - transmiting is done, 0 - transmiting isnt done	
		
	// setted by user
	unsigned 									fMessageHandled:1;		// flag: 1 - RS command is handled, 				0 - RS command isnt handled yet
	unsigned 									fEchoResponse:1;			// flag: 1 - response with received msg,		0 - response with own msg
	unsigned 									fDeferredResponse:1;	// flag: 1 - response not in interrupt, 		0 - response in interrupt
	unsigned 									fReInit_UART:1;				// flag: 1 - need to reinitialize uart, 		0 - nothing	
	
	/* RS STATUS */
	RS_StatusTypeDef 					RS_STATUS;						// RS status
}RS_HandleTypeDef;


///////////////////////---STRUCTURES & ENUMS---//////////////////////


/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
/*--------------------Defined by users purposes--------------------*/
/** 
	* @brief 	Respond accord to received message.
	* @param 	hRS 		- указатель на хендлер RS.
	* @param 	RS_msg 	- указатель на структуру сообщения.
	* @return RS_RES	- статус о результате ответа на комманду.
	* @note		Обработка принятой комманды и ответ на неё.
	*/
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);

/** 
	* @brief 	Collect message in buffer to transmit it.
	* @param 	hRS 					- указатель на хендлер RS.
	* @param 	RS_msg 				- указатель на структуру сообщения.
	* @param 	msg_uart_buff	- указатель на буффер UART.
	* @return RS_RES				- статус о результате заполнения буфера.
	* @note		Заполнение буффера UART из структуры сообщения.
	*/
RS_StatusTypeDef Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);

/** 
	* @brief 	Parse message from buffer to process it.
	* @param 	hRS 					- указатель на хендлер RS.
	* @param 	RS_msg 				- указатель на структуру сообщения.
	* @param 	msg_uart_buff	- указатель на буффер UART.
	* @return RS_RES				- статус о результате заполнения структуры.
	* @note		Заполнение структуры сообщения из буффера UART.
	*/
RS_StatusTypeDef Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);

/** 
	* @brief 	Define size of RX Message that need to be received.
	* @param 	hRS 					- указатель на хендлер RS.
	* @param 	rx_data_size 	- указатель на переменную для записи кол-ва байт для принятия.
	* @return RS_RES				- статус о корректности рассчета кол-ва байт для принятия.
	* @note		Определение сколько байтов надо принять по протоколу.
	*/
RS_StatusTypeDef RS_Define_Size_of_RX_Message(RS_HandleTypeDef *hRS, uint32_t *rx_data_size);


//-------------------------GENERAL FUNCTIONS-------------------------
/*-----------------Should be called from main code-----------------*/
/**
	* @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);

/**
	* @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);

/** 
	* @brief 	Initialize UART and handle RS stucture.
	* @param 	hRS 					- указатель на хендлер RS.
	* @param 	suart 				- указатель на структуру с настройками UART.
	* @param 	stim 					- указатель на структуру с настройками таймера.
	* @param 	pRS_BufferPtr - указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
	* @return RS_RES				- статус о состоянии RS после инициализации.
	*/
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_SettingsTypeDef *suart, TIM_SettingsTypeDef *stim, uint8_t *pRS_BufferPtr);
/** 
	* @brief 	ReInitialize UART and RS receive.
	* @param 	hRS 					- указатель на хендлер RS.
	* @param 	suart 				- указатель на структуру с настройками UART.
	* @return RS_RES				- статус о состоянии RS после инициализации.
	*/
HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_SettingsTypeDef *suart);
/**
	* @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);
//-------------------------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);
/**  
	* @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);
/**  
	* @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);
/**  
	* @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);
/**  
	* @brief 	Handler for UART.
	* @param 	hRS 		- указатель на хендлер RS.
	* @note		Обрабатывает ошибки если есть и вызывает RS Коллбеки.
	*					Добавить вызов этой функции в UARTx_IRQHandler().
	*/
void RS_UART_Handler(RS_HandleTypeDef *hRS);
/**  
	* @brief 	Handler for TIM.
	* @param 	hRS 		- указатель на хендлер RS.
	* @note		Попадание сюда = таймаут и перезапуск RS приема
	*					Добавить вызов этой функции в TIMx_IRQHandler().
	*/
void RS_TIM_Handler(RS_HandleTypeDef *hRS);
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
///////////////////////////---FUNCTIONS---///////////////////////////

#endif // __RS_LIB_H_