OM2000: First attempt in automatically configuring most MOs

TS objects are not part yet
diff --git a/openbsc/include/openbsc/abis_om2000.h b/openbsc/include/openbsc/abis_om2000.h
index be369fe..2ff7270 100644
--- a/openbsc/include/openbsc/abis_om2000.h
+++ b/openbsc/include/openbsc/abis_om2000.h
@@ -34,6 +34,13 @@
 	OM2K_MO_CLS_RX				= 0x0c,
 };
 
+enum om2k_mo_state {
+	OM2K_MO_S_RESET = 0,
+	OM2K_MO_S_STARTED,
+	OM2K_MO_S_ENABLED,
+	OM2K_MO_S_DISABLED,
+};
+
 struct abis_om2k_mo {
 	uint8_t class;
 	uint8_t bts;
@@ -56,6 +63,11 @@
 	uint8_t ci;
 };
 
+extern const struct abis_om2k_mo om2k_mo_cf;
+extern const struct abis_om2k_mo om2k_mo_is;
+extern const struct abis_om2k_mo om2k_mo_con;
+extern const struct abis_om2k_mo om2k_mo_tf;
+
 extern const struct value_string om2k_mo_class_short_vals[];
 
 int abis_om2k_rcvmsg(struct msgb *msg);
diff --git a/openbsc/src/libbsc/bts_ericsson_rbs2000.c b/openbsc/src/libbsc/bts_ericsson_rbs2000.c
index 27d5ce6..6480d34 100644
--- a/openbsc/src/libbsc/bts_ericsson_rbs2000.c
+++ b/openbsc/src/libbsc/bts_ericsson_rbs2000.c
@@ -26,6 +26,7 @@
 #include <openbsc/debug.h>
 #include <openbsc/gsm_data.h>
 #include <openbsc/abis_om2000.h>
+#include <openbsc/abis_nm.h>
 #include <openbsc/e1_input.h>
 #include <openbsc/signal.h>
 
@@ -40,9 +41,12 @@
 
 static void bootstrap_om_trx(struct gsm_bts_trx *trx)
 {
+	struct abis_om2k_mo trx_mo = { OM2K_MO_CLS_TRXC, 0, 255, trx->nr };
+
 	LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
 	     trx->bts->nr, trx->nr);
-	/* FIXME */
+
+	abis_om2k_tx_reset_cmd(trx->bts, &trx_mo);
 }
 
 static int shutdown_om(struct gsm_bts *bts)
@@ -137,6 +141,91 @@
 	return 0;
 }
 
+static void nm_statechg_evt(unsigned int signal,
+			    struct nm_statechg_signal_data *nsd)
+{
+	struct abis_om2k_mo mo;
+
+	if (nsd->bts->type != GSM_BTS_TYPE_RBS2000)
+		return;
+
+	switch (nsd->om2k_mo->class) {
+	case OM2K_MO_CLS_CF:
+		if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
+		    nsd->new_state->availability != OM2K_MO_S_STARTED)
+			break;
+		/* CF has started, we can trigger IS and TF start */
+		abis_om2k_tx_connect_cmd(nsd->bts, &om2k_mo_is);
+		abis_om2k_tx_connect_cmd(nsd->bts, &om2k_mo_tf);
+		break;
+	case OM2K_MO_CLS_IS:
+		if (nsd->new_state->availability == OM2K_MO_S_ENABLED) {
+			/* IS is enabled, we can proceed with TRXC/RX/TX/TS */
+		}
+		if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
+		    nsd->new_state->availability == OM2K_MO_S_DISABLED)
+			break;
+		/* IS has started, we can configure + enable it */
+		abis_om2k_tx_is_conf_req(nsd->bts);
+		abis_om2k_tx_enable_req(nsd->bts, nsd->om2k_mo);
+		break;
+	case OM2K_MO_CLS_TF:
+		if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
+		    nsd->new_state->availability == OM2K_MO_S_DISABLED)
+			break;
+		if (nsd->new_state->availability == OM2K_MO_S_STARTED) {
+			/* TF has started, configure + enable it */
+			abis_om2k_tx_is_conf_req(nsd->bts);
+			abis_om2k_tx_enable_req(nsd->bts, nsd->om2k_mo);
+		}
+		break;
+	case OM2K_MO_CLS_TRXC:
+		if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
+		    nsd->new_state->availability != OM2K_MO_S_STARTED)
+			break;
+		/* TRXC is started, connect the TX and RX objects */
+		memcpy(&mo, nsd->om2k_mo, sizeof(mo));
+		mo.class = OM2K_MO_CLS_TX;
+		abis_om2k_tx_connect_cmd(nsd->bts, &mo);
+		mo.class = OM2K_MO_CLS_RX;
+		abis_om2k_tx_connect_cmd(nsd->bts, &mo);
+		break;
+	case OM2K_MO_CLS_RX:
+		if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
+		    nsd->new_state->availability != OM2K_MO_S_STARTED)
+			break;
+		/* RX is started, configure + enable it */
+		abis_om2k_tx_rx_conf_req(nsd->obj);
+		abis_om2k_tx_enable_req(nsd->bts, nsd->om2k_mo);
+		break;
+	case OM2K_MO_CLS_TX:
+		if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
+		    nsd->new_state->availability != OM2K_MO_S_STARTED)
+			break;
+		/* RX is started, configure + enable it */
+		abis_om2k_tx_tx_conf_req(nsd->obj);
+		abis_om2k_tx_enable_req(nsd->bts, nsd->om2k_mo);
+		break;
+	}
+}
+
+static int nm_sig_cb(unsigned int subsys, unsigned int signal,
+		     void *handler_data, void *signal_data)
+{
+	if (subsys != SS_NM)
+		return 0;
+
+	switch (signal) {
+	case S_NM_STATECHG_OPER:
+	case S_NM_STATECHG_ADM:
+		nm_statechg_evt(signal, signal_data);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static void config_write_bts(struct vty *vty, struct gsm_bts *bts)
 {
 	abis_om2k_config_write_bts(vty, bts);
@@ -159,6 +248,7 @@
 
 	register_signal_handler(SS_INPUT, inp_sig_cb, NULL);
 	register_signal_handler(SS_GLOBAL, gbl_sig_cb, NULL);
+	register_signal_handler(SS_NM, nm_sig_cb, NULL);
 
 	return gsm_bts_model_register(&model_rbs2k);
 }