diff options
-rw-r--r-- | include/osmo-bts/Makefile.am | 2 | ||||
-rw-r--r-- | include/osmo-bts/amr.h | 14 | ||||
-rw-r--r-- | src/common/Makefile.am | 2 | ||||
-rw-r--r-- | src/common/amr.c | 115 | ||||
-rw-r--r-- | src/common/rsl.c | 100 |
5 files changed, 140 insertions, 93 deletions
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index ad9409e3..c734f14d 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,2 +1,2 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ - oml.h paging.h rsl.h signal.h vty.h + oml.h paging.h rsl.h signal.h vty.h amr.h diff --git a/include/osmo-bts/amr.h b/include/osmo-bts/amr.h new file mode 100644 index 00000000..059f2e03 --- /dev/null +++ b/include/osmo-bts/amr.h @@ -0,0 +1,14 @@ +#ifndef _OSMO_BTS_AMR_H +#define _OSMO_BTS_AMR_H + +#include <osmo-bts/gsm_data.h> + +void amr_log_mr_conf(int ss, int logl, const char *pfx, + struct amr_multirate_conf *amr_mrc); + +int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, + const uint8_t *mr_conf, unsigned int len); + +unsigned int amr_get_initial_mode(struct gsm_lchan *lchan); + +#endif /* _OSMO_BTS_AMR_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 8726b005..75cd7401 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -4,4 +4,4 @@ LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) noinst_LIBRARIES = libbts.a libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ - rsl.c vty.c paging.c measurement.c + rsl.c vty.c paging.c measurement.c amr.c diff --git a/src/common/amr.c b/src/common/amr.c new file mode 100644 index 00000000..eeb6e7f2 --- /dev/null +++ b/src/common/amr.c @@ -0,0 +1,115 @@ +#include <stdint.h> +#include <errno.h> + +#include <osmocom/core/logging.h> + +#include <osmo-bts/logging.h> +#include <osmo-bts/amr.h> + +void amr_log_mr_conf(int ss, int logl, const char *pfx, + struct amr_multirate_conf *amr_mrc) +{ + int i; + + LOGP(ss, logl, "%s AMR MR Conf: num_modes=%u", + pfx, amr_mrc->num_modes); + + for (i = 0; i < amr_mrc->num_modes; i++) + LOGPC(ss, logl, ", mode[%u] = %u/%u/%u", + i, amr_mrc->mode[i].mode, amr_mrc->mode[i].threshold, + amr_mrc->mode[i].hysteresis); + LOGPC(ss, logl, "\n"); +} + + +/* parse a GSM 04.08 MultiRate Config IE (10.5.2.21aa) in a more + * comfortable internal data structure */ +int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, + const uint8_t *mr_conf, unsigned int len) +{ + uint8_t mr_version = mr_conf[0] >> 5; + uint8_t num_codecs = 0; + int i, j = 0; + + if (mr_version != 1) { + LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknonw\n", + mr_version); + goto ret_einval; + } + + /* check number of active codecs */ + for (i = 0; i < 8; i++) { + if (mr_conf[1] & (1 << i)) + num_codecs++; + } + + /* check for minimum length */ + if (num_codecs == 0 || + (num_codecs == 1 && len < 2) || + (num_codecs == 2 && len < 4) || + (num_codecs == 3 && len < 5) || + (num_codecs == 4 && len < 6) || + (num_codecs > 4)) { + LOGP(DRSL, LOGL_ERROR, "AMR Multirate with %u modes len=%u " + "not possible\n", num_codecs, len); + goto ret_einval; + } + + /* copy the first two octets of the IE */ + amr_mrc->gsm48_ie[0] = mr_conf[0]; + amr_mrc->gsm48_ie[1] = mr_conf[1]; + + amr_mrc->num_modes = num_codecs; + + for (i = 0; i < 8; i++) { + if (mr_conf[1] & (1 << i)) { + amr_mrc->mode[j++].mode = i; + } + } + + if (num_codecs >= 2) { + amr_mrc->mode[0].threshold = mr_conf[1] & 0x3F; + amr_mrc->mode[0].hysteresis = mr_conf[2] >> 4; + } + if (num_codecs >= 3) { + amr_mrc->mode[1].threshold = + ((mr_conf[2] & 0xF) << 2) | (mr_conf[3] >> 6); + amr_mrc->mode[1].hysteresis = (mr_conf[3] >> 2) & 0x7; + } + if (num_codecs >= 4) { + amr_mrc->mode[3].threshold = + ((mr_conf[3] & 0x3) << 4) | (mr_conf[4] >> 4); + amr_mrc->mode[3].hysteresis = mr_conf[4] & 0xF; + } + + return num_codecs; + +ret_einval: + return -EINVAL; +} + + +unsigned int amr_get_initial_mode(struct gsm_lchan *lchan) +{ + struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr; + + if (lchan->mr_conf.icmi) { + /* initial mode given, coding in TS 05.09 3.4.1 */ + return amr_mrc->mode[lchan->mr_conf.smod].mode; + } else { + /* implicit rule according to TS 05.09 Chapter 3.4.3 */ + switch (amr_mrc->num_modes) { + case 2: + case 3: + /* return the most robust */ + return amr_mrc->mode[0].mode; + case 4: + /* return the second-most robust */ + return amr_mrc->mode[1].mode; + case 1: + default: + /* return the only mode we have */ + return amr_mrc->mode[0].mode; + } + } +} diff --git a/src/common/rsl.c b/src/common/rsl.c index db39f812..9dee4f75 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -38,6 +38,7 @@ #include <osmo-bts/bts.h> #include <osmo-bts/rsl.h> #include <osmo-bts/oml.h> +#include <osmo-bts/amr.h> #include <osmo-bts/signal.h> #include <osmo-bts/bts_model.h> #include <osmo-bts/measurement.h> @@ -121,89 +122,6 @@ static void lchan_tchmode_from_cmode(struct gsm_lchan *lchan, * support */ -static void log_mr_conf(int ss, int logl, const char *pfx, - struct amr_multirate_conf *amr_mrc) -{ - int i; - - LOGP(ss, logl, "%s AMR MR Conf: num_modes=%u", - pfx, amr_mrc->num_modes); - - for (i = 0; i < amr_mrc->num_modes; i++) - LOGPC(ss, logl, ", mode[%u] = %u/%u/%u", - i, amr_mrc->mode[i].mode, amr_mrc->mode[i].threshold, - amr_mrc->mode[i].hysteresis); - LOGPC(ss, logl, "\n"); -} - - -/* parse a GSM 04.08 MultiRate Config IE (10.5.2.21aa) in a more - * comfortable internal data structure */ -static int parse_mr_conf(struct amr_multirate_conf *amr_mrc, - const uint8_t *mr_conf, unsigned int len) -{ - uint8_t mr_version = mr_conf[0] >> 5; - uint8_t num_codecs = 0; - int i, j = 0; - - if (mr_version != 1) { - LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknonw\n", - mr_version); - goto ret_einval; - } - - /* check number of active codecs */ - for (i = 0; i < 8; i++) { - if (mr_conf[1] & (1 << i)) - num_codecs++; - } - - /* check for minimum length */ - if (num_codecs == 0 || - (num_codecs == 1 && len < 2) || - (num_codecs == 2 && len < 4) || - (num_codecs == 3 && len < 5) || - (num_codecs == 4 && len < 6) || - (num_codecs > 4)) { - LOGP(DRSL, LOGL_ERROR, "AMR Multirate with %u modes len=%u " - "not possible\n", num_codecs, len); - goto ret_einval; - } - - /* copy the first two octets of the IE */ - amr_mrc->gsm48_ie[0] = mr_conf[0]; - amr_mrc->gsm48_ie[1] = mr_conf[1]; - - amr_mrc->num_modes = num_codecs; - - for (i = 0; i < 8; i++) { - if (mr_conf[1] & (1 << i)) { - amr_mrc->mode[j++].mode = i; - } - } - - if (num_codecs >= 2) { - amr_mrc->mode[0].threshold = mr_conf[1] & 0x3F; - amr_mrc->mode[0].hysteresis = mr_conf[2] >> 4; - } - if (num_codecs >= 3) { - amr_mrc->mode[1].threshold = - ((mr_conf[2] & 0xF) << 2) | (mr_conf[3] >> 6); - amr_mrc->mode[1].hysteresis = (mr_conf[3] >> 2) & 0x7; - } - if (num_codecs >= 4) { - amr_mrc->mode[3].threshold = - ((mr_conf[3] & 0x3) << 4) | (mr_conf[4] >> 4); - amr_mrc->mode[3].hysteresis = mr_conf[4] & 0xF; - } - - return num_codecs; - -ret_einval: - return -EINVAL; -} - - #warning merge lchan_lookup with OpenBSC /* determine logical channel based on TRX and channel number IE */ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr) @@ -765,10 +683,10 @@ static int rsl_rx_chan_activ(struct msgb *msg) } memcpy(&lchan->mr_conf, TLVP_VAL(&tp, RSL_IE_MR_CONFIG), TLVP_LEN(&tp, RSL_IE_MR_CONFIG)); - parse_mr_conf(&lchan->tch.amr_mr, TLVP_VAL(&tp, RSL_IE_MR_CONFIG), - TLVP_LEN(&tp, RSL_IE_MR_CONFIG)); - log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), - &lchan->tch.amr_mr); + amr_parse_mr_conf(&lchan->tch.amr_mr, TLVP_VAL(&tp, RSL_IE_MR_CONFIG), + TLVP_LEN(&tp, RSL_IE_MR_CONFIG)); + amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), + &lchan->tch.amr_mr); } /* 9.3.53 MultiRate Control */ /* 9.3.54 Supported Codec Types */ @@ -1004,10 +922,10 @@ static int rsl_rx_mode_modif(struct msgb *msg) } memcpy(&lchan->mr_conf, TLVP_VAL(&tp, RSL_IE_MR_CONFIG), TLVP_LEN(&tp, RSL_IE_MR_CONFIG)); - parse_mr_conf(&lchan->tch.amr_mr, TLVP_VAL(&tp, RSL_IE_MR_CONFIG), - TLVP_LEN(&tp, RSL_IE_MR_CONFIG)); - log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), - &lchan->tch.amr_mr); + amr_parse_mr_conf(&lchan->tch.amr_mr, TLVP_VAL(&tp, RSL_IE_MR_CONFIG), + TLVP_LEN(&tp, RSL_IE_MR_CONFIG)); + amr_log_mr_conf(DRTP, LOGL_DEBUG, gsm_lchan_name(lchan), + &lchan->tch.amr_mr); } /* 9.3.53 MultiRate Control */ /* 9.3.54 Supported Codec Types */ |