fixeria has uploaded this change for review.
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;
+}
To view, visit change 27802. To unsubscribe, or for help writing mail filters, visit settings.