aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2019-08-01 20:43:45 +0200
committerlaforge <laforge@gnumonks.org>2019-09-10 12:26:21 +0000
commitec228cc08cd5a8c8b254fe40d0bfc9751d46d9dd (patch)
tree9e28b351b65711e5ddd25a982f7987bd6e778601 /src
parente6a72c2b8088ece6ade4c64fe18e24763a57441a (diff)
osmo-bts-trx: migrate to new generic ECU abstraction
libosmocodec has recently introduced a generic ECU abstraction layer which supports (pluggable) Error Concealment Units for not only the FR codec, but potentially any other codec, too. Change-Id: I001005aae6de76d4e045b8dc572239f057bb150d Depends: libosmocore I4d33c9c7c2d4c7462ff38a49c178b65accae1915
Diffstat (limited to 'src')
-rw-r--r--src/common/gsm_data_shared.c22
-rw-r--r--src/osmo-bts-trx/l1_if.c13
-rw-r--r--src/osmo-bts-trx/scheduler_trx.c73
3 files changed, 78 insertions, 30 deletions
diff --git a/src/common/gsm_data_shared.c b/src/common/gsm_data_shared.c
index 1ba43aa6..f0f5ae20 100644
--- a/src/common/gsm_data_shared.c
+++ b/src/common/gsm_data_shared.c
@@ -31,6 +31,7 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/abis_nm.h>
#include <osmocom/core/statistics.h>
+#include <osmocom/codec/ecu.h>
#include <osmo-bts/gsm_data.h>
@@ -807,3 +808,24 @@ const struct value_string lchan_ciph_state_names[] = {
{ LCHAN_CIPH_RXTX_CONF, "RXTX_CONF" },
{ 0, NULL }
};
+
+/* determine the ECU codec constant for the codec used by given lchan */
+int lchan2ecu_codec(const struct gsm_lchan *lchan)
+{
+ struct gsm_bts_trx_ts *ts = lchan->ts;
+
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (ts_pchan(ts) == GSM_PCHAN_TCH_H)
+ return OSMO_ECU_CODEC_HR;
+ else
+ return OSMO_ECU_CODEC_FR;
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ return OSMO_ECU_CODEC_EFR;
+ case GSM48_CMODE_SPEECH_AMR:
+ return OSMO_ECU_CODEC_AMR;
+ default:
+ return -1;
+ }
+}
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c
index 22ef2d73..db53d4c6 100644
--- a/src/osmo-bts-trx/l1_if.c
+++ b/src/osmo-bts-trx/l1_if.c
@@ -29,6 +29,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/bits.h>
+#include <osmocom/codec/ecu.h>
#include <osmocom/gsm/abis_nm.h>
#include <osmo-bts/logging.h>
@@ -626,6 +627,9 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
break;
}
+ /* attempt to allocate an Error Concealment Unit instance, if available */
+ lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
+
/* trx_chan_desc[] in scheduler.c uses the RSL_CHAN_OSMO_PDCH cbits
* (0xc0) to indicate the need for PDTCH and PTCCH SAPI activation.
* However, 0xc0 is a cbits pattern exclusively used for Osmocom style
@@ -671,6 +675,10 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
break;
}
if (l1sap->u.info.type == PRIM_INFO_MODIFY) {
+ /* ECU for possibly new codec */
+ if (lchan->ecu_state)
+ osmo_ecu_destroy(lchan->ecu_state);
+ lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
/* change mode */
trx_sched_set_mode(&l1h->l1s, chan_nr,
lchan->rsl_cmode, lchan->tch_mode,
@@ -689,6 +697,11 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
"chan_nr 0x%02x\n", chan_nr);
break;
}
+ /* clear ECU state (if any) */
+ if (lchan->ecu_state) {
+ osmo_ecu_destroy(lchan->ecu_state);
+ lchan->ecu_state = NULL;
+ }
/* deactivate associated channel */
bts_model_lchan_deactivate_sacch(lchan);
if (!l1sap->u.info.u.act_req.sacch_only) {
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index 12490539..45fc7012 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -1236,16 +1236,19 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
"Received bad data (%u/%u)\n",
bi->fn % l1ts->mf_period, l1ts->mf_period);
bfi_flag = true;
- goto bfi;
- }
- if (rc < 4) {
+ } else if (rc < 4) {
LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
"Received bad data (%u/%u) with invalid codec mode %d\n",
bi->fn % l1ts->mf_period, l1ts->mf_period, rc);
bfi_flag = true;
- goto bfi;
}
+ if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)
+ osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);
+
+ if (bfi_flag)
+ goto bfi;
+
/* FACCH */
if (rc == GSM_MACBLOCK_LEN) {
uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);
@@ -1260,21 +1263,22 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
bfi:
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
/* indicate bad frame */
- switch (tch_mode) {
- case GSM48_CMODE_SPEECH_V1: /* FR */
- if (lchan->tch.dtx.ul_sid) {
- /* DTXu: pause in progress. Push empty payload to upper layers */
- rc = 0;
- goto compose_l1sap;
- }
+ if (lchan->tch.dtx.ul_sid) {
+ /* DTXu: pause in progress. Push empty payload to upper layers */
+ rc = 0;
+ goto compose_l1sap;
+ }
- /* Perform error concealment if possible */
- rc = osmo_ecu_fr_conceal(&lchan->ecu_state.fr, tch_data);
- if (rc) {
- memset(tch_data, 0, GSM_FR_BYTES);
- tch_data[0] = 0xd0;
- }
+ /* If there is an ECU active on this channel, use its output */
+ if (lchan->ecu_state) {
+ rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);
+ goto compose_l1sap;
+ }
+ switch (tch_mode) {
+ case GSM48_CMODE_SPEECH_V1: /* FR */
+ memset(tch_data, 0, GSM_FR_BYTES);
+ tch_data[0] = 0xd0;
rc = GSM_FR_BYTES;
break;
case GSM48_CMODE_SPEECH_EFR: /* EFR */
@@ -1306,10 +1310,6 @@ bfi:
if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
return 0;
- /* Reset ECU with a good frame */
- if (!bfi_flag && tch_mode == GSM48_CMODE_SPEECH_V1)
- osmo_ecu_fr_reset(&lchan->ecu_state.fr, tch_data);
-
/* TCH or BFI */
compose_l1sap:
return _sched_compose_tch_ind(l1t, bi->tn,
@@ -1332,6 +1332,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t tch_data[128]; /* just to be safe */
int rc, amr = 0;
int n_errors, n_bits_total;
+ bool bfi_flag = false;
struct gsm_lchan *lchan =
get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);
/* Note on FN-10: If we are at FN 10, we decoded an even aligned
@@ -1444,15 +1445,20 @@ int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
"Received bad data (%u/%u)\n",
bi->fn % l1ts->mf_period, l1ts->mf_period);
- goto bfi;
- }
- if (rc < 4) {
+ bfi_flag = true;
+ } else if (rc < 4) {
LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,
"Received bad data (%u/%u) with invalid codec mode %d\n",
bi->fn % l1ts->mf_period, l1ts->mf_period, rc);
- goto bfi;
+ bfi_flag = true;
}
+ if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)
+ osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);
+
+ if (bfi_flag)
+ goto bfi;
+
/* FACCH */
if (rc == GSM_MACBLOCK_LEN) {
chan_state->ul_ongoing_facch = 1;
@@ -1470,13 +1476,20 @@ bfi:
* so we actually need to send two bad frame indications! */
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
/* indicate bad frame */
+ if (lchan->tch.dtx.ul_sid) {
+ /* DTXu: pause in progress. Push empty payload to upper layers */
+ rc = 0;
+ goto compose_l1sap;
+ }
+
+ /* If there is an ECU active on this channel, use its output */
+ if (lchan->ecu_state) {
+ rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);
+ goto compose_l1sap;
+ }
+
switch (tch_mode) {
case GSM48_CMODE_SPEECH_V1: /* HR */
- if (lchan->tch.dtx.ul_sid) {
- /* DTXu: pause in progress. Push empty payload to upper layers */
- rc = 0;
- goto compose_l1sap;
- }
tch_data[0] = 0x70; /* F = 0, FT = 111 */
memset(tch_data + 1, 0, 14);
rc = 15;