ipaccess-config / network listen: ordered list of RxLevels

Use libosmocore 'rxlev_stat' module to generate an ordered list
of ARFCN's, sorted by RxLev while performing test nr. 64
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index 13c0746..7672bb1 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -106,8 +106,7 @@
 
 int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
 			 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
-			 u_int8_t test_nr, u_int8_t auton_report,
-			 const u_int8_t *phys_config, u_int16_t phys_config_len);
+			 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg);
 
 int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan);
 
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 5ec4441..09e0a21 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -45,11 +45,13 @@
 #include <openbsc/abis_rsl.h>
 #include <openbsc/system_information.h>
 #include <openbsc/mncc.h>
+
 #include <osmocore/tlv.h>
 #include <osmocore/bitvec.h>
 #include <osmocore/statistics.h>
 #include <osmocore/gsm_utils.h>
 #include <osmocore/utils.h>
+#include <osmocore/rxlev_stat.h>
 
 #define TRX_NR_TS	8
 #define TS_MAX_LCHAN	8
@@ -381,6 +383,7 @@
 		} bs11;
 		struct {
 			unsigned int test_state;
+			struct rxlev_stats rxlev_stat;
 		} ipaccess;
 	};
 	struct gsm_bts_trx_ts ts[TRX_NR_TS];
diff --git a/openbsc/include/openbsc/network_listen.h b/openbsc/include/openbsc/network_listen.h
index afd0049..8ca5cd8 100644
--- a/openbsc/include/openbsc/network_listen.h
+++ b/openbsc/include/openbsc/network_listen.h
@@ -7,6 +7,7 @@
 void ipac_nwl_init(void);
 
 /* Start a NWL test.  It will raise the S_IPAC_TEST_COMPLETE signal. */
-int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr);
+int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr,
+			const uint8_t *phys_conf, unsigned int phys_conf_len);
 
 #endif /* _OPENBSC_NWL_H */
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index f7fac63..58f47d2 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -2120,26 +2120,20 @@
 /* Chapter 8.7.1 */
 int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
 			 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
-			 u_int8_t test_nr, u_int8_t auton_report,
-			 const u_int8_t *phys_config, u_int16_t phys_config_len)
+			 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
 {
 	struct abis_om_hdr *oh;
-	struct msgb *msg = nm_msgb_alloc();
-	int len = 4; /* 2 TV attributes */
 
 	DEBUGP(DNM, "PEFORM TEST\n");
-	
-	if (phys_config_len)
-		len += 3 + phys_config_len;
-	
-	oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
-	fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
+
+	if (!msg)
+		msg = nm_msgb_alloc();
+
+	msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
+	msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
+	oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
+	fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
 			obj_class, bts_nr, trx_nr, ts_nr);
-	msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
-	msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
-	if (phys_config_len)
-		msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
-				phys_config);
 
 	return abis_nm_sendmsg(bts, msg);
 }
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index 72bccf9..9b3cb8d 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -116,6 +116,8 @@
 	return 0;
 }
 
+const uint8_t phys_conf[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
+
 static int nwl_sig_cb(unsigned int subsys, unsigned int signal,
 		      void *handler_data, void *signal_data)
 {
@@ -124,7 +126,11 @@
 	switch (signal) {
 	case S_IPAC_NWL_COMPLETE:
 		trx = signal_data;
-		ipac_nwl_test_start(trx, net_listen_testnr);
+		DEBUGP(DNM, "received S_IPAC_NWL_COMPLETE signal\n");
+		rxlev_stat_dump(&trx->ipaccess.rxlev_stat);
+		DEBUGP(DNM, "starting next test\n");
+		ipac_nwl_test_start(trx, net_listen_testnr, phys_conf,
+				    sizeof(phys_conf));
 		break;
 	}
 	return 0;
@@ -441,7 +447,8 @@
 		struct gsm_bts_trx *trx = obj;
 
 		if (net_listen_testnr)
-			ipac_nwl_test_start(trx, net_listen_testnr);
+			ipac_nwl_test_start(trx, net_listen_testnr, phys_conf,
+					    sizeof(phys_conf));
 		else if (software) {
 			int rc;
 			printf("Attempting software upload with '%s'\n", software);
diff --git a/openbsc/src/ipaccess/network_listen.c b/openbsc/src/ipaccess/network_listen.c
index f64f44e..87bf588 100644
--- a/openbsc/src/ipaccess/network_listen.c
+++ b/openbsc/src/ipaccess/network_listen.c
@@ -27,14 +27,36 @@
 #include <errno.h>
 #include <stdint.h>
 
+#include <arpa/inet.h>
+
 #include <osmocore/talloc.h>
 #include <osmocore/timer.h>
+#include <osmocore/rxlev_stat.h>
 
 #include <openbsc/gsm_data.h>
 #include <openbsc/abis_nm.h>
 #include <openbsc/signal.h>
 #include <openbsc/debug.h>
 
+#define WHITELIST_MAX_SIZE ((NUM_ARFCNS*2)+2+1)
+
+int ipac_rxlevstat2whitelist(uint16_t *buf, const struct rxlev_stats *st)
+{
+	int i;
+	unsigned int num_arfcn = 0;
+
+	for (i = NUM_RXLEVS-1; i >= 0; i--) {
+		int16_t arfcn = -1;
+
+		while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) {
+			*buf++ = htons(arfcn);
+			num_arfcn++;
+		}
+	}
+
+	return num_arfcn;
+}
+
 enum ipac_test_state {
 	IPAC_TEST_S_IDLE,
 	IPAC_TEST_S_RQD,
@@ -42,17 +64,34 @@
 	IPAC_TEST_S_PARTIAL,
 };
 
-int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr)
+int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr,
+			const uint8_t *phys_conf, unsigned int phys_conf_len)
 {
-	const uint8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
+	struct msgb *msg;
 
 	if (trx->ipaccess.test_state != IPAC_TEST_S_IDLE) {
 		fprintf(stderr, "Cannot start test in state %u\n", trx->ipaccess.test_state);
 		return -EINVAL;
 	}
 
-	abis_nm_perform_test(trx->bts, 2, 0, trx->nr, 0xff, testnr, 1,
-			     phys_config, sizeof(phys_config));
+	switch (testnr) {
+	case NM_IPACC_TESTNO_CHAN_USAGE:
+		rxlev_stat_reset(&trx->ipaccess.rxlev_stat);
+		break;
+	}
+
+	msg = msgb_alloc_headroom(phys_conf_len+256, 128, "OML");
+
+	if (phys_conf && phys_conf_len) {
+		uint8_t *payload;
+		/* first put the phys conf header */
+		msgb_tv16_put(msg, NM_ATT_PHYS_CONF, phys_conf_len);
+		payload = msgb_put(msg, phys_conf_len);
+		memcpy(payload, phys_conf, phys_conf_len);
+	}
+
+	abis_nm_perform_test(trx->bts, NM_OC_RADIO_CARRIER, 0, trx->nr, 0xff,
+			     testnr, 1, msg);
 
 	/* FIXME: start safety timer until when test is supposed to complete */
 
@@ -113,8 +152,11 @@
 		for (i = 0; i < ferr_list_len; i+= 2) {
 			uint16_t *cu_ptr = (uint16_t *)(foh->data + 9 + i);
 			uint16_t cu = ntohs(*cu_ptr);
-			DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n",
-				cu & 0x3ff, cu >> 10);
+			uint16_t arfcn = cu & 0x3ff;
+			uint8_t rxlev = cu >> 10;
+			DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n", arfcn, rxlev);
+			rxlev_stat_input(&msg->trx->ipaccess.rxlev_stat,
+					 arfcn, rxlev);
 		}
 		break;
 	case NM_IPAC_EIE_BCCH_INFO_TYPE:
@@ -141,6 +183,7 @@
 	case NM_IPACC_TESTRES_NO_CHANS:
 		msg->trx->ipaccess.test_state = IPAC_TEST_S_IDLE;
 		/* Send signal to notify higher layers of test completion */
+		DEBUGP(DNM, "dispatching S_IPAC_NWL_COMPLETE signal\n");
 		dispatch_signal(SS_IPAC_NWL, S_IPAC_NWL_COMPLETE, msg->trx);
 		break;
 	case NM_IPACC_TESTRES_PARTIAL:
@@ -154,8 +197,6 @@
 static int nwl_sig_cb(unsigned int subsys, unsigned int signal,
 		     void *handler_data, void *signal_data)
 {
-	struct ipacc_ack_signal_data *ipacc_data;
-
 	switch (signal) {
 	case S_NM_TEST_REP:
 		return test_rep(signal_data);