/* Copyright 1999 American Power Conversion, All Rights Reserved * * Description: * Implements the UPS to the service - it does this by * either loading a UPS driver or by using the default * Generic UPS interface (simple signalling) * * Revision History: * mholly 19Apr1999 initial revision. * dsmith 29Apr1999 defaulted comm status to OK * mholly 12May1999 DLL's UPSInit no longer takes the comm port param * sberard 17May1999 added a delay to the UPSTurnOffFunction * */ #include #include #include "driver.h" #include "upsreg.h" #include "gnrcups.h" // // typedefs of function pointers to aid in // accessing functions from driver DLLs // typedef DWORD (*LPFUNCGETUPSSTATE)(void); typedef void (*LPFUNCWAITFORSTATECHANGE)(DWORD, DWORD); typedef void (*LPFUNCCANCELWAIT)(void); typedef DWORD (*LPFUNCINIT)(void); typedef void (*LPFUNCSTOP)(void); typedef void (*LPFUNCTURNUPSOFF)(DWORD); // // UPSDRIVERINTERFACE // // this struct is used to gather all the driver // interface data together in a single place, this // struct is used to dispatch function calls to // either a loaded driver dll, or to the Generic // UPS interface functions // struct UPSDRIVERINTERFACE { LPFUNCINIT Init; LPFUNCSTOP Stop; LPFUNCGETUPSSTATE GetUPSState; LPFUNCWAITFORSTATECHANGE WaitForStateChange; LPFUNCCANCELWAIT CancelWait; LPFUNCTURNUPSOFF TurnUPSOff; HINSTANCE hDll; }; // // private functions used to implement the interface // static DWORD initializeGenericInterface(struct UPSDRIVERINTERFACE*); static DWORD initializeDriverInterface(struct UPSDRIVERINTERFACE*,HINSTANCE); static DWORD loadUPSMiniDriver(struct UPSDRIVERINTERFACE *); static void unloadUPSMiniDriver(struct UPSDRIVERINTERFACE *); static void clearStatusRegistryEntries(void); // // _UpsInterface // // This is a file-scope variable that is used by all // the functions to get access to the actual driver // static struct UPSDRIVERINTERFACE _UpsInterface; /** * UPSInit * * Description: * * The UPSInit function must be called before any * other function in this file * * Parameters: * None * * Returns: * UPS_INITOK: Initalization was successful * UPS_INITNOSUCHDRIVER: The configured driver DLL can't be opened * UPS_INITBADINTERFACE: The configured driver DLL doesn't support * the UPS driver interface * UPS_INITREGISTRYERROR: The 'Options' registry value is corrupt * UPS_INITCOMMOPENERROR: The comm port could not be opened * UPS_INITCOMMSETUPERROR: The comm port could not be configured * UPS_INITUNKNOWNERROR: Undefined error has occurred * */ DWORD UPSInit(void) { DWORD init_err = UPS_INITOK; // // clear out any old status data // clearStatusRegistryEntries(); if (UPS_INITOK == init_err) { // // either load a configured driver DLL or // use the Generic UPS interface if no driver // is specified // init_err = loadUPSMiniDriver(&_UpsInterface); } if ((UPS_INITOK == init_err) && (_UpsInterface.Init)) { // // tell the UPS interface to initialize itself // init_err = _UpsInterface.Init(); } return init_err; } /** * UPSStop * * Description: * After a call to UPSStop, only the UPSInit * function is valid. This call will unload the * UPS driver interface and stop monitoring of the * UPS system * * Parameters: * None * * Returns: * None * */ void UPSStop(void) { if (_UpsInterface.Stop) { _UpsInterface.Stop(); } unloadUPSMiniDriver(&_UpsInterface); } /** * UPSWaitForStateChange * * Description: * Blocks until the state of the UPS differs * from the value passed in via aState or * anInterval milliseconds has expired. If * anInterval has a value of INFINITE this * function will never timeout * * Parameters: * aState: defines the state to wait for a change from, * possible values: * UPS_ONLINE * UPS_ONBATTERY * UPS_LOWBATTERY * UPS_NOCOMM * * anInterval: timeout in milliseconds, or INFINITE for * no timeout interval * * Returns: * None * */ void UPSWaitForStateChange(DWORD aCurrentState, DWORD anInterval) { if (_UpsInterface.WaitForStateChange) { _UpsInterface.WaitForStateChange(aCurrentState, anInterval); } } /** * UPSGetState * * Description: * returns the current state of the UPS * * Parameters: * None * * Returns: * possible values: * UPS_ONLINE * UPS_ONBATTERY * UPS_LOWBATTERY * UPS_NOCOMM * */ DWORD UPSGetState(void) { DWORD err = ERROR_INVALID_ACCESS; if (_UpsInterface.GetUPSState) { err = _UpsInterface.GetUPSState(); } return err; } /** * UPSCancelWait * * Description: * interrupts pending calls to UPSWaitForStateChange * without regard to timout or state change * * Parameters: * None * * Returns: * None * */ void UPSCancelWait(void) { if (_UpsInterface.CancelWait) { _UpsInterface.CancelWait(); } } /** * UPSTurnOff * * Description: * Attempts to turn off the outlets on the UPS * after the specified delay. This call must * return immediately. Any work, such as a timer, * must be performed on a another thread. * * Parameters: * aTurnOffDelay: the minimum amount of time to wait before * turning off the outlets on the UPS * * Returns: * None * */ void UPSTurnOff(DWORD aTurnOffDelay) { if (_UpsInterface.TurnUPSOff) { _UpsInterface.TurnUPSOff(aTurnOffDelay); } } /** * initializeGenericInterface * * Description: * Fills in the UPSDRIVERINTERFACE struct with the functions * of the Generic UPS interface * * Parameters: * anInterface: the UPSDRIVERINTERFACE structure to * fill in - the struct must have been * allocated prior to calling this function * * Returns: * ERROR_SUCCESS * */ DWORD initializeGenericInterface(struct UPSDRIVERINTERFACE* anInterface) { anInterface->hDll = NULL; anInterface->Init = GenericUPSInit; anInterface->Stop = GenericUPSStop; anInterface->GetUPSState = GenericUPSGetState; anInterface->WaitForStateChange = GenericUPSWaitForStateChange; anInterface->CancelWait = GenericUPSCancelWait; anInterface->TurnUPSOff = GenericUPSTurnOff; return ERROR_SUCCESS; } /** * initializeDriverInterface * * Description: * Fills in the UPSDRIVERINTERFACE struct with the functions * of the loaded UPS driver DLL * * Parameters: * anInterface: the UPSDRIVERINTERFACE structure to * fill in - the struct must have been * allocated prior to calling this function * hDll: a handle to a UPS driver DLL * * Returns: * ERROR_SUCCESS: DLL handle was valid, and the DLL supports the * UPS driver interface * * !ERROR_SUCCESS: either the DLL handle is invalid - or the DLL * does not fully support the UPS driver interface * */ DWORD initializeDriverInterface(struct UPSDRIVERINTERFACE * anInterface, HINSTANCE hDll) { DWORD err = ERROR_SUCCESS; anInterface->hDll = hDll; anInterface->Init = (LPFUNCINIT)GetProcAddress(hDll, "UPSInit"); if (!anInterface->Init) { err = GetLastError(); goto init_driver_end; } anInterface->Stop = (LPFUNCSTOP)GetProcAddress(hDll, "UPSStop"); if (!anInterface->Stop) { err = GetLastError(); goto init_driver_end; } anInterface->GetUPSState = (LPFUNCGETUPSSTATE)GetProcAddress(hDll, "UPSGetState"); if (!anInterface->GetUPSState) { err = GetLastError(); goto init_driver_end; } anInterface->WaitForStateChange = (LPFUNCWAITFORSTATECHANGE)GetProcAddress(hDll, "UPSWaitForStateChange"); if (!anInterface->WaitForStateChange) { err = GetLastError(); goto init_driver_end; } anInterface->CancelWait = (LPFUNCCANCELWAIT)GetProcAddress(hDll, "UPSCancelWait"); if (!anInterface->CancelWait) { err = GetLastError(); goto init_driver_end; } anInterface->TurnUPSOff = (LPFUNCTURNUPSOFF)GetProcAddress(hDll, "UPSTurnOff"); if (!anInterface->TurnUPSOff) { err = GetLastError(); goto init_driver_end; } init_driver_end: return err; } /** * loadUPSMiniDriver * * Description: * Fills in the UPSDRIVERINTERFACE struct with the functions * of a UPS interface, either a configured driver DLL or the * Generic UPS interface. If the configured DLL can't be * opened or does not support the interface then an error is * returned and the UPSDRIVERINTERFACE will not be initialized * * Parameters: * anInterface: the UPSDRIVERINTERFACE structure to * fill in - the struct must have been * allocated prior to calling this function * * Returns: * UPS_INITOK: driver interface is intialized * * UPS_INITNOSUCHDRIVER: the configured driver DLL can't be opened * UPS_INITBADINTERFACE: the configured driver DLL does not * fully support the UPS driver interface * */ DWORD loadUPSMiniDriver(struct UPSDRIVERINTERFACE * aDriverInterface) { DWORD load_err = UPS_INITOK; DWORD err = ERROR_SUCCESS; TCHAR driver_name[MAX_PATH]; HINSTANCE hDll = NULL; err = GetUPSConfigServiceDLL(driver_name, MAX_PATH); // // check to see if there is a key, and that its // value is valid (a valid key has a value that // is greater than zero characters long) // if (ERROR_SUCCESS == err && _tcslen(driver_name)) { hDll = LoadLibrary(driver_name); } else { // // NO ERROR - simply means we use the // internal generic UPS support // err = initializeGenericInterface(aDriverInterface); goto load_end; } if (!hDll) { // // the configured driver could not be opened // err = GetLastError(); load_err = UPS_INITNOSUCHDRIVER; goto load_end; } err = initializeDriverInterface(aDriverInterface, hDll); if (ERROR_SUCCESS != err) { load_err = UPS_INITBADINTERFACE; goto load_end; } load_end: return load_err; } /** * unloadUPSMiniDriver * * Description: * unloads a driver DLL if one was opened, also clears * out the function dispatch pointers * * Parameters: * anInterface: the UPSDRIVERINTERFACE structure to * check for DLL info, and to clear * * Returns: * None * */ void unloadUPSMiniDriver(struct UPSDRIVERINTERFACE * aDriverInterface) { if (aDriverInterface) { if (aDriverInterface->hDll) { FreeLibrary(aDriverInterface->hDll); aDriverInterface->hDll = NULL; } aDriverInterface->CancelWait = NULL; aDriverInterface->GetUPSState = NULL; aDriverInterface->Init = NULL; aDriverInterface->Stop = NULL; aDriverInterface->TurnUPSOff = NULL; aDriverInterface->WaitForStateChange = NULL; } } /** * clearStatusRegistryEntries * * Description: * zeros out the registry status entries * * Parameters: * None * * Returns: * None * */ void clearStatusRegistryEntries(void) { InitUPSStatusBlock(); SetUPSStatusSerialNum(_TEXT("")); SetUPSStatusFirmRev(_TEXT("")); SetUPSStatusUtilityStatus(UPS_UTILITYPOWER_UNKNOWN); SetUPSStatusRuntime(0); SetUPSStatusBatteryStatus(UPS_BATTERYSTATUS_UNKNOWN); SetUPSStatusCommStatus(UPS_COMMSTATUS_OK); SaveUPSStatusBlock(TRUE); }