diff --git a/.gitignore b/.gitignore index 6677e87..7ef04c3 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,10 @@ Temporary Items # gcc code coverage *.gcno -*.gcda \ No newline at end of file +*.gcda + +# vscode +.vscode + +# builds +build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 66c4ef1..2ff1669 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_library( ${PROJECT_NAME} qedgecheck.c qbsbuffers.c qresponse.c + qinput.c ) set( QUARKTS_CONFIG_PATH ../os_config ) set_target_properties( ${PROJECT_NAME} PROPERTIES PUBLIC_HEADER include/QuarkTS.h ) diff --git a/include/QuarkTS.h b/include/QuarkTS.h index 509ff77..c338b2f 100644 --- a/include/QuarkTS.h +++ b/include/QuarkTS.h @@ -56,6 +56,7 @@ Read the API reference here ; https://kmilo17pet.github.io/QuarkTS/ #include "qcoroutine.h" #include "qioutils.h" #include "qtrace.h" + #include "qinput.h" #if ( Q_MEMORY_MANAGER == 1 ) #include "qmemmang.h" diff --git a/include/qcoroutine.h b/include/qcoroutine.h index dd9d593..4d9b219 100644 --- a/include/qcoroutine.h +++ b/include/qcoroutine.h @@ -79,14 +79,18 @@ _qCR_Oper_t; // skipcq: CXX-E2000 /*Construction statements*/ - #define _qCR_LCInit /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_LCInit \ { _qCR_PC_INIT_VAL, _qCR_UNDEFINED, QSTIMER_INITIALIZER } \ - #define _qCR_RT( _PT_ ) /* skipcq: CXX-E2000 */ \ + // skipcq: CXX-E2000 + #define _qCR_RT( _PT_ ) \ case (_qCR_TaskPC_t)(_PT_) : \ + // skipcq: CXX-E2000 #define _qCR_JUMP( _DST_ ) switch (_DST_) // skipcq: CXX-W1164 + // skipcq: CXX-E2000 #define _qCR_LCON( _DST_ , _STATE_, _REST_, _ACTION_ ) \ ( _DST_ ) = (_STATE_); \ _ACTION_; \ @@ -94,7 +98,8 @@ #define _qCR_EXIT goto _qCR_ExitPoint // skipcq: CXX-E2000 - #define _qCR_DEF /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_DEF \ static _qCR_Instance_t _qCRState = _qCR_LCInit; \ _qCR_Instance_t * const _qcr = &_qCRState \ @@ -103,14 +108,16 @@ /*! @cond */ /*Core Statements*/ /*=======================================================================*/ - #define _qCR_Start /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_Start \ _qCR_DEF; \ _qCR_JUMP( _qcr->instr ) { /* skipcq: CXX-W1197 */\ _qCR_RT( _qCR_PC_INIT_VAL ) \ /*=======================================================================*/ - #define _qCR_hStart( handle ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_hStart( handle ) \ _qCR_DEF; \ if ( NULL == (handle) ) { \ (handle) = &_qCRState; \ @@ -120,28 +127,32 @@ _qCR_RT( _qCR_PC_INIT_VAL ) \ /*=======================================================================*/ - #define _qCR_Dispose /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_Dispose \ _qcr->instr = _qCR_PC_INIT_VAL; \ } \ _qCR_ExitPoint: Q_UNUSED(0) \ /*=======================================================================*/ - #define _qCR_Yield /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_Yield \ do { \ _qCR_LCON( _qcr->instr, __LINE__, _qCR_RT(__LINE__), _qCR_EXIT ); \ } while ( qFalse ) \ /*=======================================================================*/ - #define _qCR_Restart /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_Restart \ do { \ _qCR_LCON( _qcr->instr, _qCR_PC_INIT_VAL, Q_NONE, _qCR_EXIT ); \ } while ( qFalse ) \ /*=======================================================================*/ - #define _qCR_wu_Assert( condition ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_wu_Assert( condition ) \ do { \ _qCR_LCON( _qcr->instr, __LINE__, _qCR_RT(__LINE__), Q_UNUSED(0) ); \ if ( !(condition) ) { \ @@ -151,7 +162,8 @@ /*=======================================================================*/ - #define _qCR_GetPosition( position ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_GetPosition( position ) \ do { \ _qCR_LCON( position, __LINE__, _qCR_RT(__LINE__), Q_UNUSED(0) ); \ Q_UNUSED( (position) ); \ @@ -159,14 +171,16 @@ /*=======================================================================*/ - #define _qCR_RestoreFromPosition( position ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_RestoreFromPosition( position ) \ do { \ _qCR_LCON( _qcr->instr, (position), Q_NONE, _qCR_EXIT ); \ } while ( qFalse ) \ /*=======================================================================*/ - #define _qCR_Delay( dTime ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_Delay( dTime ) \ do { \ qCR_TimeoutSet( dTime ); \ _qCR_LCON( _qcr->instr, __LINE__, _qCR_RT(__LINE__), Q_UNUSED(0) ); \ @@ -177,7 +191,8 @@ /*=======================================================================*/ - #define _qCR_wu_TmrAssert( condition, timeout ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_wu_TmrAssert( condition, timeout ) \ do { \ qCR_TimeoutSet( timeout ); \ _qCR_LCON( _qcr->instr, __LINE__, _qCR_RT(__LINE__), Q_UNUSED(0) ); \ @@ -188,13 +203,15 @@ /*=======================================================================*/ - #define _qCR_do /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_do \ do { \ _qCR_LCON( _qcr->instr, __LINE__, _qCR_RT(__LINE__), Q_UNUSED(0) ); \ /*=======================================================================*/ - #define _qCR_until( condition ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qCR_until( condition ) \ if ( !(condition) ) { \ _qCR_EXIT; \ } \ diff --git a/include/qedgecheck.h b/include/qedgecheck.h index 04c5fdc..6e6e749 100644 --- a/include/qedgecheck.h +++ b/include/qedgecheck.h @@ -76,7 +76,8 @@ /*! @cond */ /*cppcheck-suppress misra-c2012-20.7 */ - #define _QEDGECHECK_REG_FCN_DEC(NAME) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _QEDGECHECK_REG_FCN_DEC(NAME) \ qBool_t NAME( const void *addr, qBool_t pinNumber ) \ _QEDGECHECK_REG_FCN_DEC( _qReg_32Bits ); diff --git a/include/qfsm.h b/include/qfsm.h index 782f3cb..0d154f7 100644 --- a/include/qfsm.h +++ b/include/qfsm.h @@ -195,7 +195,8 @@ /*fields for the qSM_Handler_t pointer*/ /*! @cond */ /*cppcheck-suppress misra-c2012-20.7 */ - #define _qSM_HANDLER_FIELDS( pAttrib ) /* skipcq: CXX-E2000 */\ + // skipcq: CXX-E2000 + #define _qSM_HANDLER_FIELDS( pAttrib ) \ void *StartState; \ void *NextState; \ pAttrib void *machine; \ diff --git a/include/qinput.h b/include/qinput.h new file mode 100644 index 0000000..1cc3e60 --- /dev/null +++ b/include/qinput.h @@ -0,0 +1,450 @@ +/*! +* @file qinput.h +* @author Julian Bustamante N +* @version 1.0 +* @note This file is part of the QuarkTS distribution. +* @brief A comprehensive event structure for efficient, maintainable working with +* input channels +*/ +#ifndef QINPUT_H +#define QINPUT_H + +#include +#include "qtypes.h" +#include "qclock.h" +#include "qlists.h" +#include "qstimers.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup qinput Input channel events +* @brief A comprehensive event structure for efficient, maintainable working with +* input channels. +* @{ +*/ + +/** +* @brief Input Interfaces. +*/ + +/** @addtogroup qinput +* @{ +*/ + +/** +* @brief An enum with all the possible events that can be detected by the +* watcher structure for a specified input-channel. +*/ +typedef enum qInput_Event_t { + QINPUT_NONE = 0, + QINPUT_EXCEPTION, /**< Error due a bad reading or channel configuration .*/ + QINPUT_ON_CHANGE, /**< Event on any input-channel change when crossing the thresholds*/ + QINPUT_FALLING_EDGE, /**< Event on falling-edge( high to low ) of the digital input-channel*/ + QINPUT_RISING_EDGE, /**< Event on rising-edge( low to high ) of the digital input-channel*/ + QINPUT_PULSATION_DOUBLE, /**< Event when the digital input is pulsated two times within the interval*/ + QINPUT_PULSATION_TRIPLE, /**< Event when the digital input is pulsated three times within the interval*/ + QINPUT_PULSATION_MULTI, /**< Event when the digital input is pulsated more than three times within the interval*/ + QINPUT_HIGH_THRESHOLD, /**< Event when the analog input-channel reading is above the high threshold*/ + QINPUT_LOW_THRESHOLD, /**< Event when the analog input-channel reading is below the low threshold*/ + QINPUT_IN_BAND, /**< Event when the analog input-channel reading enters the band defined by the low-high thresholds*/ + QINPUT_STEADY_IN_HIGH, /**< Event when the input-channel has been kept on high (or above the high threshold) for the specified time .*/ + QINPUT_STEADY_IN_LOW, /**< Event when the input-channel has been kept on low (or below the low threshold) for the specified time .*/ + QINPUT_STEADY_IN_BAND, /**< Event when the analog input-channel has remained within the band for the specified time .*/ + QINPUT_DELTA, /**< Event when the difference of the last and latest reading of an analog input channel is greater than the defined delta*/ + QINPUT_STEP_UP, /**< Event on step reading of the analog-input channel*/ + QINPUT_STEP_DOWN, /**< Event on step reading of the analog-input channel*/ + /*! @cond */ + QINPUT__MAX_EVENTS, + QINPUT_STEP = QINPUT_STEP_UP + /*! @endcond */ +} qInput_Event_t; + +/** +* @brief An enum class to define the types of input channels +*/ +typedef enum qType_t{ + DIGITAL_CHANNEL, /**< Digital input channel.*/ + ANALOG_CHANNEL, /**< Analog input channel.*/ +}qType_t; + + +typedef int qDigitalValue_t; +typedef uint32_t qAnalogValue_t; + + + +/** +* @brief A pointer to the wrapper function that reads the specific +* digital input-channel +* +* Prototype: @code qDigitalValue_t readerFcn( uint8_t channelNumber ) @endcode +*/ +typedef qDigitalValue_t (*qDigitalReaderFcn_t)( uint8_t ); + + + +/** +* @brief A pointer to the wrapper function that reads the specific +* analog input-channel +* +* Prototype: @code qAnalogValue_t readerFcn( uint8_t channelNumber ) @endcode +*/ +typedef qAnalogValue_t (*qAnalogReaderFcn_t)( uint8_t ); + + + + +typedef struct qChannel_t qChannel_t; + +/** +* @brief A pointer to the input-channel event callback +* +* Prototype: @code void xCallback( input::channel& c ) @endcode +*/ +typedef void (*qEventCallback_t) (qChannel_t *channel); + + +/** + * @brief A pointer to the wrapper function + * + * Prototype: @code void updateReading( qBool_t act ) @endcode + */ +typedef void (*qUpdateReading_t)( qBool_t ); + +/** + * @brief A pointer to the wrapper function + * + * Prototype: @code void evaluateState() @endcode + */ +typedef void (*qEvaluateState_t)( void ); + + +/** + * @brief A pointer to the wrapper function + * + * Prototype: @code qBool_t isValidConfig() @endcode + */ +typedef qBool_t (*qIsValidConfig_t)( void ); + + +/** + * @brief A pointer to the wrapper function + * + * Prototype: @code void setInitalState() @endcode + */ +typedef void (*qSetInitalState_t)( void ); + +/** + * @brief A pointer to the wrapper function + * + * Prototype: @code void dispatchEvent(qInput_Event_t e) @endcode + */ +typedef void (*qDispatchEvent_t)( qInput_Event_t ); + +/* inline void dispatchEvent( qInput_Event_t ) +{ + lastEvent = e; --> event = e + callback( *this ); --> callback = dispatchEvent +}*/ + +/** +* @brief Get the channel type. +* @return The channel type. +* Prototype: @code qType_t getType( void ) @endcode +*/ +typedef qType_t (*qGetType_t)( void ); + + +/** +* @brief Retrieves the last event for the given input channel. +* @return @c The last input-channel event. +* Prototype: @code qInput_Event_t getEvent( void ) @endcode +*/ +typedef qInput_Event_t (*qGetEvent_t)( void ); + + +/** +* @brief Set the callback function when event are detected on the +* input input channel. +* @param[in] cb The callback function +* Prototype: @code qBool_t setCallback( const qEventCallback_t cb ) @endcode +*/ +typedef qBool_t (*qSetCallback_t)( const qEventCallback_t ); + + + +/** +* @brief Set/Change the channel(pin) number. +* @param[in] inputChannel The specified channel number (pin) to read. +* @return @c true on success. Otherwise @c false. +* Prototype: @code qBool_t setChannel( const uint8_t ich ) @endcode +*/ +typedef qBool_t (*qSetChannel_t)( const uint8_t ); + +/** +* @brief Get the channel(pin) number. +* @return The channel(pin) number. +* Prototype: @code uint8_t getChannel( void) @endcode +*/ +typedef uint8_t (*qGetChannel_t)( void ); + + +/** +* @brief Set the channel user-data. +* @param[in] pUserData A pointer to the user-data +* Prototype: @code void setUserData( void* pUserData) @endcode +*/ +typedef void (*qSetUserData_t)( void* ); + +/** +* @brief Get the channel user-data. +* @return A pointer to the user-data +* Prototype: @code void* getUserData( void) @endcode +*/ +typedef void* (*qGetUserData_t)( void ); + +/** +* @brief Check if the channel value is shared with other channel +* with the same (pin) number. +* @return @c true if shared. Otherwise @c false. +* Prototype: @code qBool_t isShared( void) @endcode +*/ +typedef qBool_t (*qIsShared_t)( void ); + +/** +* @brief Set the timeout for the specified event. +* @param[in] e The event where the timeout will be set. +* @param[in] t The value of the timeout. +* @return @c true on success. Otherwise @c false. +* Prototype: +* @code +* qBool_t setTime( const qInput_Event_t e, const qClock_t t) +* @endcode +*/ +typedef qBool_t (*qSetTime_t)( const qInput_Event_t , const qClock_t ); + + +/** +* @brief Set the parameter for the specified event. +* @param[in] e The event where the parameter will be set. +* @param[in] p The value of the parameter. +* @return @c true on success. Otherwise @c false. +* Prototype: +* @code +* qBool_t setParameter( const qInput_Event_t e, const qAnalogValue_t p ) +* @endcode +*/ +typedef qBool_t (*qSetParameter_t)( const qInput_Event_t e, const qAnalogValue_t p); + +/** +* @brief Get pulsation count for the digital input. +* @note No valid on analog inputs +* @return The current pulsation count. +* Prototype: @code uint8_t getCount( void) @endcode +*/ +typedef uint8_t (*qGetCount_t)( void ); + +/*! @cond */ +/** +* Prototype: @code qBool_t setDigitalReader( qDigitalReaderFcn_t r) @endcode +*/ +typedef qBool_t (*qSetDigitalReader_t)( qDigitalReaderFcn_t ); +/** +* Prototype: @code qBool_t setAnalogReader( qAnalogReaderFcn_t r) @endcode +*/ +typedef qBool_t (*qSetAnalogReader_t)( qAnalogReaderFcn_t ); +/*! @endcond */ + +/** +* @brief +* @note +* Prototype: @code uint8_t unShare_t( void) @endcode +*/ +typedef qBool_t (*qUnShare_t)( void ); + + + +typedef struct qChannel_t { + qList_Node_t node; + qInput_Event_t lastEvent; + uint8_t number; + void *userData; + + qEventCallback_t callback; + qUpdateReading_t updateReading; + qEvaluateState_t evaluateState; + qIsValidConfig_t isValidConfig; + qSetInitalState_t setInitalState; + qDispatchEvent_t dispatchEvent; + qGetType_t getType; + qGetEvent_t getEvent; + qSetCallback_t setCallback; + + + qSetChannel_t setChannel; + qGetChannel_t getChannel; + qSetUserData_t setUserData; + qGetUserData_t getUserData; + qIsShared_t isShared; + qSetTime_t setTime; + qSetParameter_t setParameter; + qGetCount_t getCount; + qSetDigitalReader_t setDigitalReader; + qSetAnalogReader_t setAnalogReader; + qUnShare_t unShare; + + qClock_t tChange; //0U + qClock_t tSteadyHigh; // 0xFFFFFFFFU ; + qClock_t tSteadyLow; // 0xFFFFFFFFU ; +} qChannel_t; + + +#define NULL_CHANNELS_INITIALIZATION \ + {\ + NULL, NULL, NULL, \ + QINPUT_NONE, 0, NULL, \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\ + 0U, 0xFFFFFFFFU, 0xFFFFFFFFU \ + } + + + +typedef struct _qDigitalChannel_t { // skipcq: CXX-E2000 + qChannel_t channel; + + qDigitalValue_t value; + qDigitalValue_t *ptrValue; + qDigitalReaderFcn_t reader; + void (*channelStateFcn)(struct _qDigitalChannel_t *); + qBool_t negate; + qClock_t pulsationInterval;//250U + uint8_t pulsationCount; + + void (*fallingEdgeStateFcn)( struct _qDigitalChannel_t * ); + void (*risingEdgeStateFcn)( struct _qDigitalChannel_t * ); + void (*steadyInHighStateFcn)( struct _qDigitalChannel_t * ); + void (*steadyInLowStateFcn)( struct _qDigitalChannel_t * ); +} qDigitalChannel_t; + +#define NULL_DIGITAL_CHANNELS_INITIALIZATION \ + {\ + NULL_CHANNELS_INITIALIZATION, \ + 0, NULL , NULL, NULL, qFalse, 250, 0, \ + NULL, NULL, NULL, NULL \ + } + +typedef struct _qAnalogChannel_t { // skipcq: CXX-E2000 + qChannel_t channel; + + qAnalogValue_t value; + qAnalogValue_t *ptrValue; + qAnalogReaderFcn_t reader; + void (*channelStateFcn)(struct _qAnalogChannel_t *); + qAnalogValue_t high; + qAnalogValue_t low; + qAnalogValue_t lastStep; + qAnalogValue_t lastSampled; + qAnalogValue_t delta; + qAnalogValue_t step; + qAnalogValue_t hysteresis; + qClock_t tSteadyBand; + + void (*lowThresholdStateFcn)( struct _qAnalogChannel_t * ); + void (*highThresholdStateFcn)( struct _qAnalogChannel_t * ); + void (*inBandStateFcn)( struct _qAnalogChannel_t * ); + void (*steadyInHighStateFcn)( struct _qAnalogChannel_t * ); + void (*steadyInLowStateFcn)( struct _qAnalogChannel_t * ); + void (*steadyInBandStateFcn)( struct _qAnalogChannel_t * ); +} qAnalogChannel_t; + +#define NULL_ANALOG_CHANNELS_INITIALIZATION \ + {\ + NULL_CHANNELS_INITIALIZATION, \ + 0, NULL , NULL, NULL, 800, 200, 0, 0,\ + 0xFFFFFFFFU, 0xFFFFFFFFU, 20U, 0xFFFFFFFFU,\ + NULL, NULL, NULL, NULL, NULL, NULL \ + } + + /** + * @brief Add a channel to the watcher instance + * @param[in] c The input-Channel to watch + * @return @c true on success. Otherwise @c false. + * Prototype: @code qBool_t addChannel( qChannel_t * c ) @endcode + */ + typedef qBool_t (*addChannelFcn_t)(qChannel_t *); + + /** + * @brief Add a channel to the watcher instance + * @param[in] c The input-Channel to watch + * @param[in] cb The callback function for the input-channel + * @return @c true on success. Otherwise @c false. + * Prototype: @code qBool_t addCallback( qChannel_t *c, qEventCallback_t cb ) @endcode + */ + typedef qBool_t (*addCallbackFcn_t)(qChannel_t *, qEventCallback_t); + + /** + * @brief Add a channel to the watcher instance + * @param[in] c The input-Channel to watch + * @param[in] fcn The reader function for the digital channel + * @param[in] cb The callback function for the input-channel + * @return @c true on success. Otherwise @c false. + * Prototype: @code qBool_t addCallbackDigital( qChannel_t *c, qDigitalReaderFcn_t fcn, qEventCallback_t cb ) @endcode + */ + typedef qBool_t (*addCallbackDiFcn_t)( qChannel_t *, qDigitalReaderFcn_t , qEventCallback_t ); + + /** + * @brief Add a channel to the watcher instance + * @param[in] c The input-Channel to watch + * @param[in] fcn The reader function for the analog channel + * @param[in] cb The callback function for the input-channel + * @return @c true on success. Otherwise @c false. + * Prototype: @code qBool_t addCallbackAnalog( qChannel_t *c, qAnalogReaderFcn_t fcn, qEventCallback_t cb ) @endcode + */ + typedef qBool_t (*addCallbackAnFcn_t)( qChannel_t *, qAnalogReaderFcn_t , qEventCallback_t ); + + /** + * @brief Remove a channel to the watcher instance + * @param[in] c The input-Channel to watch + * @return @c true on success. Otherwise @c false. + * Prototype: @code qBool_t remove( qChannel_t *c ) @endcode + */ + typedef qBool_t (*removeFcn_t)( qChannel_t* ); + + +typedef struct _qWatcher_t { // skipcq: CXX-E2000 + qList_Node_t node; + + qEventCallback_t exception; + qList_t digitalChannels; + qList_t analogChannels; + qSTimer_t waitDebounce; //dt 100 + qClock_t debounceTime;//{ 100_ms }; + qDigitalReaderFcn_t digitalReader; + qAnalogReaderFcn_t analogReader; + addChannelFcn_t addChannel; + addCallbackFcn_t addCallback; + addCallbackDiFcn_t addCallbackDigital; + addCallbackAnFcn_t addCallbackAnalog; + removeFcn_t remove; +} qWatcher_t; + + +#define NULL_WATCHER_INITIALIZATION \ + {\ + NULL, NULL, NULL, \ + NULL , \ + NULL, NULL, NULL, NULL, NULL, 0,\ + NULL, NULL, NULL, NULL, NULL, 0,\ + 100, 100 \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL \ + } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qinput.c b/qinput.c new file mode 100644 index 0000000..d021a0c --- /dev/null +++ b/qinput.c @@ -0,0 +1,746 @@ +#include "include/qinput.h" + +#define DEFAULT_DIGITAL_CHANNELS_FUNCTIONS_PTR \ + digitalXCallback, digitalUpdateReading, digitalEvaluateState, \ + digitalIsValidConfig, digitalSetInitalState, digitalDispatchEvent, \ + digitalGetType, digitalGetEvent, digitalSetCallback,\ + digitalSetChannel, digitalGetChannel, digitalSetUserData,\ + digitalGetUserData, digitalIsShared , digitalSetTime, \ + digitalSetParameter, digitalGetCount, digitalSetReader, NULL, \ + digitalUnShare \ + +#define DEFAULT_DIGITAL_INTERNAL_FUNCTIONS_PTR \ + fallingEdgeState, risingEdgeState, digitalSteadyInHighState, digitalSteadyInLowState\ + +#define DEFAULT_DIGITAL_CHANNELS_INITIALIZATION \ + {\ + NULL, NULL, NULL, \ + QINPUT_NONE, 0, NULL, \ + DEFAULT_DIGITAL_CHANNELS_FUNCTIONS_PTR , \ + 0U, 0xFFFFFFFFU, 0xFFFFFFFFU, \ + 0, NULL , NULL, NULL, qFalse, 250, 0, \ + DEFAULT_DIGITAL_INTERNAL_FUNCTIONS_PTR \ + } + + +#define DEFAULT_ANALOG_CHANNELS_FUNCTIONS_PTR \ + analogXCallback, analogUpdateReading, analogEvaluateState, \ + analogIsValidConfig, analogSetInitalState, analogDispatchEvent, \ + analogGetType, analogGetEvent, analogSetCallback, \ + analogSetChannel, analogGetChannel, analogSetUserData,\ + analogGetUserData, analogIsShared , analogSetTime, \ + analogSetParameter, analogGetCount, NULL, analogSetReader, \ + analogUnShare \ + +#define DEFAULT_ANALOG_INTERNAL_FUNCTIONS_PTR \ + lowThresholdState, highThresholdState, inBandState, analogSteadyInHighState, \ + analogSteadyInLowState, steadyInBandState \ + +#define DEFAULT_ANALOG_CHANNELS_INITIALIZATION \ + {\ + NULL, NULL, NULL, \ + QINPUT_NONE, 0, NULL, \ + DEFAULT_ANALOG_CHANNELS_FUNCTIONS_PTR , \ + 0U, 0xFFFFFFFFU, 0xFFFFFFFFU, \ + 0, NULL , NULL, NULL, 800, 200, 0, 0,\ + 0xFFFFFFFFU, 0xFFFFFFFFU, 20U, 0xFFFFFFFFU,\ + DEFAULT_ANALOG_INTERNAL_FUNCTIONS_PTR \ + } + +#define DEFAULT_WATCHER_FUNCTIONS_PTR \ + addChannel, addCallback, addCallbackDigital, addCallbackAnalog, remove \ + +#define DEFAULT_WATCHER_INITIALIZATION \ + {\ + NULL, NULL, NULL, \ + NULL , \ + NULL, NULL, NULL, NULL, NULL, 0,\ + NULL, NULL, NULL, NULL, NULL, 0,\ + 100, 100 \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL \ + } + +qChannel_t channels = NULL_CHANNELS_INITIALIZATION; // skipcq: CXX-W2009 + +// skipcq: CXX-W2009 +qDigitalChannel_t digitalChannels = + NULL_DIGITAL_CHANNELS_INITIALIZATION; + +// skipcq: CXX-W2009 +qAnalogChannel_t analogChannels = + NULL_ANALOG_CHANNELS_INITIALIZATION; + +qWatcher_t watcher; // skipcq: CXX-W2009 +//---------------------------------------------------- +static void analogXCallback( qChannel_t *c ) { + +} + +static void analogUpdateReading( qBool_t act ) { + analogChannels.value = ( analogChannels.channel.isShared() ) ? + analogChannels.ptrValue[ 0 ] : analogChannels.reader( analogChannels.channel.number ); + + const qAnalogValue_t currentStep = analogChannels.value/analogChannels.step; + if ( currentStep != analogChannels.lastStep ) { + qAnalogValue_t diff; + qInput_Event_t dir; + + if ( currentStep > analogChannels.lastStep ) { + diff = currentStep - analogChannels.lastStep; + dir = QINPUT_STEP_UP; + } + else { + diff = analogChannels.lastStep - currentStep; + dir = QINPUT_STEP_DOWN; + } + for ( qAnalogValue_t i = 0; i < diff; ++i ) { + analogChannels.channel.dispatchEvent( dir ); + } + analogChannels.lastStep = currentStep; + } + + if ( act ) { + const qAnalogValue_t diff = + ( analogChannels.value > analogChannels.lastSampled ) ? + analogChannels.value - analogChannels.lastSampled : + analogChannels.lastSampled - analogChannels.value; + + if ( diff >= analogChannels.delta ) { + analogChannels.channel.dispatchEvent( QINPUT_DELTA ); + } + analogChannels.lastSampled = analogChannels.value; + } +} + +static void analogEvaluateState() { + //channelState( *this ); + //TODO: is this good? + analogChannels.channelStateFcn(&analogChannels); +} + +static qBool_t analogIsValidConfig() { + + return ( analogChannels.high - analogChannels.low ) > + analogChannels.hysteresis; +} + +static void analogSetInitalState() { + const qAnalogValue_t val = ( NULL != analogChannels.reader ) ? + analogChannels.reader( analogChannels.channel.number ) : 0U; + + if ( val > analogChannels.high ) { + analogChannels.channelStateFcn = analogChannels.highThresholdStateFcn; + } + else if ( val < analogChannels.low ) { + analogChannels.channelStateFcn = analogChannels.lowThresholdStateFcn; + } + else { + analogChannels.channelStateFcn = analogChannels.inBandStateFcn; + } + analogChannels.lastStep = val/analogChannels.step; + analogChannels.lastSampled = val; +} + +static void analogDispatchEvent(qInput_Event_t e) { + analogChannels.channel.lastEvent = e; +} + + +static qType_t analogGetType( void ) { + return ANALOG_CHANNEL; +} + +static qInput_Event_t analogGetEvent( void ) { + return analogChannels.channel.lastEvent; +} + +static qBool_t analogSetCallback( const qEventCallback_t cb ) { + analogChannels.channel.callback = cb; + return (cb != analogChannels.channel.callback); +} + +static qBool_t analogSetChannel( const uint8_t inputChannel ) { + qBool_t retValue = qFalse; + + if ( inputChannel < 32U ) { + analogChannels.channel.number = inputChannel; + retValue = qTrue; + } + + return retValue; +} + +static uint8_t analogGetChannel( void) { + return analogChannels.channel.number; +} + +static void analogSetUserData( void* pUserData) { + analogChannels.channel.userData = pUserData; +} + +static void* analogGetUserData( void) { + return analogChannels.channel.userData; +} + +static qBool_t analogIsShared( void) { + return ( &analogChannels.value != analogChannels.ptrValue ); +} + +static qBool_t analogSetTime( const qInput_Event_t e, const qClock_t t) { + qBool_t retValue = qTrue; + + if ( t > 0U ) { + switch( e ) { + case QINPUT_STEADY_IN_BAND: + analogChannels.tSteadyBand = (qClock_t)t; + break; + case QINPUT_STEADY_IN_HIGH: + analogChannels.channel.tSteadyHigh = (qClock_t)t; + break; + case QINPUT_STEADY_IN_LOW: + analogChannels.channel.tSteadyLow = (qClock_t)t; + break; + default: + retValue = qFalse; + break; + } + } + else { + retValue = qFalse; + } + + return retValue; +} + +static qBool_t analogSetParameter( const qInput_Event_t e, const qAnalogValue_t p ) { + qBool_t retValue = qTrue; + + switch( e ) { + case QINPUT_HIGH_THRESHOLD: + analogChannels.high = p; + break; + case QINPUT_LOW_THRESHOLD: + analogChannels.low = p; + break; + case QINPUT_IN_BAND: + analogChannels.hysteresis = p; + break; + case QINPUT_DELTA: + analogChannels.delta = p; + break; + case QINPUT_STEP_UP: + case QINPUT_STEP_DOWN: // skipcq: CXX-C1001 + analogChannels.step = p; + break; + default: + retValue = qFalse; + break; + } + + return retValue; +} + +static uint8_t analogGetCount( void) { + return 0; +} + +static qBool_t analogSetReader( qAnalogReaderFcn_t r) { + analogChannels.reader = r; + return qTrue; +} + +static uint8_t analogUnShare( void) { + analogChannels.ptrValue = &analogChannels.value; + return qTrue; +} + +static void lowThresholdState( struct _qAnalogChannel_t * c ) { + const qClock_t CURRENT_TIME = qClock_GetTick(); + + if ( c->value > c->high ) { + c->channelStateFcn = analogChannels.highThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_HIGH_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = CURRENT_TIME; + } + else if ( c->value > ( c->low + c->hysteresis ) ) { + c->channelStateFcn = analogChannels.inBandStateFcn; + c->channel.dispatchEvent( QINPUT_IN_BAND ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = CURRENT_TIME; + } + else { + /*Nothing to do here*/ + } + + if ( ( CURRENT_TIME - c->channel.tChange ) > c->channel.tSteadyLow ) { + c->channelStateFcn = analogChannels.steadyInLowStateFcn; + c->channel.dispatchEvent( QINPUT_STEADY_IN_LOW ); + c->channel.tChange = CURRENT_TIME; + } +} +static void highThresholdState( struct _qAnalogChannel_t * c ) { + const qClock_t CURRENT_TIME = qClock_GetTick(); + + if ( c->value < c->low ) { + c->channelStateFcn = analogChannels.lowThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_LOW_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = CURRENT_TIME; + } + else if ( c->value < ( c->high - c->hysteresis ) ) { + c->channelStateFcn = analogChannels.inBandStateFcn; + c->channel.dispatchEvent( QINPUT_IN_BAND ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = CURRENT_TIME; + } + else { + /*Nothing to do here*/ + } + + if ( ( CURRENT_TIME - c->channel.tChange ) > c->channel.tSteadyHigh ) { + c->channelStateFcn = analogChannels.steadyInHighStateFcn; + c->channel.dispatchEvent( QINPUT_STEADY_IN_HIGH ); + c->channel.tChange = CURRENT_TIME; + } +} +static void inBandState( struct _qAnalogChannel_t * c ) { + const qClock_t CURRENT_TIME = qClock_GetTick(); + + if ( c->value > c->high ) { + c->channelStateFcn = analogChannels.highThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_HIGH_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = CURRENT_TIME; + } + else if ( c->value < c->low ) { + c->channelStateFcn = analogChannels.lowThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_LOW_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = CURRENT_TIME; + } + else { + /*Nothing to do here*/ + } + + if ( ( CURRENT_TIME - c->channel.tChange ) > c->tSteadyBand ) { + c->channelStateFcn = analogChannels.steadyInBandStateFcn; + c->channel.dispatchEvent( QINPUT_STEADY_IN_BAND ); + c->channel.tChange = CURRENT_TIME; + } +} +static void analogSteadyInHighState( struct _qAnalogChannel_t * c ) { + if ( c->value < c->low ) { + c->channelStateFcn = analogChannels.lowThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_LOW_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } + else if ( c->value < ( c->high - c->hysteresis ) ) { + c->channelStateFcn = analogChannels.inBandStateFcn; + c->channel.dispatchEvent( QINPUT_IN_BAND ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } + else { + /*Nothing to do here*/ + } +} +static void analogSteadyInLowState( struct _qAnalogChannel_t * c ) { + if ( c->value > c->high ) { + c->channelStateFcn = analogChannels.highThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_HIGH_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } + else if ( c->value > ( c->low + c->hysteresis ) ) { + c->channelStateFcn = analogChannels.inBandStateFcn; + c->channel.dispatchEvent( QINPUT_IN_BAND ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } + else { + /*Nothing to do here*/ + } +} +static void steadyInBandState( struct _qAnalogChannel_t * c ) { + if ( c->value > c->high ) { + c->channelStateFcn = analogChannels.highThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_HIGH_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } + else if ( c->value < c->low ) { + c->channelStateFcn = analogChannels.lowThresholdStateFcn; + c->channel.dispatchEvent( QINPUT_LOW_THRESHOLD ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } + else { + /*Nothing to do here*/ + } +} + +//------------------------------------------------------------ +static void digitalXCallback( qChannel_t *c ) { + +} + +static void digitalUpdateReading( qBool_t act ) { + qDigitalValue_t sample = + digitalChannels.reader(digitalChannels.channel.number); + + if ( digitalChannels.negate ) { + sample = !sample; + } + digitalChannels.value = sample; +} + +static void digitalEvaluateState() { + //channelStateFcn = + //TODO: is this good? + digitalChannels.channelStateFcn(&digitalChannels); +} + +static qBool_t digitalIsValidConfig() { + + return qTrue; +} + +static void digitalSetInitalState() { + qDigitalValue_t val = + ( NULL != digitalChannels.reader ) ? + digitalChannels.reader( digitalChannels.channel.number ) : -1; + + if ( digitalChannels.negate ) { + val = !val; + } + digitalChannels.channelStateFcn = + ( 0 == val ) ? digitalChannels.fallingEdgeStateFcn + : digitalChannels.risingEdgeStateFcn; +} + +static void digitalDispatchEvent(qInput_Event_t e) { + digitalChannels.channel.lastEvent = e; +} + + +static qType_t digitalGetType( void ) { + return DIGITAL_CHANNEL; +} + +static qInput_Event_t digitalGetEvent( void ) { + return digitalChannels.channel.lastEvent; +} + +static qBool_t digitalSetCallback( const qEventCallback_t cb ) { + digitalChannels.channel.callback = cb; + return (cb != digitalChannels.channel.callback); +} + +static qBool_t digitalSetChannel( const uint8_t inputChannel ) { + qBool_t retValue = qFalse; + + if ( inputChannel < 32U ) { + digitalChannels.channel.number = inputChannel; + retValue = qTrue; + } + + return retValue; +} + +static uint8_t digitalGetChannel( void) { + return digitalChannels.channel.number; +} + +static void digitalSetUserData( void* pUserData) { + digitalChannels.channel.userData = pUserData; +} + +static void* digitalGetUserData( void) { + return digitalChannels.channel.userData; +} + +static qBool_t digitalIsShared( void) { + return ( &digitalChannels.value != digitalChannels.ptrValue ); +} + +static qBool_t digitalSetTime( const qInput_Event_t e, const qClock_t t) { + qBool_t retValue = qTrue; + + if ( t > 0U ) { + switch( e ) { + case QINPUT_PULSATION_DOUBLE: + case QINPUT_PULSATION_TRIPLE: // skipcq: CXX-C1001 + case QINPUT_PULSATION_MULTI: // skipcq: CXX-C1001 + digitalChannels.pulsationInterval = (qClock_t)t; + break; + case QINPUT_STEADY_IN_HIGH: + digitalChannels.channel.tSteadyHigh = (qClock_t)t; + break; + case QINPUT_STEADY_IN_LOW: + digitalChannels.channel.tSteadyLow = (qClock_t)t; + break; + default: + retValue = qFalse; + break; + } + } + else { + retValue = qFalse; + } + + return retValue; +} + +static qBool_t digitalSetParameter( const qInput_Event_t e, const qAnalogValue_t p ) { + (void)e; + (void)p; + return qFalse; +} + +static uint8_t digitalGetCount( void) { + return digitalChannels.pulsationCount; +} + +static qBool_t digitalSetReader( qDigitalReaderFcn_t r) { + digitalChannels.reader = r; + return qTrue; +} + +static uint8_t digitalUnShare( void) { + digitalChannels.ptrValue = &digitalChannels.value; +} + +static void fallingEdgeState( struct _qDigitalChannel_t * c ) { + const qClock_t CURRENT_TIME = qClock_GetTick(); + + if ( 0 != c->value ) { + c->channelStateFcn = digitalChannels.risingEdgeStateFcn; + c->channel.dispatchEvent( QINPUT_RISING_EDGE ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + if ( ( CURRENT_TIME - c->channel.tChange ) > c->pulsationInterval ) { + c->pulsationCount = 0U; + } + c->channel.tChange = CURRENT_TIME; + } + if ( ( CURRENT_TIME - c->channel.tChange ) > c->channel.tSteadyLow ) { + c->channelStateFcn = digitalChannels.steadyInLowStateFcn; + c->channel.dispatchEvent( QINPUT_STEADY_IN_LOW ); + c->channel.tChange = CURRENT_TIME; + } +} +static void risingEdgeState( struct _qDigitalChannel_t * c ) { + const qClock_t CURRENT_TIME = qClock_GetTick(); + + if ( 0 == c->value ) { + c->channelStateFcn = digitalChannels.fallingEdgeStateFcn; + c->channel.dispatchEvent( QINPUT_FALLING_EDGE ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + if ( ( CURRENT_TIME - c->channel.tChange ) <= c->pulsationInterval ) { + ++c->pulsationCount; + } + c->channel.tChange = CURRENT_TIME; + + switch ( c->pulsationCount ) { + case 0 : case 1: break; + case 2: + c->channel.dispatchEvent( QINPUT_PULSATION_DOUBLE ); + break; + case 3: + c->channel.dispatchEvent( QINPUT_PULSATION_TRIPLE ); + break; + default: + c->channel.dispatchEvent( QINPUT_PULSATION_MULTI ); + break; + } + } + if ( ( CURRENT_TIME - c->channel.tChange ) > c->channel.tSteadyHigh ) { + c->channelStateFcn = digitalChannels.steadyInHighStateFcn; + c->channel.dispatchEvent( QINPUT_STEADY_IN_HIGH ); + c->channel.tChange = CURRENT_TIME; + } +} + +static void digitalSteadyInHighState( struct _qDigitalChannel_t * c ) { + if ( 0 == c->value ) { + c->channelStateFcn = digitalChannels.fallingEdgeStateFcn; + c->channel.dispatchEvent( QINPUT_FALLING_EDGE ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } +} + +static void digitalSteadyInLowState( struct _qDigitalChannel_t * c ) { + if ( 0 != c->value ) { + c->channelStateFcn = digitalChannels.risingEdgeStateFcn; + c->channel.dispatchEvent( QINPUT_RISING_EDGE ); + c->channel.dispatchEvent( QINPUT_ON_CHANGE ); + c->channel.tChange = qClock_GetTick(); + } +} + + +static qBool_t addChannel( qChannel_t * c ) { + qBool_t retValue; + qList_Iterator_t i; + + if ( DIGITAL_CHANNEL == c->getType() ) { + (void)c->setDigitalReader( watcher.digitalReader ); + c->setInitalState(); + retValue = qList_Insert( &watcher.digitalChannels, c, QLIST_AT_BACK ); + } + else { + (void)c->setAnalogReader( watcher.analogReader ); + (void)c->setInitalState(); + qAnalogChannel_t *chan = (qAnalogChannel_t*)c; + /* check if channel is shared( same channel number)*/ + for ( i = qList_Begin( &watcher.analogChannels) ; + qListIterator_Until( &i, NULL ) ; + qListIterator_Forward( &i ) ) { + + qAnalogChannel_t * channelInWatcher = + (qAnalogChannel_t *)qListIterator_Get( &i ); + + if ( chan->channel.number == channelInWatcher->channel.number ) { + chan->ptrValue = &channelInWatcher->value; + break; + } + } + retValue = qList_Insert( &watcher.analogChannels, c, QLIST_AT_BACK ); + } + c->tChange = qClock_GetTick(); + + return retValue; +} + +static qBool_t addCallback( qChannel_t *c, qEventCallback_t cb ) { + + (void)c->setCallback( cb ); + return addChannel( c ); +} + +static qBool_t addCallbackDigital( qChannel_t *c, qDigitalReaderFcn_t fcn, qEventCallback_t cb ) { + qBool_t retValue; + (void)c->setCallback( cb ); + retValue = addChannel( c ); + (void)c->setDigitalReader( fcn ); + return retValue; +} + +static qBool_t addCallbackAnalog( qChannel_t *c, qAnalogReaderFcn_t fcn, qEventCallback_t cb ) { + qBool_t retValue; + (void)c->setCallback( cb ); + retValue = addChannel( c ); + (void)c->setAnalogReader( fcn ); + return retValue; +} + +static qBool_t remove( qChannel_t *c ) { + qList_Iterator_t i; + qList_t* const channelContainer = c->node.container; + const qBool_t retValue = //channelContainer->remove( &c ); + qList_Remove(channelContainer, c, QLIST_AT_BACK) == NULL? qFalse:qTrue; + + (void)c->unShare(); + + if ( (ANALOG_CHANNEL == c->getType() ) && !c->isShared() ) { // no side-effects here + qAnalogValue_t *newPtrVal = NULL; + /*find the next shared channel*/ + for ( i = qList_Begin( &watcher.analogChannels) ; + qListIterator_Until( &i, NULL ) ; + qListIterator_Forward( &i ) ) { + + qAnalogChannel_t *channelInList = + (qAnalogChannel_t *)qListIterator_Get( &i ); + + if ( channelInList->channel.number == c->number ) { + if ( NULL == newPtrVal ) { /*first shared channel*/ + newPtrVal = &channelInList->value; + channelInList->ptrValue = &channelInList->value; + } + else { + channelInList->ptrValue = newPtrVal; + } + } + } + } + + return retValue; +} + +/*============================================================================*/ +static qBool_t watch( void ) +{ + qList_Iterator_t i; + const qBool_t act = qSTimer_FreeRun( + &watcher.waitDebounce, watcher.debounceTime); + + if ( ( qList_Length(&watcher.digitalChannels) > 0U ) && act ) { + + for ( i = qList_Begin( &watcher.digitalChannels) ; + qListIterator_Until( &i, NULL ) ; + qListIterator_Forward( &i ) ) { + + qChannel_t *c = (qChannel_t *)qListIterator_Get( &i ); + if ( NULL != c->callback ) { + if ( NULL != watcher.digitalReader ) { + c->updateReading( qTrue ); + c->evaluateState(); + } + else { + c->dispatchEvent( QINPUT_EXCEPTION ); + } + } + } + } + + if ( ( qList_Length(&watcher.analogChannels) > 0U ) > 0U ) { + for ( i = qList_Begin( &watcher.analogChannels) ; + qListIterator_Until( &i, NULL ) ; + qListIterator_Forward( &i ) ) { + + qChannel_t *c = (qChannel_t *)qListIterator_Get( &i ); + if ( NULL != c->callback ) { + if ( ( NULL != watcher.analogReader ) && c->isValidConfig() ) { // no side-effects here + c->updateReading( act ); + c->evaluateState(); + } + else { + c->dispatchEvent( QINPUT_EXCEPTION ); + } + } + } + } + + return qTrue; +} + +/** + * @brief This function should be invoked at the begining + */ +void qInputInitialize() { + + const qDigitalChannel_t _digitalChannels = + DEFAULT_DIGITAL_CHANNELS_INITIALIZATION; + const qAnalogChannel_t _analogChannels = + DEFAULT_ANALOG_CHANNELS_INITIALIZATION; + + const qWatcher_t _watcher ; + digitalChannels = _digitalChannels; + analogChannels = _analogChannels; + watcher = _watcher; + (void)qList_Initialize( &watcher.digitalChannels ); + (void)qList_Initialize( &watcher.analogChannels ); + +} + + +void test () { + + digitalChannels.channel.callback(&channels); + analogChannels.channel.callback(&channels); + + analogChannels.channel.dispatchEvent(QINPUT_LOW_THRESHOLD); + +}