diff --git a/MAC/APL/MainCU/src/MACScheduler/ChildControl.cc b/MAC/APL/MainCU/src/MACScheduler/ChildControl.cc index a64a502e986cbaaecb500b103813da1228a0e161..e12187d34dd7da656846715b8e5f8b91f4fa7146 100644 --- a/MAC/APL/MainCU/src/MACScheduler/ChildControl.cc +++ b/MAC/APL/MainCU/src/MACScheduler/ChildControl.cc @@ -30,7 +30,7 @@ #include <GCF/GCF_ServiceInfo.h> #include <GCF/Utils.h> #include <APL/APLCommon/APLUtilities.h> -#include <APL/APLCommon/LogicalDevice_Protocol.ph> +#include <APL/APLCommon/Controller_Protocol.ph> #include <APL/APLCommon/StartDaemon_Protocol.ph> namespace LOFAR { @@ -61,11 +61,13 @@ ChildControl::ChildControl() : itsStartupRetryInterval (10), itsMaxStartupRetries (5), itsCntlrList (), - itsActionList () + itsActionList (), + itsCompletionTimer (0), + itsCompletionPort (0) { // Log the protocols I use. - registerProtocol(LOGICALDEVICE_PROTOCOL, LOGICALDEVICE_PROTOCOL_signalnames); - registerProtocol(STARTDAEMON_PROTOCOL, STARTDAEMON_PROTOCOL_signalnames); + registerProtocol(CONTROLLER_PROTOCOL, CONTROLLER_PROTOCOL_signalnames); + registerProtocol(STARTDAEMON_PROTOCOL,STARTDAEMON_PROTOCOL_signalnames); // adopt optional redefinition of startup-retry settings if (globalParameterSet()->isDefined("ChildControl.StartupRetryInterval")) { @@ -127,11 +129,12 @@ void ChildControl::openService(const string& aServiceName, } // -// startChild (name, obsId, aCntlType, hostname) +// startChild (name, obsId, aCntlType, instanceNr, hostname) // bool ChildControl::startChild (const string& aName, OTDB::treeIDType anObsID, const string& aCntlrType, + uint32 instanceNr, const string& hostname) { // first check if child already exists @@ -139,10 +142,41 @@ bool ChildControl::startChild (const string& aName, return (false); } + // make sure there is a parameterSet for the program. + if (aCntlrType != CNTLRTYPE_OBSERVATIONCTRL) { + // search observation-parset for controller name and determine prefix + string baseSetName = formatString("%s/Observation_%d", + LOFAR_SHARE_LOCATION, anObsID); + LOG_DEBUG_STR ("Reading parameterfile: " << baseSetName); + ParameterSet wholeSet (baseSetName); + ParameterSet::iterator iter = wholeSet.begin(); + ParameterSet::iterator end = wholeSet.end(); + while (iter != end) { + // search a parameter that is meant for this controller + // to determine the position of the controller in the tree. + if (keyName(moduleName(iter->first)) == aName) { + string cntlrSetName = formatString("%s/%s", LOFAR_SHARE_LOCATION, + aName.c_str()); + LOG_DEBUG_STR("Creating parameterfile: " << cntlrSetName); + ParameterSet cntlrSet = wholeSet.makeSubset(moduleName(iter->first)); + cntlrSet.add("prefix", moduleName(iter->first)); + cntlrSet.writeFile (cntlrSetName); + break; + } + iter++; + } + if (iter == end) { // could not create a parameterset, report failure. + LOG_ERROR_STR("No parameter information found for controller " << aName << + " in file " << baseSetName << ". Cannot start controller!"); + return (false); + } + } + // Alright, child does not exist yet. // construct structure with all information ControllerInfo ci; ci.name = aName; + ci.instanceNr = instanceNr; ci.obsID = anObsID; ci.cntlrType = aCntlrType; ci.port = 0; @@ -182,7 +216,7 @@ bool ChildControl::requestState (LDState::LDstateNr aState, { bool checkName = (aName != ""); bool checkID = (anObsID != 0); - bool checkType = (aCntlrType != LDTYPE_NO_TYPE); + bool checkType = (aCntlrType != CNTLRTYPE_NO_TYPE); time_t currentTime = time(0); // stateChangeEvent request; @@ -253,7 +287,7 @@ uint32 ChildControl::countChilds (OTDB::treeIDType anObsID, const string& aCntlrType) { bool checkID = (anObsID != 0); - bool checkType = (aCntlrType != LDTYPE_NO_TYPE); + bool checkType = (aCntlrType != CNTLRTYPE_NO_TYPE); if (!checkID && !checkType) { return (itsCntlrList.size()); @@ -290,7 +324,7 @@ ChildControl::getPendingRequest (const string& aName, bool checkName = (aName != ""); bool checkID = (anObsID != 0); - bool checkType = (aCntlrType != LDTYPE_NO_TYPE); + bool checkType = (aCntlrType != CNTLRTYPE_NO_TYPE); const_CIiter iter = itsCntlrList.begin(); const_CIiter end = itsCntlrList.end(); @@ -316,6 +350,37 @@ ChildControl::getPendingRequest (const string& aName, return (resultVec); } +// +// getCompletedStates (lastPollTime) +// +// Returns a vector with all requests that are completed since lastPollTime +// +vector<ChildControl::StateInfo> +ChildControl::getCompletedStates (time_t lastPollTime) +{ + vector<ChildControl::StateInfo> resultVec; + + const_CIiter iter = itsCntlrList.begin(); + const_CIiter end = itsCntlrList.end(); + while (iter != end) { + if (iter->establishTime > lastPollTime) { + // add info to vector + StateInfo si; + si.name = iter->name; + si.cntlrType = iter->cntlrType; + si.isConnected = (iter->port != 0); + si.requestedState = iter->requestedState; + si.requestTime = iter->requestTime; + si.currentState = iter->currentState; + si.establishTime = iter->establishTime; + resultVec.push_back(si); + } + iter++; + } + + return (resultVec); +} + // -------------------- PRIVATE ROUTINES -------------------- // @@ -402,18 +467,19 @@ void ChildControl::_processActionList() LOG_DEBUG_STR("Requesting start of " << action->name << " at " << action->hostname); STARTDAEMONCreateEvent startRequest; - startRequest.logicalDeviceType = action->cntlrType; - startRequest.taskName = action->name; - startRequest.parentHost = GCF::Common::myHostname(); - startRequest.parentService = itsListener->makeServiceName(); + startRequest.cntlrType = action->cntlrType; + startRequest.cntlrName = action->name; + startRequest.parentHost = GCF::Common::myHostname(); + startRequest.parentService = itsListener->makeServiceName(); startDaemon->second->send(startRequest); - // we don't know if startup is successfull, reschedule startup - // over x seconds for safety. Note: when a succesfull startup + // we don't know if startup is successful, reschedule startup + // over x seconds for safety. Note: when a successful startup // is received the rescheduled action is removed. - action->retryTime = time(0) + itsStartupRetryInterval; - action->nrRetries++; - itsActionList.push_back(*action); // reschedule +// action->retryTime = time(0) + itsStartupRetryInterval; +// action->nrRetries++; +// itsActionList.push_back(*action); // reschedule +// ... Parent is responsible for rescheduling! ... } else { LOG_WARN_STR ("Could not start controller " << action->name << @@ -425,28 +491,32 @@ void ChildControl::_processActionList() case LDState::CLAIMED: { - LOGICALDEVICEClaimEvent request; + CONTROLClaimEvent request; + request.cntlrName = controller->name; controller->port->send(request); } break; case LDState::PREPARED: { - LOGICALDEVICEPrepareEvent request; + CONTROLPrepareEvent request; + request.cntlrName = controller->name; controller->port->send(request); } break; case LDState::ACTIVE: { - LOGICALDEVICEResumeEvent request; + CONTROLResumeEvent request; + request.cntlrName = controller->name; controller->port->send(request); } break; case LDState::SUSPENDED: { - LOGICALDEVICESuspendEvent request; + CONTROLSuspendEvent request; + request.cntlrName = controller->name; controller->port->send(request); } break; @@ -454,7 +524,8 @@ void ChildControl::_processActionList() case LDState::RELEASED: case LDState::FINISHED: { - LOGICALDEVICEReleaseEvent request; + CONTROLReleaseEvent request; + request.cntlrName = controller->name; controller->port->send(request); } break; @@ -498,7 +569,8 @@ void ChildControl::_removeAction (const string& aName, // void ChildControl::_setEstablishedState(const string& aName, LDState::LDstateNr newState, - time_t atTime) + time_t atTime, + bool successful) { CIiter controller = findController(aName); if (controller == itsCntlrList.end()) { @@ -506,8 +578,84 @@ void ChildControl::_setEstablishedState(const string& aName, return; } - controller->currentState = newState; + // update controller information + if (!(controller->failed = !successful)) {; + controller->currentState = newState; + } controller->establishTime = atTime; + + if (itsCompletionTimer) { + itsCompletionTimer->setTimer(0.0); + } + + if (!itsCompletionPort) { + return; + } + + LOG_DEBUG_STR("newState=" << newState); + + TLDResult result = controller->failed ? LD_RESULT_UNSPECIFIED : LD_RESULT_NO_ERROR; + switch (newState) { + case LDState::CREATED: { + CONTROLStartedEvent msg; + msg.cntlrName = controller->name; + msg.successful= successful; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::CONNECTED: { + CONTROLConnectedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::CLAIMED: { + CONTROLClaimedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::PREPARED: { + CONTROLPreparedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::ACTIVE: { + CONTROLResumedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::SUSPENDED: { + CONTROLSuspendedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::RELEASED: { + CONTROLReleasedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + case LDState::FINISHED: { + CONTROLFinishedEvent msg; + msg.cntlrName = controller->name; + msg.result = result; + itsCompletionPort->sendBack(msg); + } + break; + default: + // do nothing + break; + } } // -------------------- STATE MACHINES FOR GCFTASK -------------------- @@ -542,6 +690,7 @@ GCFEvent::TResult ChildControl::initial (GCFEvent& event, break; case F_DISCONNECTED: + port.close(); if (&port == itsListener) { port.setTimer(1.0); } @@ -556,7 +705,7 @@ GCFEvent::TResult ChildControl::initial (GCFEvent& event, break; default: - LOG_DEBUG_STR ("ChildControl(" << getName() << ")::initial, default"); + LOG_DEBUG ("ChildControl::initial, default"); status = GCFEvent::NOT_HANDLED; break; } @@ -574,7 +723,8 @@ GCFEvent::TResult ChildControl::operational(GCFEvent& event, GCFPortInterface& port) { - LOG_DEBUG ("ChildControl::operational"); + LOG_DEBUG_STR ("ChildControl::operational:" << evtstr(event) + << "@" << port.getName()); GCFEvent::TResult status = GCFEvent::HANDLED; @@ -587,14 +737,12 @@ GCFEvent::TResult ChildControl::operational(GCFEvent& event, case F_ACCEPT_REQ: { // Should be from a just started Child. - ASSERTSTR(port.getProtocol() == LOGICALDEVICE_PROTOCOL, - "AcceptReq on port " << port.getName()); - // accept connection and add port to port-vector GCFTCPPort* client(new GCFTCPPort); + // reminder: init (task, name, type, protocol [,raw]) client->init(*this, "newChild", GCFPortInterface::SPP, - LOGICALDEVICE_PROTOCOL); + CONTROLLER_PROTOCOL); itsListener->accept(*client); // Note: we do not keep an administration of the accepted child @@ -607,6 +755,8 @@ GCFEvent::TResult ChildControl::operational(GCFEvent& event, break; case F_DISCONNECTED: { + port.close(); // always close port + CIiter controller = itsCntlrList.begin(); CIiter end = itsCntlrList.end(); while (controller != end) { @@ -617,8 +767,7 @@ GCFEvent::TResult ChildControl::operational(GCFEvent& event, } // found controller, close port - port.close(); - if (controller->currentState == LDState::FINISHED) { // expected disconnect? + if (controller->currentState == LDState::FINISHED) {// expected disconnect? itsCntlrList.erase(controller); // just remove } else { @@ -638,31 +787,28 @@ GCFEvent::TResult ChildControl::operational(GCFEvent& event, case STARTDAEMON_CREATED: // startDaemon reports startup of program { STARTDAEMONCreatedEvent result(event); - LOG_DEBUG_STR("Startup of " << result.taskName << "ready, result=" + LOG_DEBUG_STR("Startup of " << result.cntlrName << " ready, result=" << result.result); - if (result.result == SD_RESULT_NO_ERROR) { - // startup is successfull, remove rescheduled startup. - _removeAction(result.taskName, LDState::CONNECTED); - } - // note: when startup of child failed the state is not updated and the - // parent will discover this when checking the pending requests. + _setEstablishedState(result.cntlrName, LDState::CREATED, time(0), + result.result == SD_RESULT_NO_ERROR); } break; - case LOGICALDEVICE_CONNECT: + case CONTROL_CONNECT: // received from just started controller { - LOGICALDEVICEConnectEvent msg(event); - LOGICALDEVICEConnectedEvent answer; + CONTROLConnectEvent msg(event); + CONTROLConnectedEvent answer; - CIiter controller = findController(msg.nodeId); + CIiter controller = findController(msg.cntlrName); if (controller == itsCntlrList.end()) { // not found? LOG_WARN_STR ("CONNECT event received from unknown controller: " << - msg.nodeId); + msg.cntlrName); answer.result = LD_RESULT_UNSPECIFIED; } else { - LOG_DEBUG_STR("CONNECT event received from " << msg.nodeId); - _setEstablishedState(msg.nodeId, LDState::CONNECTED, time(0)); + LOG_DEBUG_STR("CONNECT event received from " << msg.cntlrName); + _setEstablishedState(msg.cntlrName, LDState::CONNECTED, time(0), true); + // first direct contact with controller, remember port controller->port = &port; answer.result = LD_RESULT_NO_ERROR; } @@ -670,8 +816,27 @@ GCFEvent::TResult ChildControl::operational(GCFEvent& event, } break; + case CONTROL_CLAIMED: + break; + + case CONTROL_PREPARED: + break; + + case CONTROL_RESUMED: + break; + + case CONTROL_SUSPENDED: + break; + + case CONTROL_RELEASED: + break; + + case CONTROL_FINISH: + break; + + default: - LOG_DEBUG_STR ("ChildControl(" << getName() << ")::operational, default"); + LOG_DEBUG ("ChildControl::operational, default"); status = GCFEvent::NOT_HANDLED; break; } diff --git a/MAC/APL/MainCU/src/MACScheduler/ChildControl.h b/MAC/APL/MainCU/src/MACScheduler/ChildControl.h index f26d04ee24dc6787e0513ea4daa58f7775a0ffe1..332915cf399cc6740d04f51430deaf8fae041cb9 100644 --- a/MAC/APL/MainCU/src/MACScheduler/ChildControl.h +++ b/MAC/APL/MainCU/src/MACScheduler/ChildControl.h @@ -32,7 +32,9 @@ #include <Common/lofar_map.h> #include <Common/lofar_list.h> #include <GCF/TM/GCF_Task.h> +#include <GCF/TM/GCF_ITCPort.h> #include <GCF/TM/GCF_TCPPort.h> +#include <GCF/TM/GCF_TimerPort.h> #include <APL/APLCommon/APL_Defines.h> #include <OTDB/OTDBtypes.h> #include "LDState.h" @@ -44,6 +46,8 @@ namespace LOFAR { using GCF::TM::GCFEvent; using GCF::TM::GCFTask; using GCF::TM::GCFPortInterface; + using GCF::TM::GCFITCPort; + using GCF::TM::GCFTimerPort; using APLCommon::LDState; namespace MainCU { @@ -72,6 +76,7 @@ public: time_t requestTime; // time of requested state LDState::LDstateNr currentState; // currrent (known) state of the controller time_t establishTime; // time this state was reached + bool failed; // the requested state could not be reached } StateInfo; // Assign a name to the service the task should offer to the childs @@ -82,21 +87,33 @@ public: bool startChild (const string& aName, OTDB::treeIDType anObsID, const string& aCntlrType, + uint32 instanceNr = 0, const string& hostname = "localhost"); bool requestState (LDState::LDstateNr state, const string& aName, OTDB::treeIDType anObsID = 0, - const string& aCntlrType = LDTYPE_NO_TYPE); + const string& aCntlrType = CNTLRTYPE_NO_TYPE); uint32 countChilds (OTDB::treeIDType anObsID = 0, - const string& aCntlrType = LDTYPE_NO_TYPE); + const string& aCntlrType = CNTLRTYPE_NO_TYPE); LDState::LDstateNr getCurrentState (const string& aName); LDState::LDstateNr getRequestedState (const string& aName); // management info for creator of class. - vector<StateInfo> getPendingRequest (const string& aName, - OTDB::treeIDType anObsID = 0, - const string& aCntlrType = LDTYPE_NO_TYPE); + vector<StateInfo> getPendingRequest (const string& aName, + OTDB::treeIDType anObsID = 0, + const string& aCntlrType = CNTLRTYPE_NO_TYPE); + + // The 'parent' task that uses this ChildControl class has three way of getting + // informed about the completed actions: + // [A] call getCompletedStates at regular intervals. + // [B] call setCompletionTimer once and call getCompletedStates when timer expires + // [C] call setCompletionPort once and handle the CONTROL events on that port. + vector<StateInfo> getCompletedStates (time_t lastPollTime); + void registerCompletionTimer (GCFTimerPort* theTimerPort) + { itsCompletionTimer = theTimerPort; } + void registerCompletionPort (GCFITCPort* theITCPort) + { itsCompletionPort = theITCPort; } private: // Copying is not allowed @@ -112,13 +129,15 @@ private: void _processActionList(); void _setEstablishedState (const string& aName, LDState::LDstateNr newState, - time_t atTime); + time_t atTime, + bool successful); void _removeAction (const string& aName, LDState::LDstateNr requestedState); // Define struct for administration of the child controllers. typedef struct ControllerInfo_t { string name; // uniq name of the controller + uint32 instanceNr; // for nonshared controllers OTDB::treeIDType obsID; // observation tree the cntlr belongs to GCFPortInterface* port; // connection with the controller string cntlrType; // type of controller (mnemonic) @@ -127,6 +146,7 @@ private: time_t requestTime; // time of requested state LDState::LDstateNr currentState; // the state the controller has time_t establishTime; // time the current state was reached + bool failed; // requested state could not be reached time_t retryTime; // time the request must be retried uint32 nrRetries; // nr of retries performed } ControllerInfo; @@ -143,13 +163,15 @@ private: uint32 itsStartupRetryInterval; uint32 itsMaxStartupRetries; - list<ControllerInfo> itsCntlrList; // administration of child controller + list<ControllerInfo> itsCntlrList; // admin. of child controllers // All actions from the parent task are queued as ControllerInfo objects // and handled in the operational stateMachine. list<ControllerInfo> itsActionList; // list of actions to perform. uint32 itsActionTimer; // ID of actiontimer. + GCFTimerPort* itsCompletionTimer; // to signal parent in situation B + GCFITCPort* itsCompletionPort; // to signal parent in situation C // ... }; diff --git a/MAC/APL/MainCU/src/MACScheduler/LDState.cc b/MAC/APL/MainCU/src/MACScheduler/LDState.cc index fdf0cbdd3c0ae3531d3fd07836ff2b059ae2b658..7eaad2b716fb22f8d36100b5984b738e2937cfb7 100644 --- a/MAC/APL/MainCU/src/MACScheduler/LDState.cc +++ b/MAC/APL/MainCU/src/MACScheduler/LDState.cc @@ -37,6 +37,7 @@ LDState::LDState() { itsStates.resize(LAST_STATE); itsStates[NOSTATE] = "Unknown"; + itsStates[CREATED] = "Created"; itsStates[CONNECT] = "Connecting"; itsStates[CONNECTED] = "Connected"; itsStates[CLAIM] = "Claiming"; @@ -64,8 +65,7 @@ LDState::~LDState() // string LDState::name(uint16 aStateNr) { - return (((aStateNr >= NOSTATE) && (aStateNr < LAST_STATE)) ? - itsStates[aStateNr] : ""); + return ((aStateNr < LAST_STATE) ? itsStates[aStateNr] : ""); } // diff --git a/MAC/APL/MainCU/src/MACScheduler/LDState.h b/MAC/APL/MainCU/src/MACScheduler/LDState.h index 0bba6a1eabebd8e6e1725ca272f68dd4e02e0360..a32f85482373ff1049719819efc23534b2c42b0c 100644 --- a/MAC/APL/MainCU/src/MACScheduler/LDState.h +++ b/MAC/APL/MainCU/src/MACScheduler/LDState.h @@ -51,6 +51,7 @@ public: typedef enum { ANYSTATE = -1, NOSTATE = 0, + CREATED, CONNECT, CONNECTED, CLAIM, diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc index 67321093b59e1899a83a46a5622960826ef8a168..5e155ac56f41a78427f839ee4ef7e486de9ec4dd 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc +++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc @@ -30,6 +30,7 @@ #include <GCF/Utils.h> #include <APL/APLCommon/APL_Defines.h> #include <APL/APLCommon/APLCommonExceptions.h> +#include <APL/APLCommon/Controller_Protocol.ph> #include "MACSchedulerDefines.h" #include "MACScheduler.h" @@ -56,6 +57,7 @@ MACScheduler::MACScheduler() : // itsObsCntlrMap (), itsDummyPort (0), itsChildControl (0), + itsChildPort (0), itsSecondTimer (0), itsQueuePeriod (0), itsClaimPeriod (0), @@ -65,17 +67,17 @@ MACScheduler::MACScheduler() : { LOG_TRACE_OBJ ("MACscheduler construction"); -#ifndef USE_PVSSPORT - LOG_WARN("Using GCFTCPPort in stead of GCFPVSSPort"); -#endif - // Readin some parameters from the ParameterSet. itsOTDBpollInterval = globalParameterSet()->getTime("OTDBpollInterval"); itsQueuePeriod = globalParameterSet()->getTime("QueuePeriod"); itsClaimPeriod = globalParameterSet()->getTime("ClaimPeriod"); - // get pointer to childcontrol task + // attach to child control task itsChildControl = ChildControl::instance(); + itsChildPort = new GCFITCPort (*this, *itsChildControl, "childITCport", + GCFPortInterface::SAP, CONTROLLER_PROTOCOL); + ASSERTSTR(itsChildPort, "Cannot allocate ITCport for childcontrol"); + itsChildPort->open(); // will result in F_CONNECTED } @@ -164,17 +166,15 @@ void MACScheduler::handlePropertySetAnswer(GCFEvent& answer) // GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& /*port*/) { - LOG_DEBUG ("MACScheduler::initial_state"); + LOG_DEBUG_STR ("MACScheduler::initial_state:" << evtstr(event)); GCFEvent::TResult status = GCFEvent::HANDLED; switch (event.signal) { case F_INIT: - LOG_TRACE_FLOW("initial_state:F_INIT"); break; case F_ENTRY: { - LOG_TRACE_FLOW("initial_state:F_ENTRY"); // Get access to my own propertyset. LOG_DEBUG ("Activating PropertySet"); itsPropertySet = GCFMyPropertySetPtr(new GCFMyPropertySet(MS_PROPSET_NAME, @@ -210,13 +210,14 @@ GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& // Start ChildControl task LOG_DEBUG ("Enabling ChildControltask"); itsChildControl->openService(MAC_SVCMASK_SCHEDULERCTRL, 0); + itsChildControl->registerCompletionPort(itsChildPort); // need port for timers(!) itsDummyPort = new GCFTimerPort(*this, "MACScheduler:dummy4timers"); TRAN(MACScheduler::recover_state); // go to next state. } break; -#if 0 + case F_CONNECTED: break; @@ -225,9 +226,9 @@ GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& case F_TIMER: break; -#endif + default: - LOG_DEBUG_STR ("MACScheduler(" << getName() << ")::initial_state, default"); + LOG_DEBUG ("MACScheduler::initial, default"); status = GCFEvent::NOT_HANDLED; break; } @@ -243,7 +244,8 @@ GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& // GCFEvent::TResult MACScheduler::recover_state(GCFEvent& event, GCFPortInterface& port) { - LOG_DEBUG ("MACScheduler::recover_state"); + LOG_DEBUG_STR ("MACScheduler::recover_state:" << evtstr(event) + << "@" << port.getName()); GCFEvent::TResult status = GCFEvent::HANDLED; @@ -265,7 +267,7 @@ GCFEvent::TResult MACScheduler::recover_state(GCFEvent& event, GCFPortInterface& } default: - LOG_DEBUG(formatString("MACScheduler(%s)::recover_state, default",getName().c_str())); + LOG_DEBUG("MACScheduler::recover_state, default"); status = GCFEvent::NOT_HANDLED; break; } @@ -280,7 +282,8 @@ GCFEvent::TResult MACScheduler::recover_state(GCFEvent& event, GCFPortInterface& // GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface& port) { - LOG_DEBUG ("MACScheduler::active_state"); + LOG_DEBUG_STR ("MACScheduler::active:" << evtstr(event) + << "@" << port.getName()); GCFEvent::TResult status = GCFEvent::HANDLED; @@ -335,21 +338,28 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface& break; } - case LOGICALDEVICE_SCHEDULED: { - LOGICALDEVICEScheduledEvent scheduledEvent(event); - // ... + case CONTROL_STARTED: { + CONTROLStartedEvent msg(event); + if (msg.successful) { + LOG_DEBUG_STR("Start of " << msg.cntlrName << " was successful"); + } + else { + LOG_ERROR_STR("Observation controller " << msg.cntlrName << + " could n ot be started"); + } + // TODO: do something usefull with this information! break; } - - case LOGICALDEVICE_SCHEDULECANCELLED: { - LOGICALDEVICESchedulecancelledEvent schedulecancelledEvent(event); + case CONTROL_CONNECT: { + CONTROLConnectEvent conEvent(event); + LOG_DEBUG_STR("Received CONNECT(" << conEvent.cntlrName << ")"); // ... break; } + default: - LOG_DEBUG(formatString("MACScheduler(%s)::active_state, default", - getName().c_str())); + LOG_DEBUG("MACScheduler::active, default"); status = GCFEvent::NOT_HANDLED; break; } @@ -395,7 +405,7 @@ void MACScheduler::_doOTDBcheck() } // get current state of Observation - string cntlrName = formatString("ObsCntlr_%d", newTreeList[idx].treeID()); + string cntlrName = formatString("Observation_%d", newTreeList[idx].treeID()); LDState::LDstateNr observationState = itsChildControl->getRequestedState(cntlrName); // remember: timediff <= queueperiod @@ -406,8 +416,8 @@ void MACScheduler::_doOTDBcheck() OTDB::TreeMaintenance tm(itsOTDBconnection); OTDB::treeIDType treeID = newTreeList[idx].treeID(); OTDBnode topNode = tm.getTopNode(treeID); - string filename = formatString("%s/Observation_%d", - LOFAR_SHARE_LOCATION, treeID); + string filename = string(LOFAR_SHARE_LOCATION) + + "/" + cntlrName; if (!tm.exportTree(treeID, topNode.nodeID(), filename)) { LOG_ERROR_STR ("Cannot create startup file " << filename << " for new observation. Observation CANNOT BE STARTED!"); @@ -415,9 +425,10 @@ void MACScheduler::_doOTDBcheck() else { // fire request for new controller itsChildControl->startChild(cntlrName, - treeID, - LDTYPE_OBSERVATIONCTRL, - myHostname()); + treeID, + CNTLRTYPE_OBSERVATIONCTRL, + 0, // instanceNr + myHostname()); } idx++; continue; diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h index e29612d78dd9568757b7db80c6346a15c1851214..e313c12d5608f6a10f0635def61e9544572eb2ef 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h +++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h @@ -29,6 +29,7 @@ //# GCF Includes #include <GCF/PAL/GCF_MyPropertySet.h> #include <GCF/TM/GCF_Port.h> +#include <GCF/TM/GCF_ITCPort.h> #include <GCF/TM/GCF_TimerPort.h> #include <GCF/TM/GCF_Task.h> #include <GCF/TM/GCF_Event.h> @@ -37,8 +38,7 @@ #include "APL/APLCommon/PropertySetAnswerHandlerInterface.h" #include "APL/APLCommon/PropertySetAnswer.h" #include "APL/APLCommon/APLCommonExceptions.h" -#include "APL/APLCommon/LogicalDevice_Protocol.ph" -#include "APL/APLCommon/StartDaemon_Protocol.ph" +#include "APL/APLCommon/Controller_Protocol.ph" //# Common Includes #include <Common/lofar_string.h> @@ -59,6 +59,7 @@ namespace LOFAR { namespace MainCU { using GCF::TM::GCFTimerPort; +using GCF::TM::GCFITCPort; using GCF::TM::GCFPort; using GCF::TM::GCFEvent; using GCF::TM::GCFPortInterface; @@ -122,6 +123,7 @@ private: // pointer to child control task ChildControl* itsChildControl; + GCFITCPort* itsChildPort; // Second timer used for internal timing. uint32 itsSecondTimer; // 1 second hardbeat diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in index c5531d1e00011da09bbd1f0408e0963c1f008eca..e036dd6d88d3ffbc0f59762cac3f6eccfd00ff0b 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in +++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in @@ -1,14 +1,14 @@ # add your custom loggers and appenders here # -log4cplus.rootLogger=DEBUG, STDOUT +log4cplus.rootLogger=DEBUG, STDOUT, FILE -log4cplus.logger.TRC=TRACE +log4cplus.logger.TRC=TRACE2 log4cplus.additivity.TRC=FALSE log4cplus.appender.STDOUT=log4cplus::ConsoleAppender log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout -log4cplus.appender.STDOUT.layout.ConversionPattern=%x %D{%d-%m-%y %H:%M:%S} %-5p %c{9} - %m [%.25l]%n +log4cplus.appender.STDOUT.layout.ConversionPattern=%x %D{%d-%m-%y %H:%M:%S.%q} %-5p %c{9} - %m [%.25l]%n log4cplus.appender.STDOUT.logToStdErr=true log4cplus.appender.FILE=log4cplus::RollingFileAppender @@ -16,15 +16,5 @@ log4cplus.appender.FILE.File=../log/MACScheduler.log log4cplus.appender.FILE.MaxFileSize=5MB log4cplus.appender.FILE.MaxBackupIndex=5 log4cplus.appender.FILE.layout=log4cplus::PatternLayout -log4cplus.appender.FILE.layout.ConversionPattern=%x %D{%d-%m-%y %H:%M:%S} %-5p %c{3} - %m [%.25l]%n +log4cplus.appender.FILE.layout.ConversionPattern=%x %D{%d-%m-%y %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n -log4cplus.appender.XMLFILE=log4cplus::RollingFileAppender -log4cplus.appender.XMLFILE.File=../log/MACSchedulerlog.xml -log4cplus.appender.XMLFILE.MaxFileSize=5MB -log4cplus.appender.XMLFILE.MaxBackupIndex=5 -log4cplus.appender.XMLFILE.layout=log4cplus::XMLLayout - -log4cplus.appender.CHAINSAW=log4cplus::XMLSocketAppender -log4cplus.appender.CHAINSAW.host=localhost -log4cplus.appender.CHAINSAW.port=4448 -log4cplus.appender.CHAINSAW.layout=log4cplus::XMLLayout diff --git a/MAC/APL/MainCU/src/MACScheduler/MACSchedulerDefines.h b/MAC/APL/MainCU/src/MACScheduler/MACSchedulerDefines.h index fe9949ab65fa658c23d81d6c19c6a904c091a2b9..397840acb7d23e196ec006d626435b19b6c4c46f 100644 --- a/MAC/APL/MainCU/src/MACScheduler/MACSchedulerDefines.h +++ b/MAC/APL/MainCU/src/MACScheduler/MACSchedulerDefines.h @@ -41,6 +41,9 @@ namespace LOFAR { #define PVSSNAME_FSM_STATE "state" #define PVSSNAME_FSM_ERROR "error" +#define OC_PROPSET_NAME "LOFAR_ObsSW_Observation%d" +#define OC_PROPSET_TYPE "Observation" + }; // MCU }; // LOFAR diff --git a/MAC/APL/MainCU/src/MACScheduler/Makefile.am b/MAC/APL/MainCU/src/MACScheduler/Makefile.am index 1d22e68a2bd4ce2dc45a09452a8128d0271314fc..21d2cca60b487f065164ca11bf331f57520ad584 100644 --- a/MAC/APL/MainCU/src/MACScheduler/Makefile.am +++ b/MAC/APL/MainCU/src/MACScheduler/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = MACScheduler +bin_PROGRAMS = MACScheduler ObservationControl MACScheduler_CPPFLAGS = -DBOOST_DISABLE_THREADS \ -Wno-deprecated \ @@ -8,16 +8,31 @@ MACScheduler_CPPFLAGS = -DBOOST_DISABLE_THREADS \ MACScheduler_SOURCES = MACScheduler.cc \ MACSchedulerMain.cc \ ChildControl.cc \ - LDState.cc \ - Controller.cc + LDState.cc + ParentControl.cc MACScheduler_LDADD = -lpqxx $(LOFAR_DEPEND) MACScheduler_DEPENDENCIES = $(LOFAR_DEPEND) +ObservationControl_CPPFLAGS = -DBOOST_DISABLE_THREADS \ + -Wno-deprecated \ + -fmessage-length=0 \ + -fdiagnostics-show-location=once + +ObservationControl_SOURCES = ObservationControl.cc \ + ObservationControlMain.cc \ + ChildControl.cc \ + LDState.cc\ + ParentControl.cc + +ObservationControl_LDADD = $(LOFAR_DEPEND) +ObservationControl_DEPENDENCIES = $(LOFAR_DEPEND) + NOINSTHDRS = MACScheduler.h \ MACSchedulerDefines.h INSTHDRS = ChildControl.h \ + ParentControl.h \ LDState.h pkginclude_HEADERS = $(NOINSTHDRS) $(INSTHDRS) @@ -31,7 +46,9 @@ configfilesdir=$(bindir) configfiles_DATA = customPrepPVSSDB.ctl sysconf_DATA = MACScheduler.conf \ - MACScheduler.log_prop + MACScheduler.log_prop \ + ObservationControl.conf \ + ObservationControl.log_prop %.log_prop: %.log_prop.in cp $< $@ diff --git a/MAC/APL/MainCU/src/MACScheduler/ObservationControl.cc b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.cc new file mode 100644 index 0000000000000000000000000000000000000000..4831f8772e6d515d208d7912c5be28e31a32bcbf --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.cc @@ -0,0 +1,357 @@ +//# ObservationControl.cc: Implementation of the MAC Scheduler task +//# +//# Copyright (C) 2002-2004 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ +#include <lofar_config.h> +#include <Common/LofarLogger.h> + +#include <boost/shared_array.hpp> +#include <APS/ParameterSet.h> +#include <GCF/GCF_PVTypes.h> +#include <GCF/PAL/GCF_PVSSInfo.h> +#include <GCF/Utils.h> +#include <GCF/GCF_ServiceInfo.h> +#include <APL/APLCommon/APL_Defines.h> +#include <APL/APLCommon/APLCommonExceptions.h> +#include <APL/APLCommon/Controller_Protocol.ph> + +#include "ObservationControl.h" +#include "MACSchedulerDefines.h" + +using namespace LOFAR::GCF::Common; +using namespace LOFAR::GCF::TM; +using namespace LOFAR::GCF::PAL; +using namespace LOFAR::OTDB; +using namespace std; + +namespace LOFAR { + using namespace APLCommon; + using namespace ACC::APS; + namespace MainCU { + +// +// ObservationControl() +// +ObservationControl::ObservationControl(const string& cntlrName) : + GCFTask ((State)&ObservationControl::initial_state,cntlrName), + PropertySetAnswerHandlerInterface(), + itsPropertySetAnswer(*this), + itsPropertySet (), + itsChildControl (0), + itsChildPort (0), + itsParentControl (0), + itsParentPort (0) +{ + LOG_TRACE_OBJ_STR (cntlrName << " construction"); + + // Readin some parameters from the ParameterSet. + itsTreePrefix = globalParameterSet()->getString("prefix"); + itsInstanceNr = globalParameterSet()->getUint32(itsTreePrefix + ".instanceNr"); + itsStartTime = globalParameterSet()->getTime (itsTreePrefix + ".starttime"); + itsStopTime = globalParameterSet()->getTime (itsTreePrefix + ".stoptime"); + + // attach to child control task + itsChildControl = ChildControl::instance(); + itsChildPort = new GCFITCPort (*this, *itsChildControl, "childITCport", + GCFPortInterface::SAP, CONTROLLER_PROTOCOL); + ASSERTSTR(itsChildPort, "Cannot allocate ITCport for childcontrol"); + itsChildPort->open(); // will result in F_CONNECTED + + // attach to parent control task + itsParentControl = ParentControl::instance(); + itsParentPort = new GCFITCPort (*this, *itsParentControl, "ParentITCport", + GCFPortInterface::SAP, CONTROLLER_PROTOCOL); + ASSERTSTR(itsChildPort, "Cannot allocate ITCport for Parentcontrol"); + itsParentPort->open(); // will result in F_CONNECTED +} + + +// +// ~ObservationControl() +// +ObservationControl::~ObservationControl() +{ + LOG_TRACE_OBJ_STR (getName() << " destruction"); + + if (itsPropertySet) { + itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString("down")); + itsPropertySet->disable(); + } + + // ... +} + + +// +// handlePropertySetAnswer(answer) +// +void ObservationControl::handlePropertySetAnswer(GCFEvent& answer) +{ + switch(answer.signal) { + case F_MYPS_ENABLED: { + GCFPropSetAnswerEvent* pPropAnswer=static_cast<GCFPropSetAnswerEvent*>(&answer); + if(pPropAnswer->result != GCF_NO_ERROR) { + LOG_ERROR(formatString("%s : PropertySet %s NOT ENABLED", + getName().c_str(), pPropAnswer->pScope)); + } + break; + } + + case F_PS_CONFIGURED: + { + GCFConfAnswerEvent* pConfAnswer=static_cast<GCFConfAnswerEvent*>(&answer); + if(pConfAnswer->result == GCF_NO_ERROR) { + LOG_DEBUG(formatString("%s : apc %s Loaded", + getName().c_str(), pConfAnswer->pApcName)); + //apcLoaded(); + } + else { + LOG_ERROR(formatString("%s : apc %s NOT LOADED", + getName().c_str(), pConfAnswer->pApcName)); + } + break; + } + + case F_VGETRESP: + case F_VCHANGEMSG: { + // check which property changed + GCFPropValueEvent* pPropAnswer=static_cast<GCFPropValueEvent*>(&answer); + + // TODO: implement something usefull. + // change of queueTime + if ((strstr(pPropAnswer->pPropName, MS_PROPSET_NAME) != 0) && + (pPropAnswer->pValue->getType() == LPT_INTEGER)) { + uint32 newVal = (uint32) ((GCFPVInteger*)pPropAnswer->pValue)->getValue(); +#if 0 + if (strstr(pPropAnswer->pPropName, PVSSNAME_MS_QUEUEPERIOD) != 0) { + LOG_INFO_STR ("Changing QueuePeriod from " << itsQueuePeriod << + " to " << newVal); + itsQueuePeriod = newVal; + } + else if (strstr(pPropAnswer->pPropName, PVSSNAME_MS_CLAIMPERIOD) != 0) { + LOG_INFO_STR ("Changing ClaimPeriod from " << itsClaimPeriod << + " to " << newVal); + itsClaimPeriod = newVal; + } +#endif + } + break; + } + + default: + break; + } +} + + +// +// initial_state(event, port) +// +// Setup all connections. +// +GCFEvent::TResult ObservationControl::initial_state(GCFEvent& event, GCFPortInterface& /*port*/) +{ + LOG_DEBUG_STR ("ObservationControl::initial:" << evtstr(event)); + + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (event.signal) { + case F_INIT: + break; + + case F_ENTRY: { + // Get access to my own propertyset. + LOG_DEBUG ("Activating PropertySet"); + string propSetName = formatString(OC_PROPSET_NAME, itsInstanceNr); + itsPropertySet = GCFMyPropertySetPtr(new GCFMyPropertySet(propSetName.c_str(), + OC_PROPSET_TYPE, + PS_CAT_TEMPORARY, + &itsPropertySetAnswer)); + itsPropertySet->enable(); + + // update PVSS. + LOG_TRACE_FLOW ("Updateing state to PVSS"); + itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString ("initial")); + itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),GCFPVString ("")); + + // Start ChildControl task + LOG_DEBUG ("Enabling ChildControl task"); + itsChildControl->openService(MAC_SVCMASK_OBSERVATIONCTRL, itsInstanceNr); + itsChildControl->registerCompletionPort(itsChildPort); + + // Start ParentControl task + LOG_DEBUG ("Enabling ParentControl task"); + itsParentPort = itsParentControl->registerTask(this); + + TRAN(ObservationControl::active_state); // go to next state. + } + break; + + case F_CONNECTED: + break; + + case F_DISCONNECTED: + break; + + case F_TIMER: + break; + + default: + LOG_DEBUG_STR ("ObservationControl::initial, default"); + status = GCFEvent::NOT_HANDLED; + break; + } + return (status); +} + + +// +// active_state(event, port) +// +// Normal operation state. +// +GCFEvent::TResult ObservationControl::active_state(GCFEvent& event, GCFPortInterface& port) +{ + LOG_DEBUG_STR ("ObservationControl::active:" << evtstr(event) + << "@" << port.getName()); + + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (event.signal) { + case F_INIT: + break; + + case F_ENTRY: { + // update PVSS + itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString("active")); + itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),GCFPVString("")); + break; + } + + case F_ACCEPT_REQ: + break; + + case F_CONNECTED: + _connectedHandler(port); + break; + + case F_DISCONNECTED: + _disconnectedHandler(port); + break; + + case F_TIMER: +// GCFTimerEvent& timerEvent=static_cast<GCFTimerEvent&>(event); + break; + + // -------------------- EVENT RECEIVED FROM CHILD CONTROL -------------------- + case CONTROL_STARTED: { + CONTROLStartedEvent msg(event); + LOG_DEBUG(formatString("Start of %s was %ssuccessful", msg.cntlrName.c_str(), + msg.successful ? "" : "NOT ")); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_CONNECT: { + CONTROLConnectEvent msg(event); + LOG_DEBUG_STR("Received CONNECT(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_SCHEDULED: { + CONTROLScheduledEvent msg(event); + LOG_DEBUG_STR("Received SCHEDULED(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_CLAIMED: { + CONTROLClaimedEvent msg(event); + LOG_DEBUG_STR("Received CLAIMED(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_PREPARED: { + CONTROLPreparedEvent msg(event); + LOG_DEBUG_STR("Received PREPARED(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_RESUMED: { + CONTROLResumedEvent msg(event); + LOG_DEBUG_STR("Received RESUMED(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_SUSPENDED: { + CONTROLSuspendedEvent msg(event); + LOG_DEBUG_STR("Received SUSPENDED(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_RELEASED: { + CONTROLReleasedEvent msg(event); + LOG_DEBUG_STR("Received RELEASED(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + case CONTROL_FINISH: { + CONTROLFinishEvent msg(event); + LOG_DEBUG_STR("Received FINISH(" << msg.cntlrName << ")"); + // TODO: do something usefull with this information! + break; + } + + + default: + LOG_DEBUG(formatString("ObservationControl(%s)::active_state, default", + getName().c_str())); + status = GCFEvent::NOT_HANDLED; + break; + } + + return (status); +} + + +// +// _connectedHandler(port) +// +void ObservationControl::_connectedHandler(GCFPortInterface& port) +{ +} + +// +// _disconnectedHandler(port) +// +void ObservationControl::_disconnectedHandler(GCFPortInterface& port) +{ + port.close(); +} + + +}; +}; diff --git a/MAC/APL/MainCU/src/MACScheduler/ObservationControl.conf.in b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.conf.in new file mode 100644 index 0000000000000000000000000000000000000000..a92957c18ce62d80f87bec0b8500f109d6a9d311 --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.conf.in @@ -0,0 +1,11 @@ +# new setup +prefix = Observation0 + +Observation0.instanceNr = 0 +Observation0.starttime = 0 +Observation0.stoptime = 1 + +# next parameters are optional, defaultvalues are shown +#ChildControl.StartupRetryInterval = 10s +#ChildControl.MaxStartupRetry = 5 + diff --git a/MAC/APL/MainCU/src/MACScheduler/ObservationControl.h b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.h new file mode 100644 index 0000000000000000000000000000000000000000..6169b8cd624ecaf55637bcd8baf96d998f1a48b9 --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.h @@ -0,0 +1,131 @@ +//# ObservationControl.h: Interface between MAC and SAS. +//# +//# Copyright (C) 2002-2004 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#ifndef ObservationControl_H +#define ObservationControl_H + +//# Includes +#include <boost/shared_ptr.hpp> + +//# GCF Includes +#include <GCF/PAL/GCF_MyPropertySet.h> +#include <GCF/TM/GCF_Port.h> +#include <GCF/TM/GCF_ITCPort.h> +#include <GCF/TM/GCF_TimerPort.h> +#include <GCF/TM/GCF_Task.h> +#include <GCF/TM/GCF_Event.h> + +//# local includes +#include "APL/APLCommon/PropertySetAnswerHandlerInterface.h" +#include "APL/APLCommon/PropertySetAnswer.h" +#include "APL/APLCommon/APLCommonExceptions.h" +#include "APL/APLCommon/Controller_Protocol.ph" + +//# Common Includes +#include <Common/lofar_string.h> +#include <Common/lofar_vector.h> +#include <Common/LofarLogger.h> + +//# ACC Includes +#include <APS/ParameterSet.h> +#include "ChildControl.h" +#include "ParentControl.h" +#include "LDState.h" + +// forward declaration + +namespace LOFAR { + namespace MainCU { + +using GCF::TM::GCFTimerPort; +using GCF::TM::GCFITCPort; +using GCF::TM::GCFPort; +using GCF::TM::GCFEvent; +using GCF::TM::GCFPortInterface; +using GCF::TM::GCFTask; + + +class ObservationControl : public GCFTask, + APLCommon::PropertySetAnswerHandlerInterface +{ +public: + explicit ObservationControl(const string& cntlrName); + ~ObservationControl(); + + // PropertySetAnswerHandlerInterface method + virtual void handlePropertySetAnswer(GCFEvent& answer); + + // During the initial state all connections with the other programs are made. + GCFEvent::TResult initial_state (GCFEvent& e, + GCFPortInterface& p); + + // Normal control mode. + GCFEvent::TResult active_state (GCFEvent& e, + GCFPortInterface& p); + +private: + // avoid defaultconstruction and copying + ObservationControl(); + ObservationControl(const ObservationControl&); + ObservationControl& operator=(const ObservationControl&); + + void _connectedHandler(GCFPortInterface& port); + void _disconnectedHandler(GCFPortInterface& port); + boost::shared_ptr<ACC::APS::ParameterSet> + readObservationParameters (OTDB::treeIDType ObsTreeID); + + typedef boost::shared_ptr<GCF::PAL::GCFMyPropertySet> GCFMyPropertySetPtr; + + APLCommon::PropertySetAnswer itsPropertySetAnswer; + GCFMyPropertySetPtr itsPropertySet; + +#if 0 + // Administration of the ObservationControllers + typedef struct { + OTDB::treeIDType treeID; // tree in the OTDB + GCFTCPPort* port; // TCP connection with controller + uint16 state; // state the controller has + } ObsCntlr_t; + + // Map with all active ObservationControllers. + map<GCFTCPPort*, ObsCntlr_t> itsObsCntlrMap; + vector<GCFTCPPort*> itsObsCntlrPorts; +#endif + + // pointer to child control task + ChildControl* itsChildControl; + GCFITCPort* itsChildPort; + + // pointer to parent control task + ParentControl* itsParentControl; + GCFITCPort* itsParentPort; + + // ParameterSet variables + string itsTreePrefix; + uint32 itsInstanceNr; + time_t itsStartTime; + time_t itsStopTime; +}; + + };//MainCU +};//LOFAR +#endif diff --git a/MAC/APL/MainCU/src/MACScheduler/ObservationControl.log_prop.in b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.log_prop.in new file mode 100644 index 0000000000000000000000000000000000000000..014e32162d939ee0cd2716348fc1e2e9117c10ad --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ObservationControl.log_prop.in @@ -0,0 +1,20 @@ +# add your custom loggers and appenders here +# + +log4cplus.rootLogger=DEBUG, STDOUT, FILE + +log4cplus.logger.TRC=TRACE2 +log4cplus.additivity.TRC=FALSE + +log4cplus.appender.STDOUT=log4cplus::ConsoleAppender +log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout +log4cplus.appender.STDOUT.layout.ConversionPattern=%x %D{%d-%m-%y %H:%M:%S.%q} %-5p %c{9} - %m [%.25l]%n +log4cplus.appender.STDOUT.logToStdErr=true + +log4cplus.appender.FILE=log4cplus::RollingFileAppender +log4cplus.appender.FILE.File=../log/ObservationControl.log +log4cplus.appender.FILE.MaxFileSize=5MB +log4cplus.appender.FILE.MaxBackupIndex=5 +log4cplus.appender.FILE.layout=log4cplus::PatternLayout +log4cplus.appender.FILE.layout.ConversionPattern=%x %D{%d-%m-%y %H:%M:%S.%q} %-5p %c{3} - %m [%.25l]%n + diff --git a/MAC/APL/MainCU/src/MACScheduler/ObservationControlMain.cc b/MAC/APL/MainCU/src/MACScheduler/ObservationControlMain.cc new file mode 100644 index 0000000000000000000000000000000000000000..085868055868317950b9ed1314587ae9e46717eb --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ObservationControlMain.cc @@ -0,0 +1,49 @@ +//# ObservationControlMain.cc: Main entry for the ObservationControl controller. +//# +//# Copyright (C) 2006 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ +//# +#include <lofar_config.h> +#include <Common/LofarLogger.h> + +#include "ObservationControl.h" + +using namespace LOFAR::GCF::TM; +using namespace LOFAR::MainCU; + +int main(int argc, char* argv[]) +{ + // args: cntlrname, parentHost, parentService + GCFTask::init(argc, argv); + + ChildControl* cc = ChildControl::instance(); + cc->start(); // make initial transition + + ParentControl* pc = ParentControl::instance(); + pc->start(); // make initial transition + + ObservationControl oc(argv[1]); + oc.start(); // make initial transition + + GCFTask::run(); + + return 0; +} + diff --git a/MAC/APL/MainCU/src/MACScheduler/ParentControl.cc b/MAC/APL/MainCU/src/MACScheduler/ParentControl.cc new file mode 100644 index 0000000000000000000000000000000000000000..7dc67f2a7c6721d7ef82304fbdf86e62ec5db172 --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ParentControl.cc @@ -0,0 +1,572 @@ +//# ParentControl.cc: Task that handles and dispatches all controllers events. +//# +//# Copyright (C) 2006 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +//# Always #include <lofar_config.h> first! +#include <lofar_config.h> + +//# Includes +#include <Common/LofarLogger.h> +#include <APS/ParameterSet.h> +#include <MainCU/MACScheduler/ParentControl.h> +#include <GCF/GCF_ServiceInfo.h> +#include <GCF/Utils.h> +#include <APL/APLCommon/APLUtilities.h> +#include <APL/APLCommon/Controller_Protocol.ph> +#include <APL/APLCommon/StartDaemon_Protocol.ph> +#include "ParentControl.h" + +namespace LOFAR { + using namespace GCF::TM; + using namespace APLCommon; + using namespace ACC::APS; + namespace MainCU { + +typedef struct stateFlow_t { + uint16 signal; + LDState::LDstateNr currentState; + LDState::LDstateNr requestedState; +} stateFlow; + +static stateFlow stateFlowTable[] = { +// received signal expected in state requested state +// ------------------------------------------------------------------ + { CONTROL_CONNECTED, LDState::CONNECT, LDState::CONNECTED }, + { CONTROL_CLAIM, LDState::CONNECTED, LDState::CLAIMED }, + { CONTROL_PREPARE, LDState::CLAIMED, LDState::PREPARED }, + { CONTROL_RESUME, LDState::PREPARED, LDState::ACTIVE }, + { CONTROL_RESUME, LDState::SUSPENDED, LDState::ACTIVE }, + { CONTROL_SUSPEND, LDState::ACTIVE, LDState::SUSPENDED }, + { CONTROL_RELEASE, LDState::ANYSTATE, LDState::RELEASED }, + { CONTROL_FINISHED, LDState::FINISH, LDState::FINISHED }, + { 0x00, LDState::NOSTATE, LDState::NOSTATE } +}; + +//-------------------------- creation and destroy --------------------------- + +ParentControl* ParentControl::instance() +{ + static ParentControl* theirParentControl; + + if (theirParentControl == 0) { + theirParentControl = new ParentControl(); + } + return (theirParentControl); +} + + +// +// ParentControl(name, porenthost, parentService)) +// +ParentControl::ParentControl() : + GCFTask ((State)&ParentControl::initial, "ParentControl"), + itsParentList (), + itsSDPort (0), + itsMainTaskPort (0), + itsTimerPort (*this, "parentControlTimer"), + itsControllerName() +{ + // Log the protocols I use. + registerProtocol(CONTROLLER_PROTOCOL, CONTROLLER_PROTOCOL_signalnames); + registerProtocol(STARTDAEMON_PROTOCOL, STARTDAEMON_PROTOCOL_signalnames); + +} + +// +// ~ParentControl +// +ParentControl::~ParentControl() +{ + // close and delete the ports I created + if (itsMainTaskPort) { + itsMainTaskPort->close(); + delete itsMainTaskPort; + } + + if (itsSDPort) { + itsSDPort->close(); + delete itsSDPort; + } +} + +// +// registerTask(mainTask) : ITCPort +// +GCFITCPort* ParentControl::registerTask(GCFTask* mainTask) +{ + itsMainTaskPort = new GCFITCPort(*mainTask, *this, mainTask->getName(), + GCFPortInterface::SAP, CONTROLLER_PROTOCOL); + ASSERTSTR(itsMainTaskPort, "Can not allocate ITC port for parent-control"); + itsMainTaskPort->open(); // will result in F_CONN signal + + itsSDPort = new GCFTCPPort(*this, MAC_SVCMASK_STARTDAEMON, + GCFPortInterface::SAP, STARTDAEMON_PROTOCOL); + ASSERTSTR(itsSDPort, "Can not allocate clientport to startDaemon"); + itsSDPort->open(); // will result in F_COON or F_DISCONN signal + + itsControllerName = mainTask->getName(); // remember for later + + return (itsMainTaskPort); +} + +// +// isLegalSignal(signal, parent) +// +bool ParentControl::isLegalSignal(uint16 aSignal, + PIiter aParent) +{ + uint32 i = 0; + while (stateFlowTable[i].signal) { + if (stateFlowTable[i].signal == aSignal && + (stateFlowTable[i].currentState == aParent->currentState || + stateFlowTable[i].currentState == LDState::ANYSTATE)) { + return (true); + } + i++; + } + return (false); +} + +// +// requestedState(signal) +// +LDState::LDstateNr ParentControl::requestedState(uint16 aSignal) +{ + uint32 i = 0; + while (stateFlowTable[i].signal) { + if (stateFlowTable[i].signal == aSignal) { + return (stateFlowTable[i].requestedState); + } + i++; + } + ASSERTSTR(false, "No new state defined for signal " << evtstr(aSignal)); +} + +// +// doRequestedAction(parent) +// +void ParentControl::doRequestedAction(PIiter parent) +{ + LOG_TRACE_FLOW_STR("doRequestedAction:" << parent->name); + + // state alredy reached? make sure the timer is off. + if (parent->requestedState == parent->currentState) { + parent->nrRetries = -1; + itsTimerPort.cancelTimer(parent->timerID); + parent->timerID = 0; + return; + } + + switch (parent->requestedState) { + case LDState::CONNECTED: { + // try to make first contact with parent by identifying ourself + if (parent->nrRetries == 0) { // no more retries left? + LOG_ERROR_STR("Cannot connect to parent: " << parent->servicename << + "@" << parent->hostname << ", giving up!"); + parent->establishTime = time(0); + parent->failed = true; // TODO:let garbage collection remove this entry. + return; + } + // Note: when required state == CONNECTED there are two possibilities: + // current state == NOSTATE: CONNECT msg was sent to main task, do nothing + // current state == CONNECT: CONNECTED msg was received from main task, + // send CONNECT msg to parent-controller. + if (parent->currentState == LDState::NOSTATE) { + return; + } + + ASSERTSTR(parent->currentState == LDState::CONNECT, + "Unexpected state:" << parent->currentState); + + // construct and send message + CONTROLConnectEvent hello; + hello.cntlrName = parent->name; + parent->port->send(hello); + parent->timerID = 0; + parent->nrRetries = -1; + parent->currentState = LDState::CONNECT; + parent->establishTime = time(0); + } + break; + case LDState::CLAIMED: { + CONTROLClaimEvent request; + request.cntlrName = parent->name; + itsMainTaskPort->sendBack(request); + } + break; + case LDState::PREPARED: +// concrete_prepare(parent); + break; + case LDState::ACTIVE: +// concrete_resume(parent); + break; + case LDState::SUSPENDED: +// concrete_suspend(parent); + break; + case LDState::RELEASED: +// concrete_release(parent); + break; + case LDState::FINISHED: + parent->port->close(); + itsParentList.erase(parent); + break; + default: + ASSERTSTR(false, "Serious programming error, requestedState=" << + parent->requestedState << " for task " << parent->name); + } + +} + + +// -------------------- THE GCF STATEMACHINES -------------------- + +// Wait for the F_CONNECTED event from the ITC port with the master-task. +// Connect and register at startDaemon +// +GCFEvent::TResult ParentControl::initial(GCFEvent& event, + GCFPortInterface& port) + +{ + LOG_DEBUG_STR ("ParentControl::initial:" << evtstr(event) + << "@" << port.getName()); + + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (event.signal) { + case F_INIT: + case F_ENTRY: + break; + + case F_CONNECTED: + if (&port == itsMainTaskPort) { // ITC port with parent open? + LOG_DEBUG("Connection with maintask opened"); + } + if (&port == itsSDPort) { + STARTDAEMONAnnouncementEvent msg; + msg.cntlrName = itsControllerName; + itsSDPort->send(msg); + + LOG_DEBUG_STR("Registered at startdaemon as " << itsControllerName + << ", going to operation mode"); + TRAN(ParentControl::operational); + } + break; + + case F_DISCONNECTED: + if (&port == itsSDPort) { + port.close(); + itsTimerPort.setTimer(1.0); + LOG_DEBUG("Could not connect to startDaemon, retry in 1 second"); + } + break; + + case F_TIMER: + // must be reconnect timer for startDaemon + itsSDPort->open(); + break; + + default: + LOG_DEBUG ("ParentControl::initial, default"); + status = GCFEvent::NOT_HANDLED; + break; + } + + return (status); +} + + +// +// operational (event, port) +// +// Since this base class is also used for shared controllers the controller supports +// multiple parents. For each of these parents the controller plays the role of +// stand-alone controller having a certain state and allowing certain actions. +// It is therefor difficult to implement multiple statemachine since the controller +// should be in a (different) state for each parent. +// +GCFEvent::TResult ParentControl::operational(GCFEvent& event, + GCFPortInterface& port) + +{ + LOG_DEBUG_STR ("ParentControl::operational:" << evtstr(event) + << "@" << port.getName()); + + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (event.signal) { + case F_INIT: + break; + + case F_ENTRY: + break; + + case F_ACCEPT_REQ: // will not occur, using SPP port for startDaemon + break; + + case F_CONNECTED: { + // search which connection is succesfull connected. + PIiter parent = findParent(&port); + if (isParent(parent)) { + // TODO: should we send an 'alive' msg to our parent + // so that recovered(?) parent knows we are still running? + // CHECK: is servicemask resolved at each open()? + + // contact with parent is (re)made + doRequestedAction(parent); + } + else { + LOG_DEBUG("F_CONNECTED on non-parent port"); + } + } + break; + + case F_DISCONNECTED: { + // StartDaemonPort? no problem SD will reconnect when neccesary. + if (&port == itsSDPort) { + port.close(); // close connection with current SD + port.open(); // start listener again + break; + } + + // Parent port? Might be temporarely problem, try to reconnect for a while. + PIiter parent = findParent(&port); + if (isParent(parent)) { + // trying to make first contact? + if (parent->requestedState == LDState::CONNECTED && + parent->currentState != LDState::CONNECTED) { + // try again in one second. + parent->port->close(); + parent->timerID = itsTimerPort.setTimer(1.0); + if (parent->nrRetries < 0) { + parent->nrRetries = 30; + LOG_WARN_STR ("Lost connection with new parent " << parent->name << + ", starting reconnect sequence"); + } + LOG_TRACE_VAR_STR("parent:" << parent->name << ", timerID:" + << parent->timerID); + break; + } + + // lost connection during normal operation, start reconnect sequence + parent->port->close(); + parent->timerID = itsTimerPort.setTimer(10.0);// retry every 10 seconds + if (parent->nrRetries < 0) { + parent->nrRetries = 360; // for 1 hour + LOG_WARN_STR ("Lost connection with parent " << parent->name << + ", starting reconnect sequence"); + } + LOG_TRACE_VAR_STR("parent:" << parent->name << ", timerID:" + << parent->timerID); + break; + } + + // unknown port. just close it. + LOG_INFO ("Lost connection with unknown port, closing it"); + port.close(); + } + break; + + case F_TIMER: { + GCFTimerEvent& timerEvent = static_cast<GCFTimerEvent&>(event); + LOG_TRACE_VAR_STR("timerID:" << timerEvent.id); + PIiter parent = findParent(timerEvent.id); + if (!isParent(parent)) { + LOG_DEBUG ("timerevent is not of a known parent, ignore"); + break; + } + + if (parent->port->isConnected()) { // not the reconnect timer? + doRequestedAction(parent); + } + + // its the reconnect timer of this parent. + if (parent->nrRetries > 0) { + parent->port->open(); + parent->nrRetries--; + parent->timerID = 0; + if (!parent->nrRetries%60) { + LOG_WARN_STR ("Still no connection with parent " << parent->name); + } + } + else { + LOG_WARN_STR ("Could not reconnect to parent " << + parent->name << ", deleting entry"); +// concrete_release(parent); + itsParentList.erase(parent); + } + } + break; + + case STARTDAEMON_NEWPARENT: { + // a new parent wants us to connect to it, read info. + STARTDAEMONNewparentEvent NPevent(event); + ParentInfo_t parent; + + // construct the state information the parent think we have. + parent.name = NPevent.cntlrName; + parent.port = new GCFTCPPort(*this, NPevent.parentService, + GCFPortInterface::SAP, CONTROLLER_PROTOCOL); + parent.hostname = NPevent.parentHost; + parent.servicename = NPevent.parentService; + parent.requestedState = LDState::CONNECTED; + parent.requestTime = time(0); + parent.currentState = LDState::NOSTATE; + parent.establishTime = 0; + parent.timerID = 0; + parent.nrRetries = -1; // means: not set + ASSERTSTR(parent.port, "Unable to allocate socket for " << NPevent.cntlrName); + + // add parent to the pool and open the connection with the parent + itsParentList.push_back(parent); + dynamic_cast<GCFTCPPort*>(parent.port)->setHostName (parent.hostname); + parent.port->open(); // results in F_CONN of F_DISCONN + LOG_DEBUG_STR("Registered parent "<< parent.name <<" on port "<< parent.port); + + // pass newParent event to mainTask as Connect event + LOG_DEBUG_STR("Sending CONNECT(" << parent.name << ") event to maintask"); + CONTROLConnectEvent request; + request.cntlrName = parent.name; + itsMainTaskPort->sendBack(request); + } + break; + + case CONTROL_CONNECTED: { + // this event can be received from maintask and parent-controllers + // is it the maintask? --> send CONNECT to parent controller. + if (&port == itsMainTaskPort) { + CONTROLConnectedEvent inMsg(event); + PIiter parent = findParent(inMsg.cntlrName); + if (!isParent(parent)) { + LOG_ERROR_STR("Cannot forward CONNECT event for " << inMsg.cntlrName); + break; + } + CONTROLConnectEvent outMsg; + outMsg.cntlrName = inMsg.cntlrName; + parent->port->send(outMsg); + parent->currentState = LDState::CONNECT; + break; + } + + // should be a parentport + PIiter parent = findParent(&port); + if (!isParent(parent)) { + LOG_WARN_STR ("Received CONNECTED event from unknown parent, ignoring"); + break; + } + + // warn operator when we are out of sync with our parent. + if (parent->requestedState != LDState::CONNECTED) { + LOG_WARN_STR ("Received 'CONNECTED' event while requested state is " << + parent->requestedState); + } + // always accept new state because parent thinks we are in this state. + // TODO: when we are already beyond the claiming state should we release + // the claimed resources? + parent->port->cancelTimer(parent->timerID); + parent->timerID = 0; + parent->currentState = LDState::CONNECTED; + parent->establishTime = time(0); + parent->timerID = 0; + parent->nrRetries = -1; + parent->failed = false; + } + break; + + case CONTROL_CLAIM: + case CONTROL_PREPARE: + case CONTROL_RESUME: + case CONTROL_SUSPEND: + case CONTROL_RELEASE: + case CONTROL_FINISHED: + { + // do we know this parent? + PIiter parent = findParent(&port); + if (isParent(parent)) { + LOG_WARN_STR ("Received " << evtstr(event) << + " event from unknown parent, ignoring"); + break; + } + + // warn operator when we are out of sync with our parent. + if (!isLegalSignal(event.signal, parent)) { + LOG_WARN_STR ("Received " << evtstr(event.signal) << + " event while requested state is " << parent->requestedState); + } + + parent->requestedState = requestedState(event.signal); // use stateFlowTable + parent->requestTime = time(0); + doRequestedAction(parent); + } + break; + + default: + LOG_DEBUG ("ParentControl::operational, default"); + status = GCFEvent::NOT_HANDLED; + break; + } + + return (status); +} + +// +// findParent(port) +// +ParentControl::PIiter ParentControl::findParent(GCFPortInterface* aPort) +{ + LOG_TRACE_COND_STR("findParent: " << aPort); + const_PIiter end = itsParentList.end(); + PIiter iter = itsParentList.begin(); + while (iter != end && iter->port != aPort) { + iter++; + } + return (iter); +} + +// +// findParent(timerID) +// +ParentControl::PIiter ParentControl::findParent(uint32 aTimerID) +{ + LOG_TRACE_COND_STR("findParent: " << aTimerID); + const_PIiter end = itsParentList.end(); + PIiter iter = itsParentList.begin(); + while (iter != end && iter->timerID != aTimerID) { + iter++; + } + return (iter); +} + +// +// findParent(name) +// +ParentControl::PIiter ParentControl::findParent(const string& aName) +{ + LOG_TRACE_COND_STR("findParent: " << aName); + const_PIiter end = itsParentList.end(); + PIiter iter = itsParentList.begin(); + while (iter != end && iter->name != aName) { + iter++; + } + return (iter); +} + + } // namespace MainCU +} // namespace LOFAR diff --git a/MAC/APL/MainCU/src/MACScheduler/ParentControl.h b/MAC/APL/MainCU/src/MACScheduler/ParentControl.h new file mode 100644 index 0000000000000000000000000000000000000000..33c7c33700e8f9386e357c69136b0ef1a950aaab --- /dev/null +++ b/MAC/APL/MainCU/src/MACScheduler/ParentControl.h @@ -0,0 +1,148 @@ +//# ParentControl.h: Task that handles and dispatches all controllers events. +//# +//# Copyright (C) 2006 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#ifndef MAINCU_CONTROLLER_H +#define MAINCU_CONTROLLER_H + +// \file +// Task that handles and dispatches all controllers events. + +//# Never #include <config.h> or #include <lofar_config.h> in a header file! +//# Includes +#include <Common/lofar_string.h> +#include <Common/lofar_map.h> +#include <Common/lofar_list.h> +#include <GCF/TM/GCF_Task.h> +#include <GCF/TM/GCF_TCPPort.h> +#include <GCF/TM/GCF_ITCPort.h> +#include <GCF/TM/GCF_TimerPort.h> +#include <APL/APLCommon/APL_Defines.h> +#include <OTDB/OTDBtypes.h> +#include "LDState.h" + +// Avoid 'using namespace' in headerfiles + +namespace LOFAR { + using GCF::TM::GCFTCPPort; + using GCF::TM::GCFITCPort; + using GCF::TM::GCFTimerPort; + using GCF::TM::GCFEvent; + using GCF::TM::GCFTask; + using GCF::TM::GCFPortInterface; + using APLCommon::LDState; + namespace MainCU { + +// \addtogroup MainCU +// @{ + +//# --- Forward Declarations --- +//# classes mentioned as parameter or returntype without virtual functions. +//class ...; + + +// class_description +// ... +class ParentControl : public GCFTask +{ +public: + // the only way to create the object is via instance. + static ParentControl* instance(); + ~ParentControl(); + + // Main controller task should identify itself at ParentControlTask. + // Its gets an ITCport pointer in return. + GCFITCPort* registerTask (GCFTask* mainTask); + +private: + // Copying and default construction is not allowed + ParentControl(); + ParentControl(const ParentControl& that); + ParentControl& operator=(const ParentControl& that); + + // GCFTask statemachine + GCFEvent::TResult initial (GCFEvent& event, GCFPortInterface& port); + GCFEvent::TResult operational (GCFEvent& event, GCFPortInterface& port); + + + // Note: When the controller is a shared controller it will have multiple + // parents and for each of these parents it must handle its own + // state machine. + typedef struct ParentInfo { + string name; // uniq name we have for the parent + GCFPortInterface* port; // connection with the parent + string hostname; // host the controller runs on + string servicename; // servicename to connect to + LDState::LDstateNr requestedState; // the state the controller requested + time_t requestTime; // time of requested state + LDState::LDstateNr currentState; // the state we reached for that parent + time_t establishTime; // time the current state was reached + int32 nrRetries; // nr of retries performed + uint32 timerID; // timer for this parent + bool failed; // reaching requested state failed. + } ParentInfo_t; + typedef list<ParentInfo_t>::iterator PIiter; + typedef list<ParentInfo_t>::const_iterator const_PIiter; + + // internal routines for managing the ParentInfo pool. + PIiter findParent(GCFPortInterface* port); + PIiter findParent(uint32 timerID); + PIiter findParent(const string& name); + bool isParent (PIiter parentPtr) + { return (parentPtr != itsParentList.end()); } + bool isLegalSignal (uint16 aSignal, PIiter aParent); + LDState::LDstateNr requestedState(uint16 aSignal); + + // Internal routines + void doRequestedAction(PIiter parent); + + + //# --- Datamembers --- + list<ParentInfo_t> itsParentList; // administration of child controller + + GCFTCPPort* itsSDPort; // clientport to StartDaemon + + GCFITCPort* itsMainTaskPort; // gateway to main task + + GCFTimerPort itsTimerPort; // for internal timers + + string itsServiceName; // serviceinfo of program + uint32 itsInstanceNr; + + string itsControllerName; // name to program is known as + + // All actions from the parent task are queued as ParentControlInfo objects + // and handled in the operational stateMachine. +// list<ParentControlInfo> itsActionList; // list of actions to perform. +// uint32 itsActionTimer; // ID of actiontimer. + +// ... + +}; + + +//# --- Inline functions --- + +// @} + } // namespace MainCU +} // namespace LOFAR + +#endif