mcbts: Add multi-ARFCN radio support

Add new radio interface "radioInterfaceMulti" for multi-carrier
support.

Only USRP B200/B210 devices are supported because of sample
rate requirements (3.2 Msps).

Only 4 SPS operation Tx/RX is supported.

8-PSK is supported.

Other options may be added at a later time

Signed-off-by: Tom Tsou <tom.tsou@ettus.com>
diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp
index 5ffaa62..af9fc98 100644
--- a/Transceiver52M/UHDDevice.cpp
+++ b/Transceiver52M/UHDDevice.cpp
@@ -35,6 +35,7 @@
 #endif
 
 #define B2XX_CLK_RT      26e6
+#define B2XX_MCBTS_CLK_RT   3.2e6
 #define E1XX_CLK_RT      52e6
 #define B100_BASE_RT     400000
 #define USRP2_BASE_RT    390625
@@ -61,6 +62,7 @@
 	B100,
 	B200,
 	B210,
+	B2XX_MCBTS,
 	E1XX,
 	E3XX,
 	X3XX,
@@ -110,6 +112,7 @@
 	{ B200,  4, 1, B2XX_TIMING_4SPS, "B200 4/1 Tx/Rx SPS" },
 	{ B210,  1, 1, B2XX_TIMING_1SPS, "B210 1 SPS" },
 	{ B210,  4, 1, B2XX_TIMING_4SPS, "B210 4/1 Tx/Rx SPS" },
+	{ B2XX_MCBTS, 4, 4, 1.07188e-4, "B200/B210 4 SPS Multi-ARFCN" },
 	{ E1XX,  1, 1, 9.5192e-5, "E1XX 1 SPS" },
 	{ E1XX,  4, 1, 6.5571e-5, "E1XX 4/1 Tx/Rx SPS" },
 	{ E3XX,  1, 1, 1.84616e-4, "E3XX 1 SPS" },
@@ -150,9 +153,20 @@
 		return -9999.99;
 	}
 
+
 	if ((sps != 4) && (sps != 1))
 		return -9999.99;
 
+	if (iface == RadioDevice::MULTI_ARFCN) {
+		switch (type) {
+		case B2XX_MCBTS:
+			return  4 * MCBTS_SPACING;
+		default:
+			LOG(ALERT) << "Invalid device combination";
+			return -9999.99;
+		}
+	}
+
 	switch (type) {
 	case USRP2:
 	case X3XX:
@@ -542,12 +556,15 @@
 	if ((dev_type == B200) || (dev_type == B210) || (dev_type == E3XX)) {
 		if (set_master_clk(B2XX_CLK_RT) < 0)
 			return -1;
-	}
-	else if (dev_type == E1XX) {
+	} else if (dev_type == E1XX) {
 		if (set_master_clk(E1XX_CLK_RT) < 0)
 			return -1;
+	} else if (dev_type == B2XX_MCBTS) {
+		if (set_master_clk(B2XX_MCBTS_CLK_RT) < 0)
+			return -1;
 	}
 
+
 	// Set sample rates
 	try {
 		usrp_dev->set_tx_rate(tx_rate);
@@ -574,6 +591,9 @@
 
 double uhd_device::setTxGain(double db, size_t chan)
 {
+	if (iface == MULTI_ARFCN)
+		chan = 0;
+
 	if (chan >= tx_gains.size()) {
 		LOG(ALERT) << "Requested non-existent channel" << chan;
 		return 0.0f;
@@ -620,6 +640,9 @@
 
 double uhd_device::getRxGain(size_t chan)
 {
+	if (iface == MULTI_ARFCN)
+		chan = 0;
+
 	if (chan >= rx_gains.size()) {
 		LOG(ALERT) << "Requested non-existent channel " << chan;
 		return 0.0f;
@@ -762,11 +785,24 @@
 	}
 
 	// Verify and set channels
-	if ((dev_type == B210) && (chans == 2)) {
-	} else if ((dev_type == UMTRX) && (chans == 2)) {
-		uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
-		usrp_dev->set_tx_subdev_spec(subdev_spec);
-		usrp_dev->set_rx_subdev_spec(subdev_spec);
+	if (iface == MULTI_ARFCN) {
+		if ((dev_type != B200) && (dev_type != B210)) {
+			LOG(ALERT) << "Unsupported device configuration";
+			return -1;
+		}
+
+		dev_type = B2XX_MCBTS;
+		chans = 1;
+	} else if (chans == 2) {
+		if (dev_type == B210) {
+		} else if (dev_type == UMTRX) {
+			uhd::usrp::subdev_spec_t subdev_spec(swap_channels?"B:0 A:0":"A:0 B:0");
+			usrp_dev->set_tx_subdev_spec(subdev_spec);
+			usrp_dev->set_rx_subdev_spec(subdev_spec);
+		} else {
+			LOG(ALERT) << "Invalid device configuration";
+			return -1;
+		}
 	} else if (chans != 1) {
 		LOG(ALERT) << "Invalid channel combination for device";
 		return -1;
@@ -839,6 +875,8 @@
 
 	if (iface == DIVERSITY)
 		return DIVERSITY;
+	if (iface == MULTI_ARFCN)
+		return MULTI_ARFCN;
 
 	switch (dev_type) {
 	case B100:
@@ -1295,7 +1333,7 @@
  */
 TIMESTAMP uhd_device::initialWriteTimestamp()
 {
-	if (rx_sps == tx_sps)
+	if ((iface == MULTI_ARFCN) || (rx_sps == tx_sps))
 		return ts_initial;
 	else
 		return ts_initial * tx_sps;