[PATCH] osmo-bts[master]: DTX DL: split ONSET state handling

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Max gerrit-no-reply at lists.osmocom.org
Thu Oct 27 10:26:23 UTC 2016


Hello Harald Welte, Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/1145

to look at the new patch set (#11).

DTX DL: split ONSET state handling

Handle ONSET cause by Voice and FACCH separately. In case of Voice we
have RTP payload which we have to cache and send later on in next
response to L1 RTS. FACCH have higher priority so it preempts both voice
and silence alike - hence we can send ONSET immediately but still have
to track previous state in order to get back to it gracefully.

This affects lc15 and sysmo hw as there's no FSM-based DTX
implementation for other models yet.

Change-Id: Idba14dcd0cb12cd7aee86391fcc152c49fcd7052
Related: OS#1802
---
M include/osmo-bts/dtx_dl_amr_fsm.h
M src/common/dtx_dl_amr_fsm.c
M src/common/msg_utils.c
M src/osmo-bts-litecell15/l1_if.c
M src/osmo-bts-litecell15/tch.c
M src/osmo-bts-sysmo/l1_if.c
M src/osmo-bts-sysmo/tch.c
7 files changed, 114 insertions(+), 34 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/45/1145/11

diff --git a/include/osmo-bts/dtx_dl_amr_fsm.h b/include/osmo-bts/dtx_dl_amr_fsm.h
index 8b19595..5c13c19 100644
--- a/include/osmo-bts/dtx_dl_amr_fsm.h
+++ b/include/osmo-bts/dtx_dl_amr_fsm.h
@@ -16,7 +16,6 @@
 	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 b110cf2..a75fd00 100644
--- a/src/common/dtx_dl_amr_fsm.c
+++ b/src/common/dtx_dl_amr_fsm.c
@@ -53,7 +53,7 @@
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 {
 	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 @@
 	   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 @@
 	   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 @@
 	/* 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,
 	},
@@ -275,13 +275,6 @@
 		.out_state_mask = X(ST_VOICE) | X(ST_FACCH_V),
 		.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 */
diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c
index 9c6f20f..fcc317c 100644
--- a/src/common/msg_utils.c
+++ b/src/common/msg_utils.c
@@ -220,12 +220,23 @@
  *  \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 */
diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c
index f47634e..b6f35b7 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 @@
 }
 
 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 @@
 	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 @@
 		msgb_free(l1msg);
 	}
 
+	if (rec)
+		ph_data_req(trx, msg, l1sap, true);
 	return 0;
 }
 
@@ -566,7 +603,7 @@
 	 * 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 b251388..70764f5 100644
--- a/src/osmo-bts-litecell15/tch.c
+++ b/src/osmo-bts-litecell15/tch.c
@@ -285,10 +285,9 @@
 		/* 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 @@
 			*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 bef2d30..8729c89 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -325,13 +325,15 @@
 }
 
 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 +398,46 @@
 	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 +451,8 @@
 		msgb_free(l1msg);
 	}
 
+	if (rec)
+		ph_data_req(trx, msg, l1sap, true);
 	return 0;
 }
 
@@ -561,7 +597,7 @@
 	 * 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 b08ba7e..fbb42b2 100644
--- a/src/osmo-bts-sysmo/tch.c
+++ b/src/osmo-bts-sysmo/tch.c
@@ -383,10 +383,9 @@
 		/* 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 @@
 			*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;

-- 
To view, visit https://gerrit.osmocom.org/1145
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Idba14dcd0cb12cd7aee86391fcc152c49fcd7052
Gerrit-PatchSet: 11
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Owner: Max <msuraev at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Max <msuraev at sysmocom.de>



More information about the gerrit-log mailing list