From c64d42573894d8295b58b268a64541c914b69bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Neira=20Ayuso?= Date: Sat, 17 May 2014 11:01:13 +0200 Subject: sysmobts: Add support for changing the transmit power in sbts2050 Make the sysmobts-mgr send a manufacturer O&M message with the power reduction we want the sysmobts to apply. The sysmobts will handle this message and set the new tx output power. An ACK/NACK will be send as a response to the power reduction. Signed-off-by: Alvaro Neira Ayuso --- 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(-) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index bd6a1818..2c13a9c2 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -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 e45d41f2..4aa2cbf0 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 5e0d4a7b..026afd54 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 2417c3d9..6277a6bf 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 c22a54b2..740ce2d7 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 { -- cgit v1.2.3