You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
6.8 KiB
320 lines
6.8 KiB
/* Copyright 1999 American Power Conversion, All Rights Reserved
|
|
*
|
|
* Description:
|
|
* Implements the native UPS sevice state machine. The various states executed
|
|
* within the state machine are housed in separate files.
|
|
*
|
|
* Revision History:
|
|
* dsmith 31Mar1999 Created
|
|
*
|
|
*/
|
|
#include <windows.h>
|
|
|
|
#include "states.h"
|
|
#include "events.h"
|
|
#include "driver.h"
|
|
#include "running_statmach.h"
|
|
#include "upsreg.h"
|
|
|
|
// Internal function Prototypes
|
|
static void enter_state(DWORD aNewState, DWORD anEvent);
|
|
static DWORD do_work(DWORD aCurrentState);
|
|
static void exit_state(DWORD anOldState, DWORD anEvent);
|
|
static DWORD change_state(DWORD aCurrentState, DWORD anEvent);
|
|
static DWORD get_new_state(DWORD aCurrentState, DWORD anEvent);
|
|
|
|
|
|
// State Machine Variables
|
|
BOOL theIsStateMachineActive = TRUE;
|
|
|
|
|
|
/**
|
|
* RunStateMachine
|
|
*
|
|
* Description:
|
|
* Starts the state machine. This method will not return until the state machine
|
|
* exits.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Returns:
|
|
* None
|
|
*/
|
|
void RunStateMachine(){
|
|
|
|
// Set the primary state to RUNNING
|
|
DWORD new_state = RUNNING;
|
|
DWORD current_state = new_state;
|
|
DWORD event = NO_EVENT;
|
|
|
|
enter_state(new_state, event);
|
|
|
|
// Continue processing state changes until the state becomes the EXIT_NOW state
|
|
while (new_state != EXIT_NOW){
|
|
current_state = new_state;
|
|
|
|
event = do_work(current_state);
|
|
new_state = change_state(new_state, event);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* StopStateMachine
|
|
*
|
|
* Description:
|
|
* Stops the UPS service state machine if the service is not in the
|
|
* middle of a shutdown sequence.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Returns:
|
|
* None
|
|
*/
|
|
void StopStateMachine(){
|
|
|
|
theIsStateMachineActive = FALSE;
|
|
|
|
// Wake up the main service thread
|
|
UPSCancelWait();
|
|
}
|
|
|
|
/**
|
|
* IsStateMachineActive
|
|
*
|
|
* Description:
|
|
* Returns the running status of the state machine. If the state machine
|
|
* has been commanded to exit, then the status will be FALSE, otherwise,
|
|
* this method will return true.
|
|
*
|
|
* Parameters:
|
|
* None
|
|
*
|
|
* Returns:
|
|
* TRUE if the state machine is active
|
|
* FALSE if the state machine is not active
|
|
*/
|
|
BOOL IsStateMachineActive(){
|
|
return theIsStateMachineActive;
|
|
}
|
|
|
|
/**
|
|
* change_state
|
|
*
|
|
* Description:
|
|
* Determines what the new state should be based upon the input parameters.
|
|
* The current state is exited and the new state is initialized.
|
|
*
|
|
* Parameters:
|
|
* anEvent The event that is causing the state transition.
|
|
* aCurrentState The state before the transition.
|
|
*
|
|
* Returns:
|
|
* The new state.
|
|
*/
|
|
DWORD change_state(DWORD aCurrentState, DWORD anEvent){
|
|
DWORD new_state;
|
|
|
|
new_state = get_new_state(aCurrentState, anEvent);
|
|
if (new_state != aCurrentState){
|
|
exit_state(aCurrentState, anEvent);
|
|
enter_state(new_state, anEvent);
|
|
}
|
|
return new_state;
|
|
}
|
|
|
|
/**
|
|
* get_new_state
|
|
*
|
|
* Description:
|
|
* Determines what the new state should be based upon the input parameters
|
|
* and registry entries.
|
|
*
|
|
* Parameters:
|
|
* anEvent The event that is causing the state transition.
|
|
* aCurrentState The state before the transition.
|
|
*
|
|
* Returns:
|
|
* The new state.
|
|
*/
|
|
static DWORD get_new_state(DWORD aCurrentState, DWORD anEvent){
|
|
DWORD new_state;
|
|
|
|
switch (anEvent){
|
|
case INITIALIZATION_COMPLETE:
|
|
new_state = RUNNING;
|
|
break;
|
|
|
|
case LOST_COMM:
|
|
case LOW_BATTERY:
|
|
case ON_BATTERY_TIMER_EXPIRED:
|
|
{
|
|
DWORD shutdown_behavior = UPS_SHUTDOWN_SHUTDOWN;
|
|
|
|
// Check the registry to determine if we shutdown or hibernate
|
|
InitUPSConfigBlock();
|
|
|
|
if ((GetUPSConfigCriticalPowerAction(&shutdown_behavior) == ERROR_SUCCESS)
|
|
&& (shutdown_behavior == UPS_SHUTDOWN_HIBERNATE)) {
|
|
// Hibernate was selected as the CriticalPowerAction
|
|
new_state = HIBERNATE;
|
|
|
|
}
|
|
else {
|
|
// Shutdown was selected as the CriticalPowerAction
|
|
new_state = WAITING_TO_SHUTDOWN;
|
|
}
|
|
|
|
// Free the UPS registry config block
|
|
FreeUPSConfigBlock();
|
|
}
|
|
break;
|
|
|
|
case SHUTDOWN_ACTIONS_COMPLETED:
|
|
new_state = SHUTTING_DOWN;
|
|
break;
|
|
case SHUTDOWN_COMPLETE:
|
|
new_state = STOPPING;
|
|
break;
|
|
case STOPPED:
|
|
new_state = EXIT_NOW;
|
|
break;
|
|
case RETURN_FROM_HIBERNATION:
|
|
new_state = INITIALIZING;
|
|
break;
|
|
case HIBERNATION_ERROR:
|
|
new_state = SHUTTING_DOWN;
|
|
break;
|
|
default:
|
|
new_state = aCurrentState;
|
|
}
|
|
|
|
// If the state machine has been commanded to exit, then return the
|
|
// stopping state
|
|
if (IsStateMachineActive() == FALSE){
|
|
|
|
// Ignore this condition if the transition is into the shutting down state
|
|
// Shutdowns in progress cannot be interrupted.
|
|
if (new_state != SHUTTING_DOWN && new_state != EXIT_NOW){
|
|
new_state = STOPPING;
|
|
}
|
|
}
|
|
return new_state;
|
|
}
|
|
|
|
/**
|
|
* enter_state
|
|
*
|
|
* Description:
|
|
* Initializes the new state.
|
|
*
|
|
* Parameters:
|
|
* anEvent The event that is causing the transition to a new state.
|
|
* aNewState The state to enter.
|
|
*
|
|
* Returns:
|
|
* None
|
|
*/
|
|
static void enter_state(DWORD aNewState, DWORD anEvent){
|
|
switch (aNewState){
|
|
case INITIALIZING:
|
|
Initializing_Enter(anEvent);
|
|
break;
|
|
case RUNNING:
|
|
Running_Enter(anEvent);
|
|
break;
|
|
case WAITING_TO_SHUTDOWN:
|
|
WaitingToShutdown_Enter(anEvent);
|
|
break;
|
|
case SHUTTING_DOWN:
|
|
ShuttingDown_Enter(anEvent);
|
|
break;
|
|
case HIBERNATE:
|
|
Hibernate_Enter(anEvent);
|
|
break;
|
|
case STOPPING:
|
|
Stopping_Enter(anEvent);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* do_work
|
|
*
|
|
* Description:
|
|
* Transfers control to a state.
|
|
*
|
|
* Parameters:
|
|
* aCurrentState The state to perform the work in.
|
|
*
|
|
* Returns:
|
|
* The event that caused the transition from one of the states
|
|
*/
|
|
static DWORD do_work(DWORD aCurrentState){
|
|
DWORD event = NO_EVENT;
|
|
switch (aCurrentState){
|
|
case INITIALIZING:
|
|
event = Initializing_DoWork();
|
|
break;
|
|
case RUNNING:
|
|
event = Running_DoWork();
|
|
break;
|
|
case WAITING_TO_SHUTDOWN:
|
|
event = WaitingToShutdown_DoWork();
|
|
break;
|
|
case SHUTTING_DOWN:
|
|
event = ShuttingDown_DoWork();
|
|
break;
|
|
case HIBERNATE:
|
|
event = Hibernate_DoWork();
|
|
break;
|
|
case STOPPING:
|
|
event = Stopping_DoWork();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return event;
|
|
}
|
|
|
|
/**
|
|
* exit_state
|
|
*
|
|
* Description:
|
|
* Exits the currently executing state.
|
|
*
|
|
* Parameters:
|
|
* anEvent The event that is causing the transition from the state.
|
|
* anOldState The current state.
|
|
*
|
|
* Returns:
|
|
* None
|
|
*/
|
|
static void exit_state(DWORD anOldState, DWORD anEvent){
|
|
switch (anOldState){
|
|
case INITIALIZING:
|
|
Initializing_Exit(anEvent);
|
|
break;
|
|
case RUNNING:
|
|
Running_Exit(anEvent);
|
|
break;
|
|
case WAITING_TO_SHUTDOWN:
|
|
WaitingToShutdown_Exit(anEvent);
|
|
break;
|
|
case SHUTTING_DOWN:
|
|
ShuttingDown_Exit(anEvent);
|
|
break;
|
|
case HIBERNATE:
|
|
Hibernate_Exit(anEvent);
|
|
break;
|
|
case STOPPING:
|
|
Stopping_Exit(anEvent);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|