//----------------------------------------------------
/**
	\file		ctk/inc/comm.h
	\ingroup	serial
	\ingroup	all

	\brief		Definice pro komunikacni knihovny 
				<<< ALL >>>

	\author		ConTeK s.r.o., Ing. Vladimir Kastner
	\version	01.01
	\date		12.01.2007
*/
//----------------------------------------------------


#ifndef _COMM_H_
#define _COMM_H_		//!< Definice pritomnosti knihovny

#include <ctktypes.h>
#include <timeticks.h>


//----------------------------------------------------
//!	\name	Konstanty pro definovani portu
//@{

typedef enum _DATA_BITS
{
	CMM_BITS_4			 = 0,
	CMM_BITS_5			 = 1,
	CMM_BITS_6			 = 2,
	CMM_BITS_7			 = 3,
	CMM_BITS_8			 = 4
} DATA_BITS;


typedef enum _PARITY_TYPE
{
	CMM_PARITY_NONE		 = 0,
	CMM_PARITY_EVEN		 = 1,
	CMM_PARITY_ODD		 = 2
} PARITY_TYPE;


typedef enum _STOP_BITS
{
	CMM_STOPBIT_ONE		 = 0,
	CMM_STOPBIT_TWO		 = 1
} STOP_BITS;


typedef enum _UART_MODE
{
	CMM_MODE_RS232		 = 0,
	CMM_MODE_RS485		 = 1
} UART_MODE;
//@}

//----------------------------------------------------
//!	Konstanty definujici status navraceny funkci Recv

typedef enum _RSTSTYPE
{
	RSTS_OK			= 0,	//!< prijata zprava OK.
	RSTS_ERROR		= 1		//!< prijata zprava chybna
} RSTSTYPE;


//----------------------------------------------------
//!	\name	Konstanty definujici status popisovace bufferu
//@{

#define	STS_READY		0x00		//!< vysilani/prijem dokoncen
#define	STS_ERROR		0x01		//!< vysilani/prijem chyba

#define	STS_PENDING		0x81		//!< vysilani/prijem probiha
#define STS_WAITING		0x82		//!< buffer ceka ve fronte
#define STS_FILLING		0x83		//!< buffer je prave naplnovan

#define STS_BUFREADY	0x80		//!< maska pripravenosti bufferu -> 0 = pripraven
//@}

#ifdef COMM_SMALL_BUF_SIZE

//----------------------------------------------------
//!	\name	Datove typy pro status a delku bufferu
//@{

typedef uint8_t		status_t;		//!< status bufferu
typedef uint8_t		pktsize_t;		//!< velikost buffer
//@}

//----------------------------------------------------
//!	\brief	Popisovac datoveho bufferu
//!	\note	popisovac musi mit velikost zarovnanou tak,
//!			aby sizeof(BUFDESC) bylo modulo 4

typedef struct _BUFDESC
{
	status_t			Status;			//!< Status viz. STS_xxx
	pktsize_t			BufSize;		//!< Velikost alokovaneho bufferu
	pktsize_t			UsedSize;		//!< Velikost dat v bufferu
	pktsize_t			Reserve;		//!< Rezerva
	struct _BUFDESC *	Next;			//!< Ukazatel na dalsi buffer
} BUFDESC;
#else

//----------------------------------------------------
//!	\name	Datove typy pro status a delku bufferu
//@{

typedef uint16_t	status_t;		//!< status bufferu
typedef uint16_t	pktsize_t;		//!< velikost buffer
//@}

//----------------------------------------------------
//!	\brief	Popisovac datoveho bufferu
//!	\note	popisovac musi mit velikost zarovnanou tak,
//!			aby sizeof(BUFDESC) bylo modulo 4

typedef struct _BUFDESC
{
	volatile status_t	Status;			//!< Status viz. STS_xxx
	pktsize_t			BufSize;		//!< Velikost dat v bufferu
	pktsize_t			UsedSize;		//!< Velikost dat v bufferu
	pktsize_t			Reserve;		//!< Rezerva
	struct _BUFDESC *	Next;			//!< Ukazatel na dalsi buffer
} BUFDESC;
#endif

//----------------------------------------------------
/**
	\brief	Funkce pro testovani stavu bufferu

	\param	desc		Deskriptor bufferu

	\return	nenulova hodnota, jestlize operace s bufferem
			(prijem/vysilani) byla dokoncena
*/
//----------------------------------------------------

static inline bool_t BufDescReady(const BUFDESC * const _desc)
{
	return (_desc->Status & STS_BUFREADY) ? FALSE : TRUE;
}


//----------------------------------------------------
/**
	\brief	Forward deklarace kontextu
*/
//----------------------------------------------------

struct _COMMDESC;


//----------------------------------------------------
//!	\name	CallBack funkce objektu
//@{

typedef void (*cmSended_t) (const struct _COMMDESC * const _cmm, const BUFDESC * const _desc);

typedef void (*cmReceived_t) (struct _COMMDESC * const _cmm);

typedef void (*cmPeriodic_t) (struct _COMMDESC * const _cmm);


//----------------------------------------------------
//!	\name	Metody objektu
//@{
typedef void (*cmSend_t) (struct _COMMDESC * const _cmm, BUFDESC * const _desc, const pktsize_t _size);

typedef const BUFDESC * (*cmSendBuffRemove_t) (struct _COMMDESC * const _cmm);

typedef BUFDESC * (*cmRecv_t) (struct _COMMDESC * const _cmm, RSTSTYPE * const _status);

typedef const BUFDESC * (*cmRecvBuffRemove_t) (const struct _COMMDESC * const _cmm);

typedef void (*cmRecvEnable_t) (const struct _COMMDESC * const _cmm);

typedef void (*cmRecvDisable_t) (const struct _COMMDESC * const _cmm);

typedef void (*cmPeriodicTick_t) (struct _COMMDESC * const _cmm);

typedef void (*cmSendTick_t) (struct _COMMDESC * const _cmm);

typedef void (*cmRecvTick_t) (struct _COMMDESC * const _cmm);

typedef void (*cmCommTick_t) (struct _COMMDESC * const _cmm);

// Nasledujici metody jsou volany z preruseni a neni v nich zajistena reentrance systemovych knihoven

typedef uint8_t (*cmGetChar_t) (struct _COMMDESC * const _cmm);

typedef void (*cmPutChar_t) (struct _COMMDESC * const _cmm, const uint8_t _chr);

typedef void (*cmSendCtrl_t) (const struct _COMMDESC * const _cmm, const bool_t _enable);

typedef void (*cmSendMsgEnd_t) (struct _COMMDESC * const _cmm);

typedef void (*cmRecvMsgEnd_t) (struct _COMMDESC * const _cmm);

typedef void (*cmRecvBuffPrepare_t) (struct _COMMDESC * const _cmm, BUFDESC * const _desc, const pktsize_t _size);

#ifdef COMM_ERROR
typedef void (*cmRecvError_t) (struct _COMMDESC * const _cmm, const uint8_t _chr);
#endif // COMM_ERROR

//@}

//----------------------------------------------------
//!	Popisovac automatu

typedef struct
{
	BUFDESC *			Desc;			//!< Ukazatel na popisovac bufferu
	BUFDESC *	 		CurDesc;		//!< popisovac aktualniho bufferu
	BUFDESC * 			FirstDesc;		//!< popisovac prvniho bufferu ve fronte
	BUFDESC * 			LastDesc;		//!< popisovac posledniho bufferu ve fronte
	uint8_t * 			DataPtr;		//!< Ukazatel na odesilana data
	pktsize_t			DataSize;		//!< Zbyvajici delka odesilanych dat
	volatile uint8_t	State;			//!< Stav automatu
	volatile bool_t		flTick;			//!< Priznak provadeni Ticku
	bool_t				flCtrl;			//!< Priznak (povoleni vystupu Tx, ...)
	volatile uint16_t	flMsgEnd;		//!< Pocet ukoncenych zprav
	bool_t				flTimeOut;		//!< Priznak pro vyuzivani TimeOut
	ticks_t				Timer;			//!< Casovac (, ...)
	ticks_t				Timeout;		//!< Pozadovana hodnota casu
} CMDESC;

//----------------------------------------------------
//!	\brief	Popisovac komunicnich automatu
//!			Tato struktura musi byt ve strukture dedice pouzita na prvnim miste

typedef struct _COMMDESC
{
	volatile bool_t		flRunning;		//!< je inicializovano, po ininializaci na TRUE, pred ukoncenim FALSE

	const struct _COMMDESC *	CmmP1;	//!< ukazatel na knihovnu fyzicke vrstvy (layer 1)
	void *				CmmL1;			//!< ukazatel na knihovnu linkove vrstvy a (layer 2)
	const void *		CmmL2;			//!< ukazatel na knihovnu linkove vrstvy b (layer 2)
	const void *		CmmN1;			//!< ukazatel na knihovnu sitove vrstvy (layer 3)
	void *				CmmA1;			//!< ukazatel na knihovnu aplikacni vrstvy (layer 7)

	CMDESC				Snd;			//!< stav vysilace
	CMDESC				Rcv;			//!< stav prijimace

	cmSendCtrl_t		cbSendCtrl;		//!< CallBack pri zacatku/ukonceni vysilani, ovladat signal Tx_
	cmGetChar_t			cbGetChar;		//!< CallBack pro ziskani znaku k odvysilani
	cmSended_t			cbSended;		//!< CallBack po odvysilani zpravy, navraci uvolneny buffer

#ifdef COMM_ERROR
	cmRecvError_t		cbRecvError;	//!< CallBack pri prijmu chyby
#endif // COMM_ERROR

	cmPutChar_t			cbPutChar;		//!< CallBack pri prijmu znaku
	cmReceived_t		cbReceived;		//!< CallBack pri prijmu zpravy
    cmPeriodic_t		cbPeriodic;     //!< Callback pro periodicke zpravy

	cmSend_t			Send;			//!< Metoda pro odesilani
	cmSendBuffRemove_t	SendBuffRemove;	//!< Metoda pro odejmuti odvysilaneho bufferu
	cmSendMsgEnd_t		SendMsgEnd;		//!< CallBack po odeslani zpravy
	cmRecv_t			Recv;			//!< Metoda pro prijem
	cmRecvBuffPrepare_t	RecvBuffPrepare;	//!< Metoda pro pripravu prijmaciho bufferu
	cmRecvBuffRemove_t	RecvBuffRemove;	//!< Metoda pro odejmuti prijmaciho bufferu
	cmRecvEnable_t		RecvEnable;		//!< Metoda povoleni prijmu
    cmRecvDisable_t		RecvDisable;	//!< Metoda zakazani prijmu
    cmPeriodicTick_t    PeriodicTick;    //!< Metoda vysilace periodickych zprav
	cmSendTick_t		SendTick;		//!< Metoda vysilace
	cmRecvTick_t		RecvTick;		//!< Metoda prijmace
	cmCommTick_t		Tick;			//!< Metoda automatu
	cmRecvMsgEnd_t		RecvMsgEnd;		//!< CallBack po prijeti zpravy

#ifdef COMM_MSG_COUNTERS
	unsigned long long RecvTotal;		// prijata data celkem
	unsigned long long SendTotal;		// odeslana data celkem
#endif //COMM_MSG_COUNTERS

} COMMDESC;


//----------------------------------------------------
/**
	\brief	Funkce pro inicializaci komunikacniho automatu

	\param	cmm			Struktura kontextu automatu
	\param	timeout		neni-li prijat znak do xx ticku,
						je predan neuplne zaplneny buffer

	\note 	Dedicove musi po volani jednotlive polozky
			dle potreby pre nastavit
*/
//----------------------------------------------------

bool_t CommInitialize(COMMDESC * const _cmm, const ticks_t _timeout);


//----------------------------------------------------
/**
	\brief	Funkce pro ukonceni komunikacniho automatu

	\param	cmm			Struktura kontextu automatu

	\note 	Dedicove musi na konci ukonceni tuto fci volat
*/
//----------------------------------------------------

void CommFinalize(const COMMDESC * const _cmm);

#endif // _COMM_H_
