summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-06-20 18:15:19 +0200
committerHarald Welte <laforge@gnumonks.org>2009-06-20 19:22:18 +0200
commitfcd2445d05e24c20310790ef0041c8cbe6e6546d (patch)
tree7cde37b69818798fa0cb712401854f3c358f9ac6
parenta865f1b0c99b3c3ed2d0bb5973738024b62630cc (diff)
Introduce BS and MS power control related functions
* add bts->band field plus corresponding VTY and commandline argument * add trx->nominal_power and trx->max_power_red fields * add rsl_chan_bs_power_ctrl() to control TRX RF power for a given TS * add rsl_chan_ms_power_ctrl() to control MS RF power for a given lchan.
-rw-r--r--openbsc/include/openbsc/abis_rsl.h3
-rw-r--r--openbsc/include/openbsc/gsm_data.h14
-rw-r--r--openbsc/src/abis_rsl.c89
-rw-r--r--openbsc/src/bsc_hack.c11
-rw-r--r--openbsc/src/gsm_data.c37
-rw-r--r--openbsc/src/vty_interface.c64
6 files changed, 212 insertions, 6 deletions
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index 532595b90..c928ffa2d 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -411,5 +411,8 @@ int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf);
int rsl_number_of_paging_subchannels(struct gsm_bts *bts);
+int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db);
+int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm);
+
#endif /* RSL_MT_H */
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index a401a4780..8c44ba54d 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -3,6 +3,14 @@
#include <sys/types.h>
+enum gsm_band {
+ GSM_BAND_400,
+ GSM_BAND_850,
+ GSM_BAND_900,
+ GSM_BAND_1800,
+ GSM_BAND_1900,
+};
+
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
@@ -223,6 +231,8 @@ struct gsm_bts_trx {
} bb_transc;
u_int16_t arfcn;
+ int nominal_power; /* in dBm */
+ unsigned int max_power_red; /* in actual dB */
union {
struct {
@@ -301,6 +311,7 @@ struct gsm_bts {
u_int8_t bsic;
/* type of BTS */
enum gsm_bts_type type;
+ enum gsm_band band;
/* how do we talk OML with this TRX? */
struct e1inp_sign_link *oml_link;
@@ -396,6 +407,9 @@ const char *btstype2str(enum gsm_bts_type type);
struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
struct gsm_bts *start_bts);
+char *gsm_band_name(enum gsm_band band);
+enum gsm_band gsm_band_parse(int mhz);
+
static inline int is_ipaccess_bts(struct gsm_bts *bts)
{
switch (bts->type) {
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 4b2a7fccf..5c1967d38 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -356,6 +356,95 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type,
return abis_rsl_sendmsg(msg);
}
+int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db)
+{
+ struct abis_rsl_dchan_hdr *dh;
+ struct msgb *msg = rsl_msgb_alloc();
+ u_int8_t chan_nr = lchan2chan_nr(lchan);
+
+ db = abs(db);
+ if (db > 30)
+ return -EINVAL;
+
+ lchan->bs_power = db/2;
+ if (fpc)
+ lchan->bs_power |= 0x10;
+
+ dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
+ init_dchan_hdr(dh, RSL_MT_BS_POWER_CONTROL);
+ dh->chan_nr = chan_nr;
+
+ msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
+
+ msg->trx = lchan->ts->trx;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+/* determine power control level for given dBm value, as indicated
+ * by the tables in chapter 4.1.1 of GSM TS 05.05 */
+static int ms_pwr_ctl_lvl(struct gsm_bts *bts, unsigned int dbm)
+{
+ switch (bts->band) {
+ case GSM_BAND_400:
+ case GSM_BAND_900:
+ case GSM_BAND_850:
+ if (dbm >= 39)
+ return 0;
+ else if (dbm < 5)
+ return 19;
+ else
+ return 2 + ((39 - dbm) / 2);
+ break;
+ case GSM_BAND_1800:
+ if (dbm >= 36)
+ return 29;
+ else if (dbm >= 34)
+ return 30;
+ else if (dbm >= 32)
+ return 31;
+ else
+ return (30 - dbm) / 2;
+ break;
+ case GSM_BAND_1900:
+ if (dbm >= 33)
+ return 30;
+ else if (dbm >= 32)
+ return 31;
+ else
+ return (30 - dbm) / 2;
+ break;
+ }
+ return -EINVAL;
+}
+
+int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm)
+{
+ struct abis_rsl_dchan_hdr *dh;
+ struct msgb *msg = rsl_msgb_alloc();
+ u_int8_t chan_nr = lchan2chan_nr(lchan);
+ int ctl_lvl;
+
+ ctl_lvl = ms_pwr_ctl_lvl(lchan->ts->trx->bts, dbm);
+ if (ctl_lvl < 0)
+ return ctl_lvl;
+
+ lchan->ms_power = ctl_lvl;
+
+ if (fpc)
+ lchan->ms_power |= 0x20;
+
+ dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
+ init_dchan_hdr(dh, RSL_MT_MS_POWER_CONTROL);
+ dh->chan_nr = chan_nr;
+
+ msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
+
+ msg->trx = lchan->ts->trx;
+
+ return abis_rsl_sendmsg(msg);
+}
+
/* Chapter 8.4.1 */
#if 0
int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 0322ff793..43f1011c7 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -59,6 +59,7 @@ static int ARFCN = HARDCODED_ARFCN;
static int cardnr = 0;
static int release_l2 = 0;
static enum gsm_bts_type BTS_TYPE = GSM_BTS_TYPE_BS11;
+static enum gsm_band BAND = GSM_BAND_900;
static const char *database_name = "hlr.sqlite3";
/* The following definitions are for OM and NM packets that we cannot yet
@@ -927,6 +928,7 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
static int bootstrap_bts(struct gsm_bts *bts)
{
+ bts->band = BAND;
bts->location_area_code = LAC;
bts->trx[0].arfcn = ARFCN;
@@ -1027,6 +1029,7 @@ static int bootstrap_network(void)
/* FIXME: do this dynamic */
bts->ip_access.site_id = 1801;
bts->ip_access.bts_id = 0;
+
bts = &gsmnet->bts[1];
bootstrap_bts(bts);
bts->ip_access.site_id = 1800;
@@ -1075,7 +1078,7 @@ static void print_help()
static void handle_options(int argc, char** argv)
{
while (1) {
- int option_index = 0, c;
+ int tmp, option_index = 0, c;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"debug", 1, 0, 'd'},
@@ -1092,10 +1095,11 @@ static void handle_options(int argc, char** argv)
{"cardnr", 1, 0, 'C'},
{"release-l2", 0, 0, 'R'},
{"timestamp", 0, 0, 'T'},
+ {"band", 0, 0, 'b'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:T",
+ c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:",
long_options, &option_index);
if (c == -1)
break;
@@ -1147,6 +1151,9 @@ static void handle_options(int argc, char** argv)
case 'T':
debug_timestamp(1);
break;
+ case 'b':
+ BAND = gsm_band_parse(atoi(optarg));
+ break;
default:
/* ignore */
break;
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index e71a6cb0d..80020e509 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include <openbsc/gsm_data.h>
@@ -213,3 +214,39 @@ struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
}
return NULL;
}
+
+char *gsm_band_name(enum gsm_band band)
+{
+ switch (band) {
+ case GSM_BAND_400:
+ return "GSM 400";
+ case GSM_BAND_850:
+ return "GSM 850";
+ case GSM_BAND_900:
+ return "GSM 900";
+ case GSM_BAND_1800:
+ return "DCS 1800";
+ case GSM_BAND_1900:
+ return "PCS 1900";
+ }
+ return "invalid";
+}
+
+enum gsm_band gsm_band_parse(int mhz)
+{
+ switch (mhz) {
+ case 400:
+ return GSM_BAND_400;
+ case 850:
+ return GSM_BAND_850;
+ case 900:
+ return GSM_BAND_900;
+ case 1800:
+ return GSM_BAND_1800;
+ case 1900:
+ return GSM_BAND_1900;
+ default:
+ return -EINVAL;
+ }
+}
+
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 6597e440f..a2b3e5620 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -112,9 +112,11 @@ static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
{
- vty_out(vty, "BTS %u is of %s type, has LAC %u, BSIC %u, TSC %u and %u TRX%s",
- bts->nr, btstype2str(bts->type), bts->location_area_code,
- bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE);
+ vty_out(vty, "BTS %u is of %s type in band %s, has LAC %u, "
+ "BSIC %u, TSC %u and %u TRX%s",
+ bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
+ bts->location_area_code, bts->bsic, bts->tsc,
+ bts->num_trx, VTY_NEWLINE);
if (is_ipaccess_bts(bts))
vty_out(vty, " Unit ID: %u/%u/0%s",
bts->ip_access.site_id, bts->ip_access.bts_id,
@@ -159,6 +161,10 @@ static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
{
vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
trx->nr, trx->bts->nr, trx->arfcn, VTY_NEWLINE);
+ vty_out(vty, " RF Nominal Power: %d dBm, reduced by %u dB, "
+ "resulting BS power: %d dBm\n",
+ trx->nominal_power, trx->max_power_red,
+ trx->nominal_power - trx->max_power_red);
vty_out(vty, " NM State: ");
net_dump_nmstate(vty, &trx->nm_state);
vty_out(vty, " Baseband Transceiver NM State: ");
@@ -297,7 +303,7 @@ DEFUN(show_ts,
static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
{
- vty_out(vty, " ID: %lu, Authorized: %d%s", subscr->id,
+ vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
subscr->authorized, VTY_NEWLINE);
if (subscr->name)
vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
@@ -628,10 +634,30 @@ DEFUN(cfg_bts_type,
{
struct gsm_bts *bts = vty->index;
+ /* FIXME: implementation */
//bts->type =
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_band,
+ cfg_bts_band_cmd,
+ "band BAND",
+ "Set the frequency band of this BTS\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int band = gsm_band_parse(atoi(argv[0]));
+
+ if (band < 0) {
+ vty_out(vty, "%% BAND %d is not a valid GSM band%s",
+ band, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->band = band;
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_bts_lac,
cfg_bts_lac_cmd,
"location_area_code <0-255>",
@@ -758,6 +784,34 @@ DEFUN(cfg_trx_arfcn,
return CMD_SUCCESS;
}
+DEFUN(cfg_trx_max_power_red,
+ cfg_trx_max_power_red_cmd,
+ "max_power_red <0-100>",
+ "Reduction of maximum BS RF Power in dB\n")
+{
+ int maxpwr_r = atoi(argv[0]);
+ struct gsm_bts_trx *trx = vty->index;
+ int upper_limit = 12; /* default 12.21 max power red. */
+
+ /* FIXME: check if our BTS type supports more than 12 */
+ if (maxpwr_r < 0 || maxpwr_r > upper_limit) {
+ vty_out(vty, "%% Power %d dB is not in the valid range%s",
+ maxpwr_r, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (maxpwr_r & 1) {
+ vty_out(vty, "%% Power %d dB is not an even value%s",
+ maxpwr_r, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ trx->max_power_red = maxpwr_r;
+
+ /* FIXME: make sure we update this using OML */
+
+ return CMD_SUCCESS;
+}
+
/* per TS configuration */
DEFUN(cfg_ts,
cfg_ts_cmd,
@@ -884,6 +938,7 @@ int bsc_vty_init(struct gsm_network *net)
install_node(&bts_node, dummy_config_write);
install_default(BTS_NODE);
install_element(BTS_NODE, &cfg_bts_type_cmd);
+ install_element(BTS_NODE, &cfg_bts_band_cmd);
install_element(BTS_NODE, &cfg_bts_lac_cmd);
install_element(BTS_NODE, &cfg_bts_tsc_cmd);
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
@@ -892,6 +947,7 @@ int bsc_vty_init(struct gsm_network *net)
install_node(&trx_node, dummy_config_write);
install_default(TRX_NODE);
install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
+ install_element(TRX_NODE, &cfg_trx_max_power_red);
install_element(TRX_NODE, &cfg_ts_cmd);
install_node(&ts_node, dummy_config_write);