From b9c4a043dcbaf9dd51730438afad99b5154df04a Mon Sep 17 00:00:00 2001
From: Auke Klazema <klazema@astron.nl>
Date: Thu, 24 Jan 2019 09:24:59 +0000
Subject: [PATCH] task SW-575: Added processing of multiple complex weights

---
 MAC/APL/PIC/RSP_Driver/src/rspctl.cc   | 64 +++++++++++++++++++++-----
 MAC/APL/PIC/RSP_Driver/src/rspctl.h    | 34 ++++++++++----
 MAC/APL/PIC/RSP_Driver/test/tRSPCtl.cc | 27 +++++++++++
 3 files changed, 105 insertions(+), 20 deletions(-)

diff --git a/MAC/APL/PIC/RSP_Driver/src/rspctl.cc b/MAC/APL/PIC/RSP_Driver/src/rspctl.cc
index 0c3f5a4a257..322726b62d1 100644
--- a/MAC/APL/PIC/RSP_Driver/src/rspctl.cc
+++ b/MAC/APL/PIC/RSP_Driver/src/rspctl.cc
@@ -213,19 +213,28 @@ void WeightsCommand::send()
 		boost::dynamic_bitset<> beamlet_mask = getBEAMLETSMask(itsBitsPerSample);
 
 		// -1 < m_value <= 1
-		complex<double> value = m_value;
-		value *= (1<<14); // -.99999 should become -16383 and 1 should become 16384
 		setweights.weights() = itsWeights;
 		int rcunr = 0;
 		int max_beamlets = maxBeamlets(itsBitsPerSample);
+        bool multiple_values = (m_values.size() > 1);
 		for (int rcu = 0; rcu < MAX_RCUS; rcu++) {
 			if (setweights.rcumask.test(rcu)) {
+                std::list<complex<double>>::iterator itr = m_values.begin();
 				for (int beamlet = 0; beamlet < max_beamlets; beamlet++) {
 					if (beamlet_mask.test(beamlet)) {
+                        complex<double> value = *itr;
+                        value *= (1<<14); // -.99999 should become -16383 and 1 should become 16384
 					    int plane = beamlet / maxBeamletsPerBank(itsBitsPerSample);
 						int beamletnr = beamlet % maxBeamletsPerBank(itsBitsPerSample);
 						setweights.weights()(0,rcunr,plane,beamletnr) = complex<int16>((int16)value.real(), (int16)value.imag());
 						//setweights.weights()(0,rcunr,plane,beamletnr) = complex<int16>(10+plane, beamletnr); // for testing
+                        if(multiple_values) { // advance value if we have multiple values otherwise use the single value for all beamlets
+                            itr++;
+                            if(itr == m_values.end()) {
+                                logMessage(cerr,formatString("Error: not enough complex numbers for the amount of beamlets"));
+                                rspctl_exit_code = EXIT_FAILURE;
+                            }
+                        }
 					}
 				} // beamlet
 				rcunr++;
@@ -3301,6 +3310,22 @@ GCFEvent::TResult LatencyCommand::ack(GCFEvent& e)
 	return GCFEvent::HANDLED;
 }
 
+TestableRSPCtl::TestableRSPCtl(string name, int argc, char** argv) :
+    RSPCtl(name, argc, argv),
+	m_argc           (argc),
+	m_argv           (argv)
+{
+}
+
+TestableRSPCtl::~TestableRSPCtl()
+{
+}
+
+Command* TestableRSPCtl::getCommand()
+{
+    return parse_options(m_argc, m_argv);
+}
+
 //
 // RSPCtl()
 //
@@ -4058,15 +4083,28 @@ Command* RSPCtl::parse_options(int argc, char** argv)
 
 			if (optarg) {
 				weightscommand->setMode(false);
-				double re = 0.0, im = 0.0;
-				int numitems = sscanf(optarg, "%lf,%lf", &re, &im);
-				if (numitems == 0 || numitems == EOF) {
-					logMessage(cerr,"Error: invalid weights value. Should be of the format "
-					"'--weights=value.re[,value.im]' where value is a floating point value in the range (-1,1].");
-	   				rspctl_exit_code = EXIT_FAILURE;
-					exit(EXIT_FAILURE);
-				}
-				weightscommand->setValue(complex<double>(re,im));
+                std::list<std::complex<double>> weights;
+
+                if(optarg[0] == '(') {
+                     weights = utility::strtocomplexlist(optarg);
+                     if (weights.empty()) {
+                         logMessage(cerr,"Error: invalid or missing '--weights' option");
+                         rspctl_exit_code = EXIT_FAILURE;
+                         exit(EXIT_FAILURE);
+                     }
+                }
+                else {
+                    double re = 0.0, im = 0.0;
+                    int numitems = sscanf(optarg, "%lf,%lf", &re, &im);
+                    if (numitems == 0 || numitems == EOF) {
+                        logMessage(cerr,"Error: invalid weights value. Should be of the format "
+                                   "'--weights=value.re[,value.im]' where value is a floating point value in the range (-1,1].");
+                        rspctl_exit_code = EXIT_FAILURE;
+                        exit(EXIT_FAILURE);
+                    }
+                    weights.push_back(complex<double>(re,im));
+                }
+				weightscommand->setValues(weights);
 			}
 		}
 		break;
@@ -4099,7 +4137,9 @@ Command* RSPCtl::parse_options(int argc, char** argv)
 				}
 
 				//weightscommand->setValue(complex<double>(amplitude * ::cos(angle), amplitude * ::sin(angle)));
-				weightscommand->setValue(amplitude * exp(complex<double>(0,angle / 180.0 * M_PI)));
+                std::list<std::complex<double>> weights;
+                weights.push_back(amplitude * exp(complex<double>(0,angle / 180.0 * M_PI)));
+				weightscommand->setValues(weights);
 			}
 		}
 		break;
diff --git a/MAC/APL/PIC/RSP_Driver/src/rspctl.h b/MAC/APL/PIC/RSP_Driver/src/rspctl.h
index e876edd886f..55d99b66f3a 100644
--- a/MAC/APL/PIC/RSP_Driver/src/rspctl.h
+++ b/MAC/APL/PIC/RSP_Driver/src/rspctl.h
@@ -215,12 +215,15 @@ public:
 	virtual ~WeightsCommand() {}
 	virtual void send();
 	virtual GCFEvent::TResult ack(GCFEvent& e);
-	void setValue(std::complex<double> value) {
-		m_value = value;
+    void setValues(std::list<std::complex<double>> values) {
+		m_values = values;
 	}
 	void setType(int type) { m_type = type; }
+    std::list<std::complex<double>> getValues() {
+      return m_values;
+    }
 private:
-	std::complex<double>                    m_value;
+    std::list<std::complex<double>>         m_values;
 	int                                     m_type;
 	int                                     itsStage;
 	blitz::Array<std::complex<int16>, 4>    itsWeights;
@@ -850,18 +853,17 @@ public:
 
 	// Start the controller main loop.
 	void mainloop();
-
+protected:
+	// the command to execute
+	Command*        itsCommand;
+	Command* parse_options(int argc, char** argv);
 private:
 	// private methods
-	Command* parse_options(int argc, char** argv);
 	void logMessage(ostream& stream, const string& message);
 
 	// ports
 	GCFTCPPort*     itsRSPDriver;
 
-	// the command to execute
-	Command*        itsCommand;
-
 	// dimensions of the connected hardware
 	int             m_nrcus;
 	int             m_nrspboards;
@@ -884,6 +886,22 @@ private:
 	SubClockCommand m_subclock; // always subscribe to clock updates
 };
 
+class TestableRSPCtl : public RSPCtl
+{
+public:
+	// The constructor of the RSPCtl task.
+	// @param name The name of the task. The name is used for looking
+	// up connection establishment information using the GTMNameService and
+	// GTMTopologyService classes.
+	TestableRSPCtl(string name, int argc, char** argv);
+	virtual ~TestableRSPCtl();
+    Command* getCommand();
+private:
+  	// commandline parameters
+	int             m_argc;
+	char**          m_argv;
+};
+
   }; // namespace rspctl
 }; // namespace LOFAR
 
diff --git a/MAC/APL/PIC/RSP_Driver/test/tRSPCtl.cc b/MAC/APL/PIC/RSP_Driver/test/tRSPCtl.cc
index b8d2dbe144e..ae99cf37a36 100644
--- a/MAC/APL/PIC/RSP_Driver/test/tRSPCtl.cc
+++ b/MAC/APL/PIC/RSP_Driver/test/tRSPCtl.cc
@@ -5,6 +5,7 @@
 #include "rspctl.h"
 
 using namespace LOFAR::TYPES;
+using namespace LOFAR::rspctl;
 using namespace LOFAR::rspctl::utility;
 
 TEST(returns_empty_complex_list_with_empty_string)
@@ -43,6 +44,32 @@ TEST(strtocomplexlist_contains_correct_complex_number_when_string_has_a_pair_wit
   CHECK_EQUAL(0, first_value.imag());
 }
 
+TEST(rspctl_should_create_the_weightscommand_when_weights_option_is_given)
+{
+  char* argv[2];
+  argv[0] =  const_cast<char*>("rspctl");
+  argv[1] =  const_cast<char*>("--weights=(1,1)");
+  TestableRSPCtl rspctl("RSPCtl", 2, argv);
+
+  Command* command = rspctl.getCommand();
+  CHECK_EQUAL(true, (dynamic_cast<WeightsCommand*>(command) != NULL));
+}
+
+TEST(rspctl_should_set_weights_correctly_on_command)
+{
+  char* argv[2];
+  argv[0] = const_cast<char*>("rspctl");
+  argv[1] = const_cast<char*>("--weights=(0.2,0.1)");
+  TestableRSPCtl rspctl("RSPCtl", 2, argv);
+
+  Command* command = rspctl.getCommand();
+  WeightsCommand* weights_command = dynamic_cast<WeightsCommand*>(command);
+  std::list<std::complex<double>> values = weights_command->getValues();
+
+  CHECK_EQUAL(0.2, values.front().real());
+  CHECK_EQUAL(0.1, values.front().imag());
+}
+
 int main(int, const char *[])
 {
    return UnitTest::RunAllTests();
-- 
GitLab