[osmo-bts,3/3,v9] sysmobts: Add support for changing the transmit power in sbts2050
diff mbox

Message ID 1400317273-24414-1-git-send-email-anayuso@sysmocom.de
State Accepted
Headers show

Commit Message

Alvaro Neira May 17, 2014, 9:01 a.m. UTC
From: Álvaro Neira Ayuso <anayuso@sysmocom.de>

Make the sysmobts-mgr sends a manufacturer O&M message with the
relative value that we want to reduce in the sysmobts. The
sysmobts receives this messages. Messages passing a sanity check takes
the relative value that we want to reduce and the sysmobts reduces
the transmit power. The sysmobts-mgr receives a ACK/NACK for
knowing that the transmit power has been updated.

Signed-off-by: Alvaro Neira Ayuso <anayuso@sysmocom.de>
---
[changes in v9]
* Removed the code for adding the manufacturer ID label and used the new
  function inside utils.
* Removed leak when we send the ack/nack when we receive the reduce manufacturer
  O&M message and it has passed a sanity check.
* Moved the code when we check if the PA or the Board is under a temperature
  warning situation and when we send the relative value that we want to use for
  reduce the transmit power to a new function for make easy future changes.
* Changed some log messages for adding more util information for debugging.

 src/osmo-bts-sysmo/main.c               |  122 ++++++++++++++++++++++++++++++-
 src/osmo-bts-sysmo/misc/sysmobts_mgr.c  |   41 ++++++++---
 src/osmo-bts-sysmo/misc/sysmobts_mgr.h  |    5 ++
 src/osmo-bts-sysmo/misc/sysmobts_misc.c |   72 ++++++++++++++++++
 src/osmo-bts-sysmo/misc/sysmobts_misc.h |    2 +
 5 files changed, 231 insertions(+), 11 deletions(-)

Patch
diff mbox

diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c
index bd6a181..2c13a9c 100644
--- a/src/osmo-bts-sysmo/main.c
+++ b/src/osmo-bts-sysmo/main.c
@@ -39,6 +39,7 @@ 
 #include <osmocom/vty/telnet_interface.h>
 #include <osmocom/vty/logging.h>
 #include <osmocom/gsm/protocol/ipaccess.h>
+#include <osmocom/gsm/abis_nm.h>
 
 #include <osmo-bts/gsm_data.h>
 #include <osmo-bts/logging.h>
@@ -294,10 +295,106 @@  static int write_pid_file(char *procname)
 	return 0;
 }
 
+#define oml_tlv_parse(dec, buf, len)	\
+	tlv_parse(dec, &abis_nm_att_tlvdef, buf, len, 0, 0)
+
+static int send_oml_fom_ack_nack(int fd_unix, struct msgb *old_msg,
+				 uint8_t cause, int is_manuf)
+{
+	struct abis_om_hdr *old_om = msgb_l2(old_msg);
+	struct abis_om_fom_hdr *old_foh = msgb_l3(old_msg);
+	struct msgb *msg;
+	struct abis_om_fom_hdr *foh;
+	struct abis_om_hdr *om;
+	int rc;
+
+	msg = oml_msgb_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	msg->l3h = msgb_push(msg, sizeof(*foh));
+	foh = (struct abis_om_fom_hdr *) msg->l3h;
+	memcpy(foh, old_foh, sizeof(*foh));
+
+	if (is_manuf)
+		add_manufacturer_id_label(msg, OSMOCOM_MANUF_ID);
+
+	msg->l2h = msgb_push(msg, sizeof(*om));
+	om = (struct abis_om_hdr *) msg->l2h;
+	memcpy(om, old_om, sizeof(*om));
+
+	/* alter message type */
+	if (cause) {
+		LOGP(DOML, LOGL_ERROR, "Sending FOM NACK with cause %s.\n",
+		     abis_nm_nack_cause_name(cause));
+		foh->msg_type += 2; /* nack */
+		msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause);
+	} else {
+		LOGP(DOML, LOGL_DEBUG, "Sending FOM ACK.\n");
+		foh->msg_type++; /* ack */
+	}
+
+	prepend_oml_ipa_header(msg);
+
+	rc = send(fd_unix, msg->data, msg->len, 0);
+	if (rc < 0 || rc != msg->len) {
+		LOGP(DTEMP, LOGL_ERROR,
+		     "send error %s during ACK/NACK message send\n",
+		     strerror(errno));
+		close(fd_unix);
+		msgb_free(msg);
+		return -1;
+	}
+
+	msgb_free(msg);
+	return rc;
+}
+
+static void update_transmiter_power(struct gsm_bts_trx *trx)
+{
+	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+
+	if (fl1h->hLayer1)
+		l1if_set_txpower(fl1h, sysmobts_get_power_trx(trx));
+}
+
+static int take_reduce_power(struct msgb *msg)
+{
+	int recv_reduce_power;
+	struct tlv_parsed tlv_out;
+	struct gsm_bts_trx *trx = bts->c0;
+	int rc, abis_oml_hdr_len;
+
+	abis_oml_hdr_len = sizeof(struct abis_om_hdr);
+	abis_oml_hdr_len += sizeof(struct abis_om_fom_hdr);
+	abis_oml_hdr_len += sizeof(osmocom_magic) + 1;
+
+	rc = oml_tlv_parse(&tlv_out, msg->data + abis_oml_hdr_len,
+			   msg->len - abis_oml_hdr_len);
+
+	if (rc < 0) {
+		msgb_free(msg);
+		return -1;
+	}
+
+	if (TLVP_PRESENT(&tlv_out, NM_ATT_O_REDUCEPOWER))
+		recv_reduce_power = *TLVP_VAL(&tlv_out,
+					      NM_ATT_O_REDUCEPOWER);
+	else
+		return -1;
+
+	trx->power_reduce = recv_reduce_power;
+
+	update_transmiter_power(trx);
+
+	return 0;
+}
+
 static int read_sock(struct osmo_fd *fd, unsigned int what)
 {
 	struct msgb *msg;
 	struct gsm_abis_mo *mo;
+	struct abis_om_fom_hdr *fom;
 	int rc;
 
 	msg = oml_msgb_alloc();
@@ -324,9 +421,32 @@  static int read_sock(struct osmo_fd *fd, unsigned int what)
 
 	mo = &bts->mo;
 	msg->trx = mo->bts->c0;
+	fom = (struct abis_om_fom_hdr *) msg->l3h;
 
-	return abis_oml_sendmsg(msg);
+	switch (fom->msg_type) {
+	case NM_MT_SET_RADIO_ATTR:
+		rc = take_reduce_power(msg);
+		if (rc < 0) {
+			rc = send_oml_fom_ack_nack(fd->fd, msg,
+						   NM_NACK_INCORR_STRUCT, 1);
+		} else {
+			rc = send_oml_fom_ack_nack(fd->fd, msg, 0, 1);
+		}
+		msgb_free(msg);
+		break;
+	case NM_MT_FAILURE_EVENT_REP:
+		rc = abis_oml_sendmsg(msg);
+		break;
+	default:
+		LOGP(DL1C, LOGL_ERROR, "Unknown Fom message type %d\n",
+		     fom->msg_type);
+		goto err;
+	}
 
+	if (rc < 0)
+		goto err;
+
+	return rc;
 err:
 	msgb_free(msg);
 	return -1;
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
index e45d41f..4aa2cbf 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
@@ -82,6 +82,7 @@  static struct vty_app_info vty_info = {
 static int fd_unix = -1;
 static int trx_nr = -1;
 static int state_connection;
+static int status_change_power_red;
 
 static struct osmo_timer_list temp_uc_timer;
 static struct osmo_timer_list connect_timer;
@@ -135,21 +136,39 @@  static int check_temperature(struct uc *ucontrol0, int lowlimit, int highlimit,
 	return 1;
 }
 
+static int check_warning_state(int pa_warning, int board_warning)
+{
+	if ((pa_warning || board_warning) &&
+	    status_change_power_red == SBTS2050_DISABLE_CHANGE_POWER) {
+		status_change_power_red = SBTS2050_ENABLE_CHANGE_POWER;
+		send_manufacturer_reduce_msg(fd_unix, confinfo.reduce_max_power,
+					     trx_nr);
+	} else if (!pa_warning && !board_warning &&
+		   status_change_power_red == SBTS2050_ENABLE_CHANGE_POWER) {
+		status_change_power_red = SBTS2050_DISABLE_CHANGE_POWER;
+		send_manufacturer_reduce_msg(fd_unix, 0, trx_nr);
+	} else
+		return -1;
+
+	return 0;
+}
+
 static void check_uctemp_timer_cb(void *data)
 {
 	int temp_pa = 0, temp_board = 0;
 	struct uc *ucontrol0 = data;
+	int pa_warning, board_warning;
 
 	sbts2050_uc_check_temp(ucontrol0, &temp_pa, &temp_board);
 
 	confinfo.temp_pa_cur = temp_pa;
 	confinfo.temp_board_cur = temp_board;
 
-	check_temperature(ucontrol0,
-			  confinfo.temp_min_pa_warn_limit,
-			  confinfo.temp_max_pa_warn_limit,
-			  temp_pa, SBTS2050_TEMP_PA,
-			  SBTS2050_WARN_ALERT);
+	pa_warning = check_temperature(ucontrol0,
+				       confinfo.temp_min_pa_warn_limit,
+				       confinfo.temp_max_pa_warn_limit,
+				       temp_pa, SBTS2050_TEMP_PA,
+				       SBTS2050_WARN_ALERT);
 
 	check_temperature(ucontrol0,
 			  confinfo.temp_min_pa_severe_limit,
@@ -157,11 +176,11 @@  static void check_uctemp_timer_cb(void *data)
 			  temp_pa, SBTS2050_TEMP_PA,
 			  SBTS2050_SEVERE_ALERT);
 
-	check_temperature(ucontrol0,
-			  confinfo.temp_min_board_warn_limit,
-			  confinfo.temp_max_board_warn_limit,
-			  temp_board, SBTS2050_TEMP_BOARD,
-			  SBTS2050_WARN_ALERT);
+	board_warning = check_temperature(ucontrol0,
+					  confinfo.temp_min_board_warn_limit,
+					  confinfo.temp_max_board_warn_limit,
+					  temp_board, SBTS2050_TEMP_BOARD,
+					  SBTS2050_WARN_ALERT);
 
 	check_temperature(ucontrol0,
 			  confinfo.temp_min_board_severe_limit,
@@ -169,6 +188,8 @@  static void check_uctemp_timer_cb(void *data)
 			  temp_board, SBTS2050_TEMP_BOARD,
 			  SBTS2050_SEVERE_ALERT);
 
+	check_warning_state(pa_warning, board_warning);
+
 	osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0);
 }
 #endif
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
index 5e0d4a7..026afd5 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
@@ -15,6 +15,11 @@  enum {
 	SYSMO_MGR_CONNECTED,
 };
 
+enum {
+	SBTS2050_DISABLE_CHANGE_POWER = 0,
+	SBTS2050_ENABLE_CHANGE_POWER,
+};
+
 #define SOCKET_PATH		"/var/run/bts_oml"
 
 struct sbts2050_config_info;
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
index 2417c3d..6277a6b 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
@@ -58,6 +58,23 @@ 
 #define OM_HEADROOM_SIZE	128
 
 #ifdef BUILD_SBTS2050
+
+static int check_manufacturer_reduce_nach_ack(struct msgb *msg)
+{
+	struct abis_om_fom_hdr *foh = msgb_l3(msg);
+
+	if (foh->msg_type == NM_MT_SET_RADIO_ATTR + 2) { /* NACK */
+		LOGP(DTEMP, LOGL_ERROR, "Reduce Power: Received a BTS NACK\n");
+		return -1;
+	} else if (foh->msg_type != NM_MT_SET_RADIO_ATTR + 1) { /* ACK */
+		LOGP(DTEMP, LOGL_ERROR, "Unknown message type %d\n",
+		     foh->msg_type);
+		return -1;
+	}
+
+	return 0;
+}
+
 static void add_sw_descr(struct msgb *msg)
 {
 	char file_version[255];
@@ -112,6 +129,61 @@  static void add_oml_hdr_msg(struct msgb *msg, uint8_t msg_type,
 	omh->length = msgb_l3len(msg);
 }
 
+int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr)
+{
+	int rc;
+	struct msgb *msg;
+
+	msg = msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML");
+	if (msg == NULL) {
+		LOGP(DTEMP, LOGL_ERROR, "Error creating oml msg\n");
+		return -1;
+	}
+
+	add_oml_hdr_msg(msg, NM_MT_SET_RADIO_ATTR, 2, 0, trx_nr, 255, 1);
+
+	msgb_tv_put(msg, NM_ATT_O_REDUCEPOWER, reduce_power);
+
+	prepend_oml_ipa_header(msg);
+
+	rc = send(fd_unix, msg->data, msg->len, 0);
+	if (rc < 0 || rc != msg->len) {
+		LOGP(DTEMP, LOGL_ERROR,
+		     "send error %s during Reduce Manufacturer O&M msg send\n",
+		     strerror(errno));
+		goto err;
+	}
+
+	msgb_reset(msg);
+	rc = recv(fd_unix, msg->tail, msg->data_len, 0);
+	if (rc <= 0) {
+		LOGP(DTEMP, LOGL_ERROR, "recv error %s during ACK/NACK recv\n",
+		     strerror(errno));
+		goto err;
+	}
+	msgb_put(msg, rc);
+
+	if (check_oml_msg(msg) < 0) {
+		close(fd_unix);
+		msgb_free(msg);
+		return -1;
+	}
+
+	if (check_manufacturer_reduce_nach_ack(msg) < 0) {
+		close(fd_unix);
+		msgb_free(msg);
+		return -1;
+	}
+
+	msgb_free(msg);
+	return SYSMO_MGR_CONNECTED;
+
+err:
+	close(fd_unix);
+	msgb_free(msg);
+	return SYSMO_MGR_DISCONNECTED;
+}
+
 int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert,
 		   enum sbts2050_temp_sensor sensor,
 		   struct sbts2050_config_info *add_info, int trx_nr)
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h
index c22a54b..740ce2d 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h
@@ -75,6 +75,8 @@  int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert,
 		   enum sbts2050_temp_sensor sensor,
 		   struct sbts2050_config_info *add_info, int trx_nr);
 
+int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr);
+
 int sysmobts_update_hours(int no_epprom_write);
 
 enum sysmobts_firmware_type {