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.
This commit is contained in:
Harald Welte 2009-06-20 18:15:19 +02:00
parent a865f1b0c9
commit fcd2445d05
6 changed files with 212 additions and 6 deletions

View File

@ -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 */

View File

@ -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) {

View File

@ -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,

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);