fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/27802 )
Change subject: osmo-bts-trx: move tx_tch_common() into a separate file ......................................................................
osmo-bts-trx: move tx_tch_common() into a separate file
Having this function defined as 'static inline' in a header file would allow the compiler to optimize it better for particular caller.
Change-Id: Id0b9d604e6969a8db73ef451fbcad00f57325fc4 Related: SYS#5919, OS#4823 --- M src/osmo-bts-trx/Makefile.am M src/osmo-bts-trx/sched_lchan_tchf.c M src/osmo-bts-trx/sched_lchan_tchh.c A src/osmo-bts-trx/sched_tch.h 4 files changed, 218 insertions(+), 196 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/02/27802/1
diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am index f6094dd..b7a4e8b 100644 --- a/src/osmo-bts-trx/Makefile.am +++ b/src/osmo-bts-trx/Makefile.am @@ -30,6 +30,7 @@
noinst_HEADERS = \ sched_utils.h \ + sched_tch.h \ trx_if.h \ l1_if.h \ amr_loop.h \ diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c index 8ca0961..e6e1eff 100644 --- a/src/osmo-bts-trx/sched_lchan_tchf.c +++ b/src/osmo-bts-trx/sched_lchan_tchf.c @@ -43,6 +43,7 @@ #include <osmo-bts/msg_utils.h>
#include <sched_utils.h> +#include <sched_tch.h> #include <amr_loop.h>
/* 3GPP TS 45.009, table 3.2.1.3-{1,3}: AMR on Uplink TCH/F. @@ -319,196 +320,6 @@ meas_avg.ci_cb, is_sub); }
-/* common section for generation of TCH bursts (TCH/H and TCH/F). - * FIXME: this function is over-complicated, refactor / get rid of it. */ -void tx_tch_common(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br, - struct msgb **_msg_tch, struct msgb **_msg_facch) -{ - struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL; - struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan]; - uint8_t rsl_cmode = chan_state->rsl_cmode; - uint8_t tch_mode = chan_state->tch_mode; - struct osmo_phsap_prim *l1sap; - - /* handle loss detection of received TCH frames */ - if (rsl_cmode == RSL_CMOD_SPD_SPEECH - && ++(chan_state->lost_frames) > 5) { - uint8_t tch_data[GSM_FR_BYTES]; - int len; - - LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Missing TCH bursts detected, sending BFI\n"); - - /* indicate bad frame */ - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR / HR */ - if (br->chan != TRXC_TCHF) { /* HR */ - tch_data[0] = 0x70; /* F = 0, FT = 111 */ - memset(tch_data + 1, 0, 14); - len = 15; - break; - } - memset(tch_data, 0, GSM_FR_BYTES); - len = GSM_FR_BYTES; - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - if (br->chan != TRXC_TCHF) - goto inval_mode1; - memset(tch_data, 0, GSM_EFR_BYTES); - len = GSM_EFR_BYTES; - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - len = osmo_amr_rtp_enc(tch_data, - chan_state->codec[chan_state->dl_cmr], - chan_state->codec[chan_state->dl_ft], AMR_BAD); - if (len < 2) { - LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, - "Failed to encode AMR_BAD frame (rc=%d), " - "not sending BFI\n", len); - return; - } - memset(tch_data + 2, 0, len - 2); - break; - default: -inval_mode1: - LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n"); - len = 0; - } - - if (len) { - /* Note: RSSI/ToA256 is set to 0 to indicate to the higher - * layers that this is a faked tch_ind */ - _sched_compose_tch_ind(l1ts, br->fn, br->chan, - tch_data, len, 0, 10000, 0, 0, 0); - } - } - - /* get frame and unlink from queue */ - msg1 = _sched_dequeue_prim(l1ts, br); - msg2 = _sched_dequeue_prim(l1ts, br); - if (msg1) { - l1sap = msgb_l1sap_prim(msg1); - if (l1sap->oph.primitive == PRIM_TCH) { - msg_tch = msg1; - if (msg2) { - l1sap = msgb_l1sap_prim(msg2); - if (l1sap->oph.primitive == PRIM_TCH) { - LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "TCH twice, please FIX!\n"); - msgb_free(msg2); - } else - msg_facch = msg2; - } - } else { - msg_facch = msg1; - if (msg2) { - l1sap = msgb_l1sap_prim(msg2); - if (l1sap->oph.primitive != PRIM_TCH) { - LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "FACCH twice, please FIX!\n"); - msgb_free(msg2); - } else - msg_tch = msg2; - } - } - } - - /* check validity of message */ - if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) { - LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n", - msgb_l2len(msg_facch), GSM_MACBLOCK_LEN); - /* free message */ - msgb_free(msg_facch); - msg_facch = NULL; - } - - /* check validity of message, get AMR ft and cmr */ - if (!msg_facch && msg_tch) { - int len; - uint8_t cmr_codec; - int cmr, ft, i; - enum osmo_amr_type ft_codec; - enum osmo_amr_quality bfi; - int8_t sti, cmi; - bool amr_is_cmr = !dl_amr_fn_is_cmi(br->fn); - - if (rsl_cmode != RSL_CMOD_SPD_SPEECH) { - LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, " - "because we are not in speech mode\n"); - goto free_bad_msg; - } - - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR / HR */ - if (br->chan != TRXC_TCHF) /* HR */ - len = 15; - else - len = GSM_FR_BYTES; - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - if (br->chan != TRXC_TCHF) - goto inval_mode2; - len = GSM_EFR_BYTES; - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - len = osmo_amr_rtp_dec(msg_tch->l2h, msgb_l2len(msg_tch), - &cmr_codec, &cmi, &ft_codec, - &bfi, &sti); - if (len < 0) { - LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send invalid AMR payload\n"); - goto free_bad_msg; - } - cmr = -1; - ft = -1; - for (i = 0; i < chan_state->codecs; i++) { - if (chan_state->codec[i] == cmr_codec) - cmr = i; - if (chan_state->codec[i] == ft_codec) - ft = i; - } - if (cmr >= 0) { /* new request */ - chan_state->dl_cmr = cmr; - /* disable AMR loop */ - trx_loop_amr_set(chan_state, 0); - } else { - /* enable AMR loop */ - trx_loop_amr_set(chan_state, 1); - } - if (ft < 0) { - LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, - "Codec (FT = %d) of RTP frame not in list\n", ft_codec); - goto free_bad_msg; - } - if (amr_is_cmr && chan_state->dl_ft != ft) { - LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Codec (FT = %d) " - " of RTP cannot be changed now, but in next frame\n", ft_codec); - goto free_bad_msg; - } - chan_state->dl_ft = ft; - if (bfi == AMR_BAD) { - LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad AMR frame'\n"); - goto free_bad_msg; - } - break; - default: -inval_mode2: - LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n"); - goto free_bad_msg; - } - if (msgb_l2len(msg_tch) != len) { - LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send payload with " - "invalid length! (expecting %d, received %d)\n", - len, msgb_l2len(msg_tch)); -free_bad_msg: - /* free message */ - msgb_free(msg_tch); - msg_tch = NULL; - goto send_frame; - } - } - -send_frame: - *_msg_tch = msg_tch; - *_msg_facch = msg_facch; -} - /* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) { diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c index e3ce600..bacd49b 100644 --- a/src/osmo-bts-trx/sched_lchan_tchh.c +++ b/src/osmo-bts-trx/sched_lchan_tchh.c @@ -43,6 +43,7 @@ #include <osmo-bts/msg_utils.h>
#include <sched_utils.h> +#include <sched_tch.h> #include <amr_loop.h>
/* 3GPP TS 45.009, table 3.2.1.3-{2,4}: AMR on Uplink TCH/H. @@ -350,12 +351,6 @@ meas_avg.ci_cb, is_sub); }
-/* common section for generation of TCH bursts (TCH/H and TCH/F). - * FIXME: this function is over-complicated, refactor / get rid of it. */ -extern void tx_tch_common(struct l1sched_ts *l1ts, - const struct trx_dl_burst_req *br, - struct msgb **_msg_tch, struct msgb **_msg_facch); - /* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) { diff --git a/src/osmo-bts-trx/sched_tch.h b/src/osmo-bts-trx/sched_tch.h new file mode 100644 index 0000000..f3e9c69 --- /dev/null +++ b/src/osmo-bts-trx/sched_tch.h @@ -0,0 +1,215 @@ +/* Common API for TCH channels. + * + * (C) 2013 by Andreas Eversberg jolly@eversberg.eu + * (C) 2015-2017 by Harald Welte laforge@gnumonks.org + * Contributions by sysmocom - s.f.m.c. GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#pragma once + +void trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop); + +/* Common section for generation of Downlink bursts (TCH/H and TCH/F) */ +static inline void tx_tch_common(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br, + struct msgb **_msg_tch, struct msgb **_msg_facch) +{ + struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan]; + uint8_t rsl_cmode = chan_state->rsl_cmode; + uint8_t tch_mode = chan_state->tch_mode; + struct osmo_phsap_prim *l1sap; + + /* handle loss detection of received TCH frames */ + if (rsl_cmode == RSL_CMOD_SPD_SPEECH + && ++(chan_state->lost_frames) > 5) { + uint8_t tch_data[GSM_FR_BYTES]; + int len; + + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Missing TCH bursts detected, sending BFI\n"); + + /* indicate bad frame */ + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* FR / HR */ + if (br->chan != TRXC_TCHF) { /* HR */ + tch_data[0] = 0x70; /* F = 0, FT = 111 */ + memset(tch_data + 1, 0, 14); + len = 15; + break; + } + memset(tch_data, 0, GSM_FR_BYTES); + len = GSM_FR_BYTES; + break; + case GSM48_CMODE_SPEECH_EFR: /* EFR */ + if (br->chan != TRXC_TCHF) + goto inval_mode1; + memset(tch_data, 0, GSM_EFR_BYTES); + len = GSM_EFR_BYTES; + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + len = osmo_amr_rtp_enc(tch_data, + chan_state->codec[chan_state->dl_cmr], + chan_state->codec[chan_state->dl_ft], AMR_BAD); + if (len < 2) { + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, + "Failed to encode AMR_BAD frame (rc=%d), " + "not sending BFI\n", len); + return; + } + memset(tch_data + 2, 0, len - 2); + break; + default: +inval_mode1: + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n"); + len = 0; + } + + if (len) { + /* Note: RSSI/ToA256 is set to 0 to indicate to the higher + * layers that this is a faked tch_ind */ + _sched_compose_tch_ind(l1ts, br->fn, br->chan, + tch_data, len, 0, 10000, 0, 0, 0); + } + } + + /* get frame and unlink from queue */ + msg1 = _sched_dequeue_prim(l1ts, br); + msg2 = _sched_dequeue_prim(l1ts, br); + if (msg1) { + l1sap = msgb_l1sap_prim(msg1); + if (l1sap->oph.primitive == PRIM_TCH) { + msg_tch = msg1; + if (msg2) { + l1sap = msgb_l1sap_prim(msg2); + if (l1sap->oph.primitive == PRIM_TCH) { + LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "TCH twice, please FIX!\n"); + msgb_free(msg2); + } else + msg_facch = msg2; + } + } else { + msg_facch = msg1; + if (msg2) { + l1sap = msgb_l1sap_prim(msg2); + if (l1sap->oph.primitive != PRIM_TCH) { + LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "FACCH twice, please FIX!\n"); + msgb_free(msg2); + } else + msg_tch = msg2; + } + } + } + + /* check validity of message */ + if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) { + LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n", + msgb_l2len(msg_facch), GSM_MACBLOCK_LEN); + /* free message */ + msgb_free(msg_facch); + msg_facch = NULL; + } + + /* check validity of message, get AMR ft and cmr */ + if (!msg_facch && msg_tch) { + int len; + uint8_t cmr_codec; + int cmr, ft, i; + enum osmo_amr_type ft_codec; + enum osmo_amr_quality bfi; + int8_t sti, cmi; + bool amr_is_cmr = !dl_amr_fn_is_cmi(br->fn); + + if (rsl_cmode != RSL_CMOD_SPD_SPEECH) { + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, " + "because we are not in speech mode\n"); + goto free_bad_msg; + } + + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* FR / HR */ + if (br->chan != TRXC_TCHF) /* HR */ + len = 15; + else + len = GSM_FR_BYTES; + break; + case GSM48_CMODE_SPEECH_EFR: /* EFR */ + if (br->chan != TRXC_TCHF) + goto inval_mode2; + len = GSM_EFR_BYTES; + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + len = osmo_amr_rtp_dec(msg_tch->l2h, msgb_l2len(msg_tch), + &cmr_codec, &cmi, &ft_codec, + &bfi, &sti); + if (len < 0) { + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send invalid AMR payload\n"); + goto free_bad_msg; + } + cmr = -1; + ft = -1; + for (i = 0; i < chan_state->codecs; i++) { + if (chan_state->codec[i] == cmr_codec) + cmr = i; + if (chan_state->codec[i] == ft_codec) + ft = i; + } + if (cmr >= 0) { /* new request */ + chan_state->dl_cmr = cmr; + /* disable AMR loop */ + trx_loop_amr_set(chan_state, 0); + } else { + /* enable AMR loop */ + trx_loop_amr_set(chan_state, 1); + } + if (ft < 0) { + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, + "Codec (FT = %d) of RTP frame not in list\n", ft_codec); + goto free_bad_msg; + } + if (amr_is_cmr && chan_state->dl_ft != ft) { + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Codec (FT = %d) " + " of RTP cannot be changed now, but in next frame\n", ft_codec); + goto free_bad_msg; + } + chan_state->dl_ft = ft; + if (bfi == AMR_BAD) { + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad AMR frame'\n"); + goto free_bad_msg; + } + break; + default: +inval_mode2: + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n"); + goto free_bad_msg; + } + if (msgb_l2len(msg_tch) != len) { + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send payload with " + "invalid length! (expecting %d, received %d)\n", + len, msgb_l2len(msg_tch)); +free_bad_msg: + /* free message */ + msgb_free(msg_tch); + msg_tch = NULL; + goto send_frame; + } + } + +send_frame: + *_msg_tch = msg_tch; + *_msg_facch = msg_facch; +}