Add full AMR multirate IE support with VTY config for MS and BTS side
This commit is contained in:
parent
354d1f3084
commit
732665269e
|
@ -40,7 +40,7 @@ struct bsc_api {
|
|||
* not implemented AMR5.9 will be used.
|
||||
*/
|
||||
void (*mr_config)(struct gsm_subscriber_connection *conn,
|
||||
struct gsm48_multi_rate_conf *conf);
|
||||
uint8_t *mr_ms_lv, uint8_t *mr_bts_lv);
|
||||
};
|
||||
|
||||
int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
|
||||
|
|
|
@ -13,6 +13,7 @@ struct gsm_subscriber;
|
|||
struct gsm_network;
|
||||
struct gsm_trans;
|
||||
struct gsm_subscriber_connection;
|
||||
struct amr_multirate_conf;
|
||||
|
||||
#define GSM48_ALLOC_SIZE 2048
|
||||
#define GSM48_ALLOC_HEADROOM 256
|
||||
|
@ -89,4 +90,6 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
|
|||
void release_security_operation(struct gsm_subscriber_connection *conn);
|
||||
void allocate_security_operation(struct gsm_subscriber_connection *conn);
|
||||
|
||||
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, int ms);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -150,8 +150,10 @@ struct bts_codec_conf {
|
|||
|
||||
struct amr_mode {
|
||||
uint8_t mode;
|
||||
uint8_t threshold;
|
||||
uint8_t hysteresis;
|
||||
uint8_t threshold_ms;
|
||||
uint8_t hysteresis_ms;
|
||||
uint8_t threshold_bts;
|
||||
uint8_t hysteresis_bts;
|
||||
};
|
||||
struct amr_multirate_conf {
|
||||
uint8_t gsm48_ie[2];
|
||||
|
@ -207,7 +209,8 @@ struct gsm_lchan {
|
|||
} encr;
|
||||
|
||||
/* AMR bits */
|
||||
struct gsm48_multi_rate_conf mr_conf;
|
||||
uint8_t mr_ms_lv[7];
|
||||
uint8_t mr_bts_lv[7];
|
||||
|
||||
/* Established data link layer services */
|
||||
uint8_t sapis[8];
|
||||
|
@ -732,6 +735,11 @@ struct gsm_bts {
|
|||
|
||||
/* BTS dependencies bit field */
|
||||
uint32_t depends_on[256/(8*4)];
|
||||
|
||||
/* full and half rate multirate config */
|
||||
struct amr_multirate_conf mr_full;
|
||||
struct amr_multirate_conf mr_half;
|
||||
|
||||
#endif /* ROLE_BSC */
|
||||
void *role;
|
||||
};
|
||||
|
|
|
@ -520,8 +520,8 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
|
|||
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
|
||||
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
|
||||
(uint8_t *) &lchan->mr_conf);
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, lchan->mr_bts_lv[0],
|
||||
lchan->mr_bts_lv + 1);
|
||||
|
||||
msg->dst = lchan->ts->trx->rsl_link;
|
||||
|
||||
|
@ -557,10 +557,11 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
|
|||
msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
|
||||
}
|
||||
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
|
||||
(uint8_t *) &lchan->mr_conf);
|
||||
}
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
{
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, lchan->mr_bts_lv[0],
|
||||
lchan->mr_bts_lv + 1);
|
||||
}
|
||||
|
||||
msg->dst = lchan->ts->trx->rsl_link;
|
||||
|
||||
|
|
|
@ -155,17 +155,31 @@ static void assignment_t10_timeout(void *_conn)
|
|||
* Handle the multirate config
|
||||
*/
|
||||
static void handle_mr_config(struct gsm_subscriber_connection *conn,
|
||||
struct gsm_lchan *lchan)
|
||||
struct gsm_lchan *lchan, int full_rate)
|
||||
{
|
||||
struct bsc_api *api;
|
||||
api = conn->bts->network->bsc_api;
|
||||
struct amr_multirate_conf *mr;
|
||||
struct gsm48_multi_rate_conf *mr_conf;
|
||||
|
||||
if (api->mr_config)
|
||||
return api->mr_config(conn, &lchan->mr_conf);
|
||||
return api->mr_config(conn, lchan->mr_ms_lv, lchan->mr_bts_lv);
|
||||
|
||||
lchan->mr_conf.ver = 1;
|
||||
lchan->mr_conf.icmi = 1;
|
||||
lchan->mr_conf.m5_90 = 1;
|
||||
if (full_rate)
|
||||
mr = &lchan->ts->trx->bts->mr_full;
|
||||
else
|
||||
mr = &lchan->ts->trx->bts->mr_half;
|
||||
|
||||
mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
mr_conf->ver = 1;
|
||||
|
||||
/* default, if no AMR codec defined */
|
||||
if (!mr->gsm48_ie[1]) {
|
||||
mr_conf->icmi = 1;
|
||||
mr_conf->m5_90 = 1;
|
||||
}
|
||||
gsm48_multirate_config(lchan->mr_ms_lv, mr, 1);
|
||||
gsm48_multirate_config(lchan->mr_bts_lv, mr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -209,7 +223,7 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
|
|||
|
||||
/* handle AMR correctly */
|
||||
if (chan_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
handle_mr_config(conn, new_lchan);
|
||||
handle_mr_config(conn, new_lchan, full_rate);
|
||||
|
||||
if (rsl_chan_activate_lchan(new_lchan, 0x1, 0) < 0) {
|
||||
LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
|
||||
|
@ -382,7 +396,7 @@ int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, in
|
|||
LOGP(DMSC, LOGL_NOTICE,
|
||||
"Sending ChanModify for speech %d %d\n", chan_mode, full_rate);
|
||||
if (chan_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
handle_mr_config(conn, conn->lchan);
|
||||
handle_mr_config(conn, conn->lchan, full_rate);
|
||||
|
||||
gsm48_lchan_modify(conn->lchan, chan_mode);
|
||||
}
|
||||
|
|
|
@ -479,6 +479,66 @@ static void config_write_bts_model(struct vty *vty, struct gsm_bts *bts)
|
|||
config_write_trx_single(vty, trx);
|
||||
}
|
||||
|
||||
static void config_write_bts_amr(struct vty *vty, struct gsm_bts *bts,
|
||||
struct amr_multirate_conf *mr, int full)
|
||||
{
|
||||
struct gsm48_multi_rate_conf *mr_conf;
|
||||
const char *prefix = (full) ? "amr tch-f" : "amr tch-h";
|
||||
int i, num;
|
||||
|
||||
if (!(mr->gsm48_ie[1]))
|
||||
return;
|
||||
|
||||
mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
|
||||
num = 0;
|
||||
vty_out(vty, " %s modes", prefix);
|
||||
for (i = 0; i < ((full) ? 8 : 6); i++) {
|
||||
if ((mr->gsm48_ie[1] & (1 << i))) {
|
||||
vty_out(vty, " %d", i);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
if (num > 4)
|
||||
num = 4;
|
||||
if (num > 1) {
|
||||
vty_out(vty, " %s threshold ms", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].threshold_ms);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %s hysteresis ms", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].hysteresis_ms);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %s threshold bts", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].threshold_bts);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %s hysteresis bts", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].hysteresis_bts);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
vty_out(vty, " %s start-mode ", prefix);
|
||||
if (mr_conf->icmi) {
|
||||
num = 0;
|
||||
for (i = 0; i < ((full) ? 8 : 6) && num < 4; i++) {
|
||||
if ((mr->gsm48_ie[1] & (1 << i)))
|
||||
num++;
|
||||
if (mr_conf->smod == num - 1) {
|
||||
vty_out(vty, "%d%s", num, VTY_NEWLINE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
vty_out(vty, "auto%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
{
|
||||
int i;
|
||||
|
@ -646,6 +706,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
|||
vty_out(vty, " amr");
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
|
||||
config_write_bts_amr(vty, bts, &bts->mr_full, 1);
|
||||
config_write_bts_amr(vty, bts, &bts->mr_half, 0);
|
||||
|
||||
config_write_bts_gprs(vty, bts);
|
||||
|
||||
if (bts->excl_from_rf_lock)
|
||||
|
@ -2865,6 +2928,288 @@ DEFUN(cfg_bts_no_depends_on, cfg_bts_no_depends_on_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define AMR_TEXT "Adaptive Multi Rate settings\n"
|
||||
#define AMR_MODE_TEXT "Codec modes to use with AMR codec\n"
|
||||
#define AMR_START_TEXT "Initial codec to use with AMR\n" \
|
||||
"Automatically\nFirst codec\nSecond codec\nThird codec\nFourth codec\n"
|
||||
#define AMR_TH_TEXT "AMR threshold between codecs\nMS side\nBTS side\n"
|
||||
#define AMR_HY_TEXT "AMR hysteresis between codecs\nMS side\nBTS side\n"
|
||||
|
||||
static void get_amr_from_arg(struct vty *vty, int argc, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
struct gsm48_multi_rate_conf *mr_conf =
|
||||
(struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
int i;
|
||||
|
||||
mr->gsm48_ie[1] = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
mr->gsm48_ie[1] |= 1 << atoi(argv[i]);
|
||||
mr_conf->icmi = 0;
|
||||
}
|
||||
|
||||
static void get_amr_th_from_arg(struct vty *vty, int argc, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
int i;
|
||||
|
||||
if (argv[0][0]=='m') {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].threshold_ms = atoi(argv[i + 1]);
|
||||
} else {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].threshold_bts = atoi(argv[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_amr_hy_from_arg(struct vty *vty, int argc, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
int i;
|
||||
|
||||
if (argv[0][0]=='m') {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].hysteresis_ms = atoi(argv[i + 1]);
|
||||
} else {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].hysteresis_bts = atoi(argv[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_amr_start_from_arg(struct vty *vty, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
struct gsm48_multi_rate_conf *mr_conf =
|
||||
(struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
int num = 0, i;
|
||||
|
||||
for (i = 0; i < ((full) ? 8 : 6); i++) {
|
||||
if ((mr->gsm48_ie[1] & (1 << i))) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[0][0] == 'a' || num == 0)
|
||||
mr_conf->icmi = 0;
|
||||
else {
|
||||
mr_conf->icmi = 1;
|
||||
if (num < atoi(argv[0]))
|
||||
mr_conf->smod = num - 1;
|
||||
else
|
||||
mr_conf->smod = atoi(argv[0]) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define AMR_TCHF_PAR_STR " (0|1|2|3|4|5|6|7)"
|
||||
#define AMR_TCHF_HELP_STR "4,75k\n5,15k\n5,90k\n6,70k\n7,40k\n7,95k\n" \
|
||||
"10,2k\n12,2k\n"
|
||||
|
||||
#define AMR_TCHH_PAR_STR " (0|1|2|3|4|5)"
|
||||
#define AMR_TCHH_HELP_STR "4,75k\n5,15k\n5,90k\n6,70k\n7,40k\n7,95k\n"
|
||||
|
||||
#define AMR_TH_HELP_STR "Threshold between codec 1 and 2\n"
|
||||
#define AMR_HY_HELP_STR "Hysteresis between codec 1 and 2\n"
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes1, cfg_bts_amr_fr_modes1_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 1, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes2, cfg_bts_amr_fr_modes2_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 2, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes3, cfg_bts_amr_fr_modes3_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 3, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes4, cfg_bts_amr_fr_modes4_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 4, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_start_mode, cfg_bts_amr_fr_start_mode_cmd,
|
||||
"amr tch-f start-mode (auto|1|2|3|4)",
|
||||
AMR_TEXT "Full Rate\n" AMR_START_TEXT)
|
||||
{
|
||||
get_amr_start_from_arg(vty, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_thres1, cfg_bts_amr_fr_thres1_cmd,
|
||||
"amr tch-f threshold (ms|bts) <0-63>",
|
||||
AMR_TEXT "Full Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 2, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_thres2, cfg_bts_amr_fr_thres2_cmd,
|
||||
"amr tch-f threshold (ms|bts) <0-63> <0-63>",
|
||||
AMR_TEXT "Full Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 3, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_thres3, cfg_bts_amr_fr_thres3_cmd,
|
||||
"amr tch-f threshold (ms|bts) <0-63> <0-63> <0-63>",
|
||||
AMR_TEXT "Full Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 4, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_hyst1, cfg_bts_amr_fr_hyst1_cmd,
|
||||
"amr tch-f hysteresis (ms|bts) <0-15>",
|
||||
AMR_TEXT "Full Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 2, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_hyst2, cfg_bts_amr_fr_hyst2_cmd,
|
||||
"amr tch-f hysteresis (ms|bts) <0-15> <0-15>",
|
||||
AMR_TEXT "Full Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 3, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_hyst3, cfg_bts_amr_fr_hyst3_cmd,
|
||||
"amr tch-f hysteresis (ms|bts) <0-15> <0-15> <0-15>",
|
||||
AMR_TEXT "Full Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 4, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes1, cfg_bts_amr_hr_modes1_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 1, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes2, cfg_bts_amr_hr_modes2_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 2, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes3, cfg_bts_amr_hr_modes3_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 3, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes4, cfg_bts_amr_hr_modes4_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 4, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_start_mode, cfg_bts_amr_hr_start_mode_cmd,
|
||||
"amr tch-h start-mode (auto|1|2|3|4)",
|
||||
AMR_TEXT "Half Rate\n" AMR_START_TEXT)
|
||||
{
|
||||
get_amr_start_from_arg(vty, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_thres1, cfg_bts_amr_hr_thres1_cmd,
|
||||
"amr tch-h threshold (ms|bts) <0-63>",
|
||||
AMR_TEXT "Half Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 2, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_thres2, cfg_bts_amr_hr_thres2_cmd,
|
||||
"amr tch-h threshold (ms|bts) <0-63> <0-63>",
|
||||
AMR_TEXT "Half Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 3, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_thres3, cfg_bts_amr_hr_thres3_cmd,
|
||||
"amr tch-h threshold (ms|bts) <0-63> <0-63> <0-63>",
|
||||
AMR_TEXT "Half Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 4, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_hyst1, cfg_bts_amr_hr_hyst1_cmd,
|
||||
"amr tch-h hysteresis (ms|bts) <0-15>",
|
||||
AMR_TEXT "Half Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 2, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_hyst2, cfg_bts_amr_hr_hyst2_cmd,
|
||||
"amr tch-h hysteresis (ms|bts) <0-15> <0-15>",
|
||||
AMR_TEXT "Half Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 3, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_hyst3, cfg_bts_amr_hr_hyst3_cmd,
|
||||
"amr tch-h hysteresis (ms|bts) <0-15> <0-15> <0-15>",
|
||||
AMR_TEXT "Half Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 4, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define TRX_TEXT "Radio Transceiver\n"
|
||||
|
||||
/* per TRX configuration */
|
||||
|
@ -3511,6 +3856,28 @@ int bsc_vty_init(const struct log_info *cat)
|
|||
install_element(BTS_NODE, &cfg_bts_codec4_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_depends_on_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_depends_on_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes4_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_thres1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_thres2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_thres3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_hyst1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_hyst2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_hyst3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_start_mode_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes4_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_thres1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_thres2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_thres3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd);
|
||||
|
||||
install_element(BTS_NODE, &cfg_trx_cmd);
|
||||
install_node(&trx_node, dummy_config_write);
|
||||
|
|
|
@ -197,8 +197,8 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
|
|||
memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
|
||||
|
||||
/* clear multi rate config */
|
||||
memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
|
||||
|
||||
memset(&lchan->mr_ms_lv, 0, sizeof(lchan->mr_ms_lv));
|
||||
memset(&lchan->mr_bts_lv, 0, sizeof(lchan->mr_bts_lv));
|
||||
lchan->broken_reason = "";
|
||||
} else {
|
||||
struct challoc_signal_data sig;
|
||||
|
|
|
@ -357,6 +357,60 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
|
|||
}
|
||||
}
|
||||
|
||||
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, int ms)
|
||||
{
|
||||
int num = 0, i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (((mr->gsm48_ie[1] >> i) & 1))
|
||||
num++;
|
||||
}
|
||||
if (num > 4) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec with too "
|
||||
"many modes in config.\n");
|
||||
num = 4;
|
||||
}
|
||||
if (num < 1) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec with no "
|
||||
"mode in config.\n");
|
||||
num = 1;
|
||||
}
|
||||
|
||||
lv[0] = (num == 1) ? 2 : (num + 2);
|
||||
memcpy(lv + 1, mr->gsm48_ie, 2);
|
||||
if (num == 1)
|
||||
return 0;
|
||||
if (ms) {
|
||||
lv[3] = mr->mode[0].threshold_ms & 0x3f;
|
||||
lv[4] = mr->mode[0].hysteresis_ms << 4;
|
||||
if (num == 2)
|
||||
return 0;
|
||||
lv[4] |= (mr->mode[1].threshold_ms & 0x3f) >> 2;
|
||||
lv[5] = mr->mode[1].threshold_ms << 6;
|
||||
lv[5] |= (mr->mode[1].hysteresis_ms & 0x0f) << 2;
|
||||
if (num == 3)
|
||||
return 0;
|
||||
lv[5] |= (mr->mode[2].threshold_ms & 0x3f) >> 4;
|
||||
lv[6] = mr->mode[2].threshold_ms << 4;
|
||||
lv[6] |= mr->mode[2].hysteresis_ms & 0x0f;
|
||||
} else {
|
||||
lv[3] = mr->mode[0].threshold_bts & 0x3f;
|
||||
lv[4] = mr->mode[0].hysteresis_bts << 4;
|
||||
if (num == 2)
|
||||
return 0;
|
||||
lv[4] |= (mr->mode[1].threshold_bts & 0x3f) >> 2;
|
||||
lv[5] = mr->mode[1].threshold_bts << 6;
|
||||
lv[5] |= (mr->mode[1].hysteresis_bts & 0x0f) << 2;
|
||||
if (num == 3)
|
||||
return 0;
|
||||
lv[5] |= (mr->mode[2].threshold_bts & 0x3f) >> 4;
|
||||
lv[6] = mr->mode[2].threshold_bts << 4;
|
||||
lv[6] |= mr->mode[2].hysteresis_bts & 0x0f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GSM48_HOCMD_CCHDESC_LEN 16
|
||||
|
||||
/* Chapter 9.1.15: Handover Command */
|
||||
|
@ -435,17 +489,9 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan,
|
|||
}
|
||||
|
||||
/* in case of multi rate we need to attach a config */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (lchan->mr_conf.ver == 0) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
|
||||
"without multirate config.\n");
|
||||
} else {
|
||||
uint8_t *data = msgb_put(msg, 4);
|
||||
data[0] = GSM48_IE_MUL_RATE_CFG;
|
||||
data[1] = 0x2;
|
||||
memcpy(&data[2], &lchan->mr_conf, 2);
|
||||
}
|
||||
}
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, lchan->mr_ms_lv[0],
|
||||
lchan->mr_ms_lv + 1);
|
||||
|
||||
return gsm48_sendmsg(msg);
|
||||
}
|
||||
|
@ -471,17 +517,9 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, uint8_t mode)
|
|||
cmm->mode = mode;
|
||||
|
||||
/* in case of multi rate we need to attach a config */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (lchan->mr_conf.ver == 0) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
|
||||
"without multirate config.\n");
|
||||
} else {
|
||||
uint8_t *data = msgb_put(msg, 4);
|
||||
data[0] = GSM48_IE_MUL_RATE_CFG;
|
||||
data[1] = 0x2;
|
||||
memcpy(&data[2], &lchan->mr_conf, 2);
|
||||
}
|
||||
}
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, lchan->mr_ms_lv[0],
|
||||
lchan->mr_ms_lv + 1);
|
||||
|
||||
return gsm48_sendmsg(msg);
|
||||
}
|
||||
|
|
|
@ -133,7 +133,8 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
|
|||
new_lchan->bs_power = old_lchan->bs_power;
|
||||
new_lchan->rsl_cmode = old_lchan->rsl_cmode;
|
||||
new_lchan->tch_mode = old_lchan->tch_mode;
|
||||
new_lchan->mr_conf = old_lchan->mr_conf;
|
||||
memcpy(&new_lchan->mr_ms_lv, &old_lchan->mr_ms_lv, ARRAY_SIZE(new_lchan->mr_ms_lv));
|
||||
memcpy(&new_lchan->mr_bts_lv, &old_lchan->mr_bts_lv, ARRAY_SIZE(new_lchan->mr_bts_lv));
|
||||
|
||||
new_lchan->conn = old_lchan->conn;
|
||||
new_lchan->conn->ho_lchan = new_lchan;
|
||||
|
|
Loading…
Reference in New Issue