472 lines
10 KiB
C++
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;
|
||
|
}
|