Skip to content
Snippets Groups Projects
MACScheduler.cc 22.6 KiB
Newer Older
Ruud Overeem's avatar
Ruud Overeem committed
//#  MACScheduler.cc: Implementation of the MAC Scheduler task
//#
Ruud Overeem's avatar
Ruud Overeem committed
//#  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 <Common/Version.h>
Ruud Overeem's avatar
Ruud Overeem committed

#include <Common/ParameterSet.h>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/TM/GCF_Protocols.h>
#include <GCF/PVSS/GCF_PVTypes.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/Controller_Protocol.ph>
Ruud Overeem's avatar
Ruud Overeem committed
#include <GCF/RTDB/DP_Protocol.ph>
#include <APL/RTDBCommon/CM_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 "MACScheduler.h"
Ruud Overeem's avatar
Ruud Overeem committed

using namespace LOFAR::GCF::PVSS;
Ruud Overeem's avatar
Ruud Overeem committed
using namespace LOFAR::GCF::TM;
Ruud Overeem's avatar
Ruud Overeem committed
using namespace LOFAR::GCF::RTDB;
Ruud Overeem's avatar
Ruud Overeem committed
using namespace LOFAR::OTDB;
using namespace std;

namespace LOFAR {
	using namespace APLCommon;
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("MACScheduler")),
Ruud Overeem's avatar
Ruud Overeem committed
	itsPropertySet		(0),
Ruud Overeem's avatar
Ruud Overeem committed
	itsChildControl		(0),
Ruud Overeem's avatar
Ruud Overeem committed
	itsChildPort		(0),
	itsClaimerTask		(0),
	itsClaimerPort		(0),
	itsTimerPort		(0),
Ruud Overeem's avatar
Ruud Overeem committed
	itsSecondTimer		(0),
	itsNextPlannedTime	(0),
	itsNextActiveTime	(0),
	itsNextFinishedTime	(0),
	itsOTDBconnection	(0)
Ruud Overeem's avatar
Ruud Overeem committed
{
	LOG_TRACE_OBJ ("MACscheduler construction");

	LOG_INFO_STR("MACProcessScope: " << PSN_MAC_SCHEDULER);
	LOG_INFO(Version::getInfo<MainCUVersion>("MACScheduler"));
Ruud Overeem's avatar
Ruud Overeem committed

	// Read timersettings from the ParameterSet
	itsPlannedItv	 = globalParameterSet()->getTime("pollIntervalPlanned", 60);
	itsActiveItv	 = globalParameterSet()->getTime("pollIntervalExecute", 5);
	itsFinishedItv	 = globalParameterSet()->getTime("pollIntervalFinished", 60);
	itsPlannedPeriod = globalParameterSet()->getTime("plannedPeriod",  86400) / 60;	// in minutes
	itsFinishedPeriod= globalParameterSet()->getTime("finishedPeriod", 86400) / 60; // in minutes

	// Read the schedule periods for starting observations.
Ruud Overeem's avatar
Ruud Overeem committed
	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

	// create an PVSSprepare Task
	itsClaimerTask = new ObsClaimer(this);
	ASSERTSTR(itsClaimerTask, "Cannot construct a ObsClaimerTask");
	itsClaimerPort = new GCFITCPort (*this, *itsClaimerTask, "ObsClaimerPort",
									GCFPortInterface::SAP, CM_PROTOCOL);

Ruud Overeem's avatar
Ruud Overeem committed
	// need port for timers
	itsTimerPort = new GCFTimerPort(*this, "Timerport");

	registerProtocol(CONTROLLER_PROTOCOL, CONTROLLER_PROTOCOL_STRINGS);
	registerProtocol(DP_PROTOCOL, 		  DP_PROTOCOL_STRINGS);
Ruud Overeem's avatar
Ruud Overeem committed
}


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

Ruud Overeem's avatar
Ruud Overeem committed
	if (itsPropertySet) {
		delete itsPropertySet;
	}
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

//
Ruud Overeem's avatar
Ruud Overeem committed
// _databaseEventHandler(event)
Ruud Overeem's avatar
Ruud Overeem committed
//
Ruud Overeem's avatar
Ruud Overeem committed
void MACScheduler::_databaseEventHandler(GCFEvent& event)
Ruud Overeem's avatar
Ruud Overeem committed
{
Ruud Overeem's avatar
Ruud Overeem committed

//	LOG_DEBUG_STR ("_databaseEventHandler:" << eventName(event));
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	switch(event.signal) {
	case DP_CHANGED: {
		DPChangedEvent	dpEvent(event);
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
		// TODO: implement something usefull.
Ruud Overeem's avatar
Ruud Overeem committed
		if (strstr(dpEvent.DPname.c_str(), PVSSNAME_MS_QUEUEPERIOD) != 0) {
			uint32	newVal = ((GCFPVUnsigned*) (dpEvent.value._pValue))->getValue();
			LOG_INFO_STR ("Changing QueuePeriod from " << itsQueuePeriod << " to " << newVal);
			itsQueuePeriod = newVal;
		}
		if (strstr(dpEvent.DPname.c_str(), PVSSNAME_MS_CLAIMPERIOD) != 0) {
			uint32	newVal = ((GCFPVUnsigned*) (dpEvent.value._pValue))->getValue();
			LOG_INFO_STR ("Changing ClaimPeriod from " << itsClaimPeriod << " to " << newVal);
			itsClaimPeriod = newVal;
Ruud Overeem's avatar
Ruud Overeem committed
		}
Ruud Overeem's avatar
Ruud Overeem committed
	}  
Ruud Overeem's avatar
Ruud Overeem committed
	break;
Ruud Overeem's avatar
Ruud Overeem committed

	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:" << eventName(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 = new RTDBPropertySet(PSN_MAC_SCHEDULER,
											 PST_MAC_SCHEDULER,
											 PSAT_RW,
											 this);
Ruud Overeem's avatar
Ruud Overeem committed
		}
		break;
Ruud Overeem's avatar
Ruud Overeem committed

	case DP_CREATED: {
			// NOTE: thsi function may be called DURING the construction of the PropertySet.
			// Always exit this event in a way that GCF can end the construction.
			DPCreatedEvent	dpEvent(event);
			LOG_DEBUG_STR("Result of creating " << dpEvent.DPname << " = " << dpEvent.result);
			itsTimerPort->cancelAllTimers();
			itsTimerPort->setTimer(0.0);
        }
		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");
		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION,		  GCFPVString  ("initial"));
		itsPropertySet->setValue(PN_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, 	  GCFPVInteger (itsPlannedItv));
		GCFPValueArray	emptyArr;
		itsPropertySet->setValue(PN_MS_ACTIVE_OBSERVATIONS,   GCFPVDynArr(LPT_STRING, emptyArr));
		itsPropertySet->setValue(PN_MS_PLANNED_OBSERVATIONS,  GCFPVDynArr(LPT_STRING, emptyArr));
		itsPropertySet->setValue(PN_MS_FINISHED_OBSERVATIONS, GCFPVDynArr(LPT_STRING, emptyArr));
Ruud Overeem's avatar
Ruud Overeem committed

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

Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG_STR ("Trying to connect to the OTDB on " << hostname);
		itsOTDBconnection= new OTDBconnection(username, password, DBname, hostname);
Ruud Overeem's avatar
Ruud Overeem committed
		ASSERTSTR (itsOTDBconnection, "Memory allocation error (OTDB)");
		ASSERTSTR (itsOTDBconnection->connect(),
Ruud Overeem's avatar
Ruud Overeem committed
					"Unable to connect to database " << DBname << " on " << hostname << 
					" 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(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

		// setup initial schedule: first planned, next run active, second run finished
		itsNextPlannedTime  = time(0);
		itsNextActiveTime   = itsNextPlannedTime +   itsPlannedItv;
		itsNextFinishedTime = itsNextPlannedTime + 2*itsPlannedItv;

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:" << eventName(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(PN_FSM_CURRENT_ACTION),GCFPVString("recover"));
		itsPropertySet->setValue(string(PN_FSM_ERROR),GCFPVString(""));
Ruud Overeem's avatar
Ruud Overeem committed

		//
		// 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 itsActiveItv seconds and control
Ruud Overeem's avatar
Ruud Overeem committed
// the running observations.
//
GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface& port)
{
Ruud Overeem's avatar
Ruud Overeem committed
	LOG_DEBUG_STR ("active:" << eventName(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(PN_FSM_CURRENT_ACTION),GCFPVString("active"));
		itsPropertySet->setValue(string(PN_FSM_ERROR),GCFPVString(""));
Ruud Overeem's avatar
Ruud Overeem committed

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;

Ruud Overeem's avatar
Ruud Overeem committed
	case DP_CHANGED:
		_databaseEventHandler(event);
		break;

	case CM_CLAIM_RESULT: {
			// some observation was claimed by the claimMgr. Update our prepare_list.
			CMClaimResultEvent	cmEvent(event);
			LOG_INFO_STR(cmEvent.nameInAppl << " is mapped to " << cmEvent.DPname);
			ltrim(cmEvent.nameInAppl, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_");
			int		obsID = atoi(cmEvent.nameInAppl.c_str());
			LOG_DEBUG_STR("PVSS preparation of observation " << obsID << " ready.");
			itsPreparedObs[obsID] = true;
		}
		break;

Ruud Overeem's avatar
Ruud Overeem committed
	case F_TIMER: {		// secondTimer or reconnectTimer.
		GCFTimerEvent& timerEvent=static_cast<GCFTimerEvent&>(event);
		if (timerEvent.id == itsSecondTimer) {
			// time to poll the OTDB?
			// Note: We assume here that the PlannedItv is smaller than the ActiveItv and the FinishedItv.
			//		 When it is not smaller (very unlikely) than the ActiveItv and FinishedItv those two
			//		 intervals will default to the PlannedItv.
			if (time(0) >= itsNextPlannedTime) {		// check shortest interval
Ruud Overeem's avatar
Ruud Overeem committed
				_doOTDBcheck();
Ruud Overeem's avatar
Ruud Overeem committed
				// reinit polltime at multiple of intervaltime.
				// (=more change to hit hh.mm:00)
				itsNextPlannedTime = time(0) + itsPlannedItv;
				itsNextPlannedTime -= (itsNextPlannedTime % itsPlannedItv);
Ruud Overeem's avatar
Ruud Overeem committed
			}
Ruud Overeem's avatar
Ruud Overeem committed
			port.cancelTimer(itsSecondTimer);
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 --------------------
	//
	// That must be events from the ObservationControllers that are currently 
	// started or running.
	//
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) {
Ruud Overeem's avatar
Ruud Overeem committed
			LOG_DEBUG_STR("Start of " << msg.cntlrName << 
						  " was successful, waiting for connection.");
Ruud Overeem's avatar
Ruud Overeem committed
		}
		else {
			LOG_ERROR_STR("Observation controller " << msg.cntlrName <<
Ruud Overeem's avatar
Ruud Overeem committed
						  " could not be started");
			LOG_INFO_STR("Observation is be removed from administration, " << 
						 "restart will occur in next cycle");
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
		// The observationController has registered itself at childControl.
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG_STR(conEvent.cntlrName << " is connected, updating SAS)");

		// Ok, controller is really up, update SAS so that obs will not appear in
		// in the SAS list again.
		CMiter	theObs(itsControllerMap.find(conEvent.cntlrName));
		if (theObs == itsControllerMap.end()) {
Ruud Overeem's avatar
Ruud Overeem committed
			LOG_WARN_STR("Cannot find controller " << conEvent.cntlrName << 	
						  ". Can't update the SAS database");
			break;
		}
		OTDB::TreeMaintenance	tm(itsOTDBconnection);
		TreeStateConv			tsc(itsOTDBconnection);
		tm.setTreeState(theObs->second, tsc.get("queued"));
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	}

Ruud Overeem's avatar
Ruud Overeem committed
	case CONTROL_QUITED: {
Ruud Overeem's avatar
Ruud Overeem committed
		// The observationController is going down.
Ruud Overeem's avatar
Ruud Overeem committed
		CONTROLQuitedEvent quitedEvent(event);
Ruud Overeem's avatar
Ruud Overeem committed
		LOG_DEBUG_STR("Received QUITED(" << quitedEvent.cntlrName << "," << quitedEvent.result << ")");
Ruud Overeem's avatar
Ruud Overeem committed

		// update SAS database.
		CMiter	theObs(itsControllerMap.find(quitedEvent.cntlrName));
		if (theObs == itsControllerMap.end()) {
Ruud Overeem's avatar
Ruud Overeem committed
			LOG_WARN_STR("Cannot find controller " << quitedEvent.cntlrName << 	
						  ". Can't update the SAS database");
			break;
		}
		OTDB::TreeMaintenance	tm(itsOTDBconnection);
		TreeStateConv			tsc(itsOTDBconnection);
Ruud Overeem's avatar
Ruud Overeem committed
		if (quitedEvent.result == CT_RESULT_NO_ERROR) {
			tm.setTreeState(theObs->second, tsc.get("finished"));
Ruud Overeem's avatar
Ruud Overeem committed
		}
		else {
			tm.setTreeState(theObs->second, tsc.get("aborted"));
Ruud Overeem's avatar
Ruud Overeem committed
		}
Ruud Overeem's avatar
Ruud Overeem committed

		// update our administration
		LOG_DEBUG_STR("Removing observation " << quitedEvent.cntlrName << 
Ruud Overeem's avatar
Ruud Overeem committed
						" from activeList");
//		_removeActiveObservation(quitedEvent.cntlrName);
Ruud Overeem's avatar
Ruud Overeem committed
		break;
	}
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	case CONTROL_RESUMED: {
		// update SAS database.
		CONTROLResumedEvent		msg(event);
		CMiter	theObs(itsControllerMap.find(msg.cntlrName));
		if (theObs == itsControllerMap.end()) {
Ruud Overeem's avatar
Ruud Overeem committed
			LOG_WARN_STR("Cannot find controller " << msg.cntlrName << 	
						  ". Can't update the SAS database");
			break;
		}
		OTDB::TreeMaintenance	tm(itsOTDBconnection);
		TreeStateConv			tsc(itsOTDBconnection);
		tm.setTreeState(theObs->second, tsc.get("active"));
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)
{
Ruud Overeem's avatar
Ruud Overeem committed
	LOG_DEBUG_STR ("finishing_state:" << eventName(event) << "@" << port.getName());
blaakmeer's avatar
blaakmeer committed

	GCFEvent::TResult status = GCFEvent::HANDLED;

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

	case F_ENTRY: {
		// update PVSS
		itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("finished"));
		itsPropertySet->setValue(PN_FSM_ERROR, 			GCFPVString(""));
		itsPropertySet->setValue(PN_MS_OTDB_CONNECTED,  GCFPVBool  (false));
blaakmeer's avatar
blaakmeer committed

		itsTimerPort->setTimer(1L);
		break;
	}
  
    case F_TIMER:
Ruud Overeem's avatar
Ruud Overeem committed
      GCFScheduler::instance()->stop();
blaakmeer's avatar
blaakmeer committed
      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 with polltime
	time_t		now = time(0);
	ptime	currentTime = from_time_t(now);
	itsPropertySet->setValue(string(PN_MS_OTDB_LAST_POLL), GCFPVString(to_simple_string(currentTime)));

	// always update planned list because we might need to start some of those
	// (and we assumed that the PlannedItv was the smallest)
	_updatePlannedList();

	// update active lists when its time to do so.
	if (now >= itsNextActiveTime) {
		_updateActiveList();
		while (itsNextActiveTime <= now) {
			itsNextActiveTime += itsActiveItv;
		}
	}

	// update finished lists when its time to do so.
	if (now >= itsNextFinishedTime) {
		_updateFinishedList();
		while (itsNextFinishedTime <= now) {
			itsNextFinishedTime += itsFinishedItv;
		}
	}
}

//
// _updatePlannedList()
//
void MACScheduler::_updatePlannedList()
{
	LOG_DEBUG("_updatePlannedList()");
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed
	// get new list (list is ordered on starttime)
	vector<OTDBtree> plannedDBlist = itsOTDBconnection->getTreeGroup(1, itsPlannedPeriod);	// planned observations
Ruud Overeem's avatar
Ruud Overeem committed

	if (!plannedDBlist.empty()) {
		LOG_DEBUG(formatString("OTDBCheck:First planned observation is at %s (tree=%d)", 
				to_simple_string(plannedDBlist[0].starttime).c_str(), plannedDBlist[0].treeID()));
	}
	// NOTE: do not exit routine on emptylist: we need to write an empty list to clear the DB
Ruud Overeem's avatar
Ruud Overeem committed

	// walk through the list, prepare PVSS for the new obs, update own admin lists.
	GCFPValueArray	plannedArr;
	uint32			listSize = plannedDBlist.size();
	uint32			idx = 0;
	time_t			now = time(0);
	ptime			currentTime = from_time_t(now);
Ruud Overeem's avatar
Ruud Overeem committed
	ASSERTSTR (currentTime != not_a_date_time, "Can't determine systemtime, bailing out");

	while (idx < listSize)  {
		// construct name and timings info for observation
		treeIDType		obsID = plannedDBlist[idx].treeID();
		string			obsName(observationName(obsID));

		// must we claim this observation at the claimMgr?
		OLiter	prepIter = itsPreparedObs.find(obsID);
		if ((prepIter == itsPreparedObs.end()) || (prepIter->second == false)) {
			// create a ParameterFile for this Observation
			TreeMaintenance		tm(itsOTDBconnection);
			OTDBnode			topNode = tm.getTopNode(obsID);
			string				filename(observationParset(obsID));
			if (!tm.exportTree(obsID, topNode.nodeID(), filename)) {
				LOG_ERROR_STR ("Cannot create ParameterSet '" << filename << 
								"' for new observation. Observation CANNOT BE STARTED!");
			}
			else {
				// Claim a DP in PVSS and write obssettings to it so the operator can see it.
				LOG_DEBUG_STR("Requesting preparation of PVSS for " << obsName);
				itsClaimerTask->prepareObservation(obsName);
				itsPreparedObs[obsID] = false;	// requested claim but no answer yet.
			}
Ruud Overeem's avatar
Ruud Overeem committed
		}
		else {
			// only add observations to the PVSS list when the claim was succesfull
			// otherwise thing will go wrong in the Navigator
			plannedArr.push_back(new GCFPVString(obsName));
		}
	
		// should this observation (have) be(en) started?
		time_duration	timeBeforeStart(plannedDBlist[idx].starttime - currentTime);
//		LOG_TRACE_VAR_STR(obsName << " starts over " << timeBeforeStart << " seconds");
		if (timeBeforeStart > seconds(0) && timeBeforeStart <= seconds(itsQueuePeriod)) {
			if (itsPreparedObs[obsID] == false) {
				LOG_ERROR_STR("Observation " << obsID << " must be started but is not claimed yet.");
Ruud Overeem's avatar
Ruud Overeem committed
			}
Ruud Overeem's avatar
Ruud Overeem committed
			else {
				// starttime of observation lays in queuePeriod. Start the controller-chain,
				// this will result in CONTROL_STARTED event in our main task
				// Note: as soon as the ObservationController has reported itself to the MACScheduler
				//		 the observation will not be returned in the 'plannedDBlist' anymore.
				string	cntlrName(controllerName(CNTLRTYPE_OBSERVATIONCTRL, 0, obsID));
				LOG_DEBUG_STR("Requesting start of " << cntlrName);
Ruud Overeem's avatar
Ruud Overeem committed
				itsChildControl->startChild(CNTLRTYPE_OBSERVATIONCTRL, 
Ruud Overeem's avatar
Ruud Overeem committed
											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)

				// add controller to our 'monitor' administration
				itsControllerMap[cntlrName] =  obsID;
				LOG_DEBUG_STR("itsControllerMap[" << cntlrName << "]=" <<  obsID);
Ruud Overeem's avatar
Ruud Overeem committed
			}
Ruud Overeem's avatar
Ruud Overeem committed
		}
		idx++;
	} // while processing all planned obs'
Ruud Overeem's avatar
Ruud Overeem committed

	// Finally we can pass the list with planned observations to PVSS.
	itsPropertySet->setValue(PN_MS_PLANNED_OBSERVATIONS, GCFPVDynArr(LPT_DYNSTRING, plannedArr));
Ruud Overeem's avatar
Ruud Overeem committed

}

Ruud Overeem's avatar
Ruud Overeem committed
//
Ruud Overeem's avatar
Ruud Overeem committed
//
Ruud Overeem's avatar
Ruud Overeem committed
{
Ruud Overeem's avatar
Ruud Overeem committed

	// get new list (list is ordered on starttime)
	vector<OTDBtree> activeDBlist = itsOTDBconnection->getTreeGroup(2, 0);
	if (activeDBlist.empty()) {
		LOG_DEBUG ("No active Observations");
		// NOTE: do not exit routine on emptylist: we need to write an empty list to clear the DB
Ruud Overeem's avatar
Ruud Overeem committed
	}

	// walk through the list, prepare PVSS for the new obs, update own admin lists.
	GCFPValueArray	activeArr;
	uint32			listSize = activeDBlist.size();
	uint32			idx = 0;
	while (idx < listSize)  {
		// construct name and timings info for observation
		string		obsName(observationName(activeDBlist[idx].treeID()));
		activeArr.push_back(new GCFPVString(obsName));

		// remove obs from planned-list if its still their.
		OLiter	prepIter = itsPreparedObs.find(activeDBlist[idx].treeID());
		if (prepIter != itsPreparedObs.end()) {
			itsPreparedObs.erase(prepIter);
		}
Ruud Overeem's avatar
Ruud Overeem committed

Ruud Overeem's avatar
Ruud Overeem committed

	// Finally we can pass the list with active observations to PVSS.
	itsPropertySet->setValue(PN_MS_ACTIVE_OBSERVATIONS,	GCFPVDynArr(LPT_DYNSTRING, activeArr));
Ruud Overeem's avatar
Ruud Overeem committed
}

//
Ruud Overeem's avatar
Ruud Overeem committed
//
Ruud Overeem's avatar
Ruud Overeem committed
{
Ruud Overeem's avatar
Ruud Overeem committed

	// get new list (list is ordered on starttime)
	vector<OTDBtree> finishedDBlist = itsOTDBconnection->getTreeGroup(3, itsFinishedPeriod);
	if (finishedDBlist.empty()) {
		LOG_DEBUG ("No finished Observations");
		// NOTE: do not exit routine on emptylist: we need to write an empty list to clear the DB
Ruud Overeem's avatar
Ruud Overeem committed
	}

	// walk through the list, prepare PVSS for the new obs, update own admin lists.
	GCFPValueArray	finishedArr;
	uint32			listSize = finishedDBlist.size();
	uint32			idx = 0;
	while (idx < listSize)  {
		// construct name and timings info for observation
		string		obsName(observationName(finishedDBlist[idx].treeID()));
		finishedArr.push_back(new GCFPVString(obsName));
		idx++;
	} // while

	// Finally we can pass the list with finished observations to PVSS.
	itsPropertySet->setValue(PN_MS_FINISHED_OBSERVATIONS,
								GCFPVDynArr(LPT_DYNSTRING, finishedArr));
Ruud Overeem's avatar
Ruud Overeem committed
}

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)
{
	port.close();
}


};
};