windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/upssvc/apcsmart/upsdev.cxx
2020-09-26 16:20:57 +08:00

472 lines
10 KiB
C++

/*
* pcy30Nov92 - Changed object.h to apcobj.h
* ane02DEC92 - fixed memory corruption problem by allocating more space to
* receive message from UPS
* sja09Dec92 - Will Work with windows now.
* sja10Dec92 - Allocates a proper Stream under windows now.
* pcy11Dec92 - Move Windows stuff out of here
* pcy14Dec92 - #include "cfgmgr.h"
* pcy14Dec92 - Fixed misplaced else due to comment
* pcy27Dec92: GlobalCommDevice can't be static
* jod29Dec92: Edited Retry();
* ane11Jan93: Edited Retry();
* jod13Jan93: Fixed Retry to add the NO_COMM event to the eventList
* ane25Jan93: Added extra error checking and returns on initialization
* jod28Jan93: Fixed the Data and Decrement Sets
* ane03Feb93: Changed error checking
* rct17May93: fixed include files
* cad10Jun93: Changes to allow MUps
* cad14Sep93: Cleaning up theState
* cad15Nov93: Changing how lost comm works
* cad17Nov93: .. more little fixups
* mwh19Nov93: changed EventID to INT
* rct21Dec93: fixed rebuild port - if the open fails, writes won't occur
* cad14Jan94: not including old global stuff
* rct21Dec93: fixed rebuildPort again - if the open fails, writes won't occur
* ajr08Mar94: added some error checking to rebuildPort.
* pcy10Mar94: Got rid of meaningless overides of Get and Set
* pcy08Apr94: Trim size, use static iterators, dead code removal
* pcy13Apr94: Use automatic variables decrease dynamic mem allocation
* cad17Jun94: Flushing UPS Input after retry succeeds, re-syncs conversation
* ajr12Jul94: The Flushing stuff broke BackUps. sendRetryMessage() should
* return true for Backups
* cgm28Feb96: Add override switch for nlm
* cgm04May96: TestResponse now uses BufferSize
* poc28Sep96: Added valuable debugging code.
* tjg10Nov97: Cancel the RetryTimer on RETRY_CONSTRUCT
*/
#include "cdefine.h"
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
}
#include "_defs.h"
#include "codes.h"
#include "apcobj.h"
#include "list.h"
#include "dispatch.h"
#include "comctrl.h"
#include "event.h"
#include "message.h"
#include "pollparm.h"
#include "ulinkdef.h"
#include "trans.h"
#include "protsmrt.h"
#include "cdevice.h"
#include "upsdev.h"
#include "cfgmgr.h"
#include "timerman.h"
#include "protlist.h"
#include "err.h"
#include "stream.h"
#if APCDEBUG
#include "errlogr.h"
#endif
#define UNKNOWN 0
#define RETRY_FAILED 1
#define RETRY_SUCCESS 0
#define ASKUPS_FAILED 1
#define ASKUPS_OK 0
#define RETRY_MAX 3
UpsCommDevice::UpsCommDevice(CommController* control)
: CommDevice(control),
theRetryTimer(0),
theForceCommEventFlag(FALSE),
theCableType(NORMAL)
{
CreateProtocol();
}
UpsCommDevice::~UpsCommDevice()
{
theController->UnregisterEvent(EXIT_THREAD_NOW, this);
if(theRetryTimer) {
_theTimerManager->CancelTimer(theRetryTimer);
theRetryTimer = 0;
}
}
INT UpsCommDevice::Initialize()
{
CHAR value[64], cable_type[10];
_theConfigManager->Get(CFG_UPS_POLL_INTERVAL, value);
thePollInterval = atoi(value);
INT err = rebuildPort();
if (err == ErrNO_ERROR)
{
Connect();
}
// Register here instead of in CommDevice::Initialize() - that method
// does things with the port we don't want to
theController->RegisterEvent(EXIT_THREAD_NOW, this);
return err;
}
/*--------------------------------------------------------------------
*
* Function...: Connect
*
* Description: Opens the device and make a comm connection.
*
*-------------------------------------------------------------------*/
INT UpsCommDevice::Connect()
{
if (!thePollThread) {
StartPollThread();
}
return ErrNO_ERROR;
}
INT UpsCommDevice::Get(INT pid, PCHAR value)
{
INT err = ErrNO_ERROR;
switch(pid) {
case COMMUNICATION_STATE:
sprintf(value, "%d", theLostCommFlag ?
COMMUNICATION_LOST : COMMUNICATION_ESTABLISHED);
break;
default:
err = CommDevice::Get(pid, value);
break;
}
return err;
}
INT UpsCommDevice::Set(INT pid, const PCHAR value)
{
INT err = ErrNO_ERROR;
switch(pid) {
case RETRY_CONSTRUCT:
if (theRetryTimer) {
_theTimerManager->CancelTimer(theRetryTimer);
theRetryTimer = 0;
}
theLostCommFlag = TRUE;
theForceCommEventFlag = TRUE;
_theTimerManager->Wait(2000L); // Allow On-going Operations to Stop
err = rebuildPort();
break;
default:
err = CommDevice::Set(pid, value);
break;
}
return err;
}
INT UpsCommDevice::sendRetryMessage()
{
INT done = FALSE;
if ( !(Set(TURN_ON_SMART_MODE, (CHAR*)NULL)) ) {
done = TRUE;
}
CHAR buf[128];
USHORT len = sizeof(buf);
//
// clearing out extra chars in the serial buffer
//
while (thePort->Read(buf, (USHORT *) &len, 500L) == ErrNO_ERROR);
return done;
}
/*--------------------------------------------------------------------
*
* Function...: Retry
*
* Description: .
*
*-------------------------------------------------------------------*/
INT UpsCommDevice::Retry()
{
INT index = 0;
if(theState != RETRYING) {
theState = RETRYING;
INT done = sendRetryMessage();
if (!done)
{
theLostCommFlag = TRUE;
Event event(COMMUNICATION_STATE, COMMUNICATION_LOST);
event.SetAttributeValue(FAILURE_CAUSE, COMMUNICATION_LOST);
theForceCommEventFlag = FALSE;
UpdateObj::Update(&event);
if (!theRetryTimer)
{
Event retry_event(RETRY_CONSTRUCT, RETRY_PORT);
theRetryTimer =_theTimerManager->SetTheTimer((ULONG)2,
&retry_event,
this);
}
return RETRY_FAILED;
}
theState = NORMAL_STATE;
}
return RETRY_SUCCESS;
}
INT UpsCommDevice::Update(PEvent anEvent)
{
INT err = ErrNO_ERROR;
switch(anEvent->GetCode())
{
case RETRY_CONSTRUCT:
theRetryTimer = 0;
err = rebuildPort();
break;
case EXIT_THREAD_NOW:
_theTimerManager->CancelTimer(theRetryTimer);
theRetryTimer = 0;
err = CommDevice::Update(anEvent);
break;
}
return err;
}
INT UpsCommDevice::rebuildPort()
{
if(thePort)
{
delete thePort;
thePort = (PStream)NULL;
}
INT err = CreatePort();
if (thePort) {
err = thePort->Initialize(); // don't reset this value !!!
}
INT have_comm = FALSE;
if (err == ErrNO_ERROR)
{
have_comm = sendRetryMessage();
}
if (!have_comm) {
// Toggle the cable type
if (theCableType == NORMAL) {
theCableType = PNP;
}
else {
theCableType = NORMAL;
}
}
if (have_comm)
{
theState = NORMAL_STATE;
theLostCommFlag = FALSE;
Event event(COMMUNICATION_STATE, COMMUNICATION_ESTABLISHED);
UpdateObj::Update(&event);
if (theCurrentTransaction == (PTransactionGroup)NULL)
{
theCurrentTransaction = (PTransactionGroup) thePollList->GetHead();
}
}
else
{
if (!theLostCommFlag || theForceCommEventFlag)
{
if (!theLostCommFlag)
{
theState = COMM_STOPPED;
theLostCommFlag = TRUE;
}
theForceCommEventFlag = FALSE;
Event event(COMMUNICATION_STATE, COMMUNICATION_LOST);
UpdateObj::Update(&event);
}
if ((!theRetryTimer) && (err == ErrNO_ERROR))
{
Event retry_event(RETRY_CONSTRUCT, RETRY_PORT);
theRetryTimer =_theTimerManager->SetTheTimer((ULONG)5, &retry_event,
this);
}
}
return err;
}
/*--------------------------------------------------------------------
*
* Function...: AskUps
*
* Description: .
*
*-------------------------------------------------------------------*/
INT UpsCommDevice::AskUps(Message* msg)
{
CHAR Buffer[512];
USHORT BufferSize = 0;
INT writecomplete = FALSE;
INT ret = ErrNO_ERROR;
//
// Clean out old errors
//
msg->setErrcode(ErrNO_ERROR);
if (!thePort)
{
return ret;
}
if (theAbortSem) {
theAbortSem->TimedWait(250);
}
while (!writecomplete) {
thePort->SetRequestCode(msg->getId());
thePort->SetWaitTime(msg->getWaitTime());
ret = thePort->Write(msg->getSubmit());
if (ret == ErrWRITE_FAILED)
{
if (!theLostCommFlag && Retry() )/* If RETY FAILED */
{
msg->setErrcode(ErrCOMMUNICATION_LOST);
return ASKUPS_OK; /* Return Ok-- Let */
} /* UPS do RESTART */
else
{
msg->setErrcode(ErrWRITE_FAILED);
return ASKUPS_FAILED;
}
}
else
writecomplete = TRUE;
}
*Buffer = 0;
BufferSize = 511;
INT readcomplete = FALSE;
ret = 0;
while (!readcomplete) {
int testRet;
ret = thePort->Read(Buffer, &BufferSize, (ULONG)msg->getTimeout());
if ((ret == ErrREAD_FAILED) && (testRet = theProtocol->TestResponse(msg,Buffer,BufferSize)) )
{
if (testRet == ErrNO_MEASURE_UPS)
{
msg->setErrcode(testRet);
return ASKUPS_OK;
}
else
{
if ( Retry() )
{ /* If RETRY FAILED */
msg->setErrcode(ErrCOMMUNICATION_LOST);
return ASKUPS_OK;/* Return Ok-- Let */
} /* UPS do RESTART */
else
{
msg->setErrcode(ErrREAD_FAILED);
return ASKUPS_FAILED;
}
}
}
else
{
readcomplete = TRUE;
}
}
Buffer[BufferSize] = '\0';
msg->setResponse(Buffer);
return ASKUPS_OK;
}
INT UpsCommDevice::CreateProtocol()
{
CHAR signal_type[64];
_theConfigManager->Get(CFG_UPS_SIGNALLING_TYPE, signal_type);
if(strcmp((_strupr(signal_type)), "SIMPLE") == 0) {
theProtocol = new SimpleUpsProtocol();
}
else {
CHAR protocol[32];
_theConfigManager->Get(CFG_UPS_PROTOCOL, protocol);
if(strcmp((_strupr(protocol)), "UPSLINK") == 0) {
theProtocol = new UpsLinkProtocol();
}
else if(strcmp((_strupr(protocol)), "GCIP") == 0) {
// theProtocol = new GcipProtocol();
}
else {
theProtocol = new SimpleUpsProtocol();
}
}
return TRUE;
}