aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-sysmo
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-21 23:55:37 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-08-21 23:55:37 +0200
commit3a54b7aa308be6672ce7335a621030ba979bb0be (patch)
treee10f2099acc0f5204feff094df0fe75b4c9c3061 /src/osmo-bts-sysmo
parent7be58a173aae516a185fd5c2a56ffc3a8a698e05 (diff)
parent1f8053e366c9d0f4ab7160595a3cb1ead915e0d6 (diff)
Merge branch 'sysmocom/features/sysmobts-mgr-temp'
Implement the first round of temperature control and actions. Only the PA can be switched off, it will never be switched on again, in case the microcontroller doesn't respond we will do nothing as well. These todos need to be addressed in the near future.
Diffstat (limited to 'src/osmo-bts-sysmo')
-rw-r--r--src/osmo-bts-sysmo/Makefile.am4
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr.c208
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr.h54
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c47
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c196
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c228
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c229
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_misc.c4
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_misc.h13
9 files changed, 780 insertions, 203 deletions
diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am
index fe318549..cc669339 100644
--- a/src/osmo-bts-sysmo/Makefile.am
+++ b/src/osmo-bts-sysmo/Makefile.am
@@ -24,7 +24,9 @@ sysmobts_mgr_SOURCES = \
misc/sysmobts_mgr.c misc/sysmobts_misc.c \
misc/sysmobts_par.c misc/sysmobts_nl.c \
misc/sysmobts_mgr_2050.c \
- misc/sysmobts_mgr_vty.c
+ misc/sysmobts_mgr_vty.c \
+ misc/sysmobts_mgr_nl.c \
+ misc/sysmobts_mgr_temp.c
sysmobts_mgr_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS)
sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
index f8b3302e..484e08ff 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
@@ -26,22 +26,18 @@
#include <errno.h>
#include <getopt.h>
#include <limits.h>
-#include <arpa/inet.h>
#include <sys/signal.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/application.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/msgb.h>
-#include <osmocom/core/serial.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include "misc/sysmobts_misc.h"
#include "misc/sysmobts_mgr.h"
-#include "misc/sysmobts_nl.h"
#include "misc/sysmobts_par.h"
static int bts_type;
@@ -49,9 +45,38 @@ static int trx_number;
static int no_eeprom_write = 0;
static int daemonize = 0;
-static const char *cfgfile = "sysmobts-mgr.cfg";
void *tall_mgr_ctx;
+/* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */
+#define TEMP_TIMER_SECS (6 * 3600)
+
+/* every 1 hours means 365*24 = 8760 EEprom writes per year (max) */
+#define HOURS_TIMER_SECS (1 * 3600)
+
+/* the initial state */
+static struct sysmobts_mgr_instance manager = {
+ .config_file = "sysmobts-mgr.cfg",
+ .rf_limit = {
+ .thresh_warn = 60,
+ .thresh_crit = 78,
+ },
+ .digital_limit = {
+ .thresh_warn = 60,
+ .thresh_crit = 78,
+ },
+ .board_limit = {
+ .thresh_warn = 60,
+ .thresh_crit = 78,
+ },
+ .pa_limit = {
+ .thresh_warn = 60,
+ .thresh_crit = 100,
+ },
+ .action_warn = 0,
+ .action_crit = TEMP_ACT_PA_OFF,
+ .state = STATE_NORMAL,
+};
+
static int classify_bts(void)
{
@@ -72,6 +97,16 @@ static int classify_bts(void)
return 0;
}
+int sysmobts_bts_type(void)
+{
+ return bts_type;
+}
+
+int sysmobts_trx_number(void)
+{
+ return trx_number;
+}
+
int is_sbts2050(void)
{
return bts_type == 2050;
@@ -139,7 +174,7 @@ static int parse_options(int argc, char **argv)
daemonize = 1;
break;
case 'c':
- cfgfile = optarg;
+ manager.config_file = optarg;
break;
default:
return -1;
@@ -169,17 +204,6 @@ static void signal_handler(int signal)
}
}
-#include <osmocom/core/logging.h>
-#include <osmocom/core/application.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/socket.h>
-
-#include <osmocom/gsm/protocol/ipaccess.h>
-#include <osmocom/gsm/tlv.h>
-
-#include <osmo-bts/bts.h>
-#include <osmo-bts/logging.h>
-
static struct log_info_cat mgr_log_info_cat[] = {
[DTEMP] = {
.name = "DTEMP",
@@ -212,146 +236,8 @@ static int mgr_log_init(void)
return 0;
}
-/*
- * The TLV structure in IPA messages in UDP packages is a bit
- * weird. First the header appears to have an extra NULL byte
- * and second the L16 of the L16TV needs to include +1 for the
- * tag. The default msgb/tlv and libosmo-abis routines do not
- * provide this.
- */
-
-static void ipaccess_prepend_header_quirk(struct msgb *msg, int proto)
-{
- struct ipaccess_head *hh;
-
- /* prepend the ip.access header */
- hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh) + 1);
- hh->len = htons(msg->len - sizeof(*hh) - 1);
- hh->proto = proto;
-}
-
-static void quirk_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
- const uint8_t *val)
-{
- uint8_t *buf = msgb_put(msg, len + 2 + 1);
-
- *buf++ = (len + 1) >> 8;
- *buf++ = (len + 1) & 0xff;
- *buf++ = tag;
- memcpy(buf, val, len);
-}
-
-/*
- * We don't look at the content of the request yet and lie
- * about most of the responses.
- */
-static void respond_to(struct sockaddr_in *src, struct osmo_fd *fd,
- uint8_t *data, size_t len)
-{
- static int fetched_info = 0;
- static char mac_str[20] = { };
- static char *model_name;
-
- struct sockaddr_in loc_addr;
- int rc;
- char loc_ip[INET_ADDRSTRLEN];
- struct msgb *msg = msgb_alloc_headroom(512, 128, "ipa get response");
- if (!msg) {
- LOGP(DFIND, LOGL_ERROR, "Failed to allocate msgb\n");
- return;
- }
-
- if (!fetched_info) {
- uint8_t mac[6];
-
- /* fetch the MAC */
- sysmobts_par_get_buf(SYSMOBTS_PAR_MAC, mac, sizeof(mac));
- snprintf(mac_str, sizeof(mac_str), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
- mac[0], mac[1], mac[2],
- mac[3], mac[4], mac[5]);
-
- /* fetch the model and trx number */
- switch(bts_type) {
- case 0:
- case 0xffff:
- case 1002:
- model_name = "sysmoBTS 1002";
- break;
- case 2050:
- if (trx_number == 0)
- model_name = "sysmoBTS 2050 (master)";
- else if (trx_number == 1)
- model_name = "sysmoBTS 2050 (slave)";
- else
- model_name = "sysmoBTS 2050 (unknown)";
- break;
- default:
- model_name = "Unknown";
- break;
- }
-
-
- fetched_info = 1;
- }
-
- if (source_for_dest(&src->sin_addr, &loc_addr.sin_addr) != 0) {
- LOGP(DFIND, LOGL_ERROR, "Failed to determine local source\n");
- return;
- }
-
- msgb_put_u8(msg, IPAC_MSGT_ID_RESP);
-
- /* append MAC addr */
- quirk_l16tv_put(msg, strlen(mac_str) + 1, IPAC_IDTAG_MACADDR, (uint8_t *) mac_str);
-
- /* append ip address */
- inet_ntop(AF_INET, &loc_addr.sin_addr, loc_ip, sizeof(loc_ip));
- quirk_l16tv_put(msg, strlen(loc_ip) + 1, IPAC_IDTAG_IPADDR, (uint8_t *) loc_ip);
-
- /* abuse some flags */
- quirk_l16tv_put(msg, strlen(model_name) + 1, IPAC_IDTAG_UNIT, (uint8_t *) model_name);
-
- /* ip.access nanoBTS would reply to port==3006 */
- ipaccess_prepend_header_quirk(msg, IPAC_PROTO_IPACCESS);
- rc = sendto(fd->fd, msg->data, msg->len, 0, (struct sockaddr *)src, sizeof(*src));
- if (rc != msg->len)
- LOGP(DFIND, LOGL_ERROR,
- "Failed to send with rc(%d) errno(%d)\n", rc, errno);
-}
-
-static int ipaccess_bcast(struct osmo_fd *fd, unsigned int what)
-{
- uint8_t data[2048];
- char src[INET_ADDRSTRLEN];
- struct sockaddr_in addr = {};
- socklen_t len = sizeof(addr);
- int rc;
-
- rc = recvfrom(fd->fd, data, sizeof(data), 0,
- (struct sockaddr *) &addr, &len);
- if (rc <= 0) {
- LOGP(DFIND, LOGL_ERROR,
- "Failed to read from socket errno(%d)\n", errno);
- return -1;
- }
-
- LOGP(DFIND, LOGL_DEBUG,
- "Received request from: %s size %d\n",
- inet_ntop(AF_INET, &addr.sin_addr, src, sizeof(src)), rc);
-
- if (rc < 6)
- return 0;
-
- if (data[2] != IPAC_PROTO_IPACCESS || data[4] != IPAC_MSGT_ID_GET)
- return 0;
-
- respond_to(&addr, fd, data + 6, rc - 6);
- return 0;
-}
-
int main(int argc, char **argv)
{
- struct osmo_fd fd;
void *tall_msgb_ctx;
int rc;
@@ -375,7 +261,7 @@ int main(int argc, char **argv)
sysmobts_mgr_vty_init();
logging_vty_add_cmds(&mgr_log_info);
- rc = sysmobts_mgr_parse_config(cfgfile);
+ rc = sysmobts_mgr_parse_config(&manager);
if (rc < 0) {
LOGP(DFIND, LOGL_FATAL, "Cannot parse config file\n");
exit(1);
@@ -399,13 +285,11 @@ int main(int argc, char **argv)
sbts2050_uc_initialize();
/* handle broadcast messages for ipaccess-find */
- fd.cb = ipaccess_bcast;
- rc = osmo_sock_init_ofd(&fd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
- "0.0.0.0", 3006, OSMO_SOCK_F_BIND);
- if (rc < 0) {
- perror("Socket creation");
+ if (sysmobts_mgr_nl_init() != 0)
exit(3);
- }
+
+ /* Initialize the temperature control */
+ sysmobts_mgr_temp_init(&manager);
if (daemonize) {
rc = osmo_daemonize();
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
index aaa43736..fd6f2bcb 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
@@ -10,14 +10,62 @@ enum {
DFIND,
};
+
+enum {
+ TEMP_ACT_PWR_CONTRL = 0x1,
+ TEMP_ACT_MASTER_OFF = 0x2,
+ TEMP_ACT_SLAVE_OFF = 0x4,
+ TEMP_ACT_PA_OFF = 0x8,
+};
+
+enum sysmobts_temp_state {
+ STATE_NORMAL, /* Everything is fine */
+ STATE_WARNING_HYST, /* Go back to normal next? */
+ STATE_WARNING, /* We are above the warning threshold */
+ STATE_CRITICAL, /* We have an issue. Wait for below warning */
+};
+
+/**
+ * Temperature Limits. We separate from a threshold
+ * that will generate a warning and one that is so
+ * severe that an action will be taken.
+ */
+struct sysmobts_temp_limit {
+ int thresh_warn;
+ int thresh_crit;
+};
+
enum mgr_vty_node {
MGR_NODE = _LAST_OSMOVTY_NODE + 1,
-};
-int sysmobts_mgr_vty_init(void);
-int sysmobts_mgr_parse_config(const char *config_file);
+ ACT_WARN_NODE,
+ ACT_CRIT_NODE,
+ LIMIT_RF_NODE,
+ LIMIT_DIGITAL_NODE,
+ LIMIT_BOARD_NODE,
+ LIMIT_PA_NODE,
+};
struct sysmobts_mgr_instance {
const char *config_file;
+
+ struct sysmobts_temp_limit rf_limit;
+ struct sysmobts_temp_limit digital_limit;
+
+ /* Only available on sysmobts 2050 */
+ struct sysmobts_temp_limit board_limit;
+ struct sysmobts_temp_limit pa_limit;
+
+ int action_warn;
+ int action_crit;
+
+ enum sysmobts_temp_state state;
};
+
+int sysmobts_mgr_vty_init(void);
+int sysmobts_mgr_parse_config(struct sysmobts_mgr_instance *mgr);
+int sysmobts_mgr_nl_init(void);
+int sysmobts_mgr_temp_init(struct sysmobts_mgr_instance *mgr);
+const char *sysmobts_mgr_temp_get_state(enum sysmobts_temp_state state);
+
#endif
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c
index daad7647..3064319f 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_2050.c
@@ -25,6 +25,7 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/timer.h>
+#include <osmocom/core/serial.h>
#include <errno.h>
#include <unistd.h>
@@ -246,7 +247,7 @@ int sbts2050_uc_get_status(struct sbts2050_power_status *status)
/**********************************************************************
* Uc Power Switching handling
*********************************************************************/
-void sbts2050_uc_set_power(int pmaster, int pslave, int ppa)
+int sbts2050_uc_set_power(int pmaster, int pslave, int ppa)
{
struct msgb *msg;
const struct ucinfo info = {
@@ -260,7 +261,7 @@ void sbts2050_uc_set_power(int pmaster, int pslave, int ppa)
if (msg == NULL) {
LOGP(DTEMP, LOGL_ERROR, "Error switching off some unit.\n");
- return;
+ return -1;
}
LOGP(DTEMP, LOGL_DEBUG, "Switch off/on success:\n"
@@ -272,12 +273,13 @@ void sbts2050_uc_set_power(int pmaster, int pslave, int ppa)
ppa ? "ON" : "OFF");
msgb_free(msg);
+ return 0;
}
/**********************************************************************
* Uc temperature handling
*********************************************************************/
-void sbts2050_uc_check_temp(int *temp_pa, int *temp_board)
+int sbts2050_uc_check_temp(int *temp_pa, int *temp_board)
{
rsppkt_t *response;
struct msgb *msg;
@@ -289,7 +291,7 @@ void sbts2050_uc_check_temp(int *temp_pa, int *temp_board)
if (msg == NULL) {
LOGP(DTEMP, LOGL_ERROR, "Error reading temperature\n");
- return;
+ return -1;
}
response = (rsppkt_t *)msg->data;
@@ -297,21 +299,12 @@ void sbts2050_uc_check_temp(int *temp_pa, int *temp_board)
*temp_board = response->rsp.tempGet.i8BrdTemp;
*temp_pa = response->rsp.tempGet.i8PaTemp;
- LOGP(DTEMP, LOGL_DEBUG, "Temperature Board: %+3d C\n"
+ LOGP(DTEMP, LOGL_DEBUG, "Temperature Board: %+3d C, "
"Tempeture PA: %+3d C\n",
response->rsp.tempGet.i8BrdTemp,
response->rsp.tempGet.i8PaTemp);
msgb_free(msg);
-}
-
-static struct osmo_timer_list temp_uc_timer;
-static void check_uctemp_timer_cb(void *data)
-{
- int temp_pa = 0, temp_board = 0;
-
- sbts2050_uc_check_temp(&temp_pa, &temp_board);
-
- osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0);
+ return 0;
}
void sbts2050_uc_initialize(void)
@@ -326,8 +319,19 @@ void sbts2050_uc_initialize(void)
return;
}
- temp_uc_timer.cb = check_uctemp_timer_cb;
- check_uctemp_timer_cb(NULL);
+ LOGP(DTEMP, LOGL_NOTICE, "Going to enable the PA.\n");
+ sbts2050_uc_set_pa_power(1);
+}
+
+int sbts2050_uc_set_pa_power(int on_off)
+{
+ struct sbts2050_power_status status;
+ if (sbts2050_uc_get_status(&status) != 0) {
+ LOGP(DTEMP, LOGL_ERROR, "Failed to read current power status.\n");
+ return -1;
+ }
+
+ return sbts2050_uc_set_power(status.master_enabled, status.slave_enabled, on_off);
}
#else
void sbts2050_uc_initialize(void)
@@ -335,10 +339,11 @@ void sbts2050_uc_initialize(void)
LOGP(DTEMP, LOGL_NOTICE, "sysmoBTS2050 was not enabled at compile time.\n");
}
-void sbts2050_uc_check_temp(int *temp_pa, int *temp_board)
+int sbts2050_uc_check_temp(int *temp_pa, int *temp_board)
{
LOGP(DTEMP, LOGL_ERROR, "sysmoBTS2050 compiled without temp support.\n");
*temp_pa = *temp_board = 99999;
+ return -1;
}
int sbts2050_uc_get_status(struct sbts2050_power_status *status)
@@ -348,4 +353,10 @@ int sbts2050_uc_get_status(struct sbts2050_power_status *status)
return -1;
}
+int sbts2050_uc_set_pa_power(int on_off)
+{
+ LOGP(DTEMP, LOGL_ERROR, "sysmoBTS2050 compiled without PA support.\n");
+ return -1;
+}
+
#endif
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c
new file mode 100644
index 00000000..4bbc7193
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_nl.c
@@ -0,0 +1,196 @@
+/* NetworkListen for SysmoBTS management daemon */
+
+/*
+ * (C) 2014 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "misc/sysmobts_mgr.h"
+#include "misc/sysmobts_misc.h"
+#include "misc/sysmobts_nl.h"
+#include "misc/sysmobts_par.h"
+
+#include <osmo-bts/logging.h>
+
+#include <osmocom/gsm/protocol/ipaccess.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/select.h>
+
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+
+static struct osmo_fd nl_fd;
+
+/*
+ * The TLV structure in IPA messages in UDP packages is a bit
+ * weird. First the header appears to have an extra NULL byte
+ * and second the L16 of the L16TV needs to include +1 for the
+ * tag. The default msgb/tlv and libosmo-abis routines do not
+ * provide this.
+ */
+
+static void ipaccess_prepend_header_quirk(struct msgb *msg, int proto)
+{
+ struct ipaccess_head *hh;
+
+ /* prepend the ip.access header */
+ hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh) + 1);
+ hh->len = htons(msg->len - sizeof(*hh) - 1);
+ hh->proto = proto;
+}
+
+static void quirk_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
+ const uint8_t *val)
+{
+ uint8_t *buf = msgb_put(msg, len + 2 + 1);
+
+ *buf++ = (len + 1) >> 8;
+ *buf++ = (len + 1) & 0xff;
+ *buf++ = tag;
+ memcpy(buf, val, len);
+}
+
+/*
+ * We don't look at the content of the request yet and lie
+ * about most of the responses.
+ */
+static void respond_to(struct sockaddr_in *src, struct osmo_fd *fd,
+ uint8_t *data, size_t len)
+{
+ static int fetched_info = 0;
+ static char mac_str[20] = { };
+ static char *model_name;
+
+ struct sockaddr_in loc_addr;
+ int rc;
+ char loc_ip[INET_ADDRSTRLEN];
+ struct msgb *msg = msgb_alloc_headroom(512, 128, "ipa get response");
+ if (!msg) {
+ LOGP(DFIND, LOGL_ERROR, "Failed to allocate msgb\n");
+ return;
+ }
+
+ if (!fetched_info) {
+ uint8_t mac[6];
+
+ /* fetch the MAC */
+ sysmobts_par_get_buf(SYSMOBTS_PAR_MAC, mac, sizeof(mac));
+ snprintf(mac_str, sizeof(mac_str), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+
+ /* fetch the model and trx number */
+ switch(sysmobts_bts_type()) {
+ case 0:
+ case 0xffff:
+ case 1002:
+ model_name = "sysmoBTS 1002";
+ break;
+ case 2050:
+ if (sysmobts_trx_number() == 0)
+ model_name = "sysmoBTS 2050 (master)";
+ else if (sysmobts_trx_number() == 1)
+ model_name = "sysmoBTS 2050 (slave)";
+ else
+ model_name = "sysmoBTS 2050 (unknown)";
+ break;
+ default:
+ model_name = "Unknown";
+ break;
+ }
+
+
+ fetched_info = 1;
+ }
+
+ if (source_for_dest(&src->sin_addr, &loc_addr.sin_addr) != 0) {
+ LOGP(DFIND, LOGL_ERROR, "Failed to determine local source\n");
+ return;
+ }
+
+ msgb_put_u8(msg, IPAC_MSGT_ID_RESP);
+
+ /* append MAC addr */
+ quirk_l16tv_put(msg, strlen(mac_str) + 1, IPAC_IDTAG_MACADDR, (uint8_t *) mac_str);
+
+ /* append ip address */
+ inet_ntop(AF_INET, &loc_addr.sin_addr, loc_ip, sizeof(loc_ip));
+ quirk_l16tv_put(msg, strlen(loc_ip) + 1, IPAC_IDTAG_IPADDR, (uint8_t *) loc_ip);
+
+ /* abuse some flags */
+ quirk_l16tv_put(msg, strlen(model_name) + 1, IPAC_IDTAG_UNIT, (uint8_t *) model_name);
+
+ /* ip.access nanoBTS would reply to port==3006 */
+ ipaccess_prepend_header_quirk(msg, IPAC_PROTO_IPACCESS);
+ rc = sendto(fd->fd, msg->data, msg->len, 0, (struct sockaddr *)src, sizeof(*src));
+ if (rc != msg->len)
+ LOGP(DFIND, LOGL_ERROR,
+ "Failed to send with rc(%d) errno(%d)\n", rc, errno);
+}
+
+static int ipaccess_bcast(struct osmo_fd *fd, unsigned int what)
+{
+ uint8_t data[2048];
+ char src[INET_ADDRSTRLEN];
+ struct sockaddr_in addr = {};
+ socklen_t len = sizeof(addr);
+ int rc;
+
+ rc = recvfrom(fd->fd, data, sizeof(data), 0,
+ (struct sockaddr *) &addr, &len);
+ if (rc <= 0) {
+ LOGP(DFIND, LOGL_ERROR,
+ "Failed to read from socket errno(%d)\n", errno);
+ return -1;
+ }
+
+ LOGP(DFIND, LOGL_DEBUG,
+ "Received request from: %s size %d\n",
+ inet_ntop(AF_INET, &addr.sin_addr, src, sizeof(src)), rc);
+
+ if (rc < 6)
+ return 0;
+
+ if (data[2] != IPAC_PROTO_IPACCESS || data[4] != IPAC_MSGT_ID_GET)
+ return 0;
+
+ respond_to(&addr, fd, data + 6, rc - 6);
+ return 0;
+}
+
+int sysmobts_mgr_nl_init(void)
+{
+ int rc;
+
+ nl_fd.cb = ipaccess_bcast;
+ rc = osmo_sock_init_ofd(&nl_fd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
+ "0.0.0.0", 3006, OSMO_SOCK_F_BIND);
+ if (rc < 0) {
+ perror("Socket creation");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c
new file mode 100644
index 00000000..dac226f5
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_temp.c
@@ -0,0 +1,228 @@
+/* Temperature control for SysmoBTS management daemon */
+
+/*
+ * (C) 2014 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "misc/sysmobts_mgr.h"
+#include "misc/sysmobts_misc.h"
+
+#include <osmo-bts/logging.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/core/utils.h>
+
+static struct sysmobts_mgr_instance *s_mgr;
+static struct osmo_timer_list temp_ctrl_timer;
+
+static const struct value_string state_names[] = {
+ { STATE_NORMAL, "NORMAL" },
+ { STATE_WARNING_HYST, "WARNING (HYST)" },
+ { STATE_WARNING, "WARNING" },
+ { STATE_CRITICAL, "CRITICAL" },
+ { 0, NULL }
+};
+
+const char *sysmobts_mgr_temp_get_state(enum sysmobts_temp_state state)
+{
+ return get_value_string(state_names, state);
+}
+
+static int next_state(enum sysmobts_temp_state current_state, int critical, int warning)
+{
+ int next_state = -1;
+ switch (current_state) {
+ case STATE_NORMAL:
+ if (critical)
+ next_state = STATE_CRITICAL;
+ else if (warning)
+ next_state = STATE_WARNING;
+ break;
+ case STATE_WARNING_HYST:
+ if (critical)
+ next_state = STATE_CRITICAL;
+ else if (warning)
+ next_state = STATE_WARNING;
+ else
+ next_state = STATE_NORMAL;
+ break;
+ case STATE_WARNING:
+ if (critical)
+ next_state = STATE_CRITICAL;
+ else if (!warning)
+ next_state = STATE_WARNING_HYST;
+ break;
+ case STATE_CRITICAL:
+ if (!critical && !warning)
+ next_state = STATE_WARNING;
+ break;
+ };
+
+ return next_state;
+}
+
+/**
+ * Go back to normal! Undo everything we did in the other states. For
+ * reducint the transmit power, the question is if we should slowly set
+ * it back to normal, let the BTS slowly increase it.. or handle it here
+ * as well?
+ */
+static void execute_normal_act(struct sysmobts_mgr_instance *manager)
+{
+ LOGP(DTEMP, LOGL_NOTICE, "System is back to normal temperature.\n");
+}
+
+static void execute_warning_act(struct sysmobts_mgr_instance *manager)
+{
+ LOGP(DTEMP, LOGL_NOTICE, "System has reached temperature warning.\n");
+}
+
+static void execute_critical_act(struct sysmobts_mgr_instance *manager)
+{
+ LOGP(DTEMP, LOGL_NOTICE, "System has reached critical warning.\n");
+
+ /* switch off the PA */
+ if (manager->action_crit & TEMP_ACT_PA_OFF) {
+ if (!is_sbts2050_master()) {
+ LOGP(DTEMP, LOGL_NOTICE,
+ "PA can only be switched-off on the master\n");
+ } else if (sbts2050_uc_set_pa_power(0) != 0) {
+ LOGP(DTEMP, LOGL_ERROR,
+ "Failed to switch off the PA. Stop BTS?\n");
+ } else {
+ LOGP(DTEMP, LOGL_NOTICE,
+ "Switched off the PA due temperature.\n");
+ }
+ /*
+ * TODO: remember we switched off things so we could switch
+ * it back on. But we would need to make sure that the BTS
+ * will not transmit with full power at that time. This
+ * requires the control protocol.
+ */
+ }
+}
+
+static void sysmobts_mgr_temp_handle(struct sysmobts_mgr_instance *manager,
+ int critical, int warning)
+{
+ int new_state = next_state(manager->state, critical, warning);
+
+ /* Nothing changed */
+ if (new_state < 0)
+ return;
+
+ LOGP(DTEMP, LOGL_NOTICE, "Moving from state %s to %s.\n",
+ get_value_string(state_names, manager->state),
+ get_value_string(state_names, new_state));
+ manager->state = new_state;
+ switch (manager->state) {
+ case STATE_NORMAL:
+ execute_normal_act(manager);
+ break;
+ case STATE_WARNING_HYST:
+ /* do nothing? Maybe start to increase transmit power? */
+ break;
+ case STATE_WARNING:
+ execute_warning_act(manager);
+ break;
+ case STATE_CRITICAL:
+ execute_critical_act(manager);
+ break;
+ };
+}
+
+static void temp_ctrl_check()
+{
+ int rc;
+ int warn_thresh_passed = 0;
+ int crit_thresh_passed = 0;
+
+ LOGP(DTEMP, LOGL_DEBUG, "Going to check the temperature.\n");
+
+ /* Read the current digital temperature */
+ rc = sysmobts_temp_get(SYSMOBTS_TEMP_DIGITAL, SYSMOBTS_TEMP_INPUT);
+ if (rc < 0) {
+ LOGP(DTEMP, LOGL_ERROR,
+ "Failed to read the digital temperature. rc=%d\n", rc);
+ warn_thresh_passed = crit_thresh_passed = 1;
+ } else {
+ int temp = rc / 1000;
+ if (temp > s_mgr->digital_limit.thresh_warn)
+ warn_thresh_passed = 1;
+ if (temp > s_mgr->digital_limit.thresh_crit)
+ crit_thresh_passed = 1;
+ LOGP(DTEMP, LOGL_DEBUG, "Digital temperature is: %d\n", temp);
+ }
+
+ /* Read the current RF temperature */
+ rc = sysmobts_temp_get(SYSMOBTS_TEMP_RF, SYSMOBTS_TEMP_INPUT);
+ if (rc < 0) {
+ LOGP(DTEMP, LOGL_ERROR,
+ "Failed to read the RF temperature. rc=%d\n", rc);
+ warn_thresh_passed = crit_thresh_passed = 1;
+ } else {
+ int temp = rc / 1000;
+ if (temp > s_mgr->rf_limit.thresh_warn)
+ warn_thresh_passed = 1;
+ if (temp > s_mgr->rf_limit.thresh_crit)
+ crit_thresh_passed = 1;
+ LOGP(DTEMP, LOGL_DEBUG, "RF temperature is: %d\n", temp);
+ }
+
+ if (is_sbts2050_master()) {
+ int temp_pa, temp_board;
+
+ rc = sbts2050_uc_check_temp(&temp_pa, &temp_board);
+ if (rc != 0) {
+ /* XXX what do here? */
+ LOGP(DTEMP, LOGL_ERROR,
+ "Failed to read the temperature! Reboot?!\n");
+ warn_thresh_passed = 1;
+ crit_thresh_passed = 1;
+ } else {
+ LOGP(DTEMP, LOGL_DEBUG, "SBTS2050 board(%d) PA(%d)\n",
+ temp_board, temp_pa);
+ if (temp_pa > s_mgr->pa_limit.thresh_warn)
+ warn_thresh_passed = 1;
+ if (temp_pa > s_mgr->pa_limit.thresh_crit)
+ crit_thresh_passed = 1;
+ if (temp_board > s_mgr->board_limit.thresh_warn)
+ warn_thresh_passed = 1;
+ if (temp_board > s_mgr->board_limit.thresh_crit)
+ crit_thresh_passed = 1;
+ }
+ }
+
+ sysmobts_mgr_temp_handle(s_mgr, crit_thresh_passed, warn_thresh_passed);
+}
+
+static void temp_ctrl_check_cb(void *unused)
+{
+ temp_ctrl_check();
+ /* Check every two minutes? XXX make it configurable! */
+ osmo_timer_schedule(&temp_ctrl_timer, 2 * 60, 0);
+}
+
+int sysmobts_mgr_temp_init(struct sysmobts_mgr_instance *mgr)
+{
+ s_mgr = mgr;
+ temp_ctrl_timer.cb = temp_ctrl_check_cb;
+ temp_ctrl_check_cb(NULL);
+ return 0;
+}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c
index 1cabe44a..16373748 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c
@@ -39,6 +39,8 @@
#include "sysmobts_mgr.h"
#include "btsconfig.h"
+static struct sysmobts_mgr_instance *s_mgr;
+
static const char copyright[] =
"(C) 2012 by Harald Welte <laforge@gnumonks.org>\r\n"
"(C) 2014 by Holger Hans Peter Freyther\r\n"
@@ -52,6 +54,14 @@ static enum node_type go_to_parent(struct vty *vty)
case MGR_NODE:
vty->node = CONFIG_NODE;
break;
+ case ACT_WARN_NODE:
+ case ACT_CRIT_NODE:
+ case LIMIT_RF_NODE:
+ case LIMIT_DIGITAL_NODE:
+ case LIMIT_BOARD_NODE:
+ case LIMIT_PA_NODE:
+ vty->node = MGR_NODE;
+ break;
default:
vty->node = CONFIG_NODE;
}
@@ -62,6 +72,12 @@ static int is_config_node(struct vty *vty, int node)
{
switch (node) {
case MGR_NODE:
+ case ACT_WARN_NODE:
+ case ACT_CRIT_NODE:
+ case LIMIT_RF_NODE:
+ case LIMIT_DIGITAL_NODE:
+ case LIMIT_BOARD_NODE:
+ case LIMIT_PA_NODE:
return 1;
default:
return 0;
@@ -85,6 +101,42 @@ static struct cmd_node mgr_node = {
1,
};
+static struct cmd_node act_warn_node = {
+ ACT_WARN_NODE,
+ "%s(action-warn)# ",
+ 1,
+};
+
+static struct cmd_node act_crit_node = {
+ ACT_CRIT_NODE,
+ "%s(action-critical)# ",
+ 1,
+};
+
+static struct cmd_node limit_rf_node = {
+ LIMIT_RF_NODE,
+ "%s(limit-rf)# ",
+ 1,
+};
+
+static struct cmd_node limit_digital_node = {
+ LIMIT_DIGITAL_NODE,
+ "%s(limit-digital)# ",
+ 1,
+};
+
+static struct cmd_node limit_board_node = {
+ LIMIT_BOARD_NODE,
+ "%s(limit-board)# ",
+ 1,
+};
+
+static struct cmd_node limit_pa_node = {
+ LIMIT_PA_NODE,
+ "%s(limit-pa)# ",
+ 1,
+};
+
DEFUN(cfg_mgr, cfg_mgr_cmd,
"sysmobts-mgr",
MGR_STR)
@@ -93,9 +145,123 @@ DEFUN(cfg_mgr, cfg_mgr_cmd,
return CMD_SUCCESS;
}
+static void write_temp_limit(struct vty *vty, const char *name,
+ struct sysmobts_temp_limit *limit)
+{
+ vty_out(vty, " %s%s", name, VTY_NEWLINE);
+ vty_out(vty, " threshold warning %d%s",
+ limit->thresh_warn, VTY_NEWLINE);
+ vty_out(vty, " threshold critical %d%s",
+ limit->thresh_crit, VTY_NEWLINE);
+}
+
+static void write_action(struct vty *vty, const char *name, int actions)
+{
+ vty_out(vty, " %s%s", name, VTY_NEWLINE);
+#if 0
+ vty_out(vty, " %spower-control%s",
+ (actions & TEMP_ACT_PWR_CONTRL) ? "" : "no ", VTY_NEWLINE);
+
+ /* only on the sysmobts 2050 */
+ vty_out(vty, " %smaster-off%s",
+ (actions & TEMP_ACT_MASTER_OFF) ? "" : "no ", VTY_NEWLINE);
+ vty_out(vty, " %sslave-off%s",
+ (actions & TEMP_ACT_MASTER_OFF) ? "" : "no ", VTY_NEWLINE);
+#endif
+ vty_out(vty, " %spa-off%s",
+ (actions & TEMP_ACT_PA_OFF) ? "" : "no ", VTY_NEWLINE);
+}
+
+static int config_write_mgr(struct vty *vty)
+{
+ vty_out(vty, "sysmobts-mgr%s", VTY_NEWLINE);
+
+ write_temp_limit(vty, "limits rf", &s_mgr->rf_limit);
+ write_temp_limit(vty, "limits digital", &s_mgr->digital_limit);
+ write_temp_limit(vty, "limits board", &s_mgr->board_limit);
+ write_temp_limit(vty, "limits pa", &s_mgr->pa_limit);
+
+ write_action(vty, "actions warn", s_mgr->action_warn);
+ write_action(vty, "actions critical", s_mgr->action_crit);
+
+ return CMD_SUCCESS;
+}
+
+static int config_write_dummy(struct vty *vty)
+{
+ return CMD_SUCCESS;
+}
+
+#define CFG_LIMIT(name, expl, switch_to, variable) \
+DEFUN(cfg_limit_##name, cfg_limit_##name##_cmd, \
+ "limits " #name, \
+ "Configure Limits\n" expl) \
+{ \
+ vty->node = switch_to; \
+ vty->index = &s_mgr->variable; \
+ return CMD_SUCCESS; \
+}
+
+CFG_LIMIT(rf, "RF\n", LIMIT_RF_NODE, rf_limit)
+CFG_LIMIT(digital, "Digital\n", LIMIT_DIGITAL_NODE, digital_limit)
+CFG_LIMIT(board, "Board\n", LIMIT_BOARD_NODE, board_limit)
+CFG_LIMIT(pa, "Power Amplifier\n", LIMIT_PA_NODE, pa_limit)
+#undef CFG_LIMIT
+
+DEFUN(cfg_limit_warning, cfg_thresh_warning_cmd,
+ "threshold warning <0-200>",
+ "Threshold to reach\n" "Warning level\n" "Range\n")
+{
+ struct sysmobts_temp_limit *limit = vty->index;
+ limit->thresh_warn = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_limit_crit, cfg_thresh_crit_cmd,
+ "threshold critical <0-200>",
+ "Threshold to reach\n" "Severe level\n" "Range\n")
+{
+ struct sysmobts_temp_limit *limit = vty->index;
+ limit->thresh_crit = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+#define CFG_ACTION(name, expl, switch_to, variable) \
+DEFUN(cfg_action_##name, cfg_action_##name##_cmd, \
+ "actions " #name, \
+ "Configure Actions\n" expl) \
+{ \
+ vty->node = switch_to; \
+ vty->index = &s_mgr->variable; \
+ return CMD_SUCCESS; \
+}
+CFG_ACTION(warn, "Warning Actions\n", ACT_WARN_NODE, action_warn)
+CFG_ACTION(critical, "Critical Actions\n", ACT_CRIT_NODE, action_crit)
+#undef CFG_ACTION
+
+DEFUN(cfg_action_pa_off, cfg_action_pa_off_cmd,
+ "pa-off",
+ "Switch the Power Amplifier off\n")
+{
+ int *action = vty->index;
+ *action |= TEMP_ACT_PA_OFF;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_action_pa_off, cfg_no_action_pa_off_cmd,
+ "no pa-off",
+ NO_STR "Do not switch off the Power Amplifier\n")
+{
+ int *action = vty->index;
+ *action &= ~TEMP_ACT_PA_OFF;
+ return CMD_SUCCESS;
+}
+
DEFUN(show_mgr, show_mgr_cmd, "show manager",
SHOW_STR "Display information about the manager")
{
+ vty_out(vty, "Temperature control state: %s%s",
+ sysmobts_mgr_temp_get_state(s_mgr->state), VTY_NEWLINE);
vty_out(vty, "Current Temperatures%s", VTY_NEWLINE);
vty_out(vty, " Digital: %f Celcius%s",
sysmobts_temp_get(SYSMOBTS_TEMP_DIGITAL,
@@ -111,7 +277,7 @@ DEFUN(show_mgr, show_mgr_cmd, "show manager",
sbts2050_uc_check_temp(&temp_pa, &temp_board);
vty_out(vty, " sysmoBTS 2050 PA: %d Celcius%s", temp_pa, VTY_NEWLINE);
- vty_out(vty, " sysmoBTS 2050 PA: %d CelciusC%s", temp_board, VTY_NEWLINE);
+ vty_out(vty, " sysmoBTS 2050 PA: %d Celcius%s", temp_board, VTY_NEWLINE);
sbts2050_uc_get_status(&status);
vty_out(vty, "Power Status%s", VTY_NEWLINE);
@@ -138,10 +304,26 @@ DEFUN(show_mgr, show_mgr_cmd, "show manager",
return CMD_SUCCESS;
}
-static int config_write_mgr(struct vty *vty)
+static void register_limit(int limit)
{
- vty_out(vty, "sysmobts-mgr%s", VTY_NEWLINE);
- return CMD_SUCCESS;
+ install_element(limit, &cfg_thresh_warning_cmd);
+ install_element(limit, &cfg_thresh_crit_cmd);
+}
+
+static void register_action(int act)
+{
+#if 0
+ install_element(act, &cfg_action_pwr_contrl_cmd);
+ install_element(act, &cfg_no_action_pwr_contrl_cmd);
+
+ /* these only work on the sysmobts 2050 */
+ install_element(act, &cfg_action_master_off_cmd);
+ install_element(act, &cfg_no_action_master_off_cmd);
+ install_element(act, &cfg_action_slave_off_cmd);
+ install_element(act, &cfg_no_action_slave_off_cmd);
+#endif
+ install_element(act, &cfg_action_pa_off_cmd);
+ install_element(act, &cfg_no_action_pa_off_cmd);
}
int sysmobts_mgr_vty_init(void)
@@ -154,17 +336,50 @@ int sysmobts_mgr_vty_init(void)
install_element(CONFIG_NODE, &cfg_mgr_cmd);
vty_install_default(MGR_NODE);
+ /* install the limit nodes */
+ install_node(&limit_rf_node, config_write_dummy);
+ install_element(MGR_NODE, &cfg_limit_rf_cmd);
+ register_limit(LIMIT_RF_NODE);
+ vty_install_default(LIMIT_RF_NODE);
+
+ install_node(&limit_digital_node, config_write_dummy);
+ install_element(MGR_NODE, &cfg_limit_digital_cmd);
+ register_limit(LIMIT_DIGITAL_NODE);
+ vty_install_default(LIMIT_DIGITAL_NODE);
+
+ install_node(&limit_board_node, config_write_dummy);
+ install_element(MGR_NODE, &cfg_limit_board_cmd);
+ register_limit(LIMIT_BOARD_NODE);
+ vty_install_default(LIMIT_BOARD_NODE);
+
+ install_node(&limit_pa_node, config_write_dummy);
+ install_element(MGR_NODE, &cfg_limit_pa_cmd);
+ register_limit(LIMIT_PA_NODE);
+ vty_install_default(LIMIT_PA_NODE);
+
+ /* install the warning and critical node */
+ install_node(&act_warn_node, config_write_dummy);
+ install_element(MGR_NODE, &cfg_action_warn_cmd);
+ register_action(ACT_WARN_NODE);
+ vty_install_default(ACT_WARN_NODE);
+
+ install_node(&act_crit_node, config_write_dummy);
+ install_element(MGR_NODE, &cfg_action_critical_cmd);
+ register_action(ACT_CRIT_NODE);
+ vty_install_default(ACT_CRIT_NODE);
+
return 0;
}
-int sysmobts_mgr_parse_config(const char *config_file)
+int sysmobts_mgr_parse_config(struct sysmobts_mgr_instance *manager)
{
int rc;
- rc = vty_read_config_file(config_file, NULL);
+ s_mgr = manager;
+ rc = vty_read_config_file(s_mgr->config_file, NULL);
if (rc < 0) {
fprintf(stderr, "Failed to parse the config file: '%s'\n",
- config_file);
+ s_mgr->config_file);
return rc;
}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
index 94f73857..d996d644 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
@@ -42,10 +42,6 @@
#include "sysmobts_par.h"
#include "sysmobts_mgr.h"
-#ifdef BUILD_SBTS2050
-#include <sysmocom/femtobts/sbts2050_header.h>
-#endif
-
/*********************************************************************
* Temperature handling
*********************************************************************/
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h
index 9d1bb47b..8a6337e2 100644
--- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h
@@ -3,12 +3,6 @@
#include <stdint.h>
-/* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */
-#define TEMP_TIMER_SECS (6 * 3600)
-
-/* every 1 hours means 365*24 = 8760 EEprom writes per year (max) */
-#define HOURS_TIMER_SECS (1 * 3600)
-
enum sysmobts_temp_sensor {
SYSMOBTS_TEMP_DIGITAL = 1,
SYSMOBTS_TEMP_RF = 2,
@@ -37,6 +31,8 @@ enum sysmobts_firmware_type {
int sysmobts_firmware_reload(enum sysmobts_firmware_type type);
+int sysmobts_bts_type();
+int sysmobts_trx_number();
int is_sbts2050(void);
int is_sbts2050_trx(int);
int is_sbts2050_master(void);
@@ -59,9 +55,10 @@ struct sbts2050_power_status {
float pa_bias_voltage;
};
-void sbts2050_uc_check_temp(int *temp_pa, int *temp_board);
-void sbts2050_uc_set_power(int pmaster, int pslave, int ppa);
+int sbts2050_uc_check_temp(int *temp_pa, int *temp_board);
+int sbts2050_uc_set_power(int pmaster, int pslave, int ppa);
int sbts2050_uc_get_status(struct sbts2050_power_status *status);
+int sbts2050_uc_set_pa_power(int on_off);
void sbts2050_uc_initialize();
#endif