/**
* @file
* @brief Public QEP/C interface
* @ingroup qep
* @cond
******************************************************************************
* Last updated for version 6.0.1
* Last updated on  2017-11-01
*
*                    Q u a n t u m     L e a P s
*                    ---------------------------
*                    innovating embedded systems
*
* Copyright (C) Quantum Leaps, LLC. All rights reserved.
*
* This program is open source software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alternatively, this program may be distributed and modified under the
* terms of Quantum Leaps commercial licenses, which expressly supersede
* the GNU General Public License and are specifically designed for
* licensees interested in retaining the proprietary status of their code.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact information:
* https://state-machine.com
* mailto:info@state-machine.com
******************************************************************************
* @endcond
*/
#ifndef qep_h
#define qep_h

/****************************************************************************/
/*! The current QP version as a decimal constant XYZ, where X is a 1-digit
* major version number, Y is a 1-digit minor version number, and Z is
* a 1-digit release number.
*/
#define QP_VERSION      601

/*! The current QP version number string of the form X.Y.Z, where X is
* a 1-digit major version number, Y is a 1-digit minor version number,
* and Z is a 1-digit release number.
*/
#define QP_VERSION_STR  "6.0.1"

/*! Tamperproof current QP release (6.0.1) and date (2017-11-10) */
#define QP_RELEASE      0x9A02AD46U


/****************************************************************************/
/* typedefs for basic numerical types; MISRA-C 2004 rule 6.3(req). */

/*! typedef for character strings. */
/**
* @description
* This typedef specifies character type for exclusive use in character
* strings. Use of this type, rather than plain 'char', is in compliance
* with the MISRA-C 2004 Rules 6.1(req), 6.3(adv).
*/
typedef char char_t;

/*! typedef for line numbers in assertions and return from QF_run() */
typedef int int_t;

/*! typedef for enumerations used for event signals */
typedef int enum_t;

/*! IEEE 754 32-bit floating point number, MISRA-C 2004 rule 6.3(req) */
/**
* @note QP does not use floating-point types anywhere in the internal
* implementation, except in QS software tracing, where utilities for
* output of floating-point numbers are provided for application-level
* trace records.
*/
typedef float float32_t;

/*! IEEE 754 64-bit floating point number, MISRA-C 2004 rule 6.3(req) */
/**
* @note QP does not use floating-point types anywhere in the internal
* implementation, except in QS software tracing, where utilities for
* output of floating-point numbers are provided for application-level
* trace records.
*/
typedef double float64_t;


/*! the current QP version number string in ROM, based on QP_VERSION_STR */
extern char_t const QP_versionStr[6];

/*! get the current QEP version number string of the form "X.Y.Z" */
#define QEP_getVersion() (QP_versionStr)


/****************************************************************************/
#ifndef Q_SIGNAL_SIZE

    /*! The size (in bytes) of the signal of an event. Valid values:
    * 1, 2, or 4; default 1 */
    /**
    * @description
    * This macro can be defined in the QEP port file (qep_port.h) to
    * configure the ::QSignal type. When the macro is not defined, the
    * default of 2 bytes is applied.
    */
    #define Q_SIGNAL_SIZE 2
#endif
#if (Q_SIGNAL_SIZE == 1)
    typedef uint8_t QSignal;
#elif (Q_SIGNAL_SIZE == 2)
    /*! QSignal represents the signal of an event. */
    /**
    * @description
    * The relationship between an event and a signal is as follows. A signal
    * in UML is the specification of an asynchronous stimulus that triggers
    * reactions, and as such is an essential part of an event.
    * (The signal conveys the type of the occurrence-what happened?)
    * However, an event can also contain additional quantitative information
    * about the occurrence in form of event parameters.
    */
    typedef uint16_t QSignal;
#elif (Q_SIGNAL_SIZE == 4)
    typedef uint32_t QSignal;
#else
    #error "Q_SIGNAL_SIZE defined incorrectly, expected 1, 2, or 4"
#endif


/****************************************************************************/
/*! Event structure. */
/**
* @description
* QEvt represents events without parameters and serves as the base structure
* for derivation of events with parameters.
*
* @usage
* The following example illustrates how to add an event parameter by
* derivation of the QEvt structure. Please note that the QEvt member
* super_ is defined as the FIRST member of the derived struct.
* @include qep_qevt.c
*
* @sa @ref oop
*/
typedef struct {
    QSignal sig;              /*!< signal of the event instance */
    uint8_t poolId_;          /*!< pool ID (0 for static event) */
    uint8_t volatile refCtr_; /*!< reference counter */
} QEvt;

#ifdef Q_EVT_CTOR /* Shall the constructor for the QEvt class be provided? */

/*! Custom event constructor. */
QEvt *QEvt_ctor(QEvt * const me, enum_t const sig);

#endif

/****************************************************************************/
/*! Perform upcast from a subclass of ::QHsm to the base class ::QHsm */
/**
* @description
* Upcasting from a subclass to superclass is a very frequent and __safe__
* operation in object-oriented programming and object-oriented languages
* (such as C++) perform such upcasting automatically. However, OOP is
* implemented in C just as a set of coding conventions (see @ref oop),
* and the C compiler does not "know" that certain types are related by
* inheritance. Therefore for C, the upcast must be performed explicitly.
* Unfortunately, pointer casting violates the advisory MISRA-C 2004 rule 11.4
* "cast pointer to pointer". This macro encapsulates this deviation and
* provides a descriptive name for the reason of this cast.
*/
#define Q_HSM_UPCAST(ptr_) ((QHsm *)(ptr_))

/*! Perform downcast of an event onto a subclass of QEvt @p class_ */
/**
* @description
* QEvt represents events without parameters and serves as the base structure
* This macro encapsulates the downcast of QEvt pointers, which violates
* MISRA-C 2004 rule 11.4(advisory). This macro helps to localize this
* deviation.
*/
#define Q_EVT_CAST(class_) ((class_ const *)e)

/*! Helper macro to calculate static dimension of a 1-dim @p array_ */
#define Q_DIM(array_) (sizeof(array_) / sizeof((array_)[0]))

/*! Perform cast from unsigned integer @p uint_ to pointer
* of type @p type_. */
/**
* @description
* This macro encapsulates the cast to (type_ *), which QP ports or
* application might use to access embedded hardware registers.
* Such uses can trigger PC-Lint "Note 923: cast from int to pointer" and
* this macro helps to encapsulate this deviation.
*/
#define Q_UINT2PTR_CAST(type_, uint_)  ((type_ *)(uint_))


/****************************************************************************/
/*! typedef of the return type from a state/action-handler function. */
typedef uint_fast8_t QState;

/*! Pointer to a state-handler function. */
typedef QState (*QStateHandler)(void * const me, QEvt const * const e);

/*! Pointer to an action-handler function. */
typedef QState (*QActionHandler)(void * const me);

/*! Perform cast to ::QStateHandler. */
/**
* @description
* This macro encapsulates the cast of a specific state handler function
* pointer to ::QStateHandler, which violates MISRA-C 2004 rule 11.4(advisory).
* This macro helps to localize this deviation.
*
* @usage
* @include qep_qhsm_ctor.c
*/
#define Q_STATE_CAST(handler_)  ((QStateHandler)(handler_))

/*! Perform cast to QActionHandler. */
/**
* @description
* This macro encapsulates the cast of a specific action handler function
* pointer to ::QActionHandler, which violates MISRA-C 2004 rule 11.4(adv).
* This macro helps to localize this deviation.
*/
#define Q_ACTION_CAST(action_)  ((QActionHandler)(action_))

/* forward declarations... */
struct QMState;
struct QMTranActTable;
struct QHsmVtbl;

/*! Attribute of for the ::QHsm class (Hierarchical State Machine). */
/**
* @description
* This union represents possible values stored in the 'state' and 'temp'
* attributes of the ::QHsm class.
*/
union QHsmAttr {
    QStateHandler  fun;          /*!< pointer to a state-handler function */
    QActionHandler act;          /*!< pointer to an action-handler function */
    struct QMState const *obj;   /*!< pointer to QMState object */
    struct QMTranActTable const *tatbl; /*!< transition-action table */
};

/****************************************************************************/
/* Hierarchical State Machine */

/**
* @description
* ::QHsm represents a Hierarchical State Machine (HSM) with full support for
* hierarchical nesting of states, entry/exit actions, initial transitions,
* and transitions to history in any composite state. This class is designed
* for ease of manual coding of HSMs in C, but it is also supported by the
* QM modeling tool.
* @n
* ::QHsm is also the base class for the ::QMsm state machine, which provides
* a superior efficiency, but requires the use of the QM modeling tool to
* generate code.
*
* @note ::QHsm is not intended to be instantiated directly, but rather serves
* as the base structure for derivation of state machines in the application
* code.
*
* @usage
* The following example illustrates how to derive a state machine structure
* from QHsm. Please note that the QHsm member super is defined as the FIRST
* member of the derived struct.
* @include qep_qhsm.c
*/
typedef struct {
    struct QHsmVtbl const *vptr; /*!< virtual pointer */
    union QHsmAttr state; /*!< current active state (state-variable) */
    union QHsmAttr temp;  /*!< temporary: tran. chain, target state, etc. */
} QHsm;

/*! Virtual table for the ::QHsm class. */
struct QHsmVtbl {
    /*! Triggers the top-most initial transition in a HSM. */
    void (*init)(QHsm * const me, QEvt const * const e);

    /*! Dispatches an event to a SM. */
    void (*dispatch)(QHsm * const me, QEvt const * const e);
};

/*! Protected "constructor" of ::QHsm */
void QHsm_ctor(QHsm * const me, QStateHandler initial);

/*! Polymorphically executes the top-most initial transition in a HSM */
/**
* @param[in,out] me_ pointer (see @ref oop)
* @param[in]     e_  constant pointer the ::QEvt or a class derived from
*                    ::QEvt (see @ref oop)
* @note Must be called only ONCE after the SM "constructor".
*
* @usage
* The following example illustrates how to initialize a SM, and dispatch
* events to it:
* @include qep_qhsm_use.c
*/
#define QHSM_INIT(me_, e_) ((*(me_)->vptr->init)((me_), (e_)))

/*! Implementation of the top-most initial transition in ::QHsm subclass */
void QHsm_init_(QHsm * const me, QEvt const * const e);

/*! Polymorphically dispatches an event to a HSM */
/**
* @description
* Processes one event at a time in Run-to-Completion fashion.
*
* @param[in,out] me_ pointer (see @ref oop)
* @param[in]     e_  constant pointer the ::QEvt or a structure derived from
*                     ::QEvt (see @ref oop)
* @note Must be called after the "constructor" and after QHSM_INIT().
*/
#define QHSM_DISPATCH(me_, e_) ((*(me_)->vptr->dispatch)((me_), (e_)))

/*! Implementation of dispatching events to a ::QHsm subclass */
void QHsm_dispatch_(QHsm * const me, QEvt const * const e);

/*! Obtain the current active state from a HSM (read only). */
/**
* @param[in] me_ pointer (see @ref oop)
* @returns the current active state of a ::QHsm subclass
* @note this macro is used in QM for auto-generating code for state history
*/
#define QHsm_state(me_) (Q_STATE_CAST(Q_HSM_UPCAST(me_)->state.fun))

/*! Obtain the current active child state of a given parent in ::QHsm */
/**
* @param[in] me_     pointer (see @ref oop)
* @param[in] parent_ pointer to the parent state-handler
* @returns the current active child state-handler of a given parent
* @note this macro is used in QM for auto-generating code for state history
*/
#define QHsm_childState(me_, parent_) \
    QHsm_childState_(Q_HSM_UPCAST(me_), Q_STATE_CAST(parent_))

/*! Helper function to obtain the current active child state of a parent */
QStateHandler QHsm_childState_(QHsm * const me,
                               QStateHandler const parent);

/*! Tests if a given state is part of the current active state
* configuration in ::QHsm subclasses.
*/
bool QHsm_isIn(QHsm * const me, QStateHandler const state);

/* protected methods */

/*! the top-state. */
QState QHsm_top(void const * const me, QEvt const * const e);


/****************************************************************************/
/*! QM State Machine implementation strategy */
/**
* @description
* ::QMsm (QM State Machine) provides a more efficient state machine
* implementation strategy than ::QHsm, but requires the use of the QM
* modeling tool, but are the fastest and need the least run-time
* support (the smallest event-processor taking up the least code space).
*
* @note
* ::QMsm is not intended to be instantiated directly, but rather serves as
* the base structure for derivation of state machines in the application code.
*
* @usage
* The following example illustrates how to derive a state machine structure
* from ::QMsm. Please note that the ::QMsm member 'super' is defined as the
* _first_ member of the derived struct.
* @include qep_qmsm.c
*
* @sa @ref oop
*/
typedef QHsm QMsm;

/*! virtual table for the ::QMsm class. */
typedef struct QHsmVtbl QMsmVtbl;

/*! State object for the ::QMsm class (QM State Machine). */
/**
* @description
* This class groups together the attributes of a ::QMsm state, such as the
* parent state (state nesting), the associated state handler function and
* the exit action handler function. These attributes are used inside the
* QMsm_dispatch() and QMsm_init() functions.
*
* @attention
* The ::QMState class is only intended for the QM code generator and should
* not be used in hand-crafted code.
*/
typedef struct QMState {
    struct QMState const *superstate;   /*!< superstate of this state */
    QStateHandler  const stateHandler;  /*!< state handler function */
    QActionHandler const entryAction;   /*!< entry action handler function */
    QActionHandler const exitAction;    /*!< exit action handler function */
    QActionHandler const initAction;    /*!< init action handler function */
} QMState;

/*! Transition-Action Table for the Meta State Machine. */
typedef struct QMTranActTable {
    QMState const *target;
    QActionHandler const act[1];
} QMTranActTable;

/*! Protected "constructor" of ::QMsm */
void QMsm_ctor(QMsm * const me, QStateHandler initial);

/*! Implementation of the top-most initial transition in ::QMsm */
void QMsm_init_(QMsm * const me, QEvt const * const e);

/*! Implementation of disparching events to ::QMsm */
void QMsm_dispatch_(QMsm * const me, QEvt const * const e);

/*! Obtain the current active state from a MSM (read only) */
/**
* @param[in] me_     pointer (see @ref oop)
* @returns the current active state-object
* @note this macro is used in QM for auto-generating code for state history
*/
#define QMsm_stateObj(me_) (Q_HSM_UPCAST(me_)->state.obj)

/*! Obtain the current active child state of a given parent in ::QMsm */
/**
* @param[in] me_     pointer (see @ref oop)
* @param[in] parent_ pointer to the parent state-object
* @returns the current active child state-object of a given parent
* @note this macro is used in QM for auto-generating code for state history
*/
#define QMsm_childStateObj(me_, parent_) \
    QMsm_childStateObj_(Q_HSM_UPCAST(me_), (parent_))

/*! Helper function to obtain the current active child state of a parent */
QMState const *QMsm_childStateObj_(QMsm const * const me,
                                   QMState const * const parent);

/*! Tests if a given state is part of the current active state
* configuration in a MSM.
*/
bool QMsm_isInState(QMsm const * const me, QMState const * const state);

/*! Macro to call in a state-handler when it executes a regular
* or and initial transition. Applicable only to ::QHsm subclasses.
* @include qep_qtran.c
*/
#define Q_TRAN(target_)  \
    ((Q_HSM_UPCAST(me))->temp.fun = Q_STATE_CAST(target_), (QState)Q_RET_TRAN)

/*! Macro to call in a state-handler when it executes a transition
* to history. Applicable only to HSMs.
*
* @usage
* @include qep_qhist.c
*/
#define Q_TRAN_HIST(hist_)  \
    ((Q_HSM_UPCAST(me))->temp.fun = (hist_), (QState)Q_RET_TRAN_HIST)

/*! Macro to call in a state-handler when it designates the
* superstate of a given state. Applicable only to ::QHsm subclasses.
*
* @usage
* @include qep_qtran.c
*/
#define Q_SUPER(super_)  \
    ((Q_HSM_UPCAST(me))->temp.fun = Q_STATE_CAST(super_), (QState)Q_RET_SUPER)

/*! Macro to call in a state-handler when it handles an event.
*  Applicable to both HSMs and FSMs.
*/
#define Q_HANDLED()      ((QState)Q_RET_HANDLED)

/*! Macro to call in a state-handler when it attempts to handle
* an event but a guard condition evaluates to 'false' and there is no other
* explicit way of handling the event. Applicable only to ::QHsm subclasses.
*/
#define Q_UNHANDLED()    ((QState)Q_RET_UNHANDLED)


/****************************************************************************/
/*! All possible values returned from state/action handlers */
/**
* @note The order matters for algorithmic correctness.
*/
enum {
    /* unhandled and need to "bubble up" */
    Q_RET_SUPER,     /*!< event passed to superstate to handle */
    Q_RET_SUPER_SUB, /*!< event passed to submachine superstate */
    Q_RET_UNHANDLED, /*!< event unhandled due to a guard */

    /* handled and do not need to "bubble up" */
    Q_RET_HANDLED,   /*!< event handled (internal transition) */
    Q_RET_IGNORED,   /*!< event silently ignored (bubbled up to top) */

    /* entry/exit */
    Q_RET_ENTRY,     /*!< state entry action executed */
    Q_RET_EXIT,      /*!< state exit  action executed */

    /* no side effects */
    Q_RET_NULL,      /*!< return value without any effect */

    /* transitions need to execute transition-action table in ::QMsm */
    Q_RET_TRAN,      /*!< regular transition */
    Q_RET_TRAN_INIT, /*!< initial transition in a state or submachine */
    Q_RET_TRAN_EP,   /*!< entry-point transition into a submachine */

    /* transitions that additionally clobber me->state */
    Q_RET_TRAN_HIST, /*!< transition to history of a given state */
    Q_RET_TRAN_XP    /*!< exit-point transition out of a submachine */
};

#ifdef Q_SPY
    /*! Macro to call in a QM action-handler when it executes
    * an entry action. Applicable only to ::QMsm subclasses.
    */
    #define QM_ENTRY(state_) \
        ((Q_HSM_UPCAST(me))->temp.obj = (state_), (QState)Q_RET_ENTRY)

    /*! Macro to call in a QM action-handler when it executes
    * an exit action. Applicable only to ::QMsm subclasses.
    */
    #define QM_EXIT(state_) \
        ((Q_HSM_UPCAST(me))->temp.obj = (state_), (QState)Q_RET_EXIT)

#else
    #define QM_ENTRY(dummy) ((QState)Q_RET_ENTRY)

    #define QM_EXIT(dummy)  ((QState)Q_RET_EXIT)

#endif /* Q_SPY */

/*! Macro to call in a QM submachine exit-handler.
* Applicable only to ::QMsm subclasses.
*/
#define QM_SM_EXIT(state_) \
    ((Q_HSM_UPCAST(me))->temp.obj = (state_), (QState)Q_RET_EXIT)

/*! Macro to call in a QM state-handler when it executes a regular
* transition. Applicable only to ::QMsm subclasses.
*/
#define QM_TRAN(tatbl_) \
    ((Q_HSM_UPCAST(me))->temp.tatbl = (QMTranActTable const *)(tatbl_), \
        (QState)Q_RET_TRAN)

/*! Macro to call in a QM state-handler when it executes an initial
* transition. Applicable only to ::QMsm subclasses.
*/
#define QM_TRAN_INIT(tatbl_) \
    ((Q_HSM_UPCAST(me))->temp.tatbl = (QMTranActTable const *)(tatbl_), \
        (QState)Q_RET_TRAN_INIT)

/*! Macro to call in a QM state-handler when it executes a transition
* to history. Applicable only to ::QMsm subclasses.
*/
#define QM_TRAN_HIST(history_, tatbl_) \
    ((((Q_HSM_UPCAST(me))->state.obj = (history_)), \
      ((Q_HSM_UPCAST(me))->temp.tatbl = (QMTranActTable const *)(tatbl_))), \
       (QState)Q_RET_TRAN_HIST)

/*! Macro to call in a QM state-handler when it executes a transition
* to the submachine via an entry point.
*/
#define QM_TRAN_EP(tatbl_) \
    ((Q_HSM_UPCAST(me))->temp.tatbl = (QMTranActTable const *)(tatbl_), \
        (QState)Q_RET_TRAN_EP)

/*! Macro to call in a QM state-handler when it executes a transition
* to exit point. Applicable only to ::QMsm subclasses.
*/
#define QM_TRAN_XP(xp_, tatbl_) \
    ((((Q_HSM_UPCAST(me))->state.act = (xp_)), \
        ((Q_HSM_UPCAST(me))->temp.tatbl = (QMTranActTable const *)(tatbl_))),\
        (QState)Q_RET_TRAN_XP)

/*! Macro to call in a QM state-handler when it handled an event.
* Applicable only to ::QMsm subclasses.
*/
#define QM_HANDLED()     ((QState)Q_RET_HANDLED)

/*! Macro to call in a QM state-handler when when it attempts to
* handle an event but a guard condition evaluates to 'false' and there is
* no other explicit way of handling the event. Applicable only to
* ::QMsm subclasses.
*/
#define QM_UNHANDLED()   ((QState)Q_RET_UNHANDLED)

/*! Macro to call in a QM state-handler when it designates the
* superstate to handle an event. Applicable only to QMSMs.
*/
#define QM_SUPER()       ((QState)Q_RET_SUPER)

/*! Macro to call in a QM submachine-handler when it designates the
* host state to handle an event. Applicable only to QMSMs.
*/
#define QM_SUPER_SUB(host_) \
    ((Q_HSM_UPCAST(me))->temp.obj = (host_), (QState)Q_RET_SUPER_SUB)

/*! QEP reserved signals */
enum {
    Q_ENTRY_SIG = 1,  /*!< signal for coding entry actions */
    Q_EXIT_SIG,       /*!< signal for coding exit actions */
    Q_INIT_SIG,       /*!< signal for coding initial transitions */
    Q_USER_SIG        /*!< first signal that can be used for user signals */
};

#endif /* qep_h */

