Skip to content
Snippets Groups Projects
MACScheduler.cc 19 KiB
Newer Older
Ruud Overeem's avatar
Ruud Overeem committed
//#  MACScheduler.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>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/GCF_ServiceInfo.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/GCF_PVTypes.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/Protocols/PA_Protocol.ph>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/PAL/GCF_PVSSInfo.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/Utils.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <APL/APLCommon/APL_Defines.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <APL/APLCommon/ControllerDefines.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <APL/APLCommon/StationInfo.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <APL/APLCommon/APLCommonExceptions.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <APL/APLCommon/Controller_Protocol.ph>
Ruud Overeem's avatar
Ruud Overeem committed
#include <OTDB/TreeStateConv.h>
blaakmeer's avatar
blaakmeer committed
#include <signal.h>
Ruud Overeem's avatar
Ruud Overeem committed

#include "MACSchedulerDefines.h"
#include "MACScheduler.h"

using namespace LOFAR::GCF::Common;
using namespace LOFAR::GCF::TM;
using namespace LOFAR::GCF::PAL;
using namespace LOFAR::OTDB;
Ruud Overeem's avatar
Ruud Overeem committed
using namespace LOFAR::Deployment;
Ruud Overeem's avatar
Ruud Overeem committed
using namespace std;

namespace LOFAR {
	using namespace APLCommon;
	using namespace ACC::APS;
Ruud Overeem's avatar
Ruud Overeem committed
	namespace MainCU {
blaakmeer's avatar
blaakmeer committed

// static (this) pointer used for signal handling
static MACScheduler* pMacScheduler = 0;
Ruud Overeem's avatar
Ruud Overeem committed
	
//
// MACScheduler()
//
MACScheduler::MACScheduler() :
	GCFTask 			((State)&MACScheduler::initial_state,string(MS_TASKNAME)),
	PropertySetAnswerHandlerInterface(),
	itsPropertySetAnswer(*this),
	itsPropertySet		(),
Ruud Overeem's avatar
Ruud Overeem committed
	itsObservations		(),
Ruud Overeem's avatar
Ruud Overeem committed
	itsPVSSObsList		(),
Ruud Overeem's avatar
Ruud Overeem committed
	itsTimerPort		(0),
Ruud Overeem's avatar
Ruud Overeem committed
	itsChildControl		(0),
Ruud Overeem's avatar
Ruud Overeem committed
	itsChildPort		(0),
Ruud Overeem's avatar
Ruud Overeem committed
	itsSecondTimer		(0),
	itsQueuePeriod		(0),
	itsClaimPeriod		(0),
	itsOTDBconnection	(0),
	itsOTDBpollInterval	(0),
	itsNextOTDBpolltime (0)
{
	LOG_TRACE_OBJ ("MACscheduler construction");

Ruud Overeem's avatar
Ruud Overeem committed
	LOG_INFO_STR("MACProcessScope: " << globalParameterSet()->getString("prefix"));
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	// Readin some parameters from the ParameterSet.
	itsOTDBpollInterval = globalParameterSet()->getTime("OTDBpollInterval");
	itsQueuePeriod 		= globalParameterSet()->getTime("QueuePeriod");
	itsClaimPeriod 		= globalParameterSet()->getTime("ClaimPeriod");
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	// attach to child control task
Ruud Overeem's avatar
Ruud Overeem committed
	itsChildControl = ChildControl::instance();
Ruud Overeem's avatar
Ruud Overeem committed
	itsChildPort = new GCFITCPort (*this, *itsChildControl, "childITCport", 
									GCFPortInterface::SAP, CONTROLLER_PROTOCOL);
	ASSERTSTR(itsChildPort, "Cannot allocate ITCport for childcontrol");
	itsChildPort->open();		// will result in F_CONNECTED
Ruud Overeem's avatar
Ruud Overeem committed

	// need port for timers
	itsTimerPort = new GCFTimerPort(*this, "Timerport");

Ruud Overeem's avatar
Ruud Overeem committed
	itsObservations.reserve(10);		// already reserve memory for 10 observations.

Ruud Overeem's avatar
Ruud Overeem committed
	registerProtocol(CONTROLLER_PROTOCOL, CONTROLLER_PROTOCOL_signalnames);
	registerProtocol(PA_PROTOCOL, 		  PA_PROTOCOL_signalnames);
	registerProtocol(F_PML_PROTOCOL, 	  F_PML_PROTOCOL_signalnames);
Ruud Overeem's avatar
Ruud Overeem committed
}


//
// ~MACScheduler()
//
MACScheduler::~MACScheduler()
{
	LOG_TRACE_OBJ ("~MACscheduler");

Ruud Overeem's avatar
Ruud Overeem committed
//	if (itsPropertySet) {
Ruud Overeem's avatar
Ruud Overeem committed
		// Note: disable is not neccesary because this is always done in destructor
		//		 of propertyset.
Ruud Overeem's avatar
Ruud Overeem committed
//	}
Ruud Overeem's avatar
Ruud Overeem committed

	if (itsOTDBconnection) {
		delete itsOTDBconnection;
	}
}

Ruud Overeem's avatar
Ruud Overeem committed
//
// sigintHandler(signum)
//
void MACScheduler::sigintHandler(int signum)
blaakmeer's avatar
blaakmeer committed
{
Ruud Overeem's avatar
Ruud Overeem committed
	LOG_DEBUG (formatString("SIGINT signal detected (%d)",signum));

	if (pMacScheduler) {
		pMacScheduler->finish();
	}
blaakmeer's avatar
blaakmeer committed
}

Ruud Overeem's avatar
Ruud Overeem committed

//
// handlePropertySetAnswer(answer)
//
void MACScheduler::handlePropertySetAnswer(GCFEvent& answer)
{
Ruud Overeem's avatar
Ruud Overeem committed

	LOG_DEBUG_STR ("handlePropertySetAnswer:" << evtstr(answer));

Ruud Overeem's avatar
Ruud Overeem committed
	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));
		}
Ruud Overeem's avatar
Ruud Overeem committed
		// always let timer expire so main task will continue.
		itsTimerPort->setTimer(0.0);
Ruud Overeem's avatar
Ruud Overeem committed
		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
Ruud Overeem's avatar
Ruud Overeem committed
		if ((strstr(pPropAnswer->pPropName, PSN_MAC_SCHEDULER) != 0) &&
Ruud Overeem's avatar
Ruud Overeem committed
			(pPropAnswer->pValue->getType() == LPT_INTEGER)) {
			uint32	newVal = (uint32) ((GCFPVInteger*)pPropAnswer->pValue)->getValue();
			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;
			}
		}
		break;
	}  

	default:
		break;
	}  
}


//
// initial_state(event, port)
//
// Setup all connections.
//
GCFEvent::TResult MACScheduler::initial_state(GCFEvent& event, GCFPortInterface& /*port*/)
{
Ruud Overeem's avatar
Ruud Overeem committed
	LOG_DEBUG_STR ("initial_state:" << evtstr(event));
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	GCFEvent::TResult status = GCFEvent::HANDLED;
  
	switch (event.signal) {
Ruud Overeem's avatar
Ruud Overeem committed
    case F_INIT:
Ruud Overeem's avatar
Ruud Overeem committed
   		break;

Ruud Overeem's avatar
Ruud Overeem committed
	case F_ENTRY: {
Ruud Overeem's avatar
Ruud Overeem committed
		// Get access to my own propertyset.
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG ("Activating PropertySet");
Ruud Overeem's avatar
Ruud Overeem committed
		itsPropertySet = GCFMyPropertySetPtr(new GCFMyPropertySet(PSN_MAC_SCHEDULER,
																  PST_MAC_SCHEDULER,
Ruud Overeem's avatar
Ruud Overeem committed
																  PS_CAT_PERM_AUTOLOAD,
Ruud Overeem's avatar
Ruud Overeem committed
																  &itsPropertySetAnswer));
		itsPropertySet->enable();
Ruud Overeem's avatar
Ruud Overeem committed
		// Wait for timer that is set in PropertySetAnswer on ENABLED event.
		}
		break;
Ruud Overeem's avatar
Ruud Overeem committed
	  
Ruud Overeem's avatar
Ruud Overeem committed
	case F_TIMER: {		// must be timer that PropSet is enabled.
Ruud Overeem's avatar
Ruud Overeem committed
		// update PVSS.
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_TRACE_FLOW ("Updateing state to PVSS");
Ruud Overeem's avatar
Ruud Overeem committed
		itsPropertySet->setValue(PVSSNAME_FSM_STATE,      GCFPVString  ("initial"));
		itsPropertySet->setValue(PVSSNAME_FSM_ERROR,      GCFPVString  (""));
		itsPropertySet->setValue(PN_MS_OTDB_CONNECTED,    GCFPVBool    (false));
		itsPropertySet->setValue(PN_MS_OTDB_LAST_POLL,    GCFPVString  (""));
		itsPropertySet->setValue(PN_MS_OTDB_POLLINTERVAL, GCFPVUnsigned(itsOTDBpollInterval));
		itsPropertySet->setValue(PN_MS_ACTIVE_OBSERVATIONS, GCFPVDynArr(LPT_STRING, itsPVSSObsList));
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
      
		// Try to connect to the SAS database.
		ACC::APS::ParameterSet* pParamSet = ACC::APS::globalParameterSet();
		string username	= pParamSet->getString("OTDBusername");
		string DBname 	= pParamSet->getString("OTDBdatabasename");
		string password	= pParamSet->getString("OTDBpassword");

Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG ("Trying to connect to the OTDB");
		itsOTDBconnection= new OTDBconnection(username, password, DBname);
Ruud Overeem's avatar
Ruud Overeem committed
		ASSERTSTR (itsOTDBconnection, "Memory allocation error (OTDB)");
		ASSERTSTR (itsOTDBconnection->connect(),
					"Unable to connect to database " << DBname << " using " <<
					username << "," << password);
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_INFO ("Connected to the OTDB");
Ruud Overeem's avatar
Ruud Overeem committed
		itsPropertySet->setValue(string(PN_MS_OTDB_CONNECTED),GCFPVBool(true));
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
		// Start ChildControl task
		LOG_DEBUG ("Enabling ChildControltask");
		itsChildControl->openService(MAC_SVCMASK_SCHEDULERCTRL, 0);
Ruud Overeem's avatar
Ruud Overeem committed
		itsChildControl->registerCompletionPort(itsChildPort);
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
		TRAN(MACScheduler::recover_state);				// go to next state.
Ruud Overeem's avatar
Ruud Overeem committed
		}
		break;
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	case F_CONNECTED:
		break;
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	case F_DISCONNECTED:
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	
	default:
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG ("MACScheduler::initial, default");
Ruud Overeem's avatar
Ruud Overeem committed
		status = GCFEvent::NOT_HANDLED;
		break;
	}    
	return (status);
}


//
// recover_state(event, port)
//
// Read last PVSS states, compare those to the SAS states and try to
// recover to the last situation.
//
GCFEvent::TResult MACScheduler::recover_state(GCFEvent& event, GCFPortInterface& port)
{
Ruud Overeem's avatar
Ruud Overeem committed
	LOG_DEBUG_STR ("recover_state:" << evtstr(event) << "@" << port.getName());
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	GCFEvent::TResult status = GCFEvent::HANDLED;

	switch (event.signal) {
	case F_INIT:
		break;

	case F_ENTRY: {
		// update PVSS
		itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString("recover"));
		itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),GCFPVString(""));

		//
		// TODO: do recovery

		TRAN(MACScheduler::active_state);
		
		break;
	}
  
	default:
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG("recover_state, default");
Ruud Overeem's avatar
Ruud Overeem committed
		status = GCFEvent::NOT_HANDLED;
		break;
	}    
	return (status);
}

//
// active_state(event, port)
//
// Normal operation state. Check OTDB every OTDBpollInterval seconds and control
// the running observations.
//
GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface& port)
{
Ruud Overeem's avatar
Ruud Overeem committed
	LOG_DEBUG_STR ("active:" << evtstr(event) << "@" << port.getName());
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	GCFEvent::TResult status = GCFEvent::HANDLED;

	switch (event.signal) {
	case F_INIT:
		break;

	case F_ENTRY: {
Ruud Overeem's avatar
Ruud Overeem committed
  	    // install my own signal handler. GCFTask also installs a handler so we have 
		// to install our handler later than the GCFTask handler.
blaakmeer's avatar
blaakmeer committed
	    pMacScheduler = this;
Ruud Overeem's avatar
Ruud Overeem committed
		signal (SIGINT, MACScheduler::sigintHandler);	// ctrl-c
Ruud Overeem's avatar
Ruud Overeem committed
		signal (SIGTERM, MACScheduler::sigintHandler);	// kill
blaakmeer's avatar
blaakmeer committed

Ruud Overeem's avatar
Ruud Overeem committed
		// update PVSS
		itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString("active"));
		itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),GCFPVString(""));

		// Timers must be connected to ports, so abuse serverPort for second timer.
Ruud Overeem's avatar
Ruud Overeem committed
		itsSecondTimer = itsTimerPort->setTimer(1L);
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	}

Ruud Overeem's avatar
Ruud Overeem committed
	case F_ACCEPT_REQ:
Ruud Overeem's avatar
Ruud Overeem committed
		break;

	case F_CONNECTED:	
		// Should be from the (lost) connection with the SD
		_connectedHandler(port);
		break;

	case F_DISCONNECTED:	
		// Can be from StartDaemon or ObsController.
		// StartDaemon: trouble! Try to reconnect asap.
		// ObsController: ok when obs is finished, BIG TROUBLE when not!
		_disconnectedHandler(port);
		break;

	case F_TIMER: {		// secondTimer or reconnectTimer.
		GCFTimerEvent& timerEvent=static_cast<GCFTimerEvent&>(event);
		if (timerEvent.id == itsSecondTimer) {
			// time to poll the OTDB?
			if (time(0) >= itsNextOTDBpolltime) {
				_doOTDBcheck();
Ruud Overeem's avatar
Ruud Overeem committed
				// reinit polltime at multiple of intervaltime.
				// (=more change to hit hh.mm:00)
Ruud Overeem's avatar
Ruud Overeem committed
				itsNextOTDBpolltime = time(0) + itsOTDBpollInterval;
Ruud Overeem's avatar
Ruud Overeem committed
				itsNextOTDBpolltime -= (itsNextOTDBpolltime % itsOTDBpollInterval);
Ruud Overeem's avatar
Ruud Overeem committed
			}
			itsSecondTimer = port.setTimer(1.0);
		}
		// a connection was lost and a timer was set to try to reconnect.
//		else if (...) {
			// TODO
//			map timer to port
//			port.open();
//		}
		break;
	}

Ruud Overeem's avatar
Ruud Overeem committed
	// -------------------- EVENTS FROM CHILDCONTROL --------------------

Ruud Overeem's avatar
Ruud Overeem committed
	case CONTROL_STARTED: {
Ruud Overeem's avatar
Ruud Overeem committed
		// Child control received a message from the startDaemon that the
		// observationController was started (or not)
Ruud Overeem's avatar
Ruud Overeem committed
		CONTROLStartedEvent	msg(event);
		if (msg.successful) {
			LOG_DEBUG_STR("Start of " << msg.cntlrName << " was successful");
		}
		else {
			LOG_ERROR_STR("Observation controller " << msg.cntlrName <<
Ruud Overeem's avatar
Ruud Overeem committed
						" could not be started");
Ruud Overeem's avatar
Ruud Overeem committed
			LOG_INFO("Observation will be removed from administration");
Ruud Overeem's avatar
Ruud Overeem committed
			_removeActiveObservation(msg.cntlrName);
Ruud Overeem's avatar
Ruud Overeem committed
		}
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	}
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	case CONTROL_CONNECT: {
Ruud Overeem's avatar
Ruud Overeem committed
		// The observationController has registered itself at childControl.
Ruud Overeem's avatar
Ruud Overeem committed
		CONTROLConnectEvent conEvent(event);
		LOG_DEBUG_STR("Received CONNECT(" << conEvent.cntlrName << ")");
Ruud Overeem's avatar
Ruud Overeem committed
		// TODO: do something usefull with this information?
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	}

Ruud Overeem's avatar
Ruud Overeem committed
	case CONTROL_FINISH: {
		// The observationController is going down.
		CONTROLFinishEvent finishEvent(event);
		LOG_DEBUG_STR("Received FINISH(" << finishEvent.cntlrName << ")");
		LOG_DEBUG_STR("Removing observation " << finishEvent.cntlrName << 
						" from activeList");
Ruud Overeem's avatar
Ruud Overeem committed
		_removeActiveObservation(finishEvent.cntlrName);
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	}
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	// NOTE: ignore all other CONTROL events, we are not interested in the
	// states of the Observations. (not our job).
Ruud Overeem's avatar
Ruud Overeem committed
	default:
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG("MACScheduler::active, default");
Ruud Overeem's avatar
Ruud Overeem committed
		status = GCFEvent::NOT_HANDLED;
		break;
	}

	return (status);
}

blaakmeer's avatar
blaakmeer committed
//
// finishing_state(event, port)
//
// Write controller state to PVSS, wait for 1 second (using a timer) to let GCF handle the property change
// and close the controller
//
GCFEvent::TResult MACScheduler::finishing_state(GCFEvent& event, GCFPortInterface& port)
{
	LOG_DEBUG_STR ("finishing_state:" << 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("finished"));
		itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),GCFPVString(""));

		itsTimerPort->setTimer(1L);
		break;
	}
  
    case F_TIMER:
      GCFTask::stop();
      break;
    
	default:
		LOG_DEBUG("finishing_state, default");
		status = GCFEvent::NOT_HANDLED;
		break;
	}    
	return (status);
}

//
// finish
//
// Make the transition to the finishing state
//
void MACScheduler::finish()
{
  TRAN(MACScheduler::finishing_state);
}

Ruud Overeem's avatar
Ruud Overeem committed
//
// _doOTDBcheck
//
// Check if a new action should be taken based on the contents of OTDB and our own
// administration.
//
void MACScheduler::_doOTDBcheck()
{
Ruud Overeem's avatar
Ruud Overeem committed
	// update PVSS database
Ruud Overeem's avatar
Ruud Overeem committed
	ptime	currentTime = from_time_t(time(0));
	itsPropertySet->setValue(string(PN_MS_OTDB_LAST_POLL),
										GCFPVString(to_simple_string(currentTime)));

Ruud Overeem's avatar
Ruud Overeem committed
	// get new list (list is ordered on starttime)
	vector<OTDBtree> newTreeList = itsOTDBconnection->getExecutableTrees();
	if (newTreeList.empty()) {
		return;
	}

	LOG_DEBUG(formatString("OTDBCheck:First observation is at %s (tree=%d)", 
				to_simple_string(newTreeList[0].starttime).c_str(), newTreeList[0].treeID()));

	// walk through the list and bring each observation in the right state when necc.
	uint32		listSize = newTreeList.size();
	uint32		idx = 0;
	ASSERTSTR (currentTime != not_a_date_time, "Can't determine systemtime, bailing out");

	while (idx < listSize)  {
		// timediff = time to go before start of Observation
		time_duration	timediff = newTreeList[idx].starttime - currentTime;
		LOG_TRACE_VAR_STR("timediff=" << timediff);

Ruud Overeem's avatar
Ruud Overeem committed
		// when queuetime is not reached yet we are finished with the list.
Ruud Overeem's avatar
Ruud Overeem committed
		if (timediff > seconds(itsQueuePeriod)) {
			break;
		}

		// get current state of Observation
Ruud Overeem's avatar
Ruud Overeem committed
		string		cntlrName = controllerName(CNTLRTYPE_OBSERVATIONCTRL, 
												0, newTreeList[idx].treeID());
Ruud Overeem's avatar
Ruud Overeem committed
		CTState::CTstateNr	requestedState= itsChildControl->getRequestedState(cntlrName);

		// When in startup or claimtime we should try to start the controller.
		if ((timediff > seconds(0)) && (requestedState != CTState::CONNECTED)) {
			// no, let database construct the parset for the whole observation
			OTDB::TreeMaintenance	tm(itsOTDBconnection);
			OTDB::treeIDType		treeID = newTreeList[idx].treeID();
			OTDBnode				topNode = tm.getTopNode(treeID);
Ruud Overeem's avatar
Ruud Overeem committed
			// NOTE: this name must be the same as in the ChildControl.
			string					filename = formatString("%s/Observation_%d", 
														LOFAR_SHARE_LOCATION, treeID);
Ruud Overeem's avatar
Ruud Overeem committed
			if (!tm.exportTree(treeID, topNode.nodeID(), filename)) {
Ruud Overeem's avatar
Ruud Overeem committed
				LOG_ERROR_STR ("Cannot create parset file " << filename << 
Ruud Overeem's avatar
Ruud Overeem committed
							" for new observation. Observation CANNOT BE STARTED!");
Ruud Overeem's avatar
Ruud Overeem committed
			}
Ruud Overeem's avatar
Ruud Overeem committed
			else {
				// fire request for new controller, will result in CONTROL_STARTED
Ruud Overeem's avatar
Ruud Overeem committed
				itsChildControl->startChild(CNTLRTYPE_OBSERVATIONCTRL, 
Ruud Overeem's avatar
Ruud Overeem committed
											treeID, 
											0,		// instanceNr
Ruud Overeem's avatar
Ruud Overeem committed
											myHostname(true));
Ruud Overeem's avatar
Ruud Overeem committed
				// Note: controller is now in state NO_STATE/CONNECTED (C/R)

				// register this Observation
				ParameterSet	obsPS(filename);
				Observation		newObs(&obsPS);
				newObs.name   = cntlrName;
				newObs.treeID = treeID;
Ruud Overeem's avatar
Ruud Overeem committed
				_addActiveObservation(newObs);
Ruud Overeem's avatar
Ruud Overeem committed
				LOG_DEBUG_STR("Observation " << cntlrName << " added to active Observations");
Ruud Overeem's avatar
Ruud Overeem committed

				TreeStateConv	tsc(itsOTDBconnection);
				tm.setTreeState(treeID, tsc.get("queued"));

Ruud Overeem's avatar
Ruud Overeem committed
			}
			idx++;
			continue;
Ruud Overeem's avatar
Ruud Overeem committed
		}

Ruud Overeem's avatar
Ruud Overeem committed
		// in CLAIM period?
		if ((timediff > seconds(0)) && (timediff <= seconds(itsClaimPeriod))) {
			// Observation is somewhere in the claim period its should be up by now.
			if (requestedState != CTState::CLAIMED) {
				LOG_ERROR_STR("Observation " << cntlrName << 
							" should have reached the CLAIMING state by now," <<
							" check state of observation.");
Ruud Overeem's avatar
Ruud Overeem committed
			}
Ruud Overeem's avatar
Ruud Overeem committed
			idx++;
			continue;
Ruud Overeem's avatar
Ruud Overeem committed
		}

		// observation must be running (otherwise it would not be in the newTreeList)
Ruud Overeem's avatar
Ruud Overeem committed
		// TODO: check if endtime is reached and observation is still running.
Ruud Overeem's avatar
Ruud Overeem committed
	
		idx++;	
	}
Ruud Overeem's avatar
Ruud Overeem committed

}

Ruud Overeem's avatar
Ruud Overeem committed
//
// _addActiveObservation(name)
//
void MACScheduler::_addActiveObservation(const Observation&	newObs)
{
	// Observation already in vector?
	vector<Observation>::iterator	end  = itsObservations.end();
	vector<Observation>::iterator	iter = itsObservations.begin();
	while (iter != end) {
		if (iter->name == newObs.name) {
			return;
		}
Ruud Overeem's avatar
Ruud Overeem committed
		iter++;
Ruud Overeem's avatar
Ruud Overeem committed
	}

	// update own admin and PVSS datapoint
	itsObservations.push_back(newObs);
Ruud Overeem's avatar
Ruud Overeem committed
	itsPVSSObsList.push_back(new GCFPVString(formatString("Observation%d", newObs.treeID)));
Ruud Overeem's avatar
Ruud Overeem committed
	itsPropertySet->setValue(PN_MS_ACTIVE_OBSERVATIONS, GCFPVDynArr(LPT_STRING, itsPVSSObsList));

	LOG_DEBUG_STR("Added observation " << newObs.name << " to active observation-list");

}


//
// _removeActiveObservation(name)
//
void MACScheduler::_removeActiveObservation(const string& name)
{
	// search observation.
Ruud Overeem's avatar
Ruud Overeem committed
	OTDB::treeIDType		treeID;
Ruud Overeem's avatar
Ruud Overeem committed
	vector<Observation>::iterator	end  = itsObservations.end();
	vector<Observation>::iterator	iter = itsObservations.begin();
	bool	found(false);
	while (!found && (iter != end)) {
		if (iter->name == name) {
			found = true;
Ruud Overeem's avatar
Ruud Overeem committed
			treeID = iter->treeID;
Ruud Overeem's avatar
Ruud Overeem committed
			itsObservations.erase(iter);
			LOG_DEBUG_STR("Removed observation " << name << " from active observationList");
		}
Ruud Overeem's avatar
Ruud Overeem committed
		iter++;
Ruud Overeem's avatar
Ruud Overeem committed
	}

	if (!found) {
		return;
	}

Ruud Overeem's avatar
Ruud Overeem committed
	string		obsName(formatString("Observation%d", treeID));
Ruud Overeem's avatar
Ruud Overeem committed
	GCFPValueArray::iterator	pEnd  = itsPVSSObsList.end();
	GCFPValueArray::iterator	pIter = itsPVSSObsList.begin();
	while (pIter != pEnd) {
Ruud Overeem's avatar
Ruud Overeem committed
		if ((static_cast<GCFPVString*>(*pIter))->getValue() == obsName) {
Ruud Overeem's avatar
Ruud Overeem committed
			delete 	*pIter;
			itsPVSSObsList.erase(pIter);
			break;
		}
Ruud Overeem's avatar
Ruud Overeem committed
		pIter++;
Ruud Overeem's avatar
Ruud Overeem committed
	}
	itsPropertySet->setValue(PN_MS_ACTIVE_OBSERVATIONS, GCFPVDynArr(LPT_STRING, itsPVSSObsList));
}

Ruud Overeem's avatar
Ruud Overeem committed

//
// _connectedHandler(port)
//
blaakmeer's avatar
blaakmeer committed
void MACScheduler::_connectedHandler(GCFPortInterface& /*port*/)
Ruud Overeem's avatar
Ruud Overeem committed
{
}

//
// _disconnectedHandler(port)
//
void MACScheduler::_disconnectedHandler(GCFPortInterface& port)
{
	string visd;
	port.close();
#if 0
	if(_isServerPort(itsVIparentPort,port)) {
		LOG_FATAL("VI parent server closed");
		itsVIparentPort.open(); // server closed? reopen it
	}
	else if(_isVISDclientPort(port,visd)) {
		LOG_FATAL(formatString("VI Startdaemon port disconnected: %s",visd.c_str()));
		port.setTimer(3L);
	}
	else if(_isVIclientPort(port)) {
		LOG_FATAL("VI client port disconnected");
		// do something with the nodeId?
	}
#endif
}


};
};