/************************************************************************** * * Copyright (c) 2019-2020 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 OperationModes.c * * @author (last) Quang Nguyen * @date (last) 21-Jul-2020 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 * ***************************************************************************/ #include "gio.h" #include "SystemCommMessages.h" #include "TaskGeneral.h" #include "OperationModes.h" #include "ModeChemicalDisinfect.h" #include "ModeDrain.h" #include "ModeFault.h" #include "ModeFill.h" #include "ModeFlush.h" #include "ModeHeatDisinfect.h" #include "ModeInitPOST.h" #include "ModeRecirculate.h" #include "ModeService.h" #include "ModeSolo.h" #include "ModeStandby.h" /** * @addtogroup DGOperationModes * @{ */ // ********** private definitions ********** #define BROADCAST_DG_OP_MODE_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the op mode is published on the CAN bus. // ********** private data ********** static volatile BOOL modeRequest[NUM_OF_DG_MODES - 1]; ///< Array of mode request flags. static DG_OP_MODE_T currentMode = DG_MODE_INIT; ///< The currently active mode. static U32 currentSubMode = 0; ///< The currently active state of the active mode. static U32 broadcastModeIntervalCtr = 11; ///< Interval counter used to determine when to broadcase operation mode. Initialize to 11 to stagger broadcast. /// This matrix determines legal transitions from one mode to another. static const DG_OP_MODE_T MODE_TRANSITION_TABLE[NUM_OF_DG_MODES - 1][NUM_OF_DG_MODES - 1] = { // from to-> FAULT SERVICE INIT STANBY STBY-SOLO RE-CIRC FILL DRAIN FLUSH HEAT DIS CHEM DIS /* FAUL */{ DG_MODE_FAUL, DG_MODE_SERV, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG }, /* SERV */{ DG_MODE_FAUL, DG_MODE_SERV, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG }, /* INIT */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_INIT, DG_MODE_STAN, DG_MODE_SOLO, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG }, /* STAN */{ DG_MODE_FAUL, DG_MODE_SERV, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_SOLO, DG_MODE_CIRC, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_FLUS, DG_MODE_HEAT, DG_MODE_CHEM }, /* SOLO */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_SOLO, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_FLUS, DG_MODE_HEAT, DG_MODE_NLEG }, /* CIRC */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_NLEG, DG_MODE_CIRC, DG_MODE_FILL, DG_MODE_DRAI, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG }, /* FILL */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_NLEG, DG_MODE_CIRC, DG_MODE_FILL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG }, /* DRAI */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_NLEG, DG_MODE_CIRC, DG_MODE_NLEG, DG_MODE_DRAI, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG }, /* FLUS */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_SOLO, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_FLUS, DG_MODE_NLEG, DG_MODE_NLEG }, /* HEAT */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_SOLO, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_HEAT, DG_MODE_NLEG }, /* CHEM */{ DG_MODE_FAUL, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_STAN, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_NLEG, DG_MODE_CHEM } }; static U32 dgOpModePublicationTimerCounter = 0; // ********** private function prototypes ********** static DG_OP_MODE_T arbitrateModeRequest( void ); static void transitionToNewOperationMode( DG_OP_MODE_T newMode ); static void broadcastOperationMode( void ); /*********************************************************************//** * @brief execOperationModes * The execOperationModes function initializes the Operation Modes module. * @details * Inputs : none * Outputs : Operation Modes module initialized. * @return none *************************************************************************/ void initOperationModes( void ) { U32 i; // initialize mode requests to none pending for ( i = 0; i < ( NUM_OF_DG_MODES - 1 ); i++ ) { modeRequest[i] = FALSE; } // start in init mode currentMode = DG_MODE_INIT; currentSubMode = 0; transitionToNewOperationMode( DG_MODE_INIT ); // call initializers for the individual modes initFaultMode(); initServiceMode(); initInitAndPOSTMode(); initStandbyMode(); initSoloMode(); initRecirculateMode(); initFillMode(); initDrainMode(); initFlushMode(); initHeatDisinfectMode(); initChemicalDisinfectMode(); // initialize broadcast timer counter dgOpModePublicationTimerCounter = 0; } /*********************************************************************//** * @brief execOperationModes * The execOperationModes function executes the Operation Modes state machine. * @details * Inputs : none * Outputs : currentMode is set by state machine. * @return none *************************************************************************/ void execOperationModes( void ) { DG_OP_MODE_T newMode; // any new mode requests? newMode = arbitrateModeRequest(); // will return current mode if no pending requests newMode = MODE_TRANSITION_TABLE[currentMode][newMode]; // is requested new mode valid and legal at this time? if ( newMode >= DG_MODE_NLEG ) { // TODO - s/w fault newMode = currentMode; } // has mode changed? if ( currentMode != newMode ) { // handle transition to new mode transitionToNewOperationMode( newMode ); currentMode = newMode; } // mode specific processing to be done continuously switch ( currentMode ) { case DG_MODE_FAUL: currentSubMode = execFaultMode(); break; case DG_MODE_SERV: currentSubMode = execServiceMode(); break; case DG_MODE_INIT: currentSubMode = execInitAndPOSTMode(); break; case DG_MODE_STAN: currentSubMode = execStandbyMode(); break; case DG_MODE_SOLO: currentSubMode = execSoloMode(); break; case DG_MODE_CIRC: currentSubMode = execRecirculateMode(); break; case DG_MODE_FILL: currentSubMode = execFillMode(); break; case DG_MODE_DRAI: currentSubMode = execDrainMode(); break; case DG_MODE_FLUS: currentSubMode = execFlushMode(); break; case DG_MODE_HEAT: currentSubMode = execHeatDisinfectMode(); break; case DG_MODE_CHEM: currentSubMode = execChemicalDisinfectMode(); break; default: // TODO - trigger s/w fault currentMode = DG_MODE_FAUL; currentSubMode = 0; break; } // end switch // publish op mode on interval broadcastOperationMode(); } /*********************************************************************//** * @brief requestNewOperationMode * The requestNewOperationMode function requests a new operation mode. * @details * Inputs : none * Outputs : makes the requested mode "pending". * @param newMode requested mode * @return none *************************************************************************/ void requestNewOperationMode( DG_OP_MODE_T newMode ) { // validate requested mode if ( newMode < DG_MODE_NLEG ) { // make request modeRequest[newMode] = TRUE; } else { // invalid mode requested // TODO - trigger s/w fault } } /*********************************************************************//** * @brief getCurrentOperationMode * The getCurrentOperationMode function initializes the Operation Modes module. * @details * Inputs : none * Outputs : Initializes the Operation Modes module. * @return none *************************************************************************/ DG_OP_MODE_T getCurrentOperationMode( void ) { return currentMode; } /*********************************************************************//** * @brief arbitrateModeRequest * The arbitrateModeRequest function initializes the Operation Modes module. * @details * Inputs : none * Outputs : Initializes the Operation Modes module. * @return none *************************************************************************/ static DG_OP_MODE_T arbitrateModeRequest( void ) { DG_OP_MODE_T reqMode = currentMode; U32 i; // block additional requests until after mode arbitration _disable_IRQ(); // select highest priority mode request -or- current mode if no requests pending for ( i = 0; i < DG_MODE_NLEG; i++ ) { if ( modeRequest[i] != FALSE ) { reqMode = (DG_OP_MODE_T)i; break; } } // clear all requests now that an arbitration winner is selected for ( i = 0; i < DG_MODE_NLEG; i++ ) { modeRequest[i] = FALSE; } // un-block requests _enable_IRQ(); return reqMode; } /*********************************************************************//** * @brief transitionToNewOperationMode * The transitionToNewOperationMode function initializes the Operation Modes module. * @details * Inputs : none * Outputs : Initializes the Operation Modes module. * @param newMode new op mode to transition to * @return none *************************************************************************/ static void transitionToNewOperationMode( DG_OP_MODE_T newMode ) { // setup for new operating mode switch ( newMode ) { case DG_MODE_FAUL: transitionToFaultMode(); break; case DG_MODE_SERV: transitionToServiceMode(); break; case DG_MODE_INIT: transitionToInitAndPOSTMode(); break; case DG_MODE_STAN: transitionToStandbyMode(); break; case DG_MODE_SOLO: transitionToSoloMode(); break; case DG_MODE_CIRC: transitionToRecirculateMode(); break; case DG_MODE_FILL: transitionToFillMode(); break; case DG_MODE_DRAI: transitionToDrainMode(); break; case DG_MODE_FLUS: transitionToFlushMode(); break; case DG_MODE_HEAT: transitionToHeatDisinfectMode(); break; case DG_MODE_CHEM: transitionToChemicalDisinfectMode(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, (U32)newMode ) // TODO - add s/w fault enum to 1st data param break; } } /*********************************************************************//** * @brief * The broadcastOperationMode function sends the current operation mode at \n * the prescribed interval. * @details * Inputs : broadcastModeIntervalCtr * Outputs : DG operation mode broadcast message sent. * @return none *************************************************************************/ static void broadcastOperationMode( void ) { if ( ++broadcastModeIntervalCtr >= BROADCAST_DG_OP_MODE_INTERVAL ) { broadcastModeIntervalCtr = 0; broadcastDGOperationMode( (U32)currentMode, currentSubMode ); } } /**@}*/