From 210c512c58af6f4d0aa6eaa2781cf04709fade43 Mon Sep 17 00:00:00 2001
From: Ruud Overeem <overeem@astron.nl>
Date: Fri, 28 Apr 2006 11:58:09 +0000
Subject: [PATCH] BugID: 679 Redesign of Main Control Unit software.

---
 MAC/APL/MainCU/MainCU.spec.in                 | 169 ++++
 MAC/APL/MainCU/Makefile.am                    |   8 +
 MAC/APL/MainCU/bootstrap                      |   3 +
 MAC/APL/MainCU/configure.in                   |  77 ++
 .../src/MACScheduler/APLMACScheduler.dpl      |   9 +
 .../src/MACScheduler/LogicalDeviceState.cc    |  87 ++
 .../src/MACScheduler/LogicalDeviceState.h     | 107 +++
 .../MainCU/src/MACScheduler/MACScheduler.cc   | 787 ++++++++++++++++++
 .../src/MACScheduler/MACScheduler.conf.in     |  53 ++
 .../MainCU/src/MACScheduler/MACScheduler.h    | 181 ++++
 .../src/MACScheduler/MACScheduler.log_prop.in |  44 +
 .../src/MACScheduler/MACSchedulerDefines.h    |  47 ++
 .../src/MACScheduler/MACSchedulerMain.cc      |  38 +
 MAC/APL/MainCU/src/MACScheduler/Makefile.am   |  44 +
 .../src/MACScheduler/customPrepPVSSDB.ctl.in  |  17 +
 MAC/APL/MainCU/src/Makefile.am                |   4 +
 .../StationControl/customPrepPVSSDB.ctl.in    |  17 +
 17 files changed, 1692 insertions(+)
 create mode 100644 MAC/APL/MainCU/MainCU.spec.in
 create mode 100644 MAC/APL/MainCU/Makefile.am
 create mode 100755 MAC/APL/MainCU/bootstrap
 create mode 100644 MAC/APL/MainCU/configure.in
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/APLMACScheduler.dpl
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.cc
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.h
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/MACScheduler.conf.in
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/MACScheduler.h
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/MACSchedulerDefines.h
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/MACSchedulerMain.cc
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/Makefile.am
 create mode 100644 MAC/APL/MainCU/src/MACScheduler/customPrepPVSSDB.ctl.in
 create mode 100644 MAC/APL/MainCU/src/Makefile.am
 create mode 100644 MAC/APL/StationCU/src/StationControl/customPrepPVSSDB.ctl.in

diff --git a/MAC/APL/MainCU/MainCU.spec.in b/MAC/APL/MainCU/MainCU.spec.in
new file mode 100644
index 00000000000..f68a74235b7
--- /dev/null
+++ b/MAC/APL/MainCU/MainCU.spec.in
@@ -0,0 +1,169 @@
+# -*- Mode:rpm-spec -*-
+# MCU.spec.in
+#
+
+##############################################################################
+#
+# Preamble
+#
+##############################################################################
+
+Summary: The MCU contains all controller for the MainCU.
+
+%define release @RPM_RELEASE@
+%define version @VERSION@
+%define pkgname @PACKAGE@
+%define pkgdir %{pkgname}-%{version}-%{release}
+%define prefix /opt/lofar
+%define configure_args @RPM_CONFIGURE_ARGS@
+##define build_kernel_version @BUILD_KERNEL_VERSION@
+
+Name: %{pkgname}
+Version: %{version}
+Release: %{release}
+Copyright: LGPL
+Group: Application/System
+Source: %{pkgname}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{pkgdir}-root
+URL: http://www.astron.nl
+Prefix: %{prefix}
+BuildArchitectures: i386 # Target platforms, i.e., i586
+Requires: Common = 2.3
+Requires: APS = 2.0
+Requires: OTDB = 1.0
+Requires: GCFTM = 6.0
+Requires: GCFCommon = 6.0
+Requires: GCFPAL = 6.0
+Requires: APLCommon = 3.1
+Packager: %{packager}
+Distribution: The LOFAR project
+Vendor: ASTRON
+
+AutoReqProv: no
+
+%description
+
+The MCU contains all controller for the MainCU:
+MacScheduler that scans the SAS database for new observations.
+ObservationCtrl that is the maincontroller for each observation.
+BeamDirection that makes sure that all station point in the same direction.
+
+##############################################################################
+#
+# prep
+#
+##############################################################################
+%prep
+echo $prefix
+
+# create the build directory, untar the source
+%setup
+
+##############################################################################
+#
+# build
+#
+##############################################################################
+%build
+./configure %{configure_args} --prefix=%{prefix} && make
+
+##############################################################################
+#
+# install
+#
+##############################################################################
+%install
+# To make things work with BUILDROOT
+if [ "$RPM_BUILD_ROOT" != "%{_tmppath}/%{pkgdir}-root" ]
+then
+  echo
+  echo @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+  echo @                                                                    @
+  echo @  RPM_BUILD_ROOT is not what I expected.  Please clean it yourself. @
+  echo @                                                                    @
+  echo @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+  echo
+else
+  echo Cleaning RPM_BUILD_ROOT: "$RPM_BUILD_ROOT"
+  rm -rf "$RPM_BUILD_ROOT"
+fi
+mkdir -p $RPM_BUILD_ROOT%{prefix}
+make DESTDIR="$RPM_BUILD_ROOT" install
+
+#uninstall
+
+##############################################################################
+#
+# verify
+#
+##############################################################################
+#verify
+
+##############################################################################
+#
+# clean
+#
+##############################################################################
+%clean
+# Call me paranoid, but I do not want to be responsible for nuking
+# someone's harddrive!
+if [ "$RPM_BUILD_ROOT" != "%{_tmppath}/%{pkgdir}-root" ]
+then
+  echo
+  echo @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+  echo @                                                                    @
+  echo @  RPM_BUILD_ROOT is not what I expected.  Please clean it yourself. @
+  echo @                                                                    @
+  echo @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+  echo
+else
+  echo Cleaning RPM_BUILD_ROOT: "$RPM_BUILD_ROOT"
+  rm -rf "$RPM_BUILD_ROOT"
+fi
+
+##############################################################################
+#
+# files
+#
+##############################################################################
+
+# empty 'files' means all distributed files
+%files
+%defattr(-, root, root)
+%{prefix}
+
+# Your application file list goes here
+# %{prefix}/lib/lib*.so*
+
+# Documentation
+# doc COPYING ChangeLog README AUTHORS NEWS
+# doc doc/*
+
+# link the module to the correct path
+%post 
+
+# before uninstall
+%preun
+
+# after uninstall
+%postun
+
+##############################################################################
+#
+# package devel
+#
+##############################################################################
+
+#package devel
+#Summary: Development files for %{pkgname}
+#Group: Applications/System
+#description devel
+#Development files for %{pkgname}.
+
+#files devel
+
+# Your development files go here
+# Programmers documentation goes here
+#doc doc
+
+# end of file
diff --git a/MAC/APL/MainCU/Makefile.am b/MAC/APL/MainCU/Makefile.am
new file mode 100644
index 00000000000..9f9e52186c1
--- /dev/null
+++ b/MAC/APL/MainCU/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS=src
+
+EXTRA_DIST = \
+      Makefile.common \
+      MainCU.spec \
+      autoconf_share/compiletool
+
+include $(top_srcdir)/Makefile.common
diff --git a/MAC/APL/MainCU/bootstrap b/MAC/APL/MainCU/bootstrap
new file mode 100755
index 00000000000..06f18cde1db
--- /dev/null
+++ b/MAC/APL/MainCU/bootstrap
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+../../../autoconf_share/bootstrap ../../../autoconf_share
diff --git a/MAC/APL/MainCU/configure.in b/MAC/APL/MainCU/configure.in
new file mode 100644
index 00000000000..ee57a399b4e
--- /dev/null
+++ b/MAC/APL/MainCU/configure.in
@@ -0,0 +1,77 @@
+dnl
+dnl Process this file with autoconf to produce a configure script.
+dnl
+AC_INIT
+dnl AC_CONFIG_AUX_DIR(config)
+dnl AM_CONFIG_HEADER(config/config.h)
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(MainCU, 1.0, no-define)
+
+dnl
+dnl Initialize for LOFAR (may set compilers)
+dnl
+lofar_INIT
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_DISABLE_SHARED
+AC_PROG_LIBTOOL
+AC_PROG_YACC
+AM_PROG_LEX
+
+dnl Checks for libraries.
+
+dnl dnl Replace `main' with a function in -lfl:
+dnl AC_CHECK_LIB(fl, main)
+dnl dnl Replace `main' with a function in -lcosev_r:
+dnl AC_CHECK_LIB(cosev_r, main)
+dnl dnl Replace `main' with a function in -lcosnm_r:
+dnl AC_CHECK_LIB(cosnm_r, main)
+dnl dnl Replace `main' with a function in -lorb_r:
+dnl AC_CHECK_LIB(orb_r, main)
+dnl dnl Replace `main' with a function in -lpthread:
+dnl AC_CHECK_LIB(pthread, main)
+dnl dnl Replace `main' with a function in -lvport_r:
+dnl AC_CHECK_LIB(vport_r, main)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+dnl Checks for library functions.
+AC_FUNC_VPRINTF
+
+dnl
+dnl Check for LOFAR specific things
+dnl
+lofar_GENERAL
+lofar_COMPILETOOLS
+lofar_PVSS(1)
+lofar_INTERNAL(LCS/Common, common, LCS-Common-2_3, 1, Common/LofarTypes.h,,)
+lofar_INTERNAL(LCS/ACC/APS, aps, LCS-ACC-2_0, 1, APS/ParameterSet.h,,)
+lofar_INTERNAL(SAS/OTDB, otdb, HEAD, 1, OTDB/OTDBconnection.h,,)
+lofar_INTERNAL(MAC/GCF/GCFCommon, gcfcommon, MAC-GCF-6_0, 1, GCF/GCF_Defines.h,,)
+lofar_INTERNAL(MAC/GCF/TM, gcftm, MAC-GCF-6_0, 1, GCF/TM/GCF_Task.h,,)
+lofar_INTERNAL(MAC/GCF/PAL, gcfpal, MAC-GCF-6_0, 1, GCF/PAL/GCF_PVSSInfo.h,,)
+lofar_INTERNAL(MAC/APL/APLCommon, aplcommon, MAC-APL-3_1, 1, APL/APLCommon/APL_Defines.h,,)
+lofar_EXTERNAL(boost,1.32,boost/date_time/date.hpp, boost_date_time-gcc)
+lofar_EXTERNAL(pqxx,2.5.5,pqxx/pqxx, pqxx)
+lofar_EXTERNAL(pq,,libpq-fe.h, pq, /usr/local/pgsql)
+
+dnl
+dnl Output Makefiles
+dnl
+AC_OUTPUT(
+src/Makefile
+src/MACScheduler/Makefile
+Makefile
+MainCU.spec
+)
diff --git a/MAC/APL/MainCU/src/MACScheduler/APLMACScheduler.dpl b/MAC/APL/MainCU/src/MACScheduler/APLMACScheduler.dpl
new file mode 100644
index 00000000000..18503e5533f
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/APLMACScheduler.dpl
@@ -0,0 +1,9 @@
+# ascii dump of database
+
+# DpType
+TypeName
+TAplMacScheduler.TAplMacScheduler	1#1
+	state	25#2
+	error	25#3
+	
+	
diff --git a/MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.cc b/MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.cc
new file mode 100644
index 00000000000..527192bca73
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.cc
@@ -0,0 +1,87 @@
+//#  LogicalDeviceState.cc: one_line_description
+//#
+//#  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$
+
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+//# Includes
+#include <Common/LofarLogger.h>
+#include <LogicalDeviceState.h>
+
+namespace LOFAR {
+  namespace APLCommon {
+
+//
+// LogicalDeviceState()
+//
+LogicalDeviceState::LogicalDeviceState()
+{
+	itsStates.resize(LAST_STATE);
+	itsStates[UNKNOWN] 				= "Unknown";
+	itsStates[CONNECT]				= "Connecting";
+	itsStates[CONNECTED]			= "Connected";
+	itsStates[SCHEDULE]				= "Scheduling";
+	itsStates[SCHEDULED]			= "Scheduled";
+	itsStates[CANCEL_SCHEDULE]		= "Canceling Schedule";
+	itsStates[SCHEDULE_CANCELLED]	= "Schedule Cancelled";
+	itsStates[CLAIM]				= "Claiming";
+	itsStates[CLAIMED]				= "Claimed";
+	itsStates[PREPARE]				= "Preparing";
+	itsStates[PREPARED]				= "Prepared";
+	itsStates[RESUME]				= "Resuming";
+	itsStates[RESUMED]				= "Resumed";
+	itsStates[SUSPEND]				= "Suspending";
+	itsStates[SUSPENDED]			= "Suspended";
+	itsStates[RELEASE]				= "Releasing";
+	itsStates[RELEASED]				= "Released";
+	itsStates[FINISH]				= "Finishing";
+	itsStates[FINISHED]				= "Finished";
+}
+
+//
+// ~LogicalDeviceState()
+//
+LogicalDeviceState::~LogicalDeviceState()
+{
+}
+
+string	LogicalDeviceState::name(uint16			aStateNr)
+{ 
+	return (((aStateNr >= UNKNOWN) && (aStateNr < LAST_STATE)) ?
+											itsStates[aStateNr] : "");
+}
+
+uint16	LogicalDeviceState::value(const string&		aStateName)
+{
+	uint16	i = UNKNOWN;
+	while (i < LAST_STATE) {
+		if (itsStates[i] == aStateName) {
+			return (i);
+		}
+		i++;
+	}
+
+	ASSERTSTR(false, aStateName << " is not a valid LogicalDeviceState");
+}
+
+  } // namespace APL
+} // namespace LOFAR
diff --git a/MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.h b/MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.h
new file mode 100644
index 00000000000..69c55120a8a
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/LogicalDeviceState.h
@@ -0,0 +1,107 @@
+//#  LogicalDeviceState.h: one_line_description
+//#
+//#  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 APL_LOGICALDEVICESTATE_H
+#define APL_LOGICALDEVICESTATE_H
+
+// \file LogicalDeviceState.h
+// one_line_description
+
+//# Never #include <config.h> or #include <lofar_config.h> in a header file!
+//# Includes
+#include <Common/lofar_map.h>
+
+// Avoid 'using namespace' in headerfiles
+
+namespace LOFAR {
+  namespace APLCommon {
+
+// \addtogroup package
+// @{
+
+
+// class_description
+// ...
+class LogicalDeviceState
+{
+public:
+	LogicalDeviceState();
+	~LogicalDeviceState();
+
+	// define enumeration for all states of an LogicalDevice.
+	typedef enum {
+		UNKNOWN = 0,
+		CONNECT,
+		CONNECTED,
+		SCHEDULE,
+		SCHEDULED,
+		CANCEL_SCHEDULE,
+		SCHEDULE_CANCELLED,
+		CLAIM,
+		CLAIMED,
+		PREPARE,
+		PREPARED,
+		RESUME,
+		RESUMED,
+		SUSPEND,
+		SUSPENDED,
+		RELEASE,
+		RELEASED,
+		FINISH,
+		FINISHED,
+		LAST_STATE
+	} LDstateNr;
+
+	// conversion routines
+	string	name(uint16			aStateNr);
+	uint16	value(const string&		aStateName);
+
+	// ... example
+	ostream& print (ostream& os) const
+	{	return (os); }
+
+private:
+	// Copying is not allowed
+	LogicalDeviceState(const LogicalDeviceState&	that);
+	LogicalDeviceState& operator=(const LogicalDeviceState& that);
+
+	//# --- Datamembers ---
+	vector<string>		itsStates;
+};
+
+//# --- Inline functions ---
+
+// ... example
+//#
+//# operator<<
+//#
+inline ostream& operator<< (ostream& os, const LogicalDeviceState& aLogicalDeviceState)
+{	
+	return (aLogicalDeviceState.print(os));
+}
+
+
+// @}
+  } // namespace APLCommon
+} // namespace LOFAR
+
+#endif
diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
new file mode 100644
index 00000000000..510e7468952
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
@@ -0,0 +1,787 @@
+//#  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>
+#include <GCF/GCF_PVString.h>
+#include <GCF/GCF_PVDouble.h>
+#include <GCF/GCF_PVInteger.h>
+#include <GCF/PAL/GCF_PVSSInfo.h>
+
+#include "APL/APLCommon/APLUtilities.h"
+#include "APL/APLCommon/APLCommonExceptions.h"
+#include <LogicalDeviceState.h>
+#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;
+using namespace std;
+
+namespace LOFAR {
+	using namespace APLCommon;
+	using namespace ACC::APS;
+	namespace MCU {
+	
+//
+// MACScheduler()
+//
+MACScheduler::MACScheduler() :
+	GCFTask 			((State)&MACScheduler::initial_state,string(MS_TASKNAME)),
+	PropertySetAnswerHandlerInterface(),
+	itsPropertySetAnswer(*this),
+	itsPropertySet		(),
+//	itsVISDclientPorts	(),
+//	itsVIparentPortName	(string("VIparent_server")),
+//	itsVIparentPort		(*this, m_VIparentPortName, GCFPortInterface::MSPP, LOGICALDEVICE_PROTOCOL),
+//	itsVIclientPorts	(),
+//	itsconnectedVIclientPorts(),
+
+	itsObsCntlrMap		(),
+	itsSDclientPort		(0),
+	itsLDserverPort		(0),
+	itsSecondTimer		(0),
+	itsSDretryTimer		(0),
+	itsQueuePeriod		(0),
+	itsClaimPeriod		(0),
+	itsOTDBconnection	(0),
+	itsOTDBpollInterval	(0),
+	itsNextOTDBpolltime (0)
+{
+	LOG_TRACE_OBJ ("MACscheduler construction");
+
+#ifndef USE_PVSSPORT
+	LOG_WARN("Using GCFTCPPort in stead of GCFPVSSPort");
+#endif
+
+	// Log the protocols I use.
+	registerProtocol(LOGICALDEVICE_PROTOCOL, LOGICALDEVICE_PROTOCOL_signalnames);
+	registerProtocol(STARTDAEMON_PROTOCOL, 	 STARTDAEMON_PROTOCOL_signalnames);
+
+	// Readin some parameters from the ParameterSet.
+	itsOTDBpollInterval = globalParameterSet()->getTime("OTDBpollInterval");
+	itsQueuePeriod 		= globalParameterSet()->getTime("QueuePeriod");
+	itsClaimPeriod 		= globalParameterSet()->getTime("ClaimPeriod");
+}
+
+
+//
+// ~MACScheduler()
+//
+MACScheduler::~MACScheduler()
+{
+	LOG_TRACE_OBJ ("~MACscheduler");
+
+	if (itsPropertySet) {
+		itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString("down"));
+		itsPropertySet->disable();
+	}
+
+	if (itsOTDBconnection) {
+		delete itsOTDBconnection;
+	}
+	if (itsSDclientPort) {
+		itsSDclientPort->close();
+		delete itsSDclientPort;
+	}
+}
+
+
+//
+// handlePropertySetAnswer(answer)
+//
+void MACScheduler::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 (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*/)
+{
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_INIT:
+   		break;
+
+    case F_ENTRY: {
+		// Get access to my own propertyset.
+		itsPropertySet = GCFMyPropertySetPtr(new GCFMyPropertySet(MS_PROPSET_NAME,
+																  MS_PROPSET_TYPE,
+																  PS_CAT_PERMANENT,
+																  &itsPropertySetAnswer));
+		itsPropertySet->enable();
+	  
+		// update PVSS.
+		itsPropertySet->setValue(string(PVSSNAME_FSM_STATE),GCFPVString("initial"));
+		itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),GCFPVString(""));
+      
+		// 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");
+
+		itsOTDBconnection= new OTDBconnection(username, DBname, password);
+		ASSERTSTR (itsOTDBconnection, "Memory allocation error (OTDB)");
+		ASSERTSTR (itsOTDBconnection->connect(),
+					"Unable to connect to database " << DBname << " using " <<
+					username << "," << password);
+
+		// Connect to local startDaemon 
+		itsSDclientPort = new GCFTCPPort(*this, 
+										 "StartDaemon", 
+										 GCFPortInterface::SAP,
+										 STARTDAEMON_PROTOCOL);
+		ASSERTSTR(itsSDclientPort, "Unable to allocate a port for the StartDaemon");
+		itsSDclientPort->open();		// may result in CONN or DISCONN event
+		}
+		break;
+
+	case F_CONNECTED:		// must be from SDclient port.
+		if (itsSDclientPort->isConnected()) {				// connected with SD!
+			itsSDclientPort->cancelTimer(itsSDretryTimer);	// cancel retry timer
+			TRAN(MACScheduler::recover_state);				// go to next state.
+		}
+		break;
+
+	case F_DISCONNECTED:	// must be from SDclient port.
+		if (!itsSDclientPort->isConnected()) {			// connection with SD failed
+			// tell PVSS what my problem is
+			itsPropertySet->setValue(string(PVSSNAME_FSM_ERROR),
+									 GCFPVString("Waiting for StartDaemon"));
+			itsSDretryTimer = itsSDclientPort->setTimer(1.0);	// retry in 1 second.
+		}
+		break;
+	
+	case F_TIMER:								// must be from SDclient port.
+		if (!itsSDclientPort->isConnected()) {	// really not connected?
+			itsSDclientPort->open();			// try again
+		}
+		break;
+  
+	default:
+		LOG_DEBUG_STR ("MACScheduler(" << getName() << ")::initial_state, default");
+		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)
+{
+	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(""));
+
+		// open server port for ObservationControllers
+		itsLDserverPort = new GCFTCPPort(*this, 
+										 "ObsControllers", 
+										 GCFPortInterface::MSPP,
+										 LOGICALDEVICE_PROTOCOL);
+		itsLDserverPort->open();		// LDprotocol server port
+
+		//
+		// TODO: do recovery
+
+		TRAN(MACScheduler::active_state);
+		
+		break;
+	}
+  
+	default:
+		LOG_DEBUG(formatString("MACScheduler(%s)::recover_state, default",getName().c_str()));
+		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)
+{
+	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(""));
+
+		// Timers must be connected to ports, so abuse serverPort for second timer.
+		itsSecondTimer = itsLDserverPort->setTimer(1L);
+		break;
+	}
+
+	case F_ACCEPT_REQ: {
+		// Should be from a just started ObservationController.
+		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, "newObsCntlr", GCFPortInterface::SPP, 
+														LOGICALDEVICE_PROTOCOL);
+		itsLDserverPort->accept(*client);
+		itsObsCntlrPorts.push_back(client);		// save client port in stack
+		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();
+				// reinit polltime.
+				itsNextOTDBpolltime = time(0) + itsOTDBpollInterval;
+			}
+			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;
+	}
+
+	case LOGICALDEVICE_CONNECT: {
+		// An ObsCntlr has started and reports that it is started
+		LOGICALDEVICEConnectEvent connectEvent(event);
+		GCFTCPPort*	 portPtr(static_cast<GCFTCPPort*>(&port));
+
+		// copy name of controller to portname
+		// does not exist! portPtr->setName(connectEvent.nodeId);
+
+		// construct a controller object.
+		ObsCntlr_t		controller;
+		controller.treeID = atol(connectEvent.nodeId.c_str());
+		controller.port	  = portPtr;
+		controller.state  = LogicalDeviceState::CONNECTED;
+
+		// add it to the map
+		// TODO:
+
+		// report to ObsCntlr that he is registered.
+		LOGICALDEVICEConnectedEvent connectedEvent;
+		connectedEvent.result = LD_RESULT_NO_ERROR;
+		port.send(connectedEvent);
+		break;
+	}
+
+	case LOGICALDEVICE_SCHEDULED: {
+		LOGICALDEVICEScheduledEvent scheduledEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_SCHEDULECANCELLED: {
+		LOGICALDEVICESchedulecancelledEvent schedulecancelledEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_CLAIMED: {
+		LOGICALDEVICEClaimedEvent claimedEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_PREPARED: {
+		LOGICALDEVICEPreparedEvent preparedEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_RESUMED: {
+		LOGICALDEVICEResumedEvent resumedEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_SUSPENDED: {
+		LOGICALDEVICESuspendedEvent suspendedEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_RELEASED: {
+		LOGICALDEVICEReleasedEvent releasedEvent(event);
+		// ...
+		break;
+	}
+
+	case LOGICALDEVICE_FINISH: {
+		LOGICALDEVICEFinishEvent finishEvent(event);
+		// ...
+		break;
+	}
+
+	case STARTDAEMON_SCHEDULED:
+	{
+		STARTDAEMONScheduledEvent scheduledEvent(event);
+		// ...
+		break;
+	}
+
+	default:
+		LOG_DEBUG(formatString("MACScheduler(%s)::active_state, default",
+								getName().c_str()));
+		status = GCFEvent::NOT_HANDLED;
+		break;
+	}
+
+	return (status);
+}
+
+//
+// _doOTDBcheck
+//
+// Check if a new action should be taken based on the contents of OTDB and our own
+// administration.
+//
+void MACScheduler::_doOTDBcheck()
+{
+
+}
+
+//
+// readObservationParameters(ObsTreeID)
+//
+// Ask the OTDB to create an ParameterSet of the given Tree.
+//
+boost::shared_ptr<ACC::APS::ParameterSet> 
+	MACScheduler::readObservationParameters(OTDB::treeIDType ObsTreeID)
+{
+	// Convert treeId to nodeID of top node.
+	TreeMaintenance tm(itsOTDBconnection);
+	OTDBnode topNode = tm.getTopNode(ObsTreeID);
+	LOG_INFO_STR(topNode);
+
+	// construct the filename
+	string tempFileName = string(LOFAR_SHARE_LOCATION) + "/Obs_" + toString(ObsTreeID);
+
+	// read the parameterset from the database:
+	LOG_INFO(formatString("Exporting tree %d to '%s'",
+										ObsTreeID, tempFileName.c_str()));
+	if (!tm.exportTree(ObsTreeID, topNode.nodeID(), tempFileName)) {
+		THROW(APLCommon::OTDBException, string("Unable to export tree ") + 
+									toString(ObsTreeID) + " to " + tempFileName);
+	}
+
+	// read file into ParameterSet
+	boost::shared_ptr<ACC::APS::ParameterSet> ps;
+	ps.reset(new ACC::APS::ParameterSet(tempFileName));
+
+//	createChildsSections (tm, ObsTreeID, topNode.nodeID(), string(""), ps);
+
+	return (ps);
+}
+
+#if 0
+
+//
+// _schedule (rootID, port)
+//
+// One way or another they start an observation by creating and modifying a
+// parameterSet, allocation beams?? and sending one startDaemon a schedule event.
+//
+void MACScheduler::_schedule(const string& VIrootID, GCFPortInterface* /*port*/)
+{  
+	string shareLocation = _getShareLocation();	//REO
+	try {
+		boost::shared_ptr<ACC::APS::ParameterSet> ps = _readParameterSet(VIrootID);
+
+		// replace the parent port (assigned by the ServiceBroker)
+		unsigned int parentPort = itsVIparentPort.getPortNumber();
+		ACC::APS::KVpair kvPair(string("parentPort"),(int)parentPort);
+		ps->replace(kvPair);
+
+		// get some parameters and write it to the allocated CCU
+		string allocatedCCU = ps->getString("allocatedCCU");
+		string viName = ps->getString("name");
+		string parameterFileName = viName + string(".param");
+
+		// make all relative times absolute
+//		_convertRelativeTimes(ps);
+
+		string ldTypeString = ps->getString("logicalDeviceType");
+		TLogicalDeviceTypes ldTypeRoot = APLUtilities::convertLogicalDeviceType(ldTypeString);
+
+		bool allocationOk = true;
+		TSASResult sasResult(SAS_RESULT_NO_ERROR);
+
+#if 0
+		// find the subbands allocations in VI sections
+		vector<string> childKeys = ps->getStringVector("childs");
+		for(vector<string>::iterator childsIt=childKeys.begin();
+						allocationOk && childsIt!=childKeys.end();++childsIt) {
+			string ldTypeString = ps->getString(*childsIt + ".logicalDeviceType");
+			TLogicalDeviceTypes ldType = APLUtilities::convertLogicalDeviceType(ldTypeString);
+			if(ldType == LDTYPE_VIRTUALINSTRUMENT) { //REO
+				// allocate beamlets for VI's
+				allocationOk = _allocateBeamlets(VIrootID, ps, *childsIt);
+				if(!allocationOk) {
+					sasResult = SAS_RESULT_ERROR_BEAMLET_ALLOCATION_FAILED;
+				}
+				else {
+					allocationOk = _allocateLogicalSegments(VIrootID, ps, *childsIt);
+					if(!allocationOk) {
+						sasResult = SAS_RESULT_ERROR_LOGICALSEGMENT_ALLOCATION_FAILED;
+					}
+				}
+			}
+		}
+		if(!allocationOk) {
+			SASResponseEvent sasResponseEvent;
+			sasResponseEvent.result = sasResult;
+			itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+		}
+		else
+#endif
+		{
+			string tempFileName = APLUtilities::getTempFileName();
+			ps->writeFile(tempFileName);
+			APLUtilities::remoteCopy(tempFileName,allocatedCCU,shareLocation+parameterFileName);
+			remove(tempFileName.c_str());
+
+			// send the schedule event to the VI-StartDaemon on the CCU
+			STARTDAEMONScheduleEvent sdScheduleEvent;
+			sdScheduleEvent.logicalDeviceType = ldTypeRoot;
+			sdScheduleEvent.taskName = viName;
+			sdScheduleEvent.fileName = parameterFileName;
+
+			TStringRemotePortMap::iterator it = itsVISDclientPorts.find(allocatedCCU);
+			if(it != itsVISDclientPorts.end()) {
+				it->second->send(sdScheduleEvent);
+			}
+			else {
+				SASResponseEvent sasResponseEvent;
+				sasResponseEvent.result = SAS_RESULT_ERROR_VI_NOT_FOUND;
+				itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+			}
+		}        
+	}
+	catch(Exception& e) {
+		LOG_FATAL(formatString("Error reading schedule parameters: %s",e.message().c_str()));
+		SASResponseEvent sasResponseEvent;
+		sasResponseEvent.result = SAS_RESULT_ERROR_UNSPECIFIED;
+		itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+	}
+	catch(exception& e) {
+		LOG_FATAL(formatString("Error reading schedule parameters: %s",e.what()));
+		SASResponseEvent sasResponseEvent;
+		sasResponseEvent.result = SAS_RESULT_ERROR_UNSPECIFIED;
+		itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+	}
+}
+
+
+//
+// _updateSchedule(rootVI, port)
+//
+void MACScheduler::_updateSchedule(const string& VIrootID, GCFPortInterface* port)
+{
+	string shareLocation = _getShareLocation();
+
+	// search the port of the VI
+	try
+	{
+		boost::shared_ptr<ACC::APS::ParameterSet> ps = _readParameterSet(VIrootID);
+
+		// replace the parent port (assigned by the ServiceBroker)
+		unsigned int parentPort = itsVIparentPort.getPortNumber();
+		ACC::APS::KVpair kvPair(string("parentPort"),(int)parentPort);
+		ps->replace(kvPair);
+
+		string allocatedCCU = ps->getString("allocatedCCU");
+		string viName = ps->getString("name");
+		string parameterFileName = viName + string(".param");
+
+		// make all relative times absolute
+		_convertRelativeTimes(ps);
+
+		string tempFileName = APLUtilities::getTempFileName();
+		ps->writeFile(tempFileName);
+		APLUtilities::remoteCopy(tempFileName,allocatedCCU,shareLocation+parameterFileName);
+		remove(tempFileName.c_str());
+
+		// send a SCHEDULE message
+		TStringRemotePortMap::iterator it = itsconnectedVIclientPorts.find(viName);
+		if(it != itsconnectedVIclientPorts.end()) {
+			LOGICALDEVICEScheduleEvent scheduleEvent;
+			scheduleEvent.fileName = parameterFileName;
+
+			it->second->send(scheduleEvent);
+		}
+		else {
+			SASResponseEvent sasResponseEvent;
+			sasResponseEvent.result = SAS_RESULT_ERROR_VI_NOT_FOUND;
+			itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+		}        
+	}
+	catch(Exception& e) {
+		LOG_FATAL(formatString("Error reading schedule parameters: %s",e.message().c_str()));
+		SASResponseEvent sasResponseEvent;
+		sasResponseEvent.result = SAS_RESULT_ERROR_UNSPECIFIED;
+		sasResponseEvent.VIrootID = VIrootID;
+
+		if(port != 0) {
+			port->send(sasResponseEvent);      
+		}
+		itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+	}
+}
+
+
+//
+// _cancelSchedule(rootVI, port)
+//
+void MACScheduler::_cancelSchedule(const string& VIrootID, GCFPortInterface* /*port*/)
+{
+	string shareLocation = _getShareLocation(); //REO
+
+	// search the port of the VI
+	try {
+		boost::shared_ptr<ACC::APS::ParameterSet> ps = _readParameterSet(VIrootID);
+
+		string viName = ps->getString("name");
+
+		// send a CANCELSCHEDULE message
+		TStringRemotePortMap::iterator it = itsconnectedVIclientPorts.find(viName);
+		if(it != itsconnectedVIclientPorts.end()) {
+			LOGICALDEVICECancelscheduleEvent cancelScheduleEvent;
+			it->second->send(cancelScheduleEvent);
+		}
+		else {
+			SASResponseEvent sasResponseEvent;
+			sasResponseEvent.result = SAS_RESULT_ERROR_VI_NOT_FOUND;
+			itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+		}
+
+	}
+	catch(Exception& e)
+	{
+		LOG_FATAL(formatString("Error reading schedule parameters: %s",e.message().c_str()));
+		SASResponseEvent sasResponseEvent;
+		sasResponseEvent.result = SAS_RESULT_ERROR_UNSPECIFIED;
+		itsPropertySet->setValue(string(MS_PROPNAME_STATUS),GCFPVInteger(sasResponseEvent.result));
+	}
+}
+
+//
+// _isServerPort(server, port)
+//
+bool MACScheduler::_isServerPort(const GCFPortInterface& server, 
+								 const GCFPortInterface& port) const
+{
+  return (&port == &server); // comparing two pointers. yuck?
+}
+   
+
+//
+// _isVISDclientPort(port, visd)
+//
+bool MACScheduler::_isVISDclientPort(const GCFPortInterface& port, 
+									 string& visd) const
+{
+	bool found=false;
+	TStringRemotePortMap::const_iterator it=itsVISDclientPorts.begin();
+	while(!found && it != itsVISDclientPorts.end()) {
+		found = (&port == it->second.get()); // comparing two pointers. yuck?
+		if(found) {
+			visd = it->first;
+		}
+		++it;
+	}
+	return (found);
+}
+
+
+//
+// _isVIclientPort(port)
+//
+bool MACScheduler::_isVIclientPort(const GCFPortInterface& port) const
+{
+	bool found=false;
+	TRemotePortVector::const_iterator it=itsVIclientPorts.begin();
+	while(!found && it != itsVIclientPorts.end()) {
+		found = (&port == (*it).get()); // comparing two pointers. yuck?
+		++it;
+	}
+	return (found);
+}
+
+
+//
+// _getVInameFromPort(port)
+//
+string MACScheduler::_getVInameFromPort(const GCF::TM::GCFPortInterface& port) const
+{
+	string viName("");
+	if(_isVIclientPort(port)) {
+		bool found = false;
+		TStringRemotePortMap::const_iterator it = itsconnectedVIclientPorts.begin();
+		while(!found && it != itsconnectedVIclientPorts.end()) {
+			found = (&port == it->second.get());
+			if(found) {
+				viName = it->first;
+			}
+			++it;
+		}
+	}
+	return (viName);
+}
+
+#endif
+
+//
+// _connectedHandler(port)
+//
+void MACScheduler::_connectedHandler(GCFPortInterface& port)
+{
+}
+
+//
+// _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
+}
+
+
+};
+};
diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.conf.in b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.conf.in
new file mode 100644
index 00000000000..a52cc088449
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.conf.in
@@ -0,0 +1,53 @@
+mac.ns.MACScheduler.SAS_server.type=TCP
+mac.ns.MACScheduler.SAS_server.host=lofar27
+mac.ns.MACScheduler.SAS_server.port=27000
+mac.ns.MACScheduler.VIparent_server.type=TCP
+mac.ns.MACScheduler.VIparent_server.host=lofar27
+mac.ns.MACScheduler.VIparent_server.port=27100
+
+mac.ns.CCU1_VIC_VIStartDaemon.server.type=TCP
+mac.ns.CCU1_VIC_VIStartDaemon.server.host=lofar27
+mac.ns.CCU1_VIC_VIStartDaemon.server.port=27010
+mac.top.MACScheduler.CCU1_VIC_VIStartDaemon.remoteservice=CCU1_VIC_VIStartDaemon:server
+mac.ns.CCU2_VIC_VIStartDaemon.server.type=TCP
+mac.ns.CCU2_VIC_VIStartDaemon.server.host=ccu2
+mac.ns.CCU2_VIC_VIStartDaemon.server.port=27010
+mac.top.MACScheduler.CCU2_VIC_VIStartDaemon.remoteservice=CCU2_VIC_VIStartDaemon:server
+mac.ns.CCU3_VIC_VIStartDaemon.server.type=TCP
+mac.ns.CCU3_VIC_VIStartDaemon.server.host=ccu3
+mac.ns.CCU3_VIC_VIStartDaemon.server.port=27010
+mac.top.MACScheduler.CCU3_VIC_VIStartDaemon.remoteservice=CCU3_VIC_VIStartDaemon:server
+mac.ns.CCU4_VIC_VIStartDaemon.server.type=TCP
+mac.ns.CCU4_VIC_VIStartDaemon.server.host=ccu4
+mac.ns.CCU4_VIC_VIStartDaemon.server.port=27010
+mac.top.MACScheduler.CCU4_VIC_VIStartDaemon.remoteservice=CCU4_VIC_VIStartDaemon:server
+mac.ns.CCU5_VIC_VIStartDaemon.server.type=TCP
+mac.ns.CCU5_VIC_VIStartDaemon.server.host=ccu5
+mac.ns.CCU5_VIC_VIStartDaemon.server.port=27010
+mac.top.MACScheduler.CCU5_VIC_VIStartDaemon.remoteservice=CCU5_VIC_VIStartDaemon:server
+mac.ns.CCU6_VIC_VIStartDaemon.server.type=TCP
+mac.ns.CCU6_VIC_VIStartDaemon.server.host=ccu6
+mac.ns.CCU6_VIC_VIStartDaemon.server.port=27010
+mac.top.MACScheduler.CCU6_VIC_VIStartDaemon.remoteservice=CCU6_VIC_VIStartDaemon:server
+
+# new setup
+OTDBusername		= paulus
+OTDBdatabasename	= boskabouter
+OTDBpassword		= overeem
+OTDBpollInterval	= 5s
+
+QueuePeriod			= 15m
+ClaimPeriod			= 2m
+
+
+#
+# should be obsolete
+#
+shareLocation=/opt/lofar/MAC/parametersets/
+
+#
+# Obsolete
+#
+#mac.apl.ams.CCU2.startDaemonHost=earth
+#mac.apl.ams.CCU2.startDaemonPort=server
+#mac.apl.ams.CCU2.startDaemonTask=CCU2_VIC_VIStartDaemon
diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h
new file mode 100644
index 00000000000..61d88949cae
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.h
@@ -0,0 +1,181 @@
+//#  MACScheduler.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 MACScheduler_H
+#define MACScheduler_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_TCPPort.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/LogicalDevice_Protocol.ph"
+#include "APL/APLCommon/StartDaemon_Protocol.ph"
+
+//# Common Includes
+#include <Common/lofar_string.h>
+#include <Common/lofar_vector.h>
+#include <Common/LofarLogger.h>
+
+//# ACC Includes
+#include <OTDB/OTDBconnection.h>
+#include <OTDB/TreeMaintenance.h>
+#include <OTDB/OTDBnode.h>
+#include <APS/ParameterSet.h>
+
+// forward declaration
+
+namespace LOFAR {
+	namespace MCU {
+
+using	GCF::TM::GCFTCPPort;
+using	GCF::TM::GCFEvent;
+using	GCF::TM::GCFPortInterface;
+using	GCF::TM::GCFTask;
+
+
+class MACScheduler : public GCFTask,
+							APLCommon::PropertySetAnswerHandlerInterface
+{
+public:
+	MACScheduler();
+	~MACScheduler();
+
+   	// 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);
+	
+	// In this state the last-registered state is compared with the current
+	// database-state and an appropriate recovery is made for each observation.
+   	GCFEvent::TResult recover_state (GCFEvent& e, 
+									 GCFPortInterface& p);
+
+	// Normal control mode. Watching the OTDB and controlling the observations.
+   	GCFEvent::TResult active_state  (GCFEvent& e, 
+									 GCFPortInterface& p);
+
+private:
+	// avoid copying
+	MACScheduler(const MACScheduler&);
+   	MACScheduler& operator=(const MACScheduler&);
+
+   	void _connectedHandler(GCFPortInterface& port);
+   	void _disconnectedHandler(GCFPortInterface& port);
+   	void _doOTDBcheck();
+   	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
+   	typedef GCFTCPPort  		TRemotePort;
+
+   	typedef boost::shared_ptr<GCFTCPPort>  TTCPPortPtr;
+   	typedef boost::shared_ptr<TRemotePort>  		TRemotePortPtr;
+   	typedef vector<TTCPPortPtr>             		TTCPPortVector;
+   	typedef vector<TRemotePortPtr>          		TRemotePortVector;
+   	typedef map<string,TRemotePortPtr>      		TStringRemotePortMap;
+   	typedef map<string,TTCPPortPtr>         		TStringTCPportMap;
+      
+   	bool 	_isServerPort	   (const GCFPortInterface& server, 
+							    const GCFPortInterface& port) const;
+   	bool 	_isVISDclientPort  (const GCFPortInterface& port, 
+							  	string& visd) const;
+   	bool 	_isVIclientPort    (const GCFPortInterface& port) const;
+   	string 	_getVInameFromPort (const GCFPortInterface& port) const;
+   	string 	_getShareLocation  () const;
+
+   	void 	createChildsSections(OTDB::TreeMaintenance& tm, 
+								int32 treeID, 
+								OTDB::nodeIDType topItem, 
+								const string& nodeName, 
+								boost::shared_ptr<ACC::APS::ParameterSet> ps);
+      
+   	void 	_schedule		   (const string& VIrootID, 
+								GCFPortInterface* port=0);
+   	void 	_updateSchedule	   (const string& VIrootID, 
+								GCFPortInterface* port=0);
+   	void 	_cancelSchedule	   (const string& VIrootID, 
+								GCFPortInterface* port=0);
+      
+   	TStringRemotePortMap	m_VISDclientPorts;    // connected VI StartD clients
+   	string					m_VIparentPortName;
+   	TRemotePort				m_VIparentPort;       // parent for VI's
+
+   	// the vector and map both contain the child ports. The vector is used
+   	// to cache the port at the moment of the accept. However, at that moment, 
+   	// the parent does not yet know the ID of that child. The child sends its
+   	// ID in the CONNECT event and when that message is received, the port and ID
+   	// are stored in the TPortMap. The map is used in all communication with the
+   	// childs.
+   	TRemotePortVector		m_VIclientPorts;      // created VI's
+   	TStringRemotePortMap	m_connectedVIclientPorts; // maps node ID's to ports
+#endif
+
+	// 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;
+
+	// Ports for StartDaemon and ObservationControllers.
+   	GCFTCPPort*				itsSDclientPort;		// connection to StartDaemon
+   	GCFTCPPort*				itsLDserverPort;		// listener for ObsControllers
+
+	// Second timer used for internal timing.
+	uint32					itsSecondTimer;			// 1 second hardbeat
+	uint32					itsSDretryTimer;		// for reconnecting to SD
+
+	// Scheduling settings
+	uint32					itsQueuePeriod;			// period between qeueuing and start
+	uint32					itsClaimPeriod;			// period between claiming and start
+      
+	// OTDB related variables.
+   	OTDB::OTDBconnection*	itsOTDBconnection;		// connection to the database
+	uint32					itsOTDBpollInterval;	// itv between OTDB polls
+	int32					itsNextOTDBpolltime;	// when next OTDB poll is scheduled
+
+};
+
+  };//MCU
+};//LOFAR
+#endif
diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in
new file mode 100644
index 00000000000..438f6f9039e
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.log_prop.in
@@ -0,0 +1,44 @@
+# add your custom loggers and appenders here
+#
+
+log4cplus.rootLogger=INFO, STDOUT
+
+log4cplus.logger.TRC=PUTJE
+log4cplus.additivity.TRC=FALSE
+
+log4cplus.logger.MAC=DEBUG, STDOUT, FILE
+log4cplus.additivity.MAC=FALSE
+
+log4cplus.logger.TRC.MAC=TRACE, FILE
+log4cplus.additivity.TRC.MAC=FALSE
+
+log4cplus.appender.PUTJE=log4cplus::NullAppender
+
+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.logToStdErr=true
+#log4cplus.appender.STDOUT.Threshold=WARN
+#log4cplus.appender.STDOUT.filters.1=log4cplus::spi::LogLevelRangeFilter
+#log4cplus.appender.STDOUT.filters.1.LogLevelMin=INFO
+#log4cplus.appender.STDOUT.filters.1.LogLevelMax=FATAL
+#log4cplus.appender.STDOUT.filters.1.AcceptOnMatch=true
+#log4cplus.appender.STDOUT.filters.2=log4cplus::spi::DenyAllFilter
+
+log4cplus.appender.FILE=log4cplus::RollingFileAppender
+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.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
new file mode 100644
index 00000000000..23c036e3733
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/MACSchedulerDefines.h
@@ -0,0 +1,47 @@
+//#  MACScheduler_Defines.h: preprocessor definitions of various constants
+//#
+//#  Copyright (C) 2002-2003
+//#  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 MACScheduler_DEFINES_H
+#define MACScheduler_DEFINES_H
+
+namespace LOFAR {
+  namespace MCU {
+
+#define MS_TASKNAME					"MACScheduler"
+
+#define MS_PROPSET_NAME				"MACScheduler"
+#define MS_PROPSET_TYPE				"TAplMacScheduler"
+
+#define PVSSNAME_MS_QUEUEPERIOD		"QueuePeriod"
+#define PVSSNAME_MS_CLAIMPERIOD		"ClaimPeriod"
+
+// next lines should be defined somewhere in Common.
+#define PVSSNAME_FSM_STATE			"state"
+#define PVSSNAME_FSM_ERROR			"error"
+
+#define	SN_STARTDAEMON				"StartDaemon"
+#define SN_STARTDAEMON_VERSION		"V1"
+
+}; // MCU
+}; // LOFAR
+
+#endif
diff --git a/MAC/APL/MainCU/src/MACScheduler/MACSchedulerMain.cc b/MAC/APL/MainCU/src/MACScheduler/MACSchedulerMain.cc
new file mode 100644
index 00000000000..87f6cd0e211
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/MACSchedulerMain.cc
@@ -0,0 +1,38 @@
+//#  VirtualInstrumentStartDaemonMain.cc: Main entry for the VirtualInstrument start daemon
+//#
+//#  Copyright (C) 2002-2005
+//#  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 "MACScheduler.h"
+
+int main(int argc, char* argv[])
+{
+  LOFAR::GCF::TM::GCFTask::init(argc, argv);
+  
+  LOFAR::MCU::MACScheduler ms;
+  ms.start(); // make initial transition
+
+  LOFAR::GCF::TM::GCFTask::run();
+    
+  return 0;
+}
+
diff --git a/MAC/APL/MainCU/src/MACScheduler/Makefile.am b/MAC/APL/MainCU/src/MACScheduler/Makefile.am
new file mode 100644
index 00000000000..2b02b395772
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/Makefile.am
@@ -0,0 +1,44 @@
+bin_PROGRAMS 				= MACScheduler
+
+MACScheduler_CPPFLAGS		= -DBOOST_DISABLE_THREADS \
+							  -Wno-deprecated \
+							  -fmessage-length=0 \
+							  -fdiagnostics-show-location=once
+
+MACScheduler_SOURCES		= MACScheduler.cc \
+							  MACSchedulerMain.cc \
+							  LogicalDeviceState.cc
+MACScheduler_LDADD			= -lpqxx $(LOFAR_DEPEND)
+MACScheduler_DEPENDENCIES	= $(LOFAR_DEPEND)
+
+NOINSTHDRS 					= MACScheduler.h \
+							  MACSchedulerDefines.h
+
+INSTHDRS 					= LogicalDeviceState.h
+
+pkginclude_HEADERS 			= $(NOINSTHDRS) $(INSTHDRS)
+
+DOCHDRS						= $(pkginclude_HEADERS) $(BUILT_SOURCES)
+
+EXTRA_DIST 					= $(configfiles_DATA) $(sysconf_DATA)
+
+#in case of make install these files will be copied to the bindir beside the test apps
+configfilesdir=$(bindir)
+configfiles_DATA 	= customPrepPVSSDB.ctl
+
+sysconf_DATA		= MACScheduler.conf \
+					  MACScheduler.log_prop
+
+%.log_prop: %.log_prop.in
+	cp $< $@
+
+%.conf: %.conf.in
+	cp $< $@
+
+%.ctl: %.ctl.in
+	cp $< $@
+
+clean-local:
+	rm -f *.ph
+
+include $(top_srcdir)/Makefile.common
diff --git a/MAC/APL/MainCU/src/MACScheduler/customPrepPVSSDB.ctl.in b/MAC/APL/MainCU/src/MACScheduler/customPrepPVSSDB.ctl.in
new file mode 100644
index 00000000000..f057aa4833e
--- /dev/null
+++ b/MAC/APL/MainCU/src/MACScheduler/customPrepPVSSDB.ctl.in
@@ -0,0 +1,17 @@
+// this script must reside in the <PVSS project>/scripts directory
+main()
+{
+  // create an enabled flag for CCU_PIC
+  dpCreate("PIC__enabled", "GCFPaPsEnabled");
+  dpSet("PIC__enabled.","autoloaded|TCcuPic");
+  dpCreate("PIC_Stations__enabled", "GCFPaPsEnabled");
+  dpSet("PIC_Stations__enabled.","autoloaded|TCcuPic");
+  dpCreate("PIC_CEP__enabled", "GCFPaPsEnabled");
+  dpSet("PIC_CEP__enabled.","autoloaded|TCcuCep");
+  dpCreate("GSO__enabled", "GCFPaPsEnabled");
+  dpSet("GSO__enabled.","autoloaded|TCcuPic");
+  dpCreate("VIC__enabled", "GCFPaPsEnabled");
+  dpSet("VIC__enabled.","autoloaded|TCcuPic");
+  
+  dpDelete("GSO_MACScheduler");
+}
diff --git a/MAC/APL/MainCU/src/Makefile.am b/MAC/APL/MainCU/src/Makefile.am
new file mode 100644
index 00000000000..ae74088b44c
--- /dev/null
+++ b/MAC/APL/MainCU/src/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = MACScheduler
+
+include $(top_srcdir)/Makefile.common
+
diff --git a/MAC/APL/StationCU/src/StationControl/customPrepPVSSDB.ctl.in b/MAC/APL/StationCU/src/StationControl/customPrepPVSSDB.ctl.in
new file mode 100644
index 00000000000..f057aa4833e
--- /dev/null
+++ b/MAC/APL/StationCU/src/StationControl/customPrepPVSSDB.ctl.in
@@ -0,0 +1,17 @@
+// this script must reside in the <PVSS project>/scripts directory
+main()
+{
+  // create an enabled flag for CCU_PIC
+  dpCreate("PIC__enabled", "GCFPaPsEnabled");
+  dpSet("PIC__enabled.","autoloaded|TCcuPic");
+  dpCreate("PIC_Stations__enabled", "GCFPaPsEnabled");
+  dpSet("PIC_Stations__enabled.","autoloaded|TCcuPic");
+  dpCreate("PIC_CEP__enabled", "GCFPaPsEnabled");
+  dpSet("PIC_CEP__enabled.","autoloaded|TCcuCep");
+  dpCreate("GSO__enabled", "GCFPaPsEnabled");
+  dpSet("GSO__enabled.","autoloaded|TCcuPic");
+  dpCreate("VIC__enabled", "GCFPaPsEnabled");
+  dpSet("VIC__enabled.","autoloaded|TCcuPic");
+  
+  dpDelete("GSO_MACScheduler");
+}
-- 
GitLab