aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmo-bts/dtx_dl_amr_fsm.h1
-rw-r--r--src/common/dtx_dl_amr_fsm.c23
-rw-r--r--src/common/msg_utils.c21
-rw-r--r--src/osmo-bts-litecell15/l1_if.c49
-rw-r--r--src/osmo-bts-litecell15/tch.c6
-rw-r--r--src/osmo-bts-sysmo/l1_if.c49
-rw-r--r--src/osmo-bts-sysmo/tch.c6
7 files changed, 120 insertions, 35 deletions
diff --git a/include/osmo-bts/dtx_dl_amr_fsm.h b/include/osmo-bts/dtx_dl_amr_fsm.h
index 8b195953..5c13c198 100644
--- a/include/osmo-bts/dtx_dl_amr_fsm.h
+++ b/include/osmo-bts/dtx_dl_amr_fsm.h
@@ -16,7 +16,6 @@ enum dtx_dl_amr_fsm_states {
ST_U_INH,
ST_SID_U,
ST_ONSET_V,
- ST_ONSET_F,
ST_FACCH_V,
ST_FACCH,
};
diff --git a/src/common/dtx_dl_amr_fsm.c b/src/common/dtx_dl_amr_fsm.c
index b110cf21..a75fd00e 100644
--- a/src/common/dtx_dl_amr_fsm.c
+++ b/src/common/dtx_dl_amr_fsm.c
@@ -53,7 +53,7 @@ void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data)
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
break;
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
break;
case E_COMPL:
osmo_fsm_inst_state_chg(fi, ST_SID_F2, 0, 0);
@@ -81,7 +81,7 @@ void dtx_fsm_sid_f2(struct osmo_fsm_inst *fi, uint32_t event, void *data)
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
break;
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
break;
default:
LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
@@ -97,7 +97,7 @@ void dtx_fsm_f1_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0);
break;
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
break;
default:
LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
@@ -113,7 +113,7 @@ void dtx_fsm_u_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0);
break;
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
break;
default:
LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
@@ -126,7 +126,7 @@ void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
break;
case E_VOICE:
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
@@ -234,7 +234,7 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
start of silence period (might be interrupted in case of AMR HR) */
[ST_SID_F1]= {
.in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_COMPL) | X(E_INHIB) | X(E_ONSET),
- .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_F1_INH) | X(ST_ONSET_V),
+ .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_FACCH) | X(ST_SID_F2) | X(ST_F1_INH) | X(ST_ONSET_V),
.name = "SID-FIRST (P1)",
.action = dtx_fsm_sid_f1,
},
@@ -242,7 +242,7 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
actual start of silence period in case of AMR HR*/
[ST_SID_F2]= {
.in_event_mask = X(E_SID_U) | X(E_VOICE) | X(E_FACCH),
- .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F),
+ .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_FACCH),
.name = "SID-FIRST (P2)",
.action = dtx_fsm_sid_f2,
},
@@ -265,7 +265,7 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
/* Silence period with periodic comfort noise data updates */
[ST_SID_U]= {
.in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_INHIB) | X(E_SID_U) | X(E_SID_F) | X(E_ONSET),
- .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH) | X(ST_SID_U) | X(ST_ONSET_V),
+ .out_state_mask = X(ST_FACCH) | X(ST_VOICE) | X(ST_U_INH) | X(ST_SID_U) | X(ST_ONSET_V),
.name = "SID-UPDATE",
.action = dtx_fsm_sid_upd,
},
@@ -276,13 +276,6 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
.name = "ONSET (SPEECH)",
.action = dtx_fsm_onset_v,
},
- /* ONSET - end of silent period due to incoming FACCH frame */
- [ST_ONSET_F]= {
- .in_event_mask = X(E_VOICE) | X(E_FACCH) | X(E_SID_U),
- .out_state_mask = X(ST_VOICE) | X(ST_FACCH),
- .name = "ONSET (FACCH)",
- .action = dtx_fsm_onset_f,
- },
/* FACCH sending state: SPEECH was observed before so once we're done
FSM should get back to VOICE state */
[ST_FACCH_V]= {
diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c
index 9c6f20f1..4b213665 100644
--- a/src/common/msg_utils.c
+++ b/src/common/msg_utils.c
@@ -220,12 +220,23 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
* \param[in] fn Frame Number for which we check scheduling
* \returns true if transmission can be omitted, false otherwise
*/
-static inline bool dtx_amr_sid_optional(const struct gsm_lchan *lchan,
- uint32_t fn)
+static inline bool dtx_amr_sid_optional(struct gsm_lchan *lchan, uint32_t fn)
{
/* Compute approx. time delta x26 based on Fn duration */
uint32_t dx26 = 120 * (fn - lchan->tch.dtx.fn);
+ /* We're resuming after FACCH interruption */
+ if (lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) {
+ /* force STI bit to 0 so cache is treated as SID FIRST */
+ lchan->tch.dtx.cache[6 + 2] &= ~16;
+ lchan->tch.dtx.is_update = false;
+ osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_SID_F,
+ (void *)lchan);
+ /* this FN was already used for ONSET message so we just prepare
+ things for next one */
+ return true;
+ }
+
/* according to 3GPP TS 26.093 A.5.1.1:
(*26) to avoid float math, add 1 FN tolerance (-120) */
if (lchan->tch.dtx.is_update) { /* SID UPDATE: every 8th RTP frame */
@@ -293,7 +304,11 @@ uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn)
if (lchan->tch.dtx.len) {
memcpy(dst, lchan->tch.dtx.cache, lchan->tch.dtx.len);
lchan->tch.dtx.fn = fn;
- lchan->tch.dtx.is_update = true; /* SID UPDATE sent */
+ /* enforce SID UPDATE for next repetition - it might have
+ been altered by FACCH handling */
+ lchan->tch.dtx.cache[6 + 2] |= 16;
+ if (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U)
+ lchan->tch.dtx.is_update = true;
return lchan->tch.dtx.len + 1;
}
diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c
index edc5f5b7..795172bb 100644
--- a/src/osmo-bts-litecell15/l1_if.c
+++ b/src/osmo-bts-litecell15/l1_if.c
@@ -53,6 +53,7 @@
#include <osmo-bts/cbch.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <nrw/litecell15/litecell15.h>
#include <nrw/litecell15/gsml1prim.h>
@@ -330,13 +331,15 @@ empty_req_from_l1sap(GsmL1_Prim_t *l1p, struct lc15l1_hdl *fl1,
}
static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
- struct osmo_phsap_prim *l1sap)
+ struct osmo_phsap_prim *l1sap, bool use_cache)
{
struct lc15l1_hdl *fl1 = trx_lc15l1_hdl(trx);
struct msgb *l1msg = l1p_msgb_alloc();
+ struct gsm_lchan *lchan;
uint32_t u32Fn;
uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi = 0;
uint8_t chan_nr, link_id;
+ bool rec = false;
int len;
if (!msg) {
@@ -401,14 +404,46 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
if (len) {
/* data request */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+
+ if (use_cache)
+ memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer,
+ lchan->tch.dtx.facch, msgb_l2len(msg));
+ else if (trx->bts->dtxd && lchan->tch.dtx.dl_amr_fsm &&
+ lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) {
+ if (sapi == GsmL1_Sapi_FacchF) {
+ sapi = GsmL1_Sapi_TchF;
+ }
+ if (sapi == GsmL1_Sapi_FacchH) {
+ sapi = GsmL1_Sapi_TchH;
+ }
+ if (sapi == GsmL1_Sapi_TchH || sapi == GsmL1_Sapi_TchF) {
+ /* FACCH interruption of DTX silence */
+ /* cache FACCH data */
+ memcpy(lchan->tch.dtx.facch, msg->l2h,
+ msgb_l2len(msg));
+ /* prepare ONSET message */
+ len = 3;
+ l1p->u.phDataReq.msgUnitParam.u8Buffer[0] =
+ GsmL1_TchPlType_Amr_Onset;
+ /* ignored CMR/CMI pair */
+ l1p->u.phDataReq.msgUnitParam.u8Buffer[1] = 0;
+ l1p->u.phDataReq.msgUnitParam.u8Buffer[2] = 0;
+ /* ONSET is ready, recursive call is necessary */
+ rec = true;
+ }
+ }
data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr, len);
- OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer));
- memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h, msgb_l2len(msg));
+ if (!rec && !use_cache) {
+ OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer));
+ memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
+ msgb_l2len(msg));
+ }
LOGP(DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
+ l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
/* empty frame */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
@@ -422,6 +457,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
msgb_free(l1msg);
}
+ if (rec)
+ ph_data_req(trx, msg, l1sap, true);
return 0;
}
@@ -566,7 +603,7 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
* free()d below */
switch (OSMO_PRIM_HDR(&l1sap->oph)) {
case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST):
- rc = ph_data_req(trx, msg, l1sap);
+ rc = ph_data_req(trx, msg, l1sap, false);
break;
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
rc = ph_tch_req(trx, msg, l1sap, false, l1sap->u.tch.marker);
diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-litecell15/tch.c
index b2513887..70764f5f 100644
--- a/src/osmo-bts-litecell15/tch.c
+++ b/src/osmo-bts-litecell15/tch.c
@@ -285,10 +285,9 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
/* DTX DL-specific logic below: */
switch (lchan->tch.dtx.dl_amr_fsm->state) {
case ST_ONSET_V:
- case ST_ONSET_F:
*payload_type = GsmL1_TchPlType_Amr_Onset;
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
- *len = 1;
+ *len = 3;
return 1;
case ST_VOICE:
*payload_type = GsmL1_TchPlType_Amr;
@@ -306,6 +305,9 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
*payload_type = GsmL1_TchPlType_Amr;
rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
ft);
+ /* force STI bit to 0 to make sure resume after FACCH
+ works properly */
+ l1_payload[6 + 2] &= ~16;
return 0;
case ST_SID_F2:
*payload_type = GsmL1_TchPlType_Amr;
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index bef2d303..f7585ce8 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -49,6 +49,7 @@
#include <osmo-bts/cbch.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/l1sap.h>
+#include <osmo-bts/dtx_dl_amr_fsm.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1prim.h>
@@ -325,13 +326,15 @@ empty_req_from_l1sap(GsmL1_Prim_t *l1p, struct femtol1_hdl *fl1,
}
static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
- struct osmo_phsap_prim *l1sap)
+ struct osmo_phsap_prim *l1sap, bool use_cache)
{
struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx);
struct msgb *l1msg = l1p_msgb_alloc();
+ struct gsm_lchan *lchan;
uint32_t u32Fn;
uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi = 0;
uint8_t chan_nr, link_id;
+ bool rec = false;
int len;
if (!msg) {
@@ -396,14 +399,46 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
if (len) {
/* data request */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+
+ if (use_cache)
+ memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer,
+ lchan->tch.dtx.facch, msgb_l2len(msg));
+ else if (trx->bts->dtxd && lchan->tch.dtx.dl_amr_fsm &&
+ lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) {
+ if (sapi == GsmL1_Sapi_FacchF) {
+ sapi = GsmL1_Sapi_TchF;
+ }
+ if (sapi == GsmL1_Sapi_FacchH) {
+ sapi = GsmL1_Sapi_TchH;
+ }
+ if (sapi == GsmL1_Sapi_TchH || sapi == GsmL1_Sapi_TchF) {
+ /* FACCH interruption of DTX silence */
+ /* cache FACCH data */
+ memcpy(lchan->tch.dtx.facch, msg->l2h,
+ msgb_l2len(msg));
+ /* prepare ONSET message */
+ len = 3;
+ l1p->u.phDataReq.msgUnitParam.u8Buffer[0] =
+ GsmL1_TchPlType_Amr_Onset;
+ /* ignored CMR/CMI pair */
+ l1p->u.phDataReq.msgUnitParam.u8Buffer[1] = 0;
+ l1p->u.phDataReq.msgUnitParam.u8Buffer[2] = 0;
+ /* ONSET is ready, recursive call is necessary */
+ rec = true;
+ }
+ }
data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr, len);
- OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer));
- memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h, msgb_l2len(msg));
+ if (!rec && !use_cache) {
+ OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer));
+ memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
+ msgb_l2len(msg));
+ }
LOGP(DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
+ l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
/* empty frame */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
@@ -417,6 +452,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
msgb_free(l1msg);
}
+ if (rec)
+ ph_data_req(trx, msg, l1sap, true);
return 0;
}
@@ -561,7 +598,7 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
* free()d below */
switch (OSMO_PRIM_HDR(&l1sap->oph)) {
case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST):
- rc = ph_data_req(trx, msg, l1sap);
+ rc = ph_data_req(trx, msg, l1sap, false);
break;
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
rc = ph_tch_req(trx, msg, l1sap, false, l1sap->u.tch.marker);
diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c
index b08ba7e1..fbb42b27 100644
--- a/src/osmo-bts-sysmo/tch.c
+++ b/src/osmo-bts-sysmo/tch.c
@@ -383,10 +383,9 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
/* DTX DL-specific logic below: */
switch (lchan->tch.dtx.dl_amr_fsm->state) {
case ST_ONSET_V:
- case ST_ONSET_F:
*payload_type = GsmL1_TchPlType_Amr_Onset;
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
- *len = 1;
+ *len = 3;
return 1;
case ST_VOICE:
*payload_type = GsmL1_TchPlType_Amr;
@@ -404,6 +403,9 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
*payload_type = GsmL1_TchPlType_Amr;
rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len,
ft);
+ /* force STI bit to 0 to make sure resume after FACCH
+ works properly */
+ l1_payload[6 + 2] &= ~16;
return 0;
case ST_SID_F2:
*payload_type = GsmL1_TchPlType_Amr;