diff --git a/.gitattributes b/.gitattributes
index a6ecbf12842f14b4cd6c196db248e6a0a274dd03..b6c07ba824dde0184026123a99b5e516d8fcea68 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -303,6 +303,12 @@ MAC/APL/RTDBCommon/src/RTDButilities.cc -text
 MAC/APL/RTDBCommon/test/Makefile.am -text
 MAC/APL/RTDBCommon/test/tRTDButilities.cc -text
 MAC/APL/RTDBCommon/test/tRTDButilities.h -text
+MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitor.conf -text
+MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.cc -text
+MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.h -text
+MAC/APL/StationCU/src/HardwareMonitor/TBB.dpl -text
+MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.cc -text
+MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.h -text
 MAC/APL/_GSO/MACScheduler/Makefile.am -text svneol=native#application/octet-stream
 MAC/APL/_GSO/MACScheduler/bootstrap -text svneol=native#application/octet-stream
 MAC/APL/_GSO/MACScheduler/configure.in -text svneol=native#application/octet-stream
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitor.conf b/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitor.conf
new file mode 100644
index 0000000000000000000000000000000000000000..db6ab86375969b75650e6f04aa02ce22f3959369
--- /dev/null
+++ b/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitor.conf
@@ -0,0 +1,6 @@
+#
+# HardwareMonitor.conf
+#
+WatchRSPboards	=	1
+WatchTBboards	=	1
+closingDelay	=	2.0
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitorMain.cc b/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitorMain.cc
index f10b759dacdb9aeced83ea0a8e361629adf587c1..6709dc0e56a2451201715b3d2d3c60bb5b0a1eab 100644
--- a/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitorMain.cc
+++ b/MAC/APL/StationCU/src/HardwareMonitor/HardwareMonitorMain.cc
@@ -23,8 +23,15 @@
 #include <lofar_config.h>
 #include <Common/LofarLogger.h>
 
-#include "HardwareMonitor.h"
+#include <APS/ParameterSet.h>
+#include <APL/RSP_Protocol/RSP_Protocol.ph>
+#include <GCF/RTDB/DP_Protocol.ph>
+#include "RSPMonitor.h"
+#include "TBBMonitor.h"
 
+using namespace LOFAR;
+using namespace LOFAR::ACC::APS;
+using namespace LOFAR::GCF;
 using namespace LOFAR::GCF::TM;
 using namespace LOFAR::StationCU;
 
@@ -33,11 +40,52 @@ int main(int argc, char* argv[])
 	// args: cntlrname, parentHost, parentService
 	GCFTask::init(argc, argv);
 
-	HardwareMonitor	hm("HWmonitor");
-	hm.start(); 	// make initial transition
+	// TODO
+	LOG_INFO("MACProcessScope: LOFAR.PermSW.HWmonitor");
 
-	GCFTask::run();
+	// for debugging purposes
+	registerProtocol (RSP_PROTOCOL, RSP_PROTOCOL_STRINGS);
+	registerProtocol (TBB_PROTOCOL, TBB_PROTOCOL_STRINGS);
+	registerProtocol (DP_PROTOCOL,  DP_PROTOCOL_STRINGS);
 
-	return 0;
+	// Create tasks and call initial routines
+	RSPMonitor*		rsp(0);
+	TBBMonitor*		tbb(0);
+	// monitor RSP?
+	if (globalParameterSet()->getUint32("WatchRSPboards",0)) {
+		rsp = new RSPMonitor("RSPMonitor");
+		rsp->start();
+		LOG_INFO("Monitoring the RSP boards");
+	}
+
+	// monitor TBB?
+	if (globalParameterSet()->getUint32("WatchTBboards",0)) {
+		tbb = new TBBMonitor("TBBMonitor");
+		tbb->start();
+		LOG_INFO("Monitoring the TB boards");
+	}
+
+	// sanity check
+	if (!tbb && !rsp) {
+		LOG_FATAL_STR("Non of the monitortask (WatchRSPboards, WatchTBboards) was switched on "
+						"in the configfile, terminating program");
+		return (0);
+	}
+
+	// ok, we have something to do, do it.
+	GCFTask::setDelayedQuit(true);	// we need a clean shutdown
+	GCFTask::run();	// until stop was called
+
+	if (rsp) {
+		rsp->quit();		// let task quit nicely
+	}
+	if (tbb) {
+		tbb->quit();		// let task quit nicely
+	}
+
+	double	postRunTime = globalParameterSet()->getDouble("closingDelay", 1.5);
+	GCFTask::run(postRunTime);	// let processes die.
+
+	return (0);
 }
 
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/Makefile.am b/MAC/APL/StationCU/src/HardwareMonitor/Makefile.am
index 321e45f925e6d1aaf6657cb25186b2ad6a655c79..cb5833da89e6cd295fcfcb1394f17b342f35b59e 100644
--- a/MAC/APL/StationCU/src/HardwareMonitor/Makefile.am
+++ b/MAC/APL/StationCU/src/HardwareMonitor/Makefile.am
@@ -4,13 +4,15 @@ HardwareMonitor_CPPFLAGS	= -Wno-deprecated \
 							  -fmessage-length=0 \
 							  -fdiagnostics-show-location=once
 
-HardwareMonitor_SOURCES		= HardwareMonitor.cc \
-							  HardwareMonitorMain.cc 
+HardwareMonitor_SOURCES		= HardwareMonitorMain.cc \
+							  RSPMonitor.cc  \
+							  TBBMonitor.cc 
 
 HardwareMonitor_LDADD		= $(LOFAR_DEPEND)
 HardwareMonitor_DEPENDENCIES= $(LOFAR_DEPEND)
 
-NOINSTHDRS 					= HardwareMonitor.h \
+NOINSTHDRS 					= RSPMonitor.h \
+							  TBBMonitor.h \
 							  RCUConstants.h \
 							  StationPermDatapointDefs.h
 
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/RCUConstants.h b/MAC/APL/StationCU/src/HardwareMonitor/RCUConstants.h
index b3c9ea92c6df0a55911e8643dd97e2a84a00a114..66275bcbd8f322d9bef0da90c2b60a38d014b20e 100644
--- a/MAC/APL/StationCU/src/HardwareMonitor/RCUConstants.h
+++ b/MAC/APL/StationCU/src/HardwareMonitor/RCUConstants.h
@@ -47,11 +47,13 @@ static const uint32	ATT_OFFSET			= 19;
 
 
 // NOTE: THESE CONSTANTS SHOULD BE SOMEWHERE AT A GLOBAL PLACE
-static const uint32	NR_SUBRACKS_PER_CABINET	= 2;
-static const uint32	NR_RSPBOARDS_PER_SUBRACK= 4;
-static const uint32	NR_RCUS_PER_RSPBOARD	= 8;
-static const uint32	NR_RCUS_PER_SUBRACK		= (NR_RCUS_PER_RSPBOARD * NR_RSPBOARDS_PER_SUBRACK);
-static const uint32	NR_RCUS_PER_CABINET		= (NR_RCUS_PER_SUBRACK  * NR_SUBRACKS_PER_CABINET);
+static const uint32	NR_SUBRACKS_PER_CABINET	 = 2;
+static const uint32	NR_RSPBOARDS_PER_SUBRACK = 4;
+static const uint32	NR_TBBOARDS_PER_RSPBOARD = 2;
+static const uint32	NR_RCUS_PER_RSPBOARD	 = 8;
+static const uint32	NR_RCUS_PER_TBBOARD		 = (NR_TBBOARDS_PER_RSPBOARD * NR_RCUS_PER_RSPBOARD);
+static const uint32	NR_RCUS_PER_SUBRACK		 = (NR_RCUS_PER_RSPBOARD * NR_RSPBOARDS_PER_SUBRACK);
+static const uint32	NR_RCUS_PER_CABINET		 = (NR_RCUS_PER_SUBRACK  * NR_SUBRACKS_PER_CABINET);
 
 #define PN_RSP_AP_VERSION_MASK		"AP%d.version"
 
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.cc b/MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3db6468ca615cebd8dd21b3b8289d981606d40cd
--- /dev/null
+++ b/MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.cc
@@ -0,0 +1,808 @@
+//#  RSPMonitor.cc: Implementation of the MAC Scheduler task
+//#
+//#  Copyright (C) 2006
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  This program is free software; you can redistribute it and/or modify
+//#  it under the terms of the GNU General Public License as published by
+//#  the Free Software Foundation; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  This program is distributed in the hope that it will be useful,
+//#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//#  GNU General Public License for more details.
+//#
+//#  You should have received a copy of the GNU General Public License
+//#  along with this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id: RSPMonitor.cc 10505 2007-09-07 17:14:57Z overeem $
+#include <lofar_config.h>
+#include <Common/LofarLogger.h>
+
+#include <GCF/GCF_PVTypes.h>
+#include <GCF/GCF_ServiceInfo.h>
+#include <APL/APLCommon/ControllerDefines.h>
+#include <APL/RSP_Protocol/RSP_Protocol.ph>
+#include <GCF/RTDB/DP_Protocol.ph>
+//#include <APL/APLCommon/StationInfo.h>
+#include <signal.h>
+
+#include "RSPMonitor.h"
+#include "RCUConstants.h"
+#include "StationPermDatapointDefs.h"
+
+using namespace LOFAR::GCF::Common;
+using namespace LOFAR::GCF::TM;
+using namespace LOFAR::GCF::RTDB;
+using namespace std;
+
+namespace LOFAR {
+	using namespace APLCommon;
+	namespace StationCU {
+	
+//
+// RSPMonitor()
+//
+RSPMonitor::RSPMonitor(const string&	cntlrName) :
+	GCFTask 			((State)&RSPMonitor::initial_state,cntlrName),
+	itsOwnPropertySet	(0),
+	itsTimerPort		(0),
+	itsRSPDriver		(0),
+	itsPollInterval		(10),
+	itsNrRCUs			(0),
+	itsNrRSPboards		(0),
+	itsNrSubracks		(0),
+	itsNrCabinets		(0)
+{
+	LOG_TRACE_OBJ_STR (cntlrName << " construction");
+
+	// need port for timers.
+	itsTimerPort = new GCFTimerPort(*this, "TimerPort");
+
+	// prepare TCP port to RSPDriver.
+	itsRSPDriver = new GCFTCPPort (*this, MAC_SVCMASK_RSPDRIVER,
+											GCFPortInterface::SAP, RSP_PROTOCOL);
+	ASSERTSTR(itsRSPDriver, "Cannot allocate TCPport to RSPDriver");
+	itsRSPDriver->setInstanceNr(0);
+
+}
+
+
+//
+// ~RSPMonitor()
+//
+RSPMonitor::~RSPMonitor()
+{
+	LOG_TRACE_OBJ_STR (getName() << " destruction");
+
+	if (itsRSPDriver) {
+		itsRSPDriver->close();
+	}
+
+	// ...
+}
+
+
+//
+// initial_state(event, port)
+//
+// Setup connection with PVSS
+//
+GCFEvent::TResult RSPMonitor::initial_state(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("initial:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+    case F_INIT:
+   		break;
+
+	case F_ENTRY: {
+		// Get access to my own propertyset.
+		LOG_DEBUG_STR ("Activating PropertySet " << PSN_HARDWARE_MONITOR);
+		itsTimerPort->setTimer(2.0);
+		itsOwnPropertySet = new RTDBPropertySet(PSN_HARDWARE_MONITOR,
+												PST_HARDWARE_MONITOR,
+												PSAT_WO,
+												this);
+
+		}
+		break;
+
+	case DP_CREATED: {
+		// NOTE: this 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;
+
+	case F_TIMER: {
+		// update PVSS.
+		LOG_TRACE_FLOW ("Updateing state to PVSS");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION, GCFPVString("initial"));
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,  GCFPVString(""));
+		
+		LOG_DEBUG_STR("Going to connect to the RSPDriver.");
+		TRAN (RSPMonitor::connect2RSP);
+	}
+	
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("initial, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// connect2RSP(event, port)
+//
+// Setup connection with RSPdriver
+//
+GCFEvent::TResult RSPMonitor::connect2RSP(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("connect2RSP:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_ENTRY:
+		// update PVSS
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION, GCFPVString("connecting"));
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CONNECTED,GCFPVBool(false));
+		itsRSPDriver->open();		// will result in F_CONN or F_DISCONN
+		break;
+
+	case F_CONNECTED:
+		if (&port == itsRSPDriver) {
+			LOG_DEBUG ("Connected with RSPDriver, going to get the configuration");
+			itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,  GCFPVString(""));
+			itsOwnPropertySet->setValue(PN_HWM_RSP_CONNECTED,GCFPVBool(true));
+			TRAN(RSPMonitor::askConfiguration);		// go to next state.
+		}
+		break;
+
+	case F_DISCONNECTED:
+		port.close();
+		ASSERTSTR (&port == itsRSPDriver, 
+								"F_DISCONNECTED event from port " << port.getName());
+		LOG_DEBUG("Connection with RSPDriver failed, retry in 2 seconds");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR, GCFPVString("connection timeout"));
+		itsTimerPort->setTimer(2.0);
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("connect2RSP, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+//
+// askConfiguration(event, port)
+//
+// Take subscription on clock modifications
+//
+GCFEvent::TResult RSPMonitor::askConfiguration(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askConfiguration:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION,GCFPVString("asking configuration"));
+		RSPGetconfigEvent	getconfig;
+		itsRSPDriver->send(getconfig);
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2RSP
+		break;
+
+	case RSP_GETCONFIGACK: {
+		RSPGetconfigackEvent	ack(event);
+	
+		// calc size of the propertyset vectors
+		itsNrRCUs	   = ack.n_rcus;
+		itsNrRSPboards = ack.n_rspboards;
+		itsNrSubracks  = (itsNrRSPboards/NR_RSPBOARDS_PER_SUBRACK) + 
+						 	((itsNrRSPboards%NR_RSPBOARDS_PER_SUBRACK) ? 1 : 0);
+		itsNrCabinets  = (itsNrSubracks /NR_SUBRACKS_PER_CABINET)  + 
+						 	((itsNrSubracks%NR_SUBRACKS_PER_CABINET) ? 1 : 0);
+
+		// inform user
+		LOG_DEBUG(formatString("nr RCUs      = %d",ack.n_rcus));
+		LOG_DEBUG(formatString("nr RSPboards = %d",ack.max_rspboards));
+		LOG_DEBUG(formatString("nr Subracks  = %d", itsNrSubracks));
+		LOG_DEBUG(formatString("nr Cabinets  = %d", itsNrCabinets));
+		LOG_DEBUG_STR("("<<itsNrRSPboards<<"/"<<NR_RSPBOARDS_PER_SUBRACK<<") + (("<<itsNrRSPboards<<"%"<<NR_RSPBOARDS_PER_SUBRACK<<") ? 1 : 0)");
+		LOG_DEBUG_STR("("<<itsNrRSPboards<<"/"<<NR_RSPBOARDS_PER_SUBRACK<<") = " << itsNrRSPboards/NR_RSPBOARDS_PER_SUBRACK);
+		LOG_DEBUG_STR("("<<itsNrRSPboards<<"%"<<NR_RSPBOARDS_PER_SUBRACK<<") = " << itsNrRSPboards%NR_RSPBOARDS_PER_SUBRACK);
+	
+		// do some checks
+		if (itsNrRSPboards != (uint32)ack.max_rspboards) {
+			LOG_WARN_STR("RSPdriver only controls " << itsNrRSPboards << " of " << ack.max_rspboards 
+						<< " RSPboards, cannot monitor full station");
+		}
+		if (itsNrRSPboards * NR_RCUS_PER_RSPBOARD != itsNrRCUs) {
+			LOG_INFO_STR("Station not fully equiped, only " << itsNrRCUs << " of " 
+						<< itsNrRSPboards * NR_RCUS_PER_RSPBOARD << "RCUs");
+		}
+
+		LOG_DEBUG ("Going to allocate the property-sets");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		TRAN(RSPMonitor::createPropertySets);				// go to next state.
+		}
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askConfiguration, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// createPropertySets(event, port)
+//
+// Retrieve sampleclock from RSP driver
+//
+GCFEvent::TResult RSPMonitor::createPropertySets(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("createPropertySets:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION,GCFPVString("create PropertySets"));
+		// resize vectors.
+		itsCabinets.resize(itsNrCabinets,  0);
+		itsSubracks.resize(itsNrSubracks,  0);
+		itsRSPs.resize	  (itsNrRSPboards, 0);
+		itsRCUs.resize	  (itsNrRCUs, 	   0);
+
+		int32	cabinet (-1);
+		int32	subrack (-1);
+		int32	RSP		(-1);
+		string	cabinetNameMask (createPropertySetName(PSN_CABINET,   getName()));
+		string	subrackNameMask (createPropertySetName(PSN_SUB_RACK,  getName()));
+		string	rspboardNameMask(createPropertySetName(PSN_RSP_BOARD, getName()));
+		string	rcuNameMask     (createPropertySetName(PSN_RCU, 	  getName()));
+		for (uint32	rcu = 0; rcu < itsNrRCUs; rcu++) {
+			// new cabinet?
+			if (rcu % (NR_RCUS_PER_CABINET) == 0) {
+				cabinet++;
+				string	PSname(formatString(cabinetNameMask.c_str(), cabinet));
+				itsCabinets[cabinet] = new RTDBPropertySet(PSname, PST_CABINET, PSAT_WO, this);
+			}
+
+			// new subrack?
+			if (rcu % (NR_RCUS_PER_SUBRACK) == 0) {
+				subrack++;
+				string	PSname(formatString(subrackNameMask.c_str(), cabinet, subrack));
+				itsSubracks[subrack] = new RTDBPropertySet(PSname, PST_SUB_RACK, PSAT_WO, this);
+			}
+
+			// new RSPboard?
+			if (rcu % (NR_RCUS_PER_RSPBOARD) == 0) {
+				RSP++;
+				string	PSname(formatString(rspboardNameMask.c_str(), cabinet, subrack, RSP));
+				itsRSPs[RSP] = new RTDBPropertySet(PSname, PST_RSP_BOARD, PSAT_WO, this);
+			}
+
+			// allocate RCU PS
+			string	PSname(formatString(rcuNameMask.c_str(), cabinet, subrack, RSP, rcu));
+			itsRCUs[rcu] = new RTDBPropertySet(PSname, PST_RCU, PSAT_WO, this);
+		}
+		itsTimerPort->setTimer(5.0);	// give database some time to finish the job
+	}
+	break;
+
+	case F_TIMER: {
+		// database should be ready by now, check if allocation was succesfull
+		for (uint32	cabinet = 0; cabinet < itsNrCabinets; cabinet++) {
+			ASSERTSTR(itsCabinets[cabinet], "Allocation of PS for cabinet " << cabinet << " failed.");
+		}
+		for (uint32	subrack = 0; subrack < itsNrSubracks; subrack++) {
+			ASSERTSTR(itsSubracks[subrack], "Allocation of PS for subrack " << subrack << " failed.");
+		}
+		for (uint32	rsp = 0; rsp < itsNrRSPboards; rsp++) {
+			ASSERTSTR(itsRSPs[rsp], "Allocation of PS for rsp " << rsp << " failed.");
+		}
+		for (uint32	rcu = 0; rcu < itsNrRCUs; rcu++) {
+			ASSERTSTR(itsRCUs[rcu], "Allocation of PS for rcu " << rcu << " failed.");
+		}
+		LOG_DEBUG_STR("Allocation of all propertySets successfull, going to operational mode");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		TRAN(RSPMonitor::askVersion);
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2RSP
+	break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("createPropertySets, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// askVersion(event, port)
+//
+// Set sampleclock from RSP driver
+//
+GCFEvent::TResult RSPMonitor::askVersion(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askVersion:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION,GCFPVString("getting version info"));
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		RSPGetversionEvent	getVersion;
+		getVersion.timestamp.setNow();
+		getVersion.cache = true;
+		itsRSPDriver->send(getVersion);
+	}
+	break;
+
+	case RSP_GETVERSIONACK: {
+		RSPGetversionackEvent		ack(event);
+		if (ack.status != SUCCESS) {
+			LOG_ERROR_STR ("Failed to get the version information, trying other information");
+			itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString("getVersion error"));
+			TRAN(RSPMonitor::askRSPinfo);				// go to next state.
+			break;
+		}
+
+		// move the information to the database.
+		string		versionStr;
+		string		DPEname;
+		for (uint32	rsp = 0; rsp < itsNrRSPboards; rsp++) {
+			// RSP board version
+			versionStr = formatString("%d.%d", ack.versions.bp()(rsp).rsp_version >> 4,
+											   ack.versions.bp()(rsp).rsp_version & 0xF);
+			itsRSPs[rsp]->setValue(PN_RSP_VERSION, GCFPVString(versionStr), double(ack.timestamp));
+			
+			// BP version
+			versionStr = formatString("%d.%d", ack.versions.bp()(rsp).fpga_maj,
+											   ack.versions.bp()(rsp).fpga_min);
+			itsRSPs[rsp]->setValue(PN_RSP_BP_VERSION, GCFPVString(versionStr), double(ack.timestamp));
+			
+			// APx versions
+			for (int ap = 0; ap < MEPHeader::N_AP; ap++) {
+				versionStr = formatString("%d.%d", ack.versions.ap()(rsp * MEPHeader::N_AP + ap).fpga_maj,
+												   ack.versions.ap()(rsp * MEPHeader::N_AP + ap).fpga_min);
+				DPEname = formatString (PN_RSP_AP_VERSION_MASK, ap);
+				itsRSPs[rsp]->setValue(DPEname, GCFPVString(versionStr), double(ack.timestamp));
+			}
+		}
+
+		LOG_DEBUG_STR ("Version information updated, going to status information");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		TRAN(RSPMonitor::askRSPinfo);				// go to next state.
+		break;
+	}
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2RSP
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askVersion, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// askRSPinfo(event, port)
+//
+// Set sampleclock from RSP driver
+//
+GCFEvent::TResult RSPMonitor::askRSPinfo(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askRSPinfo:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION,GCFPVString("updating RSP info"));
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		RSPGetstatusEvent	getStatus;
+		getStatus.timestamp.setNow();
+		getStatus.cache = true;
+		getStatus.rspmask = bitset<MAX_N_RSPBOARDS>((1<<itsNrRSPboards)-1);
+		itsRSPDriver->send(getStatus);
+	}
+	break;
+
+	case RSP_GETSTATUSACK: {
+		RSPGetstatusackEvent		ack(event);
+		if (ack.status != SUCCESS) {
+			LOG_ERROR_STR ("Failed to get the status information, trying other information");
+			itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString("getStatus error"));
+#if 0
+			TRAN(RSPMonitor::askRCUinfo);				// go to next state.
+#else
+			LOG_WARN ("SKIPPING RCU INFO FOR A MOMENT");
+			TRAN(RSPMonitor::waitForNextCycle);			// go to next state.
+#endif
+			break;
+		}
+
+		// move the information to the database.
+		string		versionStr;
+		string		DPEname;
+		for (uint32	rsp = 0; rsp < itsNrRSPboards; rsp++) {
+			BoardStatus		bStat = ack.sysstatus.board()(rsp);
+			// board voltages
+			itsRSPs[rsp]->setValue(PN_RSP_VOLTAGE12, GCFPVDouble(double(bStat.rsp.voltage_1_2)*(2.5/192.0)), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_VOLTAGE25, GCFPVDouble(double(bStat.rsp.voltage_2_5)*(3.3/192.0)), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_VOLTAGE33, GCFPVDouble(double(bStat.rsp.voltage_3_3)*(5.0/192.0)), 
+									double(ack.timestamp));
+			
+			// Ethernet status
+			itsRSPs[rsp]->setValue(PN_RSP_ETHERNET_PACKETS_RECEIVED, GCFPVUnsigned(bStat.eth.nof_frames), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_ETHERNET_PACKETS_ERROR,    GCFPVUnsigned(bStat.eth.nof_errors), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_ETHERNET_LAST_ERROR,       GCFPVUnsigned(bStat.eth.last_error), 
+									double(ack.timestamp));
+			
+			// MEP status
+			itsRSPs[rsp]->setValue(PN_RSP_MEP_SEQNR, GCFPVUnsigned(bStat.mep.seqnr), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_MEP_ERROR, GCFPVUnsigned(bStat.mep.error), 
+									double(ack.timestamp));
+
+			// BP status
+			itsRSPs[rsp]->setValue(PN_RSP_BP_TEMPERATURE, GCFPVDouble(double(bStat.rsp.bp_temp)), 
+									double(ack.timestamp));
+			// AP0
+			itsRSPs[rsp]->setValue(PN_RSP_AP0_TEMPERATURE,		 GCFPVDouble(double(bStat.rsp.ap0_temp)), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_AP0_SYNC_SAMPLE_COUNT, GCFPVUnsigned(bStat.ap0_sync.sample_offset), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_AP0_SYNC_SYNC_COUNT,   GCFPVUnsigned(bStat.ap0_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP0_SYNC_ERROR_COUNT,  GCFPVUnsigned(bStat.ap0_sync.ext_count)), 
+									double(ack.timestamp);
+
+			// AP1
+			itsRSPs[rsp]->setValue(PN_RSP_AP1_TEMPERATURE,		 GCFPVDouble(double(bStat.rsp.ap1_temp)), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_AP1_SYNC_SAMPLE_COUNT, GCFPVUnsigned(bStat.ap1_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP1_SYNC_SYNC_COUNT,   GCFPVUnsigned(bStat.ap1_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP1_SYNC_ERROR_COUNT,  GCFPVUnsigned(bStat.ap1_sync.ext_count)), 
+									double(ack.timestamp);
+
+			// AP2
+			itsRSPs[rsp]->setValue(PN_RSP_AP2_TEMPERATURE,		 GCFPVDouble(double(bStat.rsp.ap2_temp)), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_AP2_SYNC_SAMPLE_COUNT, GCFPVUnsigned(bStat.ap2_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP2_SYNC_SYNC_COUNT,   GCFPVUnsigned(bStat.ap2_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP2_SYNC_ERROR_COUNT,  GCFPVUnsigned(bStat.ap2_sync.ext_count)), 
+									double(ack.timestamp);
+
+			// AP3
+			itsRSPs[rsp]->setValue(PN_RSP_AP3_TEMPERATURE,		 GCFPVDouble(double(bStat.rsp.ap3_temp)), 
+									double(ack.timestamp));
+			itsRSPs[rsp]->setValue(PN_RSP_AP3_SYNC_SAMPLE_COUNT, GCFPVUnsigned(bStat.ap3_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP3_SYNC_SYNC_COUNT,   GCFPVUnsigned(bStat.ap3_sync.sample_offset)), 
+									double(ack.timestamp);
+			itsRSPs[rsp]->setValue(PN_RSP_AP3_SYNC_ERROR_COUNT,  GCFPVUnsigned(bStat.ap3_sync.ext_count)), 
+									double(ack.timestamp);
+		} // for all boards
+
+		LOG_DEBUG_STR ("RSPboard information updated, going to RCU information");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+#if 0
+		TRAN(RSPMonitor::askRCUinfo);				// go to next state.
+#else
+		LOG_WARN ("SKIPPING RCU INFO FOR A MOMENT");
+		TRAN(RSPMonitor::waitForNextCycle);			// go to next state.
+#endif
+		break;
+	}
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2RSP
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askRSPinfo, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// askRCUinfo(event, port)
+//
+// Normal operation state. 
+//
+GCFEvent::TResult RSPMonitor::askRCUinfo(GCFEvent& event, GCFPortInterface& port)
+{
+	if (eventName(event) != "DP_SET") {
+		LOG_DEBUG_STR ("askRCUinfo:" << eventName(event) << "@" << port.getName());
+	}
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+
+	switch (event.signal) {
+	case F_INIT:
+		break;
+
+	case F_ENTRY: {
+		// update PVSS
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION,GCFPVString("updating RSP info"));
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		RSPGetrcuEvent	getStatus;
+		getStatus.timestamp.setNow();
+		getStatus.cache = true;
+		getStatus.rcumask = bitset<MEPHeader::MAX_N_RCUS>((1<<itsNrRCUs)-1);
+		itsRSPDriver->send(getStatus);
+		break;
+	}
+
+	case RSP_GETRCUACK: {
+		RSPGetrcuackEvent	ack(event);
+		if (ack.status != SUCCESS) {
+			LOG_ERROR_STR ("Failed to get the RCU information, trying other information");
+			itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString("getRCU error"));
+			TRAN(RSPMonitor::waitForNextCycle);			// go to next state.
+			break;
+		}
+
+		// move the information to the database.
+		string		versionStr;
+		string		DPEname;
+		for (uint32	rcu = 0; rcu < itsNrRCUs; rcu++) {
+			LOG_DEBUG_STR("Updating rcu " << rcu);
+			uint32		rawValue = ack.settings()(rcu).getRaw();
+			// update all RCU variables
+			itsRCUs[rcu]->setValue(PN_RCU_DELAY, 
+						GCFPVUnsigned(uint32(rawValue & DELAY_MASK)),
+						double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_INPUT_ENABLE, 
+						GCFPVBool(rawValue & INPUT_ENABLE_MASK),
+						double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_LBL_ENABLE, 
+						GCFPVBool(rawValue & LBL_ANT_POWER_MASK), double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_LBH_ENABLE, 
+						GCFPVBool(rawValue & LBH_ANT_POWER_MASK), double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_HBA_ENABLE, 
+						GCFPVBool(rawValue & HBA_ANT_POWER_MASK), double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_BAND_SEL_LBA_HBA, 
+						GCFPVBool(rawValue & USE_LB_MASK),
+						double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_HBA_FILTER_SEL, 
+						GCFPVUnsigned((rawValue & HB_FILTER_MASK) >> HB_FILTER_OFFSET),
+						double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_VL_ENABLE, 
+						GCFPVBool(rawValue & LB_POWER_MASK), double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_VH_ENABLE, 
+						GCFPVBool(rawValue & HB_POWER_MASK), double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_VDD_VCC_ENABLE, 
+						GCFPVBool(rawValue & ADC_POWER_MASK), double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_BAND_SEL_LBL_LBH, 
+						GCFPVBool(rawValue & USE_LBH_MASK),
+						double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_LBA_FILTER_SEL, 
+						GCFPVUnsigned((rawValue & LB_FILTER_MASK) >> LB_FILTER_OFFSET),
+						double(ack.timestamp));
+			itsRCUs[rcu]->setValue(PN_RCU_ATTENUATION, 
+						GCFPVUnsigned(uint32((rawValue & ATT_MASK) >> ATT_OFFSET)),
+						double(ack.timestamp));
+		} // for all boards
+
+		LOG_DEBUG ("Updated all RCU information, waiting for next cycle");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString(""));
+		TRAN(RSPMonitor::waitForNextCycle);			// go to next state.
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2RSP
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG("askRCUinfo, DEFAULT");
+		break;
+	}
+
+	return (status);
+}
+
+//
+// waitForNextCycle(event, port)
+//
+// Take subscription on clock modifications
+//
+GCFEvent::TResult RSPMonitor::waitForNextCycle(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	if (eventName(event) != "DP_SET") {
+		LOG_DEBUG_STR ("waitForNextCycle:" << eventName(event) << "@" << port.getName());	}
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_RSP_CURRENT_ACTION,GCFPVString("wait for next cycle"));
+		int		waitTime = itsPollInterval - (time(0) % itsPollInterval);
+		if (waitTime == 0) {
+			waitTime = itsPollInterval;
+		}
+		itsTimerPort->cancelAllTimers();
+		itsTimerPort->setTimer(double(waitTime));
+		LOG_DEBUG_STR("Waiting " << waitTime << " seconds for next cycle");
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2RSP
+	break;
+
+	case F_TIMER: {
+		TRAN(RSPMonitor::askRSPinfo);
+	}
+	break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (RSPMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("waitForNextCycle, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// _disconnectedHandler(port)
+//
+void RSPMonitor::_disconnectedHandler(GCFPortInterface& port)
+{
+	port.close();
+	if (&port == itsRSPDriver) {
+		LOG_DEBUG("Connection with RSPDriver failed, going to reconnect state");
+		itsOwnPropertySet->setValue(PN_HWM_RSP_ERROR,GCFPVString("connection lost"));
+		TRAN (RSPMonitor::connect2RSP);
+	}
+}
+
+//
+// finish_state(event, port)
+//
+// Write controller state to PVSS
+//
+GCFEvent::TResult RSPMonitor::finish_state(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("finish_state:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+
+	switch (event.signal) {
+	case F_INIT:
+		break;
+
+	case F_ENTRY: {
+		// update PVSS
+		itsOwnPropertySet->setValue(string(PN_HWM_RSP_CURRENT_ACTION),GCFPVString("finished"));
+		itsOwnPropertySet->setValue(string(PN_HWM_RSP_ERROR),GCFPVString(""));
+		break;
+	}
+  
+	case DP_SET:
+		break;
+
+	default:
+		LOG_DEBUG("finishing_state, DEFAULT");
+		status = GCFEvent::NOT_HANDLED;
+		break;
+	}    
+	return (status);
+}
+
+
+}; // StationCU
+}; // LOFAR
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.h b/MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..bace721f9113755ae823b30dbc7aeb245551f07c
--- /dev/null
+++ b/MAC/APL/StationCU/src/HardwareMonitor/RSPMonitor.h
@@ -0,0 +1,99 @@
+//#  RSPMonitor.h: Monitors the RSP hardware.
+//#
+//#  Copyright (C) 2006
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  This program is free software; you can redistribute it and/or modify
+//#  it under the terms of the GNU General Public License as published by
+//#  the Free Software Foundation; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  This program is distributed in the hope that it will be useful,
+//#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//#  GNU General Public License for more details.
+//#
+//#  You should have received a copy of the GNU General Public License
+//#  along with this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id: RSPMonitor.h 10461 2007-08-23 22:44:03Z overeem $
+
+#ifndef STATIONCU_RSP_MONITOR_H
+#define STATIONCU_RSP_MONITOR_H
+
+//# Common Includes
+#include <Common/lofar_string.h>
+#include <Common/lofar_vector.h>
+
+//# GCF Includes
+#include <GCF/RTDB/RTDB_PropertySet.h>
+#include <GCF/TM/GCF_TCPPort.h>
+#include <GCF/TM/GCF_TimerPort.h>
+#include <GCF/TM/GCF_Task.h>
+#include <GCF/TM/GCF_Event.h>
+
+// forward declaration
+
+namespace LOFAR {
+	namespace StationCU {
+
+using	GCF::TM::GCFTimerPort;
+using	GCF::TM::GCFTCPPort;
+using	GCF::TM::GCFEvent;
+using	GCF::TM::GCFPortInterface;
+using	GCF::TM::GCFTask;
+using	GCF::RTDB::RTDBPropertySet;
+
+
+class RSPMonitor : public GCFTask
+{
+public:
+	explicit RSPMonitor(const string& cntlrName);
+	~RSPMonitor();
+
+private:
+	// During the initial state all connections with the other programs are made.
+   	GCFEvent::TResult initial_state   		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult connect2RSP   		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askConfiguration 		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult createPropertySets	 (GCFEvent& e, GCFPortInterface& p);
+
+   	GCFEvent::TResult askVersion    		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askRSPinfo	  		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askRCUinfo			 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult waitForNextCycle		 (GCFEvent& e, GCFPortInterface& p);
+
+   	GCFEvent::TResult finish_state  		 (GCFEvent& e, GCFPortInterface& p);
+
+	// avoid defaultconstruction and copying
+	RSPMonitor();
+	RSPMonitor(const RSPMonitor&);
+   	RSPMonitor& operator=(const RSPMonitor&);
+
+   	void _disconnectedHandler(GCFPortInterface& port);
+
+	// Data members
+	RTDBPropertySet*			itsOwnPropertySet;
+
+	GCFTimerPort*				itsTimerPort;
+
+	GCFTCPPort*					itsRSPDriver;
+
+	uint32						itsPollInterval;
+
+	uint32						itsNrRCUs;
+	uint32						itsNrRSPboards;
+	uint32						itsNrSubracks;
+	uint32						itsNrCabinets;
+
+	vector<RTDBPropertySet*>	itsCabinets;
+	vector<RTDBPropertySet*>	itsSubracks;
+	vector<RTDBPropertySet*>	itsRSPs;
+	vector<RTDBPropertySet*>	itsRCUs;
+};
+
+  };//StationCU
+};//LOFAR
+#endif
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/StationPermDatapointDefs.h b/MAC/APL/StationCU/src/HardwareMonitor/StationPermDatapointDefs.h
index f0084af75cc59c1cf7c866ba52a6ffbfa59244af..8de85dddd274a609e8b4697eded8523eea53b61c 100644
--- a/MAC/APL/StationCU/src/HardwareMonitor/StationPermDatapointDefs.h
+++ b/MAC/APL/StationCU/src/HardwareMonitor/StationPermDatapointDefs.h
@@ -1,14 +1,16 @@
-// This file was generated by create_db_files v1.0 on Fri Aug 24 08:34:27 UTC 2007
+// This file was generated by create_db_files v1.0 on Wed Nov 14 15:49:57 UTC 2007
 
 // Cabinet
 #define PSN_CABINET	"LOFAR_PIC_@cabinet@"
 #define PST_CABINET	"Cabinet"
-#define PN_CAB_FRONT_DOOR	"front.door"
-#define PN_CAB_FRONT_FAN	"front.fan"
-#define PN_CAB_FRONT_TEMPERATURE	"front.temperature"
-#define PN_CAB_BACK_DOOR	"back.door"
-#define PN_CAB_BACK_FAN	"back.fan"
-#define PN_CAB_BACK_TEMPERATURE	"back.temperature"
+#define PN_CAB_DOOR_OPEN	"doorOpen"
+#define PN_CAB_FAN	"fan"
+#define PN_CAB_INLET_TEMP	"inletTemp"
+#define PN_CAB_FRONT_TEMP	"frontTemp"
+#define PN_CAB_BACK_TEMP	"backTemp"
+#define PN_CAB_SETPOINT_TEMP	"setpointTemp"
+#define PN_CAB_AMBIENT_TEMP	"ambientTemp"
+#define PN_CAB_CONTROL_MODE	"controlMode"
 
 // SubRack
 #define PSN_SUB_RACK	"LOFAR_PIC_@cabinet@_@subrack@"
@@ -44,9 +46,6 @@
 #define PN_RSP_BP_STATE	"BP.state"
 #define PN_RSP_BP_TEMPERATURE	"BP.temperature"
 #define PN_RSP_BP_VERSION	"BP.version"
-#define PN_RSP_BP_SYNC_SAMPLE_COUNT	"BP.SYNC.sampleCount"
-#define PN_RSP_BP_SYNC_SYNC_COUNT	"BP.SYNC.syncCount"
-#define PN_RSP_BP_SYNC_ERROR_COUNT	"BP.SYNC.errorCount"
 #define PN_RSP_AP0_STATE	"AP0.state"
 #define PN_RSP_AP0_TEMPERATURE	"AP0.temperature"
 #define PN_RSP_AP0_VERSION	"AP0.version"
@@ -90,9 +89,45 @@
 #define PN_RCU_ATTENUATION	"Attenuation"
 #define PN_RCU_NOF_OVERFLOW	"nofOverflow"
 #define PN_RCU_ADC_STATISTICS_OVERFLOW	"ADCStatistics.overflow"
-#define PN_RCU_LBL_STATE	"LBL.state"
-#define PN_RCU_LBH_STATE	"LBH.state"
-#define PN_RCU_HBA_STATE	"HBA.state"
+#define PN_RCU_TBB_ERROR	"TBB.error"
+#define PN_RCU_TBB_MODE	"TBB.mode"
+#define PN_RCU_TBB_START_ADDR	"TBB.startAddr"
+#define PN_RCU_TBB_BUF_SIZE	"TBB.bufSize"
+#define PN_RCU_TRIGGER_STARTLEVEL	"Trigger.startlevel"
+#define PN_RCU_TRIGGER_BASELEVEL	"Trigger.baselevel"
+#define PN_RCU_TRIGGER_STOPLEVEL	"Trigger.stoplevel"
+#define PN_RCU_TRIGGER_FILTER	"Trigger.filter"
+#define PN_RCU_TRIGGER_WINDOW	"Trigger.window"
+#define PN_RCU_TRIGGER_COEFF0	"Trigger.coeff0"
+#define PN_RCU_TRIGGER_COEFF1	"Trigger.coeff1"
+#define PN_RCU_TRIGGER_COEFF2	"Trigger.coeff2"
+#define PN_RCU_TRIGGER_COEFF3	"Trigger.coeff3"
+
+// TBBoard
+#define PSN_TB_BOARD	"LOFAR_PIC_@cabinet@_@subrack@_@TBBoard@"
+#define PST_TB_BOARD	"TBBoard"
+#define PN_TBB_BOARDID	"boardID"
+#define PN_TBB_RAM_SIZE	"RAMSize"
+#define PN_TBB_SW_VERSION	"SWVersion"
+#define PN_TBB_BOARD_VERSION	"boardVersion"
+#define PN_TBB_TP_VERSION	"TPVersion"
+#define PN_TBB_MP0_VERSION	"MP0Version"
+#define PN_TBB_MP1_VERSION	"MP1Version"
+#define PN_TBB_MP2_VERSION	"MP2Version"
+#define PN_TBB_MP3_VERSION	"MP3Version"
+#define PN_TBB_VOLTAGE12	"voltage12"
+#define PN_TBB_VOLTAGE25	"voltage25"
+#define PN_TBB_VOLTAGE33	"voltage33"
+#define PN_TBB_TEMPPCB	"tempPCB"
+#define PN_TBB_TEMPTP	"tempTP"
+#define PN_TBB_TEMPMP0	"tempMP0"
+#define PN_TBB_TEMPMP1	"tempMP1"
+#define PN_TBB_TEMPMP2	"tempMP2"
+#define PN_TBB_TEMPMP3	"tempMP3"
+#define PN_TBB_IMAGE_INFO_VERSION	"imageInfo.version"
+#define PN_TBB_IMAGE_INFO_WRITE_DATE	"imageInfo.writeDate"
+#define PN_TBB_IMAGE_INFO_TP_FILE	"imageInfo.TPFile"
+#define PN_TBB_IMAGE_INFO_MP_FILE	"imageInfo.MPFile"
 
 // StationClock
 #define PSN_STATION_CLOCK	"LOFAR_PIC_StationClock"
@@ -109,8 +144,22 @@
 #define PSN_STATION_CTRL	"LOFAR_PermSW_StationCtrl"
 #define PST_STATION_CTRL	"StationCtrl"
 
+// TempCtrl
+#define PSN_TEMP_CTRL	"LOFAR_PermSW_TempCtrl"
+#define PST_TEMP_CTRL	"TempCtrl"
+#define PN_TC_SETPOINT	"setpoint"
+#define PN_TC_AMBIENT_LOWEST_TEMP	"ambient.lowestTemp"
+#define PN_TC_AMBIENT_HIGHEST_TEMP	"ambient.highestTemp"
+
 // HardwareMonitor
 #define PSN_HARDWARE_MONITOR	"LOFAR_PermSW_HardwareMonitor"
 #define PST_HARDWARE_MONITOR	"HardwareMonitor"
-#define PN_HWM_RSP_CONNECTED	"RSPConnected"
+#define PN_HWM_RSP_CONNECTED	"RSP.connected"
+#define PN_HWM_RSP_CURRENT_ACTION	"RSP.currentAction"
+#define PN_HWM_RSP_ERROR	"RSP.error"
+#define PN_HWM_RSP_LOG_MSG	"RSP.logMsg"
+#define PN_HWM_TBB_CONNECTED	"TBB.connected"
+#define PN_HWM_TBB_CURRENT_ACTION	"TBB.currentAction"
+#define PN_HWM_TBB_ERROR	"TBB.error"
+#define PN_HWM_TBB_LOG_MSG	"TBB.logMsg"
 
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/TBB.dpl b/MAC/APL/StationCU/src/HardwareMonitor/TBB.dpl
new file mode 100644
index 0000000000000000000000000000000000000000..a7b080ca62a0892873fbe951c8813b39bc993eec
--- /dev/null
+++ b/MAC/APL/StationCU/src/HardwareMonitor/TBB.dpl
@@ -0,0 +1,26 @@
+// TBBoard
+#define PSN_TB_BOARD    "LOFAR_PIC_@cabinet@_@subrack@_@TBBoard@"
+#define PST_TB_BOARD    "TBBoard"
+#define PN_TBB_BOARDID  "boardID"
+#define PN_TBB_RAM_SIZE "RAMsize"
+#define PN_TBB_SW_VERSION   "SWversion"
+#define PN_TBB_BOARD_VERSION    "boardVersion"
+#define PN_TBB_TP_VERSION   "TPversion"
+#define PN_TBB_MP0VERSION   "MP0version"
+#define PN_TBB_MP1VERSION   "MP1version"
+#define PN_TBB_MP2VERSION   "MP2version"
+#define PN_TBB_MP3VERSION   "MP3version"
+#define PN_TBB_VOLTAGE12    "voltage12"
+#define PN_TBB_VOLTAGE25    "voltage25"
+#define PN_TBB_VOLTAGE33    "voltage33"
+#define PN_TBB_TEMPPCB  "tempPCB"
+#define PN_TBB_TEMPTP   "tempTP"
+#define PN_TBB_TEMPMP0  "tempMP0"
+#define PN_TBB_TEMPMP1  "tempMP1"
+#define PN_TBB_TEMPMP2  "tempMP2"
+#define PN_TBB_TEMPMP3  "tempMP3"
+#define PN_TBB_IMAGE_INFO_VERSION   "imageInfo.version"
+#define PN_TBB_IMAGE_INFO_WRITE_DATE    "imageInfo.writeDate"
+#define PN_TBB_IMAGE_INFO_TP_FILE   "imageInfo.TPfile"
+#define PN_TBB_IMAGE_INFO_MP_FILE   "imageInfo.MPfile"
+
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.cc b/MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e89ddede2bc14e8c5d2ce182ab59165d85015ab9
--- /dev/null
+++ b/MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.cc
@@ -0,0 +1,757 @@
+//#  TBBMonitor.cc: Implementation of the MAC Scheduler task
+//#
+//#  Copyright (C) 2006
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  This program is free software; you can redistribute it and/or modify
+//#  it under the terms of the GNU General Public License as published by
+//#  the Free Software Foundation; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  This program is distributed in the hope that it will be useful,
+//#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//#  GNU General Public License for more details.
+//#
+//#  You should have received a copy of the GNU General Public License
+//#  along with this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id: TBBMonitor.cc 10505 2007-09-07 17:14:57Z overeem $
+#include <lofar_config.h>
+#include <Common/LofarLogger.h>
+
+#include <GCF/GCF_PVTypes.h>
+#include <GCF/GCF_ServiceInfo.h>
+#include <APL/APLCommon/ControllerDefines.h>
+#include <APL/APLCommon/APLUtilities.h>
+#include <APL/TBB_Protocol/TBB_Protocol.ph>
+#include <GCF/RTDB/DP_Protocol.ph>
+//#include <APL/APLCommon/StationInfo.h>
+#include <signal.h>
+
+#include "TBBMonitor.h"
+#include "RCUConstants.h"
+#include "StationPermDatapointDefs.h"
+
+using namespace LOFAR::GCF::Common;
+using namespace LOFAR::GCF::TM;
+using namespace LOFAR::GCF::RTDB;
+using namespace std;
+
+namespace LOFAR {
+	using namespace APLCommon;
+	namespace StationCU {
+	
+//
+// TBBMonitor()
+//
+TBBMonitor::TBBMonitor(const string&	cntlrName) :
+	GCFTask 			((State)&TBBMonitor::initial_state,cntlrName),
+	itsOwnPropertySet	(0),
+	itsTimerPort		(0),
+	itsTBBDriver		(0),
+	itsPollInterval		(10),
+	itsNrRCUs			(0),
+	itsNrTBboards		(0)
+{
+	LOG_TRACE_OBJ_STR (cntlrName << " construction");
+
+	// need port for timers.
+	itsTimerPort = new GCFTimerPort(*this, "TimerPort");
+
+	// prepare TCP port to TBBDriver.
+	itsTBBDriver = new GCFTCPPort (*this, MAC_SVCMASK_TBBDRIVER,
+											GCFPortInterface::SAP, TBB_PROTOCOL);
+	ASSERTSTR(itsTBBDriver, "Cannot allocate TCPport to TBBDriver");
+	itsTBBDriver->setInstanceNr(0);
+
+}
+
+
+//
+// ~TBBMonitor()
+//
+TBBMonitor::~TBBMonitor()
+{
+	LOG_TRACE_OBJ_STR (getName() << " destruction");
+
+	if (itsTBBDriver) {
+		itsTBBDriver->close();
+		delete itsTBBDriver;
+	}
+
+	if (itsTimerPort) {
+		delete itsTimerPort;
+	}
+
+	// ...
+}
+
+
+//
+// initial_state(event, port)
+//
+// Setup connection with PVSS
+//
+GCFEvent::TResult TBBMonitor::initial_state(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("initial:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+    case F_INIT:
+   		break;
+
+	case F_ENTRY: {
+		// Get access to my own propertyset.
+		LOG_DEBUG_STR ("Activating PropertySet " << PSN_HARDWARE_MONITOR);
+		itsTimerPort->setTimer(2.0);
+		itsOwnPropertySet = new RTDBPropertySet(PSN_HARDWARE_MONITOR,
+												PST_HARDWARE_MONITOR,
+												PSAT_WO,
+												this);
+
+		}
+		break;
+
+	case DP_CREATED: {
+		// NOTE: this 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;
+
+	case F_TIMER: {
+		// update PVSS.
+		LOG_TRACE_FLOW ("Updateing state to PVSS");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION, GCFPVString("initial"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,  GCFPVString(""));
+		
+		LOG_DEBUG_STR("Going to connect to the TBBDriver.");
+		TRAN (TBBMonitor::connect2TBB);
+	}
+	
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("initial, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// connect2TBB(event, port)
+//
+// Setup connection with TBBdriver
+//
+GCFEvent::TResult TBBMonitor::connect2TBB(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("connect2TBB:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_ENTRY:
+		// update PVSS
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION, GCFPVString("connecting"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CONNECTED,GCFPVBool(false));
+		itsTBBDriver->open();		// will result in F_CONN or F_DISCONN
+		break;
+
+	case F_CONNECTED:
+		if (&port == itsTBBDriver) {
+			LOG_DEBUG ("Connected with TBBDriver, going to get the configuration");
+			itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,  GCFPVString(""));
+			itsOwnPropertySet->setValue(PN_HWM_TBB_CONNECTED,GCFPVBool(true));
+			TRAN(TBBMonitor::askConfiguration);		// go to next state.
+		}
+		break;
+
+	case F_DISCONNECTED:
+		port.close();
+		ASSERTSTR (&port == itsTBBDriver, 
+								"F_DISCONNECTED event from port " << port.getName());
+		LOG_DEBUG("Connection with TBBDriver failed, retry in 2 seconds");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR, GCFPVString("connection timeout"));
+		itsTimerPort->setTimer(2.0);
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("connect2TBB, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+//
+// askConfiguration(event, port)
+//
+// Take subscription on clock modifications
+//
+GCFEvent::TResult TBBMonitor::askConfiguration(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askConfiguration:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("asking configuration"));
+		TBBGetConfigEvent	getconfig;
+		itsTBBDriver->send(getconfig);
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+		break;
+
+	case TBB_GET_CONFIG_ACK: {
+		TBBGetConfigAckEvent	ack(event);
+	
+		// calc size of the propertyset vectors
+		itsBoardMask   = bitset<MAX_N_TBBBOARDS>(ack.active_boards_mask);
+		itsNrTBboards  = ack.max_boards;
+		itsNrRCUs	   = itsNrTBboards * NR_RCUS_PER_TBBOARD;
+
+		// inform user
+		LOG_DEBUG_STR("Active boards = " << itsBoardMask);
+		LOG_DEBUG(formatString("nr TBboards = %d", itsNrTBboards));
+	
+		// do some checks
+		if (itsNrTBboards != itsBoardMask.count()) {
+			LOG_WARN_STR("Only " << itsBoardMask.count() << " of " << itsNrTBboards 
+						<< " TBboards are available.");
+		}
+
+		LOG_DEBUG ("Going to allocate the property-sets");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TRAN (TBBMonitor::finish_state);
+		TRAN(TBBMonitor::createPropertySets);				// go to next state.
+		}
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askConfiguration, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// createPropertySets(event, port)
+//
+// Retrieve sampleclock from TBB driver
+//
+GCFEvent::TResult TBBMonitor::createPropertySets(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("createPropertySets:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("create PropertySets"));
+		// resize vectors.
+		itsTBBs.resize	  (itsNrTBboards, 0);
+		itsRCUs.resize	  (itsNrRCUs, 	   0);
+
+		int32	cabinet (-1);
+		int32	subrack (-1);
+		int32	RSP		(-1);
+		int32	TBB		(-1);
+		string	tbboardNameMask(createPropertySetName(PSN_TB_BOARD, getName()));
+		string	rcuNameMask    (createPropertySetName(PSN_RCU, 	  getName()));
+		for (uint32	rcu = 0; rcu < itsNrRCUs; rcu++) {
+			// new cabinet?
+			if (rcu % (NR_RCUS_PER_CABINET) == 0) {
+				cabinet++;
+			}
+
+			// new subrack?
+			if (rcu % (NR_RCUS_PER_SUBRACK) == 0) {
+				subrack++;
+			}
+
+			// new TBboard?
+			if (rcu % (NR_RCUS_PER_TBBOARD) == 0) {
+				TBB++;
+				string	PSname(formatString(tbboardNameMask.c_str(), cabinet, subrack, TBB));
+				itsTBBs[TBB] = new RTDBPropertySet(PSname, PST_TB_BOARD, PSAT_WO, this);
+			}
+
+			// new RSPboard?
+			if (rcu % (NR_RCUS_PER_RSPBOARD) == 0) {
+				RSP++;
+			}
+
+			// allocate RCU PS
+			string	PSname(formatString(rcuNameMask.c_str(), cabinet, subrack, RSP, rcu));
+			itsRCUs[rcu] = new RTDBPropertySet(PSname, PST_RCU, PSAT_WO, this);
+		}
+		itsTimerPort->setTimer(5.0);	// give database some time to finish the job
+	}
+	break;
+
+	case F_TIMER: {
+		// database should be ready by now, check if allocation was succesfull
+		for (uint32	tbb = 0; tbb < itsNrTBboards; tbb++) {
+			ASSERTSTR(itsTBBs[tbb], "Allocation of PS for tbb " << tbb << " failed.");
+		}
+		for (uint32	rcu = 0; rcu < itsNrRCUs; rcu++) {
+			ASSERTSTR(itsRCUs[rcu], "Allocation of PS for rcu " << rcu << " failed.");
+		}
+		LOG_DEBUG_STR("Allocation of all propertySets successfull, going to operational mode");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TRAN(TBBMonitor::askVersion);
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+	break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("createPropertySets, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// askVersion(event, port)
+//
+// Set sampleclock from TBB driver
+//
+GCFEvent::TResult TBBMonitor::askVersion(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askVersion:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("getting version info"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TBBVersionEvent	getVersion;
+		getVersion.boardmask = itsBoardMask.to_uint32();
+		itsTBBDriver->send(getVersion);
+	}
+	break;
+
+	case TBB_VERSION_ACK: {
+		TBBVersionAckEvent		ack(event);
+		// move the information to the database.
+		string		versionStr;
+		string		DPEname;
+		for (uint32	tbb = 0; tbb < itsNrTBboards; tbb++) {
+			if (ack.status_mask[tbb] & TBB_SUCCESS) {
+				// TBB board version
+				versionStr = formatString("%d.%d", ack.swversion[tbb] / 10, ack.swversion[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_SW_VERSION, GCFPVString(versionStr));
+				versionStr = formatString("%d.%d", ack.boardversion[tbb] / 10, ack.boardversion[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_BOARD_VERSION, GCFPVString(versionStr));
+				itsTBBs[tbb]->setValue(PN_TBB_BOARDID, GCFPVUnsigned(ack.boardid[tbb]));
+			
+				// BP version
+				versionStr = formatString("%d.%d", ack.tpversion[tbb] / 10, ack.tpversion[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_TP_VERSION, GCFPVString(versionStr));
+			
+				// MPx versions
+				versionStr = formatString("%d.%d", ack.mp0version[tbb] / 10, ack.mp0version[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_MP0_VERSION, GCFPVString(versionStr));
+				versionStr = formatString("%d.%d", ack.mp1version[tbb] / 10, ack.mp1version[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_MP1_VERSION, GCFPVString(versionStr));
+				versionStr = formatString("%d.%d", ack.mp2version[tbb] / 10, ack.mp2version[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_MP2_VERSION, GCFPVString(versionStr));
+				versionStr = formatString("%d.%d", ack.mp3version[tbb] / 10, ack.mp3version[tbb] % 10);
+				itsTBBs[tbb]->setValue(PN_TBB_MP3_VERSION, GCFPVString(versionStr));
+			}
+			else {	// board in error set ?.?
+				itsTBBs[tbb]->setValue(PN_TBB_BOARDID,		 GCFPVUnsigned(0));
+				itsTBBs[tbb]->setValue(PN_TBB_BOARD_VERSION, GCFPVString("?.?"));
+				itsTBBs[tbb]->setValue(PN_TBB_TP_VERSION,	 GCFPVString("?.?"));
+				itsTBBs[tbb]->setValue(PN_TBB_MP0_VERSION,	 GCFPVString("?.?"));
+				itsTBBs[tbb]->setValue(PN_TBB_MP1_VERSION,	 GCFPVString("?.?"));
+				itsTBBs[tbb]->setValue(PN_TBB_MP2_VERSION,	 GCFPVString("?.?"));
+				itsTBBs[tbb]->setValue(PN_TBB_MP3_VERSION,	 GCFPVString("?.?"));
+			}
+		}
+
+		LOG_DEBUG_STR ("Version information updated, going to status information");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TRAN(TBBMonitor::askSizeInfo);				// go to next state.
+		break;
+	}
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askVersion, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+//
+// askSizeInfo(event, port)
+//
+// Set sampleclock from TBB driver
+//
+GCFEvent::TResult TBBMonitor::askSizeInfo(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askSizeInfo:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("getting version info"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TBBSizeEvent	getSize;
+		getSize.boardmask = itsBoardMask.to_uint32();
+		itsTBBDriver->send(getSize);
+	}
+	break;
+
+	case TBB_SIZE_ACK: {
+		TBBSizeAckEvent		ack(event);
+		// move the information to the database.
+		for (uint32	tbb = 0; tbb < itsNrTBboards; tbb++) {
+			if (ack.status_mask[tbb] & TBB_SUCCESS) {
+				itsTBBs[tbb]->setValue(PN_TBB_RAM_SIZE, GCFPVString(byteSize(ack.npages[tbb]*2048)));
+			}
+			else {	// board in error set ?.?
+				itsTBBs[tbb]->setValue(PN_TBB_RAM_SIZE, GCFPVString(""));
+			}
+		}
+
+		LOG_DEBUG_STR ("Size information updated, going to status information");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TRAN(TBBMonitor::askTBBinfo);				// go to next state.
+		break;
+	}
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askSizeInfo, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// askTBBinfo(event, port)
+//
+// Ask info about the TBB boards
+//
+GCFEvent::TResult TBBMonitor::askTBBinfo(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("askTBBinfo:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("updating TBB info"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TBBStatusEvent	getStatus;
+		getStatus.boardmask = itsBoardMask.to_uint32();
+		itsTBBDriver->send(getStatus);
+	}
+	break;
+
+	case TBB_STATUS_ACK: {
+		TBBStatusAckEvent		ack(event);
+		// move the information to the database.
+		string		versionStr;
+		string		DPEname;
+		for (uint32	tbb = 0; tbb < itsNrTBboards; tbb++) {
+			if (ack.status_mask[tbb] & TBB_SUCCESS) {
+				// board voltages
+				itsTBBs[tbb]->setValue(PN_TBB_VOLTAGE12, GCFPVDouble(double(ack.V12[tbb])*(2.5/192.0)));
+				itsTBBs[tbb]->setValue(PN_TBB_VOLTAGE25, GCFPVDouble(double(ack.V25[tbb])*(3.3/192.0)));
+				itsTBBs[tbb]->setValue(PN_TBB_VOLTAGE33, GCFPVDouble(double(ack.V33[tbb])*(5.0/192.0)));
+				// all temperatures
+				itsTBBs[tbb]->setValue(PN_TBB_TEMPPCB, GCFPVDouble(double(ack.Tpcb[tbb])));
+				itsTBBs[tbb]->setValue(PN_TBB_TEMPTP,  GCFPVDouble(double(ack.Ttp [tbb])));
+				itsTBBs[tbb]->setValue(PN_TBB_TEMPMP0, GCFPVDouble(double(ack.Tmp0[tbb])));
+				itsTBBs[tbb]->setValue(PN_TBB_TEMPMP1, GCFPVDouble(double(ack.Tmp1[tbb])));
+				itsTBBs[tbb]->setValue(PN_TBB_TEMPMP2, GCFPVDouble(double(ack.Tmp2[tbb])));
+				itsTBBs[tbb]->setValue(PN_TBB_TEMPMP3, GCFPVDouble(double(ack.Tmp3[tbb])));
+			}
+		} // for all boards
+
+		LOG_DEBUG_STR ("TBboard information updated, going to RCU information");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TRAN(TBBMonitor::askRCUinfo);				// go to next state.
+		break;
+	}
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("askTBBinfo, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// askRCUinfo(event, port)
+//
+// Normal operation state. 
+//
+GCFEvent::TResult TBBMonitor::askRCUinfo(GCFEvent& event, GCFPortInterface& port)
+{
+	if (eventName(event) != "DP_SET") {
+		LOG_DEBUG_STR ("askRCUinfo:" << eventName(event) << "@" << port.getName());
+	}
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+
+	switch (event.signal) {
+	case F_INIT:
+		break;
+
+	case F_ENTRY: {
+		// update PVSS
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("updating TBB info"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TBBRcuInfoEvent	getStatus;
+		itsTBBDriver->send(getStatus);
+		break;
+	}
+
+	case TBB_RCU_INFO_ACK: {
+		TBBRcuInfoAckEvent	ack(event);
+
+		// move the information to the database.
+		for (uint32	rcu = 0; rcu < itsNrRCUs; rcu++) {
+			LOG_DEBUG_STR("Updating rcu " << rcu);
+			if (ack.rcu_status[rcu] & TBB_SUCCESS) {
+				// update all RCU variables
+				itsRCUs[rcu]->setValue(PN_RCU_TBB_ERROR, 	  GCFPVBool(ack.rcu_status[rcu])),
+				itsRCUs[rcu]->setValue(PN_RCU_TBB_MODE, 	  GCFPVString(TBBRCUstate(ack.rcu_state[rcu])));
+				itsRCUs[rcu]->setValue(PN_RCU_TBB_START_ADDR, GCFPVString(formatString("0x%08d",ack.rcu_start_addr[rcu])));
+				itsRCUs[rcu]->setValue(PN_RCU_TBB_BUF_SIZE,   GCFPVString(byteSize(ack.rcu_pages[rcu]*2048)));
+			}
+		} // for all boards
+
+		LOG_DEBUG ("Updated all RCU information, waiting for next cycle");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		TRAN(TBBMonitor::waitForNextCycle);			// go to next state.
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+		break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG("askRCUinfo, DEFAULT");
+		break;
+	}
+
+	return (status);
+}
+
+//
+// waitForNextCycle(event, port)
+//
+// Take subscription on clock modifications
+//
+GCFEvent::TResult TBBMonitor::waitForNextCycle(GCFEvent& event, 
+													GCFPortInterface& port)
+{
+	if (eventName(event) != "DP_SET") {
+		LOG_DEBUG_STR ("waitForNextCycle:" << eventName(event) << "@" << port.getName());	}
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+  
+	switch (event.signal) {
+	case F_ENTRY: {
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("wait for next cycle"));
+		int		waitTime = itsPollInterval - (time(0) % itsPollInterval);
+		if (waitTime == 0) {
+			waitTime = itsPollInterval;
+		}
+		itsTimerPort->cancelAllTimers();
+		itsTimerPort->setTimer(double(waitTime));
+		LOG_DEBUG_STR("Waiting " << waitTime << " seconds for next cycle");
+	}
+	break;
+
+	case F_DISCONNECTED:
+		_disconnectedHandler(port);		// might result in transition to connect2TBB
+	break;
+
+	case F_TIMER: {
+		TRAN(TBBMonitor::askTBBinfo);
+	}
+	break;
+
+	case DP_SET:
+		break;
+
+	case F_QUIT:
+		TRAN (TBBMonitor::finish_state);
+		break;
+
+	default:
+		LOG_DEBUG_STR ("waitForNextCycle, DEFAULT");
+		break;
+	}    
+
+	return (status);
+}
+
+
+//
+// _disconnectedHandler(port)
+//
+void TBBMonitor::_disconnectedHandler(GCFPortInterface& port)
+{
+	port.close();
+	if (&port == itsTBBDriver) {
+		LOG_DEBUG("Connection with TBBDriver failed, going to reconnect state");
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString("connection lost"));
+		TRAN (TBBMonitor::connect2TBB);
+	}
+}
+
+//
+// finish_state(event, port)
+//
+// Write controller state to PVSS
+//
+GCFEvent::TResult TBBMonitor::finish_state(GCFEvent& event, GCFPortInterface& port)
+{
+	LOG_DEBUG_STR ("finish_state:" << eventName(event) << "@" << port.getName());
+
+	GCFEvent::TResult status = GCFEvent::HANDLED;
+
+	switch (event.signal) {
+	case F_INIT:
+		break;
+
+	case F_ENTRY: {
+		// update PVSS
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CURRENT_ACTION,GCFPVString("finished"));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_CONNECTED,GCFPVBool(false));
+		itsOwnPropertySet->setValue(PN_HWM_TBB_ERROR,GCFPVString(""));
+		break;
+	}
+  
+	case DP_SET:
+		break;
+
+	default:
+		LOG_DEBUG("finishing_state, DEFAULT");
+		status = GCFEvent::NOT_HANDLED;
+		break;
+	}    
+	return (status);
+}
+
+//
+// TBBRCUstate(char)
+//
+string	TBBMonitor::TBBRCUstate(char	stateCode) 
+{
+	switch (stateCode) {
+	case 'A':	return ("Allocated");
+	case 'E':	return ("Error");
+	case 'F':	return ("Free");
+	case 'R':	return ("Recording");
+	case 'S':	return ("Stopped");
+	default:	return ("Unknown");
+	}
+}
+
+}; // StationCU
+}; // LOFAR
diff --git a/MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.h b/MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..807affbb82d5a583368020e3aeb28758c8387dad
--- /dev/null
+++ b/MAC/APL/StationCU/src/HardwareMonitor/TBBMonitor.h
@@ -0,0 +1,100 @@
+//#  TBBMonitor.h: Monitors the TBB hardware.
+//#
+//#  Copyright (C) 2006
+//#  ASTRON (Netherlands Foundation for Research in Astronomy)
+//#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
+//#
+//#  This program is free software; you can redistribute it and/or modify
+//#  it under the terms of the GNU General Public License as published by
+//#  the Free Software Foundation; either version 2 of the License, or
+//#  (at your option) any later version.
+//#
+//#  This program is distributed in the hope that it will be useful,
+//#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//#  GNU General Public License for more details.
+//#
+//#  You should have received a copy of the GNU General Public License
+//#  along with this program; if not, write to the Free Software
+//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//#
+//#  $Id: TBBMonitor.h 10461 2007-08-23 22:44:03Z overeem $
+
+#ifndef STATIONCU_TBB_MONITOR_H
+#define STATIONCU_TBB_MONITOR_H
+
+//# Common Includes
+#include <Common/lofar_string.h>
+#include <Common/lofar_vector.h>
+#include <Common/lofar_bitset.h>
+
+//# GCF Includes
+#include <GCF/RTDB/RTDB_PropertySet.h>
+#include <GCF/TM/GCF_TCPPort.h>
+#include <GCF/TM/GCF_TimerPort.h>
+#include <GCF/TM/GCF_Task.h>
+#include <GCF/TM/GCF_Event.h>
+#include <APL/TBB_Protocol/TBB_Protocol.ph>
+
+// forward declaration
+
+namespace LOFAR {
+	namespace StationCU {
+
+using	GCF::TM::GCFTimerPort;
+using	GCF::TM::GCFTCPPort;
+using	GCF::TM::GCFEvent;
+using	GCF::TM::GCFPortInterface;
+using	GCF::TM::GCFTask;
+using	GCF::RTDB::RTDBPropertySet;
+
+
+class TBBMonitor : public GCFTask
+{
+public:
+	explicit TBBMonitor(const string& cntlrName);
+	~TBBMonitor();
+
+private:
+	// During the initial state all connections with the other programs are made.
+   	GCFEvent::TResult initial_state   		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult connect2TBB   		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askConfiguration 		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult createPropertySets	 (GCFEvent& e, GCFPortInterface& p);
+
+   	GCFEvent::TResult askVersion    		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askSizeInfo	  		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askTBBinfo	  		 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult askRCUinfo			 (GCFEvent& e, GCFPortInterface& p);
+   	GCFEvent::TResult waitForNextCycle		 (GCFEvent& e, GCFPortInterface& p);
+
+   	GCFEvent::TResult finish_state  		 (GCFEvent& e, GCFPortInterface& p);
+
+	// avoid defaultconstruction and copying
+	TBBMonitor();
+	TBBMonitor(const TBBMonitor&);
+   	TBBMonitor& operator=(const TBBMonitor&);
+
+   	void _disconnectedHandler(GCFPortInterface& port);
+	string	TBBRCUstate(char	stateCode) ;
+
+	// Data members
+	RTDBPropertySet*			itsOwnPropertySet;
+
+	GCFTimerPort*				itsTimerPort;
+
+	GCFTCPPort*					itsTBBDriver;
+
+	uint32						itsPollInterval;
+
+	uint32						itsNrRCUs;
+	uint32						itsNrTBboards;
+	bitset<MAX_N_TBBBOARDS>		itsBoardMask;
+
+	vector<RTDBPropertySet*>	itsTBBs;
+	vector<RTDBPropertySet*>	itsRCUs;
+};
+
+  };//StationCU
+};//LOFAR
+#endif