/************************************************************************** * * 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) Vinayakam Mani * @date (last) 11-Oct-2024 * * @author (original) Vinayakam Mani * @date (original) 11-Oct-2024 * ***************************************************************************/ #include "FpgaDD.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. /// Level status structure typedef struct { OVERRIDE_U32_T status; ///< Level status. U32 debounceStartTime; ///< Debounce start time. U32 debounceTime; ///< Debounce time } LEVEL_STATUS_T; // ********** private data ********** static U32 levelsDataPublicationCounter; ///< Level data publication counter. static OVERRIDE_U32_T levelsDataPublishInterval = { LEVEL_DATA_PUB_INTERVAL, LEVEL_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish Level data to CAN bus. static LEVEL_STATUS_T levelsStatus[ NUM_OF_LEVELS ]; ///< Level status array. // ********** private function prototypes ********** static void publishLevelsData( void ); /*********************************************************************//** * @brief * The initLevels function initializes the level module. * @details \b Inputs: none * @details \b Outputs: Level unit variables initialized. * @return none *************************************************************************/ void initLevels( void ) { U32 i; levelsDataPublicationCounter = DATA_PUBLISH_COUNTER_START_COUNT; // Initialize all the Level for ( i = 0; i < NUM_OF_LEVELS; i++ ) { levelsStatus[ i ].status.data = (U32)STATE_HIGH; levelsStatus[ i ].status.ovData = (U32)STATE_HIGH; levelsStatus[ i ].status.ovInitData = (U32)STATE_HIGH; levelsStatus[ i ].status.override = OVERRIDE_RESET; levelsStatus[ i ].debounceStartTime = 0; levelsStatus[ i ].debounceTime = LEVEL_DEBOUNCE_TIME_MS; } } /*********************************************************************//** * @brief * The execLevels function executes the floater and level sensor states. * @details \b Inputs: level sensor and floater reading from FPGA * @details \b Outputs: levelStatus * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid level sensor * executed. * @return none *************************************************************************/ void execLevels( void ) { U32 i; U32 currentLevelStatus = 0; for ( i = 0; i < NUM_OF_LEVELS; i++ ) { // Get the current level status switch ( i ) { // Process the status of the Level case FLOATER_1: currentLevelStatus = ( getFPGAFloater1Status() != 0 ? STATE_LOW : STATE_MEDIUM ); break; case FLOATER_2: currentLevelStatus = ( getFPGAFloater2Status() != 0 ? STATE_MEDIUM : STATE_HIGH ); break; case BICARB_LEVEL: currentLevelStatus = ( getFPGALevelSensor1() != 0 ? STATE_LOW : STATE_HIGH ); break; case SPENT_DIALYSATE_LEVEL: currentLevelStatus = ( getFPGALevelSensor2() != 0 ? STATE_LOW : STATE_HIGH ); break; #ifndef _VECTORCAST_ default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LEVEL_SELECTED, i ); break; #endif } // Check if the current level status is not the same as the recorded data if ( currentLevelStatus != levelsStatus[ i ].status.data ) { // If the debounce time is 0, start the timer if ( 0 == levelsStatus[ i ].debounceStartTime ) { levelsStatus[ i ].debounceStartTime = getMSTimerCount(); } // If the debounce time has been elapsed, update the level sensor status to the new status else if ( TRUE == didTimeout( levelsStatus[ i ].debounceStartTime, levelsStatus[ i ].debounceTime ) ) { switch ( i ) { case FLOATER_1: SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_FLOATER_1_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); break; case FLOATER_2: SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_FLOATER_2_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); break; case BICARB_LEVEL: SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_BICARB_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); break; case SPENT_DIALYSATE_LEVEL: SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_SPENT_DIALYSATE_LEVEL_CHANGE, (U32)levelsStatus[ i ].status.data, (U32)currentLevelStatus ); break; #ifndef _VECTORCAST_ default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_LEVEL_SELECTED, i ); break; #endif } levelsStatus[ i ].debounceStartTime = 0; levelsStatus[ i ].status.data = currentLevelStatus; } } else { levelsStatus[ i ].debounceStartTime = 0; } } publishLevelsData(); } /*********************************************************************//** * @brief * The getLevelStatus function returns the status of the called level sensor. * @details \b Inputs: levelStatus * @details \b Outputs: levelStatus * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid level sensor * passed. * @param levelId which is the sensor that its status is requested * @return level status *************************************************************************/ LEVEL_STATE_T getLevelStatus( LELVEL_T levelId ) { U32 status = 0; if ( levelId < NUM_OF_LEVELS ) { // Assume there is no override status = levelsStatus[ levelId ].status.data; if ( OVERRIDE_KEY == levelsStatus[ levelId ].status.override ) { status = levelsStatus[ levelId ].status.ovData; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_DD_INVALID_LEVEL_ID, (U32)levelId ) } 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.floater1Level = (U32)getLevelStatus( FLOATER_1 ); data.floater2Level = (U32)getLevelStatus( FLOATER_2 ); data.bicarbLevel = (U32)getLevelStatus( BICARB_LEVEL ); data.spentDialysateLevel = (U32)getLevelStatus( SPENT_DIALYSATE_LEVEL ); levelsDataPublicationCounter = 0; broadcastData( MSG_ID_DD_LEVEL_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( LEVEL_DATA_T ) ); } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testLevelsDataPublishIntervalOverride function overrides * the Level publish data 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 testLevelStatusOverride function sets the override status * for a specific level sensor. * @details \b Inputs: none * @details \b Outputs: levelStatus * @param message Override message from Dialin which includes an ID of * the level sensor to override and the state to override the level sensor to. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testLevelStatusOverride( MESSAGE_T *message ) { BOOL result = u32ArrayOverride( message, &levelsStatus[0].status, NUM_OF_LEVELS - 1, 0, NUM_OF_LEVELS_STATES -1 ); return result; } /**@}*/