/************************************************************************** * * Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file Level.c * * @author (last) Sean Nash * @date (last) 19-Nov-2024 * * @author (original) Sean Nash * @date (original) 19-Nov-2024 * ***************************************************************************/ #include "FpgaRO.h" #include "Level.h" #include "MessageSupport.h" #include "Messaging.h" #include "TaskPriority.h" #include "Timers.h" /** * @addtogroup Level * @{ */ // ********** private definitions ********** #define LEVEL_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the level data is published on the CAN bus. #define LEVEL_DEBOUNCE_TIME_MS ( MS_PER_SECOND / 10 ) ///< Level debounce time in milliseconds. #define DATA_PUBLISH_COUNTER_START_COUNT 7 ///< Data publish counter start count. #define LOW_LEVEL_SWITCH_BIT 0x01 ///< Bit position for lower level switch. #define HIGH_LEVEL_SWITCH_BIT 0x02 ///< Bit position for upper level switch. #define LEVEL_SWITCH_BIT_MASK 0x03 ///< Bit mask for level switch bits. /// Level status structure typedef struct { OVERRIDE_U32_T level; ///< Level state. U32 priorRawLevel; ///< Prior level state (not debounced). U32 debounceStartTime; ///< Debounce start time. U32 debounceTime; ///< Debounce time } LEVEL_STATE_REC_T; // ********** private data ********** static LEVEL_STATE_REC_T levelState; ///< Level state for floater level sensor. static OVERRIDE_U32_T levelsDataPublishInterval; ///< Interval (in ms) at which to publish Level data to CAN bus. static U32 levelsDataPublicationCounter; ///< Level data publication counter. // ********** private function prototypes ********** static void publishLevelsData( void ); /*********************************************************************//** * @brief * The initLevels function initializes the levels unit. * @details \b Inputs: none * @details \b Outputs: Level unit variables initialized. * @return none *************************************************************************/ void initLevels( void ) { levelsDataPublicationCounter = DATA_PUBLISH_COUNTER_START_COUNT; levelState.level.data = (U32)LEVEL_STATE_HIGH; levelState.level.ovData = (U32)LEVEL_STATE_HIGH; levelState.level.ovInitData = (U32)LEVEL_STATE_HIGH; levelState.level.override = OVERRIDE_RESET; levelState.debounceStartTime = 0; levelState.debounceTime = LEVEL_DEBOUNCE_TIME_MS; levelsDataPublishInterval.data = LEVEL_DATA_PUB_INTERVAL; levelsDataPublishInterval.ovData = LEVEL_DATA_PUB_INTERVAL; levelsDataPublishInterval.ovInitData = 0; levelsDataPublishInterval.override = OVERRIDE_RESET; } /*********************************************************************//** * @brief * The execLevels function updates and debounces the floater level sensor states. * @details \b Inputs: level sensor reading from FPGA * @details \b Outputs: levelState * @details \b Message \b Sent: MSG_ID_RO_EVENT if debounced level changes state. * @return none *************************************************************************/ void execLevels( void ) { U08 levelBits = getFPGAP25FloaterState() & LEVEL_SWITCH_BIT_MASK; U32 currentLevelState = LEVEL_STATE_LOW; // Convert floater switch bits to level if ( ( levelBits & LOW_LEVEL_SWITCH_BIT ) != 0 ) { if ( ( levelBits & HIGH_LEVEL_SWITCH_BIT ) != 0 ) { // upper switch is active low currentLevelState = LEVEL_STATE_MEDIUM; } else { currentLevelState = LEVEL_STATE_HIGH; } } // Check if the current level status is not the same as the recorded data if ( currentLevelState != levelState.level.data ) { // If the debounce time is 0 or the current state not same as prior state, restart the debounce timer if ( ( 0 == levelState.debounceStartTime ) || ( currentLevelState != levelState.priorRawLevel ) ) { levelState.debounceStartTime = getMSTimerCount(); } // If the debounce time has been elapsed, update the level sensor status to the new status else if ( TRUE == didTimeout( levelState.debounceStartTime, levelState.debounceTime ) ) { // TODO SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_FLOATER_1_LEVEL_CHANGE, (U32)levelState.level.data, (U32)currentLevelStatus ); levelState.debounceStartTime = 0; levelState.level.data = currentLevelState; } } else { levelState.debounceStartTime = 0; } levelState.priorRawLevel = currentLevelState; publishLevelsData(); } /*********************************************************************//** * @brief * The getLevelStatus function returns the level state of the floater. * @details \b Inputs: levelState * @details \b Outputs: levelState * @return level state of the floater sensor *************************************************************************/ LEVEL_STATE_T getLevelStatus( void ) { U32 status = levelState.level.data; // Assume there is no override if ( OVERRIDE_KEY == levelState.level.override ) { status = levelState.level.ovData; } return (LEVEL_STATE_T)status; } /*********************************************************************//** * @brief * The publishLevelsData function broadcasts the level data at the * publication interval. * @details \b Inputs: levelsDataPublicationCounter * @details \b Outputs: levelsDataPublicationCounter * @details \b Message \b Sent: MSG_ID_DD_LEVEL_DATA to publish level * sensors data. * @return none *************************************************************************/ static void publishLevelsData( void ) { if ( ++levelsDataPublicationCounter >= getU32OverrideValue( &levelsDataPublishInterval ) ) { LEVEL_DATA_T data; data.p25Level = (U32)getLevelStatus(); levelsDataPublicationCounter = 0; broadcastData( MSG_ID_FP_LEVEL_DATA, COMM_BUFFER_OUT_CAN_RO_BROADCAST, (U08*)&data, sizeof( LEVEL_DATA_T ) ); } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testLevelsDataPublishIntervalOverride function overrides the Level * data publish interval. * @details \b Inputs: levelsDataPublishInterval * @details \b Outputs: levelsDataPublishInterval * @param Override message from Dialin which includes the interval * (in ms) to override the level data broadcast interval to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testLevelsDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &levelsDataPublishInterval, TASK_PRIORITY_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testLevelStateOverride function sets the override state for the floater * level sensor. * @details \b Inputs: none * @details \b Outputs: levelState * @param message Override message from Dialin which includes the state to * override the floater level sensor to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testLevelStateOverride( MESSAGE_T *message ) { BOOL result = u32Override( message, &levelState.level, 0, NUM_OF_LEVELS_STATES -1 ); return result; } /**@}*/