From 08cd4f1a53610fc5d1c2afa2fd1b2cb5a63b8331 Mon Sep 17 00:00:00 2001
From: Ruud Overeem <overeem@astron.nl>
Date: Mon, 3 Mar 2008 15:28:45 +0000
Subject: [PATCH] Bug 1154: Step4 checkin.

---
 .../MainCU/src/MACScheduler/MACScheduler.cc   | 30 ++++----
 .../ObservationControl/ObservationControl.cc  | 77 +++++++++++--------
 .../ObservationControlDefines.h               | 39 +++++-----
 MAC/APL/PAC/BeamServer/src/BeamServer.cc      | 10 ++-
 MAC/APL/PAC/BeamServer/src/beamctl.cc         |  2 +-
 MAC/APL/PAC/CalServer/src/CalServer.cc        | 73 +++++++++++-------
 MAC/APL/PAC/CalServer/src/CalServer.h         |  7 +-
 7 files changed, 139 insertions(+), 99 deletions(-)

diff --git a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
index ab3a367bd1b..900259d45c2 100644
--- a/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
+++ b/MAC/APL/MainCU/src/MACScheduler/MACScheduler.cc
@@ -375,7 +375,7 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface&
 			}
 			OTDB::TreeMaintenance	tm(itsOTDBconnection);
 			TreeStateConv			tsc(itsOTDBconnection);
-			tm.setTreeState(theObs->treeID, tsc.get("queued"));
+			tm.setTreeState(theObs->obsID, tsc.get("queued"));
 			// ---
 		}
 		else {
@@ -405,7 +405,7 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface&
 		}
 		OTDB::TreeMaintenance	tm(itsOTDBconnection);
 		TreeStateConv			tsc(itsOTDBconnection);
-		tm.setTreeState(theObs->treeID, tsc.get("queued"));
+		tm.setTreeState(theObs->obsID, tsc.get("queued"));
 		break;
 	}
 
@@ -424,10 +424,10 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface&
 		OTDB::TreeMaintenance	tm(itsOTDBconnection);
 		TreeStateConv			tsc(itsOTDBconnection);
 		if (quitedEvent.result == CT_RESULT_NO_ERROR) {
-			tm.setTreeState(theObs->treeID, tsc.get("finished"));
+			tm.setTreeState(theObs->obsID, tsc.get("finished"));
 		}
 		else {
-			tm.setTreeState(theObs->treeID, tsc.get("aborted"));
+			tm.setTreeState(theObs->obsID, tsc.get("aborted"));
 		}
 
 		// update our administration
@@ -448,7 +448,7 @@ GCFEvent::TResult MACScheduler::active_state(GCFEvent& event, GCFPortInterface&
 		}
 		OTDB::TreeMaintenance	tm(itsOTDBconnection);
 		TreeStateConv			tsc(itsOTDBconnection);
-		tm.setTreeState(theObs->treeID, tsc.get("active"));
+		tm.setTreeState(theObs->obsID, tsc.get("active"));
 	}
 
 	// NOTE: ignore all other CONTROL events, we are not interested in the
@@ -570,19 +570,19 @@ void MACScheduler::_doOTDBcheck()
 		if (timediff > seconds(0)) {
 			// Let database construct the parset for the whole observation
 			OTDB::TreeMaintenance	tm(itsOTDBconnection);
-			OTDB::treeIDType		treeID = newTreeList[idx].treeID();
-			OTDBnode				topNode = tm.getTopNode(treeID);
+			OTDB::treeIDType		obsID = newTreeList[idx].treeID();
+			OTDBnode				topNode = tm.getTopNode(obsID);
 			// NOTE: this name must be the same as in the ChildControl.
 			string					filename = formatString("%s/Observation_%d", 
-														LOFAR_SHARE_LOCATION, treeID);
-			if (!tm.exportTree(treeID, topNode.nodeID(), filename)) {
+														LOFAR_SHARE_LOCATION, obsID);
+			if (!tm.exportTree(obsID, topNode.nodeID(), filename)) {
 				LOG_ERROR_STR ("Cannot create parset file " << filename << 
 							" for new observation. Observation CANNOT BE STARTED!");
 			}
 			else {
 				// fire request for new controller, will result in CONTROL_STARTED
 				itsChildControl->startChild(CNTLRTYPE_OBSERVATIONCTRL, 
-											treeID, 
+											obsID, 
 											0,		// instanceNr
 											myHostname(true));
 				// Note: controller is now in state NO_STATE/CONNECTED (C/R)
@@ -591,7 +591,7 @@ void MACScheduler::_doOTDBcheck()
 				ParameterSet	obsPS(filename);
 				Observation		newObs(&obsPS);
 				newObs.name   = cntlrName;
-				newObs.treeID = treeID;
+				newObs.obsID = obsID;
 				_addActiveObservation(newObs);
 				LOG_DEBUG_STR("Observation " << cntlrName << " added to active Observations");
 			}
@@ -659,7 +659,7 @@ void MACScheduler::_addActiveObservation(const Observation&	newObs)
 
 	// update own admin and PVSS datapoint
 	itsObservations.push_back(newObs);
-	itsPVSSObsList.push_back(new GCFPVString(formatString("Observation%d", newObs.treeID)));
+	itsPVSSObsList.push_back(new GCFPVString(formatString("Observation%d", newObs.obsID)));
 	itsPropertySet->setValue(PN_MS_ACTIVE_OBSERVATIONS, GCFPVDynArr(LPT_STRING, itsPVSSObsList));
 
 	LOG_DEBUG_STR("Added observation " << newObs.name << " to active observation-list");
@@ -673,14 +673,14 @@ void MACScheduler::_addActiveObservation(const Observation&	newObs)
 void MACScheduler::_removeActiveObservation(const string& name)
 {
 	// search observation.
-	OTDB::treeIDType		treeID;
+	OTDB::treeIDType		obsID;
 	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;
-			treeID = iter->treeID;
+			obsID = iter->obsID;
 			itsObservations.erase(iter);
 			LOG_DEBUG_STR("Removed observation " << name << " from active observationList");
 		}
@@ -691,7 +691,7 @@ void MACScheduler::_removeActiveObservation(const string& name)
 		return;
 	}
 
-	string		obsName(formatString("Observation%d", treeID));
+	string		obsName(formatString("Observation%d", obsID));
 	GCFPValueArray::iterator	pEnd  = itsPVSSObsList.end();
 	GCFPValueArray::iterator	pIter = itsPVSSObsList.begin();
 	while (pIter != pEnd) {
diff --git a/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc b/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc
index 71f6fe7e564..dbdc2586071 100644
--- a/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc
+++ b/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc
@@ -21,6 +21,7 @@
 //#  $Id$
 #include <lofar_config.h>
 #include <Common/LofarLogger.h>
+#include <Common/StreamUtil.h>
 
 #include <APS/ParameterSet.h>
 #include <GCF/GCF_PVTypes.h>
@@ -381,44 +382,60 @@ GCFEvent::TResult ObservationControl::starting_state(GCFEvent& event,
 
 		// update PVSS.
 		LOG_TRACE_FLOW ("Updateing state to PVSS");
+		Observation		theObs(globalParameterSet());
 		itsPropertySet->setValue(PVSSNAME_FSM_CURACT, GCFPVString("Initial"));
 		itsPropertySet->setValue(PVSSNAME_FSM_ERROR,  GCFPVString(""));
-		itsPropertySet->setValue(PN_OC_CLAIM_PERIOD,  GCFPVInteger(itsClaimPeriod));
-		itsPropertySet->setValue(PN_OC_PREPARE_PERIOD,GCFPVInteger(itsPreparePeriod));
-		itsPropertySet->setValue(PN_OC_START_TIME,    GCFPVString(to_simple_string(itsStartTime)));
-		itsPropertySet->setValue(PN_OC_STOP_TIME,     GCFPVString(to_simple_string(itsStopTime)));
-		itsPropertySet->setValue(PN_OC_SUBBAND_LIST,  GCFPVString(
-						APLUtilities::compactedArrayString(globalParameterSet()->
-						getString("Observation.subbandList"))));
-		itsPropertySet->setValue(PN_OC_BEAMLET_LIST, GCFPVString(
-						APLUtilities::compactedArrayString(globalParameterSet()->
-						getString("Observation.beamletList"))));
-		itsPropertySet->setValue(PN_OC_BAND_FILTER, GCFPVString(
-						globalParameterSet()->getString("Observation.bandFilter")));
-		itsPropertySet->setValue(PN_OC_NYQUISTZONE, GCFPVInteger(
-						globalParameterSet()->getInt32("Observation.nyquistZone")));
-		itsPropertySet->setValue(PN_OC_ANTENNA_ARRAY, GCFPVString(
-						globalParameterSet()->getString("Observation.antennaArray")));
-		itsPropertySet->setValue(PN_OC_RECEIVER_LIST, GCFPVString(
+		itsPropertySet->setValue(PN_OBSCTRL_CLAIM_PERIOD,	GCFPVInteger(itsClaimPeriod));
+		itsPropertySet->setValue(PN_OBSCTRL_PREPARE_PERIOD,	GCFPVInteger(itsPreparePeriod));
+		itsPropertySet->setValue(PN_OBSCTRL_START_TIME,		GCFPVString(to_simple_string(itsStartTime)));
+		itsPropertySet->setValue(PN_OBSCTRL_STOP_TIME,		GCFPVString(to_simple_string(itsStopTime)));
+		itsPropertySet->setValue(PN_OBSCTRL_BAND_FILTER, 	GCFPVString(theObs.filter));
+		itsPropertySet->setValue(PN_OBSCTRL_NYQUISTZONE, 	GCFPVInteger(theObs.nyquistZone));
+		itsPropertySet->setValue(PN_OBSCTRL_ANTENNA_ARRAY,	GCFPVString(theObs.antennaArray));
+		itsPropertySet->setValue(PN_OBSCTRL_RECEIVER_LIST, GCFPVString(
 						APLUtilities::compactedArrayString(globalParameterSet()->
 						getString("Observation.receiverList"))));
-		itsPropertySet->setValue(PN_OC_SAMPLE_CLOCK, GCFPVInteger(
-						globalParameterSet()->getUint32("Observation.sampleClock")));
-		itsPropertySet->setValue(PN_OC_MEASUREMENT_SET, GCFPVString(
+		itsPropertySet->setValue(PN_OBSCTRL_SAMPLE_CLOCK, GCFPVInteger(theObs.sampleClock));
+		itsPropertySet->setValue(PN_OBSCTRL_MEASUREMENT_SET, GCFPVString(
 						globalParameterSet()->getString("Observation.MSNameMask")));
-		itsPropertySet->setValue(PN_OC_STATION_LIST, GCFPVString(
+		itsPropertySet->setValue(PN_OBSCTRL_STATION_LIST, GCFPVString(
 						APLUtilities::compactedArrayString(globalParameterSet()->
 						getString("Observation.VirtualInstrument.stationList"))));
-		itsPropertySet->setValue(PN_OC_INPUT_NODE_LIST, GCFPVString(
+		itsPropertySet->setValue(PN_OBSCTRL_INPUT_NODE_LIST, GCFPVString(
 						APLUtilities::compactedArrayString(globalParameterSet()->
 						getString("Observation.VirtualInstrument.inputNodeList"))));
-		itsPropertySet->setValue(PN_OC_BGL_NODE_LIST, GCFPVString(
+		itsPropertySet->setValue(PN_OBSCTRL_BGL_NODE_LIST, GCFPVString(
 						APLUtilities::compactedArrayString(globalParameterSet()->
 						getString("Observation.VirtualInstrument.BGLNodeList"))));
-		itsPropertySet->setValue(PN_OC_STORAGE_NODE_LIST, GCFPVString(
+		itsPropertySet->setValue(PN_OBSCTRL_STORAGE_NODE_LIST, GCFPVString(
 						APLUtilities::compactedArrayString(globalParameterSet()->
 						getString("Observation.VirtualInstrument.storageNodeList"))));
-		
+
+		// for the beams we have to construct dyn arrays first.
+		GCFPValueArray		subbandArr;
+		GCFPValueArray		beamletArr;
+		GCFPValueArray		angle1Arr;
+		GCFPValueArray		angle2Arr;
+		GCFPValueArray		dirTypesArr;
+		for (uint32	i(0); i < theObs.beams.size(); i++) {
+			stringstream		os;
+			writeVector(os, theObs.beams[i].subbands);
+			subbandArr.push_back  (new GCFPVString(os.str()));
+			os.clear();
+			writeVector(os, theObs.beams[i].beamlets);
+			beamletArr.push_back  (new GCFPVString(os.str()));
+			angle1Arr.push_back	  (new GCFPVDouble(theObs.beams[i].angle1));
+			angle2Arr.push_back	  (new GCFPVDouble(theObs.beams[i].angle2));
+			dirTypesArr.push_back (new GCFPVString(theObs.beams[i].directionType));
+		}
+
+		// Finally we can write those value to PVSS as well.
+		itsPropertySet->setValue(PN_OBSCTRL_BEAMS_SUBBAND_LIST,		GCFPVDynArr(LPT_DYNSTRING, subbandArr));
+		itsPropertySet->setValue(PN_OBSCTRL_BEAMS_BEAMLET_LIST,		GCFPVDynArr(LPT_DYNSTRING, beamletArr));
+		itsPropertySet->setValue(PN_OBSCTRL_BEAMS_ANGLE1,			GCFPVDynArr(LPT_DYNDOUBLE, angle1Arr));
+		itsPropertySet->setValue(PN_OBSCTRL_BEAMS_ANGLE2,			GCFPVDynArr(LPT_DYNDOUBLE, angle2Arr));
+		itsPropertySet->setValue(PN_OBSCTRL_BEAMS_DIRECTION_TYPE,	GCFPVDynArr(LPT_DYNSTRING, dirTypesArr));
+
 		// Start ChildControl task
 		LOG_DEBUG ("Enabling ChildControl task");
 		itsChildControl->openService(MAC_SVCMASK_OBSERVATIONCTRL, itsTreeID);
@@ -890,21 +907,21 @@ void ObservationControl::_databaseEventHandler(GCFEvent& event)
 		}
  
 		// Change of claim_period?
-		if (strstr(dpEvent.DPname.c_str(), PN_OC_CLAIM_PERIOD) != 0) {
+		if (strstr(dpEvent.DPname.c_str(), PN_OBSCTRL_CLAIM_PERIOD) != 0) {
 			uint32  newVal = ((GCFPVInteger*) (dpEvent.value._pValue))->getValue();
 			LOG_INFO_STR ("Changing ClaimPeriod from " << itsClaimPeriod << " to " << newVal);
 			itsClaimPeriod = newVal;
 		}
 		// Change of prepare_period?
-		else if (strstr(dpEvent.DPname.c_str(), PN_OC_PREPARE_PERIOD) != 0) {
+		else if (strstr(dpEvent.DPname.c_str(), PN_OBSCTRL_PREPARE_PERIOD) != 0) {
 			uint32  newVal = ((GCFPVInteger*) (dpEvent.value._pValue))->getValue();
 			LOG_INFO_STR ("Changing PreparePeriod from " << itsPreparePeriod << " to " << newVal);
 			itsPreparePeriod = newVal;
 		}
 
 		// Change of start or stop time?
-		if ((strstr(dpEvent.DPname.c_str(), PN_OC_START_TIME) != 0)  || 
-		    (strstr(dpEvent.DPname.c_str(), PN_OC_STOP_TIME) != 0)) {
+		if ((strstr(dpEvent.DPname.c_str(), PN_OBSCTRL_START_TIME) != 0)  || 
+		    (strstr(dpEvent.DPname.c_str(), PN_OBSCTRL_STOP_TIME) != 0)) {
 			string  newVal = ((GCFPVString*) (dpEvent.value._pValue))->getValue();
 			ptime	newTime;
 			try {
@@ -914,7 +931,7 @@ void ObservationControl::_databaseEventHandler(GCFEvent& event)
 				LOG_DEBUG_STR(newVal << " is not a legal time!!!");
 				return;
 			}
-			if (strstr(dpEvent.DPname.c_str(), PN_OC_START_TIME) != 0) { 
+			if (strstr(dpEvent.DPname.c_str(), PN_OBSCTRL_START_TIME) != 0) { 
 				LOG_INFO_STR ("Changing startTime from " << to_simple_string(itsStartTime) << " to " << newVal);
 				itsStartTime = newTime;
 			}
diff --git a/MAC/APL/MainCU/src/ObservationControl/ObservationControlDefines.h b/MAC/APL/MainCU/src/ObservationControl/ObservationControlDefines.h
index 590ed64781f..d815c4cf7c6 100644
--- a/MAC/APL/MainCU/src/ObservationControl/ObservationControlDefines.h
+++ b/MAC/APL/MainCU/src/ObservationControl/ObservationControlDefines.h
@@ -30,24 +30,27 @@ namespace LOFAR {
 #define OC_OBSERVATIONSTATE			"observationState"
 
 // ObsCtrl
-#define PSN_OBS_CTRL    		"LOFAR_ObsSW_@observation@_ObsCtrl"
-#define PST_OBS_CTRL    		"ObsCtrl"
-#define PN_OC_CLAIM_PERIOD  	"claimPeriod"
-#define PN_OC_PREPARE_PERIOD    "preparePeriod"
-#define PN_OC_START_TIME    	"startTime"
-#define PN_OC_STOP_TIME	    	"stopTime"
-#define PN_OC_SUBBAND_LIST 		"subbandList"
-#define PN_OC_BEAMLET_LIST 		"beamletList"
-#define PN_OC_BAND_FILTER 		"bandFilter"
-#define PN_OC_NYQUISTZONE 		"nyquistzone"
-#define PN_OC_ANTENNA_ARRAY 	"antennaArray"
-#define PN_OC_RECEIVER_LIST 	"receiverList"
-#define PN_OC_SAMPLE_CLOCK 		"sampleClock"
-#define PN_OC_MEASUREMENT_SET 	"measurementSet"
-#define PN_OC_STATION_LIST 		"stationList"
-#define PN_OC_INPUT_NODE_LIST 	"inputNodeList"
-#define PN_OC_BGL_NODE_LIST 	"BGLNodeList"
-#define PN_OC_STORAGE_NODE_LIST	"storageNodeList"
+#define PSN_OBS_CTRL    				"LOFAR_ObsSW_@observation@_ObsCtrl"
+#define PST_OBS_CTRL    				"ObsCtrl"
+#define PN_OBSCTRL_CLAIM_PERIOD			"claimPeriod"
+#define PN_OBSCTRL_PREPARE_PERIOD		"preparePeriod"
+#define PN_OBSCTRL_START_TIME			"startTime"
+#define PN_OBSCTRL_STOP_TIME			"stopTime"
+#define PN_OBSCTRL_BAND_FILTER			"bandFilter"
+#define PN_OBSCTRL_NYQUISTZONE			"nyquistzone"
+#define PN_OBSCTRL_ANTENNA_ARRAY		"antennaArray"
+#define PN_OBSCTRL_RECEIVER_LIST		"receiverList"
+#define PN_OBSCTRL_SAMPLE_CLOCK			"sampleClock"
+#define PN_OBSCTRL_MEASUREMENT_SET		"measurementSet"
+#define PN_OBSCTRL_STATION_LIST			"stationList"
+#define PN_OBSCTRL_INPUT_NODE_LIST		"inputNodeList"
+#define PN_OBSCTRL_BGL_NODE_LIST		"BGLNodeList"
+#define PN_OBSCTRL_STORAGE_NODE_LIST	"storageNodeList"
+#define PN_OBSCTRL_BEAMS_ANGLE1			"Beams.angle1"
+#define PN_OBSCTRL_BEAMS_ANGLE2			"Beams.angle2"
+#define PN_OBSCTRL_BEAMS_DIRECTION_TYPE "Beams.directionType"
+#define PN_OBSCTRL_BEAMS_BEAMLET_LIST	"Beams.beamletList"
+#define PN_OBSCTRL_BEAMS_SUBBAND_LIST	"Beams.subbandList"
 
 
 // next lines should be defined somewhere in Common.
diff --git a/MAC/APL/PAC/BeamServer/src/BeamServer.cc b/MAC/APL/PAC/BeamServer/src/BeamServer.cc
index 65df0634934..e5d5e06781b 100644
--- a/MAC/APL/PAC/BeamServer/src/BeamServer.cc
+++ b/MAC/APL/PAC/BeamServer/src/BeamServer.cc
@@ -629,8 +629,9 @@ GCFEvent::TResult BeamServer::beamalloc_state(GCFEvent& event, GCFPortInterface&
 			m_beams.setCalibrationHandle(m_bt.getBeam(), ack.handle);
 
 			// send succesful ack
-			beamallocack.status = BS_Protocol::SUCCESS;
-			beamallocack.handle = (BS_Protocol::memptr_t)m_bt.getBeam();
+			beamallocack.status 	  = BS_Protocol::SUCCESS;
+			beamallocack.subarrayname = ack.subarray.getName();
+			beamallocack.handle 	  = (BS_Protocol::memptr_t)m_bt.getBeam();
 			m_bt.getPort()->send(beamallocack);
 		} 
 		else {
@@ -823,8 +824,9 @@ bool BeamServer::beamalloc_start(BSBeamallocEvent& ba,
 		LOG_FATAL_STR("BEAMALLOC: failed to allocate beam " << ba.name << " on " << ba.subarrayname);
 
 		BSBeamallocackEvent ack;
-		ack.handle = 0;
-		ack.status = BS_Protocol::ERR_RANGE;
+		ack.handle 		 = 0;
+		ack.subarrayname = ba.subarrayname;
+		ack.status 		 = BS_Protocol::ERR_RANGE;
 		port.send(ack);
 
 		return (false);
diff --git a/MAC/APL/PAC/BeamServer/src/beamctl.cc b/MAC/APL/PAC/BeamServer/src/beamctl.cc
index b35128ea137..306b5a40ac5 100644
--- a/MAC/APL/PAC/BeamServer/src/beamctl.cc
+++ b/MAC/APL/PAC/BeamServer/src/beamctl.cc
@@ -261,7 +261,7 @@ GCFEvent::TResult beamctl::create_beam(GCFEvent& e, GCFPortInterface& port)
 	} else {
 
 	  m_beamhandle = ack.handle;
-	  LOG_DEBUG(formatString("got beam_handle=%d", m_beamhandle));
+	  LOG_DEBUG(formatString("got beam_handle=%d for %s", m_beamhandle, ack.subarrayname.c_str()));
 
 	}
 
diff --git a/MAC/APL/PAC/CalServer/src/CalServer.cc b/MAC/APL/PAC/CalServer/src/CalServer.cc
index 94dce934cb0..3137c0aea1e 100644
--- a/MAC/APL/PAC/CalServer/src/CalServer.cc
+++ b/MAC/APL/PAC/CalServer/src/CalServer.cc
@@ -170,20 +170,34 @@ void CalServer::undertaker()
 //
 // remove_client(port)
 //
+// A disconnect was received on the given port, stop all related subarrays.
+//
 void CalServer::remove_client(GCFPortInterface* port)
 {
-	ASSERT(0 != port);
-
-	map<GCFPortInterface*, string>::iterator p = m_clients.find(port);
-	ASSERT(p != m_clients.end());
+	ASSERT(port != 0);
+
+	map<string, GCFPortInterface*>::iterator	iter = m_clients.begin();
+	map<string, GCFPortInterface*>::iterator	end  = m_clients.end();
+	while (iter != end) {
+		if (iter->second == port) {
+			// stop subarray if it is still there.
+			SubArray* subarray = m_subarrays.getByName(iter->first);
+			if (subarray) {
+				m_subarrays.schedule_remove(subarray);
+			}
 
-	SubArray* subarray = m_subarrays.getByName(m_clients[port]);
-	if (subarray) {
-		m_subarrays.schedule_remove(subarray);
-	}
+			// add to dead list.
+			m_dead_clients.push_back(iter->second);	
 
-	m_clients.erase(port);
-	m_dead_clients.push_back(port);
+			// remove entry from the map we are searching.
+			string	subArrayName(iter->first);		
+			iter++;
+			m_clients.erase(subArrayName);
+		}
+		else {
+			iter++;
+		} // if port matches
+	} // while
 }
 
 //
@@ -349,11 +363,12 @@ GCFEvent::TResult CalServer::enabled(GCFEvent& e, GCFPortInterface& port)
 		client->init(*this, "client", GCFPortInterface::SPP, CAL_PROTOCOL);
 		if (!m_acceptor.accept(*client)) {
 			delete client;
+			LOG_ERROR ("Could not setup a connection with a niew client");
 		}
-		else {
-			m_clients[client] = ""; // empty string to indicate there is a connection, but no subarray yet
-			LOG_INFO(formatString("NEW CLIENT CONNECTED: %d clients connected", m_clients.size()));
-		}
+//		else {
+//			m_clients[client] = ""; // empty string to indicate there is a connection, but no subarray yet
+//			LOG_INFO(formatString("NEW CLIENT CONNECTED: %d clients connected", m_clients.size()));
+//		}
 	}
 	break;
 
@@ -507,11 +522,6 @@ GCFEvent::TResult CalServer::handle_cal_start(GCFEvent& e, GCFPortInterface &por
 		LOG_ERROR_STR("A subarray with name='" << start.name << "' has already been registered.");
 		ack.status = ERR_ALREADY_REGISTERED;
 
-	} else if (m_clients[&port] != "") {
-		LOG_ERROR_STR("A subarray has already been registered: name=" << m_clients[&port]);
-		LOG_ERROR("Only one active subarray per client supported.");
-		ack.status = ERR_ONLY_ONE_SUBARRAY;
-
 	} else if (string(start.name) == "") {
 		LOG_ERROR("Empty subarray name.");
 		ack.status = ERR_NO_SUBARRAY_NAME;
@@ -528,7 +538,7 @@ GCFEvent::TResult CalServer::handle_cal_start(GCFEvent& e, GCFPortInterface &por
 
 	} else {
 		// register because this is a cal_start
-		m_clients[&port] = string(start.name); // register subarray with port
+		m_clients[start.name] = &port;		// register subarray and port
 
 		const Array<double, 3>& positions = parent->getAntennaPos();
 		Array<bool, 2> select;
@@ -631,20 +641,25 @@ GCFEvent::TResult CalServer::handle_cal_stop(GCFEvent& e, GCFPortInterface &port
 {
 	GCFEvent::TResult status = GCFEvent::HANDLED;
 
+	// prepare and send a response
 	CALStopEvent stop(e);
 	CALStopackEvent ack;
 	ack.name = stop.name;
-	ack.status = CAL_Protocol::SUCCESS;
+	ack.status = CAL_Protocol::SUCCESS;		// return success: don't bother client with our admin
+	port.send(ack);
 
-	// destroy subarray, what do we do with the observers?
-	if (m_subarrays.schedule_remove(stop.name)) {
-		m_clients[&port] = ""; // unregister subarray name
-	} 
-	else {
-		ack.status = ERR_NO_SUBARRAY; // subarray not found
-	}
+	m_subarrays.schedule_remove(stop.name);	// stop calibration
 
-	port.send(ack);
+	// remove subarray-port entry from the map.
+	map<string, GCFPortInterface*>::iterator	iter = m_clients.begin();
+	map<string, GCFPortInterface*>::iterator	end  = m_clients.end();
+	while (iter != end) {
+		if (iter->second == &port) {
+			m_clients.erase(iter);
+			break;
+		}
+		iter++;
+	}
 
 	return status;
 }
diff --git a/MAC/APL/PAC/CalServer/src/CalServer.h b/MAC/APL/PAC/CalServer/src/CalServer.h
index d953421c8d9..a0d1ef9bf0b 100644
--- a/MAC/APL/PAC/CalServer/src/CalServer.h
+++ b/MAC/APL/PAC/CalServer/src/CalServer.h
@@ -24,6 +24,9 @@
 #ifndef CALSERVER_H_
 #define CALSERVER_H_
 
+#include <Common/lofar_list.h>
+#include <Common/lofar_map.h>
+#include <Common/lofar_string.h>
 #include <APL/CAL_Protocol/ACC.h>
 #include <APL/CAL_Protocol/SubArray.h>
 #include "Source.h"
@@ -127,8 +130,8 @@ namespace LOFAR {
       /**
        * Client/Server management member variables.
        */
-      std::map<GCFPortInterface*, std::string> m_clients;      // list of clients with related subarray name
-      std::list<GCFPortInterface*>             m_dead_clients; // list of disconnected clients
+      map<string, GCFPortInterface*> 	m_clients;      // list of subarraynames with related clients
+      list<GCFPortInterface*>			m_dead_clients; // list of disconnected clients
 
 #ifdef USE_CAL_THREAD
       // CalibrationThread
-- 
GitLab