//----------------------------------------------------
/**
	\file		ctk/inc/stmachine.h
	\ingroup	control
	\ingroup	all

	\brief		Knihovna definujici spolecny zaklad stavovych automatu
				<<< ALL >>>

	\author		ConTeK s.r.o., Vladimir Kastner
	\version	03.01
	\date		10.10.2009
*/
//----------------------------------------------------

#ifndef _ST_MACHINE_H_
#define _ST_MACHINE_H_

#include <sync.h>
#include <timeticks.h>

#ifdef _DBGMON_DEBUG
#include <dbgmon.h>
#endif

//----------------------------------------------------
//!	\name	Zakladni stavy automatu
//@{

typedef uint8_t		stmachine_t;		//!< Typ pro ulozeni stavu automatu

typedef enum _STM_DEFAULT_STATES
{
	STM_FINISHED			= 0,
	STM_RESTART				= 1,
	STM_DUMMY				= 2,

	STM_FIRST_USER_STATE	= 3			//!< Prvni stav pouzitelny uzivatelem
} STM_DEFAULT_STATES;

//@}

//----------------------------------------------------
//!	\brief	Zakladni struktura automatu
//!
//!	\note	Musi byt umistena ve strukture dedice jako prvni.

typedef struct _STMACHINE
{
	volatile stmachine_t	State;	//!< Stav automatu
	bool_t			Abort;			//!< Priznak rychleho ukonceni automatu
	bool_t			Finish;			//!< Priznak ukonceni automatu
	bool_t			Restart;		//!< Priznak startu automatu
#ifdef STM_FIRSTPASS
	bool_t			FirstPass;		//!< Priznak prvniho pruchodu stavem automatu
#endif // STM_FIRSTPASS
#ifdef STM_TIMER
	bool_t			FlTimer;		//!< Priznak pouziti casovace
									//!< TRUE = casovac pro pouziti uvnitr stavu automatu
									//!< FALSE = casovac vyuzit pro wait - stavy automatu se nevykonavaji
	lticks_t		Timer;			//!< Prvni stav opakovani, nelze vnorene opakovani
#endif // STM_TIMER
#ifdef STM_CALL
	bool_t			ReturnPass;		//!< Priznak pruchodu automatem po navratu z podprogramu
	uint8_t			StackIdx;		//!< Ukazatel zasobniku
	uint8_t			Stack[STM_STACK_LENGTH];	//!< Zasobnik
#endif // STM_CALL
#ifdef STM_REPEAT
	uint8_t			RptState;		//!< Prvni stav opakovani, nelze vnorene opakovani
	uint16_t		RptCount;		//!< Pocet opakovani sekvenci stavu
#endif // STM_REPEAT
#if defined(_DEBUG) && defined(STM_STATE_NAMES)
	pcharptr_t		StmName;		//!< Jmeno automatu tistene pri informacich o nem
	bool_t			PrintStates;	//!< Priznak, ze se maji vypisovat stavy automatu
#endif
} STMACHINE;


//----------------------------------------------------
/**
	\brief	Funkce pro restartovani automatu ze stavu ST_FINISHED
*/
//----------------------------------------------------
static inline stmachine_t stmGetState(STMACHINE * const _ctx)
{
	return AtomRead(_ctx->State);
}

//----------------------------------------------------
/**
	/brief	Funkce pro restartovani automatu ze stavu ST_FINISHED
*/
//----------------------------------------------------
static inline void stmReqRestart(STMACHINE * const _ctx)
{
	_ctx->Abort = FALSE;
	_ctx->Finish = FALSE;
#ifdef STM_TIMER
	_ctx->Timer = ltmTicks();
#endif
	_ctx->Restart = TRUE;
}

//----------------------------------------------------
/**
	\brief	Funkce pro naplanovani rychleho ukonceni automatu
*/
//----------------------------------------------------
static inline void stmReqAbort(STMACHINE * const _ctx)
{
	_ctx->Abort = TRUE;
}

//----------------------------------------------------
/**
	\brief Funkce pro zadani pozadavku na ukonceni automatu
*/
//----------------------------------------------------
static inline void stmReqFinish(STMACHINE * const _ctx)
{
	_ctx->Finish = TRUE;
}

//----------------------------------------------------
/**
	\brief	Funkce pro testovani, zda je automat v ukoncenem stavu
*/
//----------------------------------------------------
static inline bool_t stmFinished(STMACHINE * const _ctx)
{
	return (stmGetState(_ctx) == STM_FINISHED);
}

//----------------------------------------------------
/**
	\brief Funkce pro inicializaci automatu
*/
//----------------------------------------------------
static inline void stmInitialize(STMACHINE * const _ctx)
{
	// vynulovani dat
	memset(_ctx, 0, sizeof(*_ctx));

	_ctx->State = STM_FINISHED;
	_ctx->Abort = FALSE;
	_ctx->Finish = TRUE;
	_ctx->Restart = FALSE;
#ifdef STM_FIRSTPASS
	_ctx->FirstPass = TRUE;
#endif // STM_FIRSTPASS
#ifdef STM_TIMER
	_ctx->FlTimer = FALSE;	// Implicitne na wait
	_ctx->Timer = ltmTicks();
#endif // STM_TIMER
#ifdef STM_CALL
	_ctx->ReturnPass = FALSE;
	_ctx->StackIdx = 0;
#endif // STM_CALL
#ifdef STM_REPEAT
	_ctx->RptState = STM_FINISHED;
	_ctx->RptCount = 0;
#endif // STM_REPEAT
}


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

	\note	Kazdy automat musi provest nasledujici akce
*/
//----------------------------------------------------
/*
	stmReqFinish(&AutomatCtx.Stm);	// Pozor automat musi ve stavech testovat podminku stFinish
	nebo
	stmReqAbort(&AutomatCtx.Stm);	// Podminka stAbort je v automatu testovana automaticky

	while (!stmFinished(&AutomatCtx.Stm))
	{
		AutomatTick(&AutomatCtx);

		Sleep(xx_ms);
	}
*/

//----------------------------------------------------
//!	\name Makra pouzivana uvnitr automatu
//@{

//----------------------------------------------------
//! Definice nazvu navesti automatu - uzivatelsky nepouzivat

#define stName(_name) \
	lstm##_name


//----------------------------------------------------
//! Definice pomocneho nazvu navesti automatu - uzivatelsky nepouzivat

#define stNameA(_name) \
	lstma##_name


//----------------------------------------------------
//! Navrati stav automatu

#define stState \
	(stm_ctx->State)


//----------------------------------------------------
//! Navrati novy stav automatu

#define stNewState \
	(stm_newstate)


//----------------------------------------------------
//! Odkaz na aktualni priznak return pass

#define stNewReturnPass \
	(stm_returnpass)


//----------------------------------------------------
//! Test na prvni pruchod automatem

#define stFirstPass \
	(stm_ctx->FirstPass)


//----------------------------------------------------
//! Test na prvni pruchod automatem po navratu z podprogramu

#define stReturnPass \
	(stm_ctx->ReturnPass)


//----------------------------------------------------
//! Navrati casovac

#define stTimer \
	(stm_ctx->Timer)


//----------------------------------------------------
//! Navrati RptState

#define stRptState \
	(stm_ctx->RptState)


//----------------------------------------------------
//! Navrati Stack

#define stStack \
	(stm_ctx->Stack)


//----------------------------------------------------
//! Navrati StackIdx

#define stStackIdx \
	(stm_ctx->StackIdx)


//----------------------------------------------------
//! Navrati priznak rychleho ukonceni
#define stAbort \
	(stm_ctx->Abort)


//----------------------------------------------------
//! Navrati priznak pozadavku na ukonceni

#define stFinish \
	(stm_ctx->Finish)


//----------------------------------------------------
//! Vraci TRUE, pokud je automat v ukoncenem stavu

#define stFinished \
	(stState == STM_FINISHED)


//----------------------------------------------------
//! Navrati priznak pozadavku na restart

#define stRestart \
	(stm_ctx->Restart)


//----------------------------------------------------
//! Navrati pocet cyklu

#define stRptCount \
	(stm_ctx->RptCount)


//----------------------------------------------------
//! Priznak pouziti casovace jinak nez pro wait

#define stFlTimer \
	(stm_ctx->FlTimer)


//----------------------------------------------------
//! Pozadavek na wait prodlevu

#define stWait(_wait) \
	do { \
		stFlTimer = FALSE; \
		stTimer = ltmTimeout(_wait); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na jine vyuziti casovace

#define stAfter(_time) \
	do { \
		stFlTimer = TRUE; \
		stTimer = ltmTimeout(_time); \
	} while (0)

//----------------------------------------------------
//! Test na uplynuti casovace, po volani stAfter

#define stElapsedTime() \
		ltmElapsed(stTimer)


//----------------------------------------------------
//!	\brief	Pozadavek na opakovani
//! \note	Navrat z konce je do tohoto stavu.
//!			Volani doporuceno umistit do stFirstPass.

#define stRepeat(_rpt) \
	do { \
		stRptState = stNewState; \
		stRptCount = (_rpt); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na restart automatu - pouzivat ve stavu finished

#define stReqRestart() \
	stmReqRestart(stm_ctx)

//----------------------------------------------------
//! Pozadavek na okamzity restart automatu - pouzivat ve stavu finished

#define gstReqRestart() \
	do { \
		stReqRestart(); \
		goto stName(Switch); \
	} while (0)

//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu na restart automatu - nepouzivat ve stavu finished

#define stGotoRestart() \
	stGoto(STM_RESTART)

//----------------------------------------------------
//! Pozadavek na okamzity restart automatu - nepouzivat ve stavu finished

#define gstGotoRestart() \
	gstGoto(STM_RESTART)

//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu na restart automatu s prodlevou

#define stGotoRestartWait(_timeout) \
	stGotoWait(STM_RESTART, (_timeout))

//----------------------------------------------------
//! Pozadavek na ukonceni automatu

#define stReqFinish() \
	stFinish = TRUE


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu na ukonceni automatu

#define stGotoFinish() \
	do { \
		stReqFinish(); \
		stRestart = FALSE; \
		stGoto(STM_FINISHED); \
	} while (0)

//----------------------------------------------------
//! Pozadavek na okamzite nastaveni dalsiho stavu na ukonceni automatu

#define gstGotoFinish() \
	do { \
		stGotoFinish(); \
		gxstGoto(STM_FINISHED); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na rychle ukonceni automatu

#define stGotoAbort() \
	stAbort = TRUE


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu

#define stGoto(_state) \
	(stNewState = (_state))


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu

#define stNextState() \
	stGoto(stNewState + 1)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s prodlevou

#define stGotoWait(_state, _wait) \
	do { \
		stGoto(_state); \
		stWait(_wait); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu po zadanem case
//! stav je provaden opakovane, po uplynuti casu prechod do dalsiho stavu

#define stGotoAfterTime(_state, _time) \
	do { \
		if (stFirstPass) \
		{ \
			stAfter(_time); \
		} \
		\
		if (stElapsedTime()) \
		{ \
			stTimer = ltmTicks(); \
			stGoto(_state); \
		} \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu po zadanem case a goto
//! stav je provaden opakovane, po uplynuti casu prechod do dalsiho stavu

#define gstGotoAfterTime(_state, _time) \
	do { \
		if (stFirstPass) \
		{ \
			stAfter(_time); \
		} \
		\
		if (stElapsedTime()) \
		{ \
			stTimer = ltmTicks(); \
			gstGoto(_state); \
		} \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu po zadanem case a goto
//! stav je provaden opakovane, po uplynuti casu prechod do dalsiho stavu

#define gxstGotoAfterTime(_state, _time) \
	do { \
		if (stFirstPass) \
		{ \
			stAfter(_time); \
		} \
		\
		if (ltmElapsed(stTimer)) \
		{ \
			stTimer = ltmTicks(); \
			gxstGoto(_state); \
		} \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s prodlevou

#define stNextStateWait(_wait) \
	stGotoWait(stNewState + 1, (_wait))


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim

#define stGotoRepeat(_state, _rpt) \
	do { \
		stGoto(_state); \
		stRepeat(_rpt); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim

#define stNextStateRepeat(_rpt) \
	stGotoRepeat(stNewState + 1, (_rpt))


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim a prvni prodlevou

#define stGotoRepeatWait(_state, _rpt, _wait) \
	do { \
		stGotoRepeat((_state), (_rpt)); \
		stWait(_wait); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim a prvni prodlevou

#define stNextStateRepeatWait(_rpt, _wait) \
	stGotoRepeatWait(stNewState + 1, (_rpt), (_wait))


//----------------------------------------------------
//! Pozadavek na ukonceni opakovaciho cyklu
//! navraci TRUE pokud citac opakovani je > 0

#define stRepeatEnd(_state) \
	((stRptCount > 0) ? \
		(((--stRptCount > 0) ? stGoto(stRptState) : stGoto(_state)), TRUE) : \
		(stGoto(_state), FALSE) )


//----------------------------------------------------
//! Pozadavek na ukonceni opakovaciho cyklu s prodlevou

#define stRepeatEndWait(_state, _wait) \
	do { \
		stWait(_wait); \
		stRepeatEnd(_state); \
	} while (0)


//----------------------------------------------------
//!	\brief	Pozadavek na skok do podstavu automatu (podprogram)
//!	\note	Navrat z podstavu je do stejneho stavu
//!			Volani doporuceno umistit do stFirstPass

#define stCall(_state) \
	do { \
		stStack[ stStackIdx++ ] = stNewState; \
		stGoto(_state); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na skok do podstavu automatu s prodlevou

#define stCallWait(_state, _wait) \
	do { \
		stCall(_state); \
		stWait(_wait); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na skok do podstavu automatu a navratem do returnState s prodlevou

#define stCallThru(_callState, _returnState) \
	do { \
		stStack[ stStackPtr++ ] = _returnState; \
		stGoto(_callState); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na skok do podstavu automatu a navratem do returnState s prodlevou

#define stCallThruWait(_callState, _returnState, _wait) \
	do { \
		stCallThru(_callState, _returnState); \
		stWait(_wait); \
	} \ while (0)


//----------------------------------------------------
//! Navrat z podstavu automatu (podprogram)

#define stReturn() \
	do { \
		stState = stGoto(stStack[ --stStackIdx ]); \
		stNewReturnPass = TRUE; \
	} while (0)


//----------------------------------------------------
//! Navrat z podstavu automatu s prodlevou

#define stReturnWait(_wait) \
	do { \
		stReturn(); \
		stWait(_wait); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu a goto

#define gstGoto(_state) \
	do { \
		stGoto(_state); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(_state); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na rychle ukonceni automatu a goto

#define gstGotoAbort() \
	do { \
		stGotoAbort(); \
		goto stName(Switch); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim a goto

#define gstGotoRepeat(_state, _rpt) \
	do { \
		stGotoRepeat((_state), (_rpt)); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(_state); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na ukonceni opakovaciho cyklu, navraci TRUE pokud se opakuje a goto

#define gstRepeatEnd(_state, _commands) \
	do { \
		if (stRepeatEnd(_state)) \
		{ \
			_commands \
		} \
		stSetFirstPass(); \
		if (stRptCount > 0) \
			goto stName(Switch); \
		else \
			goto stName(_state); \
	} while (0)


//----------------------------------------------------
//!	\brief	Pozadavek na skok do podstavu automatu (podprogram) a goto
//!	\note	Navrat z podstavu je do stjneho stavu
//!			Volani doporuceno umistit do stFirstPass

#define gstCall(_state) \
	do { \
		stCall(_state); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(_state); \
	} while (0)


//----------------------------------------------------
//! Navrat z podstavu automatu (podprogram) a goto

#define gstReturn() \
	do { \
		stReturn(); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(Switch); \
	} while (0)


//----------------------------------------------------
// Pozadavek na skok do podstavu a navrat jinam

#define gstCallThru(_callState, _returnState) \
	do { \
		stCallThru(_callState, _returnState); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(_callState); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu a goto

#define gxstGoto(_state) \
	do { \
		stGoto(_state); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(Switch); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu a goto

#define gxstNextState \
	gxstGoto(stNewState + 1)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim a goto

#define gxstGotoRepeat(_state, _rpt) \
	do { \
		stGotoRepeat(_state, _rpt); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(Switch); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na nastaveni dalsiho stavu automatu s opakovanim a goto

#define gxstNextStateRepeat(_state, _rpt) \
	gxstGotoRepeat(stNewState + 1, (_rpt))


//----------------------------------------------------
//! Pozadavek na ukonceni opakovaciho cyklu, navraci TRUE pokud se opakuje a goto

#define gxstRepeatEnd(_state, _commands) \
	do { \
		if (stRepeatEnd(_state)) \
		{ \
			commands; \
		} \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(Switch); \
	} while (0)


//----------------------------------------------------
//! Pozadavek na ukonceni opakovaciho cyklu, navraci TRUE pokud se opakuje a goto

#define gxstNextStateRepeatEnd(_commands) \
	gxstRepeatEnd(stNewState + 1, (_commands))


//----------------------------------------------------
//!	\brief	Pozadavek na skok do podstavu automatu (podprogram) a goto
//!	\note	Navrat z podstavu je do stjneho stavu
//!			Volani doporuceno umistit do stFirstPass

#define gxstCall(_state) \
	do { \
		stCall(_state); \
		stSetFirstPass(); \
		stSetReturnPass(); \
		goto stName(Switch); \
	} while (0)


//----------------------------------------------------
//! \brief	Nastaveni FirstPass priznaku
#ifdef STM_FIRSTPASS
 #define stSetFirstPass() \
	((stFirstPass = (stState != stNewState)) ? stState = stNewState : 0)
#else
 #define stSetFirstPass() \
	stState = stNewState
#endif // STM_FIRSTPASS

//----------------------------------------------------
//! \brief	Nastaveni ReturnPass priznaku

#ifdef STM_CALL
 #define stSetReturnPass() \
	do { \
		stReturnPass = stNewReturnPass; \
		stNewReturnPass = FALSE; \
	} while (0)
#else
 #define stSetReturnPass()
#endif  // STM_CALL
//----------------------------------------------------
//! Pomocne makro pro reset citace cyklu

#ifdef STM_REPEAT
 #define ResetRptCount() \
	stRptCount = 0
#else
 #define ResetRptCount()
#endif

//----------------------------------------------------
//! Pomocna definice stavu automatu

#define STM_ST(_name) \
			case (_name): \
				goto stName(_name); \
			stName(_name):


#if defined(_DEBUG) && defined(STM_STATE_NAMES)

//----------------------------------------------------
//! Vypis stavu automatu

#define stPrintState(_name) \
	do { \
		pcharptr_t _stm_name; \
		if (stm_ctx->StmName != NULL) \
		{ \
			_stm_name = stm_ctx->StmName; \
		} \
		else \
		{ \
			static str_pconst_store(_stm_name_str, _T("stm")); \
			_stm_name = _stm_name_str; \
		} \
		static str_pconst_store(_stm_state_name, _T(#_name)); \
		stmPrintStateFunc(_stm_name, _stm_state_name); \
	} while (0)


//----------------------------------------------------
//! Vypis ciselneho stavu automatu

#define stPrintNumState(_num) \
	do { \
		pcharptr_t _stm_name; \
		if (stm_ctx->StmName != NULL) \
		{ \
			_stm_name = stm_ctx->StmName; \
		} \
		else \
		{ \
			static str_pconst_store(_stm_name_str, _T("stm")); \
			_stm_name = _stm_name_str; \
		} \
		stmPrintNumStateFunc(_stm_name, _num); \
	} while (0)


//----------------------------------------------------
//! Definice stavu automatu

#define STM_STATE(_name) \
	break; \
			STM_ST(_name) \
			if (stFirstPass && (stm_ctx->PrintStates)) \
			{ \
				stPrintState(_name); \
            }

//----------------------------------------------------
//! Definice alternativniho nazvu stavu automatu

#define STM_STATE_ALIAS(_name) \
			goto stNameA(_name); \
			STM_ST(_name) \
			if (stFirstPass && (stm_ctx->PrintStates)) \
			{ \
				stPrintState(_name); \
            } \
			stNameA(_name):

#else

//----------------------------------------------------
//! Definice stavu automatu

#define STM_STATE(_name) \
	break; \
			STM_ST(_name)

//----------------------------------------------------
//! Definice alternativniho nazvu stavu automatu

#define STM_STATE_ALIAS(_name) \
			STM_ST(_name)

#endif


#if defined(_DEBUG) && defined(STM_STATE_NAMES)

//----------------------------------------------------
//! Ciselna definice stavu automatu

#define STM_NUM_STATE(_num) \
				break; \
			case (_num): \
			if (stFirstPass && (stm_ctx->PrintStates)) \
			{ \
				stPrintNumState(_num); \
            }


//----------------------------------------------------
//! Ciselna definice alternativniho nazvu stavu automatu

#define STM_NUM_STATE_ALIAS(_num, _name) \
			goto stNameA(_name); \
			case (_num): \
			if (stFirstPass && (stm_ctx->PrintStates)) \
			{ \
				stPrintNumState(_num); \
            } \
			stNameA(_name):
#else

//----------------------------------------------------
//! Ciselna definice stavu automatu

#define STM_NUM_STATE(_num) \
				break; \
			case (_num):

//----------------------------------------------------
//! Ciselna definice alternativniho nazvu stavu automatu

#define STM_NUM_STATE_ALIAS(_num, _name) \
			case (_num):

#endif


//----------------------------------------------------
//! Definice ukonceneho stavu automatu

#define STM_FINISHED_STATE \
			STM_STATE(STM_FINISHED)


//----------------------------------------------------
//! Definice restart stavu automatu

#define STM_RESTART_STATE \
			STM_STATE(STM_RESTART)


//----------------------------------------------------
//! Stav vykonavany pri neplatnem stavu

#define STM_DEFAULT_STATE \
				break; \
			default: \


//----------------------------------------------------
//! Makro umistovane na zacatek automatu
#ifdef STM_CALL
#define stStackIdx_0() \
		stStackIdx = 0
#else
#define stStackIdx_0()
#endif

#ifdef STM_TIMER
#define stTimer_ltmTicks() \
		stTimer = ltmTicks()
#else
#define stTimer_ltmTicks()
#endif


#ifdef STM_FIRSTPASS
 #define stFirstPassstStateSTM_FINISHED stFirstPass = (stState != STM_FINISHED)
 #define ifstFirstPassResetRptCountstStackIdx0stTimerltmTicks \
			if (stFirstPass) \
			{ \
				ResetRptCount(); \
				stStackIdx_0(); \
				stTimer_ltmTicks(); \
			}
#else
 #define stFirstPassstStateSTM_FINISHED
 #define ifstFirstPassResetRptCountstStackIdx0stTimerltmTicks
#endif // STM_FIRSTPASS

#ifdef STM_TIMER
 #define ifstFlTimerifltmElapsedstTimerstTimerltmTickselsegotostNameStmEnd \
		if (!stFlTimer) \
		{ \
			if (ltmElapsed(stTimer)) \
			{ \
				stTimer = ltmTicks(); \
			} \
			else \
			{ \
				goto stName(StmEnd); \
			} \
		}
#else
 #define ifstFlTimerifltmElapsedstTimerstTimerltmTickselsegotostNameStmEnd
#endif // STM_TIMER

#ifdef STM_CALL
 #define bool_tstm_returnpassFALSE \
		bool_t stm_returnpass = FALSE
#else
 #define bool_tstm_returnpassFALSE
#endif // STM_CALL

#define STM_BEGIN(_stmctx) \
	do { \
		STMACHINE *stm_ctx = &(_stmctx); \
		stmachine_t	stm_newstate = stState; \
		bool_tstm_returnpassFALSE; \
		goto stName(Switch); \
		stName(Switch): \
		if (stAbort) \
		{ \
			stAbort = FALSE; \
			stRestart = FALSE; \
			stFinish = TRUE; \
			stFirstPassstStateSTM_FINISHED; \
			stState = STM_FINISHED; \
			stNewState = STM_FINISHED; \
		} \
		else \
		{ \
			ifstFlTimerifltmElapsedstTimerstTimerltmTickselsegotostNameStmEnd \
		} \
		\
		if (stFinished) \
		{ \
			/* standardni obsluha stFinish */ \
			ifstFirstPassResetRptCountstStackIdx0stTimerltmTicks \
			if (stRestart) \
			{ \
				gxstGoto(STM_RESTART); \
			} \
		} \
		\
		switch (stNewState) \
		{ \
			case STM_DUMMY: \
				goto stName(STM_FINISHED); /*nevyuziva se - jen pro povinny STM_FINISHED_STATE*/

#ifdef STM_TIMER
 #define stNameStmEnd \
		stName(StmEnd):;
#else
 #define stNameStmEnd
#endif // STM_TIMER


//----------------------------------------------------
//! Konec tiku automatu s automatickym default stavem

#define STM_DEFAULT_END \
			break; \
			default: \
				stGoto(STM_FINISHED); \
				break; \
		} \
	stSetFirstPass(); \
	stSetReturnPass(); \
	stNameStmEnd \
	} while(0)


//----------------------------------------------------
//! Konec tiku automatu

#define STM_END \
			break; \
		} \
	stSetFirstPass(); \
	stSetReturnPass(); \
	stNameStmEnd \
	} while(0)
//@}

#if defined(_DEBUG) && defined(STM_STATE_NAMES)

//----------------------------------------------------
//! Funkce pro tisk stavu

 #ifndef STM_PRINT_FUNC

#define STM_PRINT_FUNC

  #ifndef MSVC
static void stmPrintStateFunc(const pcharptr_t _name, const pcharptr_t _state) __attribute__((unused));
  #endif // MSVC

static void stmPrintStateFunc(const pcharptr_t _name, const pcharptr_t _state)
{
	char_t printBuf[STM_MAX_PRINTSTATE_LENGTH];

	strcpy_pconst(printBuf, STM_MAX_PRINTSTATE_LENGTH, _name);
	strcat_pconst_store(printBuf, STM_MAX_PRINTSTATE_LENGTH, _T(": "));
	strcat_pconst(printBuf, STM_MAX_PRINTSTATE_LENGTH, _state);
	strcat_pconst_store(printBuf, STM_MAX_PRINTSTATE_LENGTH, _T("\n"));
	DebugMessage(printBuf);
}

  #ifndef MSVC
static void stmPrintNumStateFunc(const pcharptr_t _name, const int _num) __attribute__((unused));
  #endif // MSVC

static void stmPrintNumStateFunc(const pcharptr_t _name, const int _num)
{
	char_t printBuf[STM_MAX_PRINTSTATE_LENGTH];

	strcpy_pconst(printBuf, STM_MAX_PRINTSTATE_LENGTH, _name);
	strcat_pconst_store(printBuf, STM_MAX_PRINTSTATE_LENGTH, _T(": "));

	char_t printNumber[11];
	sprintf_pconst_store(printNumber, 11, _T("%d"), _num);
	strcat_C(printBuf, STM_MAX_PRINTSTATE_LENGTH, printNumber);

	strcat_pconst_store(printBuf, STM_MAX_PRINTSTATE_LENGTH, _T("\n"));
	DebugMessage(printBuf);
}

 #endif	// STM_PRINT_FUNC

#endif // _DEBUG && STM_STATE_NAMES

#endif // _ST_MACHINE_H_
