aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-trx/loops.c
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-03-26 09:05:14 +0100
committerHarald Welte <laforge@gnumonks.org>2015-09-22 16:41:27 +0200
commita7f5e077121f857e373b6e68c5fdf803933a12dc (patch)
tree57c91123c5757ef1a84e3f9bc7aeaa4ea9f3e18b /src/osmo-bts-trx/loops.c
parent5e2341411f25f4faa66ff9b4506e77d897b97daf (diff)
TRX: Support for AMR full speech
Diffstat (limited to 'src/osmo-bts-trx/loops.c')
-rw-r--r--src/osmo-bts-trx/loops.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/osmo-bts-trx/loops.c b/src/osmo-bts-trx/loops.c
index ee12e8bd..8b6844be 100644
--- a/src/osmo-bts-trx/loops.c
+++ b/src/osmo-bts-trx/loops.c
@@ -245,3 +245,100 @@ int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
return 0;
}
+int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
+ struct trx_chan_state *chan_state, float ber)
+{
+ struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)]
+ .lchan[l1sap_chan2ss(chan_nr)];
+ int c_i;
+
+ /* check if loop is enabled */
+ if (!chan_state->amr_loop)
+ return 0;
+
+ /* wait for MS to use the requested codec */
+ if (chan_state->ul_ft != chan_state->dl_cmr)
+ return 0;
+
+ /* count bit errors */
+ if (L1SAP_IS_CHAN_TCHH(chan_nr)) {
+ chan_state->ber_num += 2;
+ chan_state->ber_sum += (ber + ber);
+ } else {
+ chan_state->ber_num++;
+ chan_state->ber_sum += ber;
+ }
+
+ /* count frames */
+ if (chan_state->ber_num < 48)
+ return 0;
+
+ /* calculate average (reuse ber variable) */
+ ber = chan_state->ber_sum / chan_state->ber_num;
+
+ /* FIXME: calculate C/I from BER */
+ c_i = ber * 100;
+
+ /* reset bit errors */
+ chan_state->ber_num = 0;
+ chan_state->ber_sum = 0;
+
+ LOGP(DLOOP, LOGL_DEBUG, "Current bit error rate (BER) %.6f "
+ "codec id %d of trx=%u chan_nr=0x%02x\n", ber,
+ chan_state->ul_ft, l1h->trx->nr, chan_nr);
+
+ /* degrade */
+ if (chan_state->dl_cmr > 0) {
+ /* degrade, if ber is above threshold FIXME: C/I */
+ if (ber >
+ lchan->tch.amr_mr.mode[chan_state->dl_cmr-1].threshold_bts) {
+ LOGP(DLOOP, LOGL_DEBUG, "Degrading due to BER %.6f "
+ "from codec id %d to %d of trx=%u "
+ "chan_nr=0x%02x\n", ber, chan_state->dl_cmr,
+ chan_state->dl_cmr - 1, l1h->trx->nr, chan_nr);
+ chan_state->dl_cmr--;
+ }
+
+ return 0;
+ }
+
+ /* upgrade */
+ if (chan_state->dl_cmr < chan_state->codecs - 1) {
+ /* degrade, if ber is above threshold FIXME: C/I*/
+ if (ber <
+ lchan->tch.amr_mr.mode[chan_state->dl_cmr].threshold_bts
+ - lchan->tch.amr_mr.mode[chan_state->dl_cmr].hysteresis_bts) {
+ LOGP(DLOOP, LOGL_DEBUG, "Upgrading due to BER %.6f "
+ "from codec id %d to %d of trx=%u "
+ "chan_nr=0x%02x\n", ber, chan_state->dl_cmr,
+ chan_state->dl_cmr + 1, l1h->trx->nr, chan_nr);
+ chan_state->dl_cmr++;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop)
+{
+ if (chan_state->amr_loop && !loop) {
+ chan_state->amr_loop = 0;
+
+ return 0;
+ }
+
+ if (!chan_state->amr_loop && loop) {
+ chan_state->amr_loop = 1;
+
+ /* reset bit errors */
+ chan_state->ber_num = 0;
+ chan_state->ber_sum = 0;
+
+ return 0;
+ }
+
+ return 0;
+}
+