/** * @file * @brief Public QEP-nano interface. * @ingroup qepn * @cond ****************************************************************************** * Last updated for version 6.9.0 * Last updated on 2020-08-21 * * Q u a n t u m L e a P s * ------------------------ * Modern Embedded Software * * Copyright (C) 2005-2020 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 . * * Contact information: * * ****************************************************************************** * @endcond */ #ifndef QEPN_H #define QEPN_H /****************************************************************************/ /*! The current QP version as a decimal constant XXYZ, where XX is a 2-digit * major version number, Y is a 1-digit minor version number, and Z is * a 1-digit release number. */ #define QP_VERSION 690U /*! The current QP version number string of the form XX.Y.Z, where XX is * a 2-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.9.0" /*! Encrypted current QP release (6.9.0) and date (2020-08-21) */ #define QP_RELEASE 0x884D22FDU /****************************************************************************/ /* 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-nano does not use floating-point types anywhere in the internal * implementation. */ typedef float float32_t; /*! IEEE 754 64-bit floating point number, MISRA-C 2004 rule 6.3(req) */ /** * @note QP-nano does not use floating-point types anywhere in the internal * implementation. */ typedef double float64_t; /*! Scalar type describing the signal of an event. */ typedef uint8_t QSignal; #ifndef Q_PARAM_SIZE /*! The size of event parameter Valid values 0, 1, 2, 4 or 8; default 0 */ #define Q_PARAM_SIZE 0U #endif #if (Q_PARAM_SIZE == 0U) #elif (Q_PARAM_SIZE == 1U) typedef uint8_t QParam; #elif (Q_PARAM_SIZE == 2U) typedef uint16_t QParam; #elif (Q_PARAM_SIZE == 4U) /*! type of the event parameter. */ /** * @description * This typedef is configurable via the preprocessor switch #Q_PARAM_SIZE. * The other possible values of this type are as follows: @n * none when (Q_PARAM_SIZE == 0U);@n * uint8_t when (Q_PARAM_SIZE == 1U);@n * uint16_t when (Q_PARAM_SIZE == 2U);@n * uint32_t when (Q_PARAM_SIZE == 4U); and @n * uint64_t when (Q_PARAM_SIZE == 8U). */ typedef uint32_t QParam; #elif (Q_PARAM_SIZE == 8U) typedef uint64_t QParam; #else #error "Q_PARAM_SIZE defined incorrectly, expected 0U, 1U, 2U, 4U or 8U" #endif /****************************************************************************/ /*! Event structure. */ /** * @description * ::QEvt represents events, optionally with a single scalar parameter. * @sa Q_PARAM_SIZE * @sa ::QParam */ typedef struct { QSignal sig; /*!< signal of the event */ #if (Q_PARAM_SIZE != 0U) QParam par; /*!< scalar parameter of the event */ #endif } QEvt; /****************************************************************************/ /*! Macro to access the signal of the current event of a state machine */ /** * @param[in,out] me_ pointer to a subclass of ::QHsm (see @ref oop) */ #define Q_SIG(me_) (((QHsm *)(me_))->evt.sig) #if (Q_PARAM_SIZE != 0U) /*! Macro to access the parameter of the current event of a state machine */ /** * @param[in,out] me_ pointer to a subclass of ::QHsm (see @ref oop) */ #define Q_PAR(me_) (((QHsm *)(me_))->evt.par) #endif /* (Q_PARAM_SIZE != 0U) */ /****************************************************************************/ /*! Type returned from a state-handler function. */ typedef uint_fast8_t QState; /*! the signature of a state handler function */ typedef QState (*QStateHandler)(void * const me); /****************************************************************************/ /*! virtual table for the ::QHsm class. */ typedef struct QHsmVtable QHsmVtable; /*! Hierarchical State Machine */ /** * @description * QHsm represents a Hierarchical Finite State Machine (HSM) with full * support for hierarchical nesting of states, entry/exit actions, * and initial transitions in any composite state. * * @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 qepn_qhsm.c * * @sa @ref oop */ typedef struct { QHsmVtable const *vptr; /*!< virtual pointer */ QStateHandler state; /*!< current active state (state-variable) */ QStateHandler temp; /*!< temporary: tran. chain, target state, etc. */ QEvt evt; /*!< currently processed event in the HSM (protected) */ } QHsm; /*! Virtual table for the QHsm class */ struct QHsmVtable { /*! Triggers the top-most initial transition in a HSM. */ void (*init)(QHsm * const me); /*! Dispatches an event to a HSM. */ void (*dispatch)(QHsm * const me); }; /*! Polymorphically executes the top-most initial transition in a SM. */ /** * @param[in,out] me_ pointer (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 qepn_qhsm_use.c */ #define QHSM_INIT(me_) do { \ Q_ASSERT((me_)->vptr); \ (*(me_)->vptr->init)((me_)); \ } while (false) /*! 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) * * @note Must be called after the "constructor" and after QHSM_INIT(). */ #define QHSM_DISPATCH(me_) ((*(me_)->vptr->dispatch)((me_))) /* public methods */ /*! "constructor" of a HSM. * @protected @memberof QHsm */ void QHsm_ctor(QHsm * const me, QStateHandler initial); /*! Obtain the current active state from a HSM (read only). */ /** * @param[in] me_ pointer (see @ref oop) * * @returns the current active state of a HSM */ #define QHsm_state(me_) (Q_STATE_CAST(Q_HSM_UPCAST(me_)->state)) /*! Obtain the current active child state of a given parent in QHsm * @public @memberof 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); /*! Implementation of the top-most initial transition in QHsm. * @private @memberof QHsm */ void QHsm_init_(QHsm * const me); /*! Implementation of dispatching events to QHsm. * @private @memberof QHsm */ void QHsm_dispatch_(QHsm * const me); /*! the top-state. * @protected @memberof QHsm */ QState QHsm_top(void const * const me); /****************************************************************************/ /* All possible values returned from state/action handlers */ /* unhandled and need to "bubble up"... */ /*! event passed to superstate to handle */ #define Q_RET_SUPER ((QState)0) /*! event passed to submachine superstate */ #define Q_RET_SUPER_SUB ((QState)1) /*! event unhandled due to a guard */ #define Q_RET_UNHANDLED ((QState)2) /* handled and do not need to "bubble up"... */ /*! event handled (internal transition) */ #define Q_RET_HANDLED ((QState)3) /*! event silently ignored (bubbled up to top) */ #define Q_RET_IGNORED ((QState)4) /* entry/exit... */ /*! state entry action executed */ #define Q_RET_ENTRY ((QState)5) /*! state exit action executed */ #define Q_RET_EXIT ((QState)6) /* no side effects */ /*! return value without any effect */ #define Q_RET_NULL ((QState)7) /* transitions need to execute transition-action table in QHsm... */ /*! event handled (regular transition) */ #define Q_RET_TRAN ((QState)8) /*! initial transition in a state or submachine */ #define Q_RET_TRAN_INIT ((QState)9) /*! event handled (transition to history) */ #define Q_RET_TRAN_HIST ((QState)10) /*! 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 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 qepn_qhsm_ctor.c */ #define Q_STATE_CAST(handler_) ((QStateHandler)(handler_)) /*! Macro to call in a state-handler when it executes a regular * or and initial transition. Applicable to both HSMs and FSMs. * @include qepn_qtran.c */ #define Q_TRAN(target_) \ ((Q_HSM_UPCAST(me))->temp = 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 qepn_qhist.c */ #define Q_TRAN_HIST(hist_) \ ((Q_HSM_UPCAST(me))->temp = (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 HSMs. * * @usage * @include qepn_qtran.c */ #define Q_SUPER(super_) \ ((Q_HSM_UPCAST(me))->temp = Q_STATE_CAST(super_), Q_RET_SUPER) /*! Macro to call in a state-handler when it handles an event. * Applicable to both HSMs and FSMs. */ #define Q_HANDLED() 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 HSMs. */ #define Q_UNHANDLED() Q_RET_UNHANDLED /*! QP reserved signals */ /*! signal for coding entry actions */ #define Q_ENTRY_SIG ((QSignal)1) /*! signal for coding exit actions */ #define Q_EXIT_SIG ((QSignal)2) /*! signal for coding nested initial transitions */ #define Q_INIT_SIG ((QSignal)3) /*! timeout signal at the default tick rate 0 */ #define Q_TIMEOUT_SIG ((QSignal)4) /*! timeout signal at tick rate 1 */ #define Q_TIMEOUT1_SIG ((QSignal)5) /*! timeout signal at tick rate 2 */ #define Q_TIMEOUT2_SIG ((QSignal)6) /*! timeout signal at tick rate 3 */ #define Q_TIMEOUT3_SIG ((QSignal)7) /*!< first signal for the user applications */ #define Q_USER_SIG ((QSignal)8) /*! Perform cast from unsigned integer to a pointer of type @a 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_, uintptr_) ((type_ *)(uintptr_)) /****************************************************************************/ /* macros for accessing data in ROM */ #ifndef Q_ROM /* if NOT defined, provide the default definition */ /*! Macro to specify compiler-specific directive for placing a * constant object in ROM. */ /** * @description * Many compilers for 8-bit Harvard-architecture MCUs provide non-standard * extensions to support placement of objects in different memories. * In order to conserve the precious RAM, QP-nano uses the Q_ROM macro for * all constant objects that can be allocated in ROM. * * @note * To override the following empty definition, you need to define the * Q_ROM macro in the qpn_port.h header file. Some examples of valid * Q_ROM macro definitions are: __code (IAR 8051 compiler), code (Keil * 8051 compiler), PROGMEM (gcc for AVR), __flash (IAR for AVR). */ #define Q_ROM #endif #ifndef Q_ROM_BYTE /*! Macro to access a byte allocated in ROM */ /** * Some compilers for Harvard-architecture MCUs, such as gcc for AVR, do * not generate correct code for accessing data allocated in the program * space (ROM). The workaround for such compilers is to explicitly add * assembly code to access each data element allocated in the program * space. The macro Q_ROM_BYTE() retrieves a byte from the given ROM * address. * * @note * The Q_ROM_BYTE() macro should be defined in the qpn_port.h header file * for each compiler that cannot handle correctly data allocated in ROM * (such as the gcc). If the macro is left undefined, the default * definition simply returns the parameter and lets the compiler * synthesize the correct code. */ #define Q_ROM_BYTE(rom_var_) (rom_var_) #endif #ifndef Q_ROM_PTR /*! Macro to access a pointer allocated in ROM */ /** * Some compilers for Harvard-architecture MCUs, such as gcc for AVR, do * not generate correct code for accessing data allocated in the program * space (ROM). The workaround for such compilers is to explicitly add * assembly code to access each data element allocated in the program * space. The macro Q_ROM_PTR() retrieves an object-pointer from the given * ROM address. Please note that the pointer can be pointing to the object * in RAM or ROM. * * @note * The Q_ROM_PTR() macro should be defined in the qpn_port.h header file * for each compiler that cannot handle correctly data allocated in ROM * (such as the gcc). If the macro is left undefined, the default * definition simply returns the parameter and lets the compiler * synthesize the correct code. */ #define Q_ROM_PTR(rom_var_) (rom_var_) #endif /****************************************************************************/ /*! the current QP version number string in ROM, based on QP_VERSION_STR */ extern char_t const Q_ROM QP_versionStr[7]; /*! get the current QP-nano version number string of the form "X.Y.Z" */ #define QP_getVersion() (QP_versionStr) #endif /* QEPN_H */