mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-bts.git
				synced 2025-11-04 06:03:26 +00:00 
			
		
		
		
	osmo-bts-trx: implement CSD scheduling support
* enlarge the maximum burst buffer size to 24 * (2 * 58) bytes;
* enlarge per-l1cs Uplink burst mask to hold up to 32 bits;
* enlarge per-l1cs Uplink meas ring buffer to 24 entries;
* add new meas modes: SCHED_MEAS_AVG_M_{S22N22,S24N22};
Change-Id: I08ffbf8e79ce76a586d61f5463890c6e72a6d9b9
Depends: libosmocore.git Ib482817b5f6a4e3c7299f6e0b3841143b60fc93d
Related: OS#1572
			
			
This commit is contained in:
		@@ -94,7 +94,7 @@ struct l1sched_chan_state {
 | 
				
			|||||||
	sbit_t			*ul_bursts;	/* burst buffer for RX */
 | 
						sbit_t			*ul_bursts;	/* burst buffer for RX */
 | 
				
			||||||
	sbit_t			*ul_bursts_prev;/* previous burst buffer for RX (repeated SACCH) */
 | 
						sbit_t			*ul_bursts_prev;/* previous burst buffer for RX (repeated SACCH) */
 | 
				
			||||||
	uint32_t		ul_first_fn;	/* fn of first burst */
 | 
						uint32_t		ul_first_fn;	/* fn of first burst */
 | 
				
			||||||
	uint8_t			ul_mask;	/* mask of received bursts */
 | 
						uint32_t		ul_mask;	/* mask of received bursts */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* loss detection */
 | 
						/* loss detection */
 | 
				
			||||||
	uint32_t		last_tdma_fn;	/* last processed TDMA frame number */
 | 
						uint32_t		last_tdma_fn;	/* last processed TDMA frame number */
 | 
				
			||||||
@@ -132,7 +132,7 @@ struct l1sched_chan_state {
 | 
				
			|||||||
	/* Uplink measurements */
 | 
						/* Uplink measurements */
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/* Active channel measurements (simple ring buffer) */
 | 
							/* Active channel measurements (simple ring buffer) */
 | 
				
			||||||
		struct l1sched_meas_set buf[8]; /* up to 8 entries */
 | 
							struct l1sched_meas_set buf[24]; /* up to 24 entries */
 | 
				
			||||||
		unsigned int current; /* current position */
 | 
							unsigned int current; /* current position */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Interference measurements */
 | 
							/* Interference measurements */
 | 
				
			||||||
@@ -301,6 +301,10 @@ int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Averaging mode for trx_sched_meas_avg() */
 | 
					/* Averaging mode for trx_sched_meas_avg() */
 | 
				
			||||||
enum sched_meas_avg_mode {
 | 
					enum sched_meas_avg_mode {
 | 
				
			||||||
 | 
						/* first 22 of last 24 bursts (for TCH/F14.4, TCH/F9.6, TCH/F4.8) */
 | 
				
			||||||
 | 
						SCHED_MEAS_AVG_M_S24N22,
 | 
				
			||||||
 | 
						/* last 22 bursts (for TCH/H4.8, TCH/H2.4) */
 | 
				
			||||||
 | 
						SCHED_MEAS_AVG_M_S22N22,
 | 
				
			||||||
	/* last 4 bursts (default for xCCH, PTCCH and PDTCH) */
 | 
						/* last 4 bursts (default for xCCH, PTCCH and PDTCH) */
 | 
				
			||||||
	SCHED_MEAS_AVG_M_S4N4,
 | 
						SCHED_MEAS_AVG_M_S4N4,
 | 
				
			||||||
	/* last 8 bursts (default for TCH/F and FACCH/F) */
 | 
						/* last 8 bursts (default for TCH/F and FACCH/F) */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -780,23 +780,11 @@ struct gsm_time *get_time(struct gsm_bts *bts)
 | 
				
			|||||||
	return &bts->gsm_time;
 | 
						return &bts->gsm_time;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool bts_supports_cm(const struct gsm_bts *bts,
 | 
					bool bts_supports_cm_speech(const struct gsm_bts *bts,
 | 
				
			||||||
		     const struct rsl_ie_chan_mode *cm)
 | 
								    const struct rsl_ie_chan_mode *cm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum osmo_bts_features feature = _NUM_BTS_FEAT;
 | 
						enum osmo_bts_features feature = _NUM_BTS_FEAT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (cm->spd_ind) {
 | 
					 | 
				
			||||||
	case RSL_CMOD_SPD_SIGN:
 | 
					 | 
				
			||||||
		/* We assume that signalling support is mandatory,
 | 
					 | 
				
			||||||
		 * there is no BTS_FEAT_* definition to check that. */
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	case RSL_CMOD_SPD_SPEECH:
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case RSL_CMOD_SPD_DATA:
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Stage 1: check support for the requested channel type */
 | 
						/* Stage 1: check support for the requested channel type */
 | 
				
			||||||
	switch (cm->chan_rt) {
 | 
						switch (cm->chan_rt) {
 | 
				
			||||||
	case RSL_CMOD_CRT_TCH_GROUP_Bm:
 | 
						case RSL_CMOD_CRT_TCH_GROUP_Bm:
 | 
				
			||||||
@@ -869,6 +857,52 @@ bool bts_supports_cm(const struct gsm_bts *bts,
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool bts_supports_cm_data(const struct gsm_bts *bts,
 | 
				
			||||||
 | 
									 const struct rsl_ie_chan_mode *cm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (bts->variant) {
 | 
				
			||||||
 | 
						case BTS_OSMO_TRX:
 | 
				
			||||||
 | 
							switch (cm->chan_rate) {
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_14k4:
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_9k6:
 | 
				
			||||||
 | 
								if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm)
 | 
				
			||||||
 | 
									return false; /* invalid */
 | 
				
			||||||
 | 
								/* fall-through */
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_4k8:
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_2k4:
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_1k2:
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_600:
 | 
				
			||||||
 | 
							case RSL_CMOD_CSD_T_1200_75:
 | 
				
			||||||
 | 
								/* TODO: osmo-bts-trx does not support TCH/F2.4 */
 | 
				
			||||||
 | 
								if (cm->chan_rt == RSL_CMOD_CRT_TCH_Bm)
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool bts_supports_cm(const struct gsm_bts *bts,
 | 
				
			||||||
 | 
							     const struct rsl_ie_chan_mode *cm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (cm->spd_ind) {
 | 
				
			||||||
 | 
						case RSL_CMOD_SPD_SIGN:
 | 
				
			||||||
 | 
							/* We assume that signalling support is mandatory,
 | 
				
			||||||
 | 
							 * there is no BTS_FEAT_* definition to check that. */
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						case RSL_CMOD_SPD_SPEECH:
 | 
				
			||||||
 | 
							return bts_supports_cm_speech(bts, cm);
 | 
				
			||||||
 | 
						case RSL_CMOD_SPD_DATA:
 | 
				
			||||||
 | 
							return bts_supports_cm_data(bts, cm);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* return the gsm_lchan for the CBCH (if it exists at all) */
 | 
					/* return the gsm_lchan for the CBCH (if it exists at all) */
 | 
				
			||||||
struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts)
 | 
					struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1079,9 +1079,9 @@ static void _trx_sched_set_lchan(struct gsm_lchan *lchan,
 | 
				
			|||||||
		chan_state->lchan = lchan;
 | 
							chan_state->lchan = lchan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Allocate memory for Rx/Tx burst buffers.  Use the maximim size
 | 
							/* Allocate memory for Rx/Tx burst buffers.  Use the maximim size
 | 
				
			||||||
		 * of 4 * (3 * 2 * 58) bytes, which is sufficient to store 4 8PSK
 | 
							 * of 24 * (2 * 58) bytes, which is sufficient to store up to 24 GMSK
 | 
				
			||||||
		 * modulated bursts. */
 | 
							 * modulated bursts for CSD or up to 8 8PSK modulated bursts for EGPRS. */
 | 
				
			||||||
		const size_t buf_size = 4 * GSM_NBITS_NB_8PSK_PAYLOAD;
 | 
							const size_t buf_size = 24 * GSM_NBITS_NB_GMSK_PAYLOAD;
 | 
				
			||||||
		if (trx_chan_desc[chan].dl_fn != NULL)
 | 
							if (trx_chan_desc[chan].dl_fn != NULL)
 | 
				
			||||||
			chan_state->dl_bursts = talloc_zero_size(l1ts, buf_size);
 | 
								chan_state->dl_bursts = talloc_zero_size(l1ts, buf_size);
 | 
				
			||||||
		if (trx_chan_desc[chan].ul_fn != NULL) {
 | 
							if (trx_chan_desc[chan].ul_fn != NULL) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@ int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
	struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
						struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
				
			||||||
	sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
						sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
				
			||||||
	uint32_t first_fn;
 | 
						uint32_t first_fn;
 | 
				
			||||||
	uint8_t *mask = &chan_state->ul_mask;
 | 
						uint32_t *mask = &chan_state->ul_mask;
 | 
				
			||||||
	struct l1sched_meas_set meas_avg;
 | 
						struct l1sched_meas_set meas_avg;
 | 
				
			||||||
	uint8_t l2[EGPRS_0503_MAX_BYTES];
 | 
						uint8_t l2[EGPRS_0503_MAX_BYTES];
 | 
				
			||||||
	int n_errors = 0;
 | 
						int n_errors = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
 | 
					 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
 | 
				
			||||||
 * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
 | 
					 * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * Contributions by sysmocom - s.f.m.c. GmbH
 | 
					 * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * All Rights Reserved
 | 
					 * All Rights Reserved
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -75,10 +75,10 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
	struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
						struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
				
			||||||
	struct gsm_lchan *lchan = chan_state->lchan;
 | 
						struct gsm_lchan *lchan = chan_state->lchan;
 | 
				
			||||||
	sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
						sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
				
			||||||
	uint8_t *mask = &chan_state->ul_mask;
 | 
						uint32_t *mask = &chan_state->ul_mask;
 | 
				
			||||||
	uint8_t rsl_cmode = chan_state->rsl_cmode;
 | 
						uint8_t rsl_cmode = chan_state->rsl_cmode;
 | 
				
			||||||
	uint8_t tch_mode = chan_state->tch_mode;
 | 
						uint8_t tch_mode = chan_state->tch_mode;
 | 
				
			||||||
	uint8_t tch_data[128]; /* just to be safe */
 | 
						uint8_t tch_data[290]; /* large enough to hold 290 unpacked bits for CSD */
 | 
				
			||||||
	enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
 | 
						enum sched_meas_avg_mode meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
 | 
				
			||||||
	struct l1sched_meas_set meas_avg;
 | 
						struct l1sched_meas_set meas_avg;
 | 
				
			||||||
	int rc, amr = 0;
 | 
						int rc, amr = 0;
 | 
				
			||||||
@@ -100,8 +100,8 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* shift the buffer by 4 bursts leftwards */
 | 
						/* shift the buffer by 4 bursts leftwards */
 | 
				
			||||||
	if (bi->bid == 0) {
 | 
						if (bi->bid == 0) {
 | 
				
			||||||
		memcpy(bursts_p, bursts_p + 464, 464);
 | 
							memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4), 20 * BPLEN);
 | 
				
			||||||
		memset(bursts_p + 464, 0, 464);
 | 
							memset(BUFPOS(bursts_p, 20), 0, 4 * BPLEN);
 | 
				
			||||||
		*mask = *mask << 4;
 | 
							*mask = *mask << 4;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,8 +111,8 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
	/* store measurements */
 | 
						/* store measurements */
 | 
				
			||||||
	trx_sched_meas_push(chan_state, bi);
 | 
						trx_sched_meas_push(chan_state, bi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* copy burst to end of buffer of 8 bursts */
 | 
						/* copy burst to end of buffer of 24 bursts */
 | 
				
			||||||
	burst = bursts_p + bi->bid * 116 + 464;
 | 
						burst = BUFPOS(bursts_p, 20 + bi->bid);
 | 
				
			||||||
	if (bi->burst_len > 0) {
 | 
						if (bi->burst_len > 0) {
 | 
				
			||||||
		memcpy(burst, bi->burst + 3, 58);
 | 
							memcpy(burst, bi->burst + 3, 58);
 | 
				
			||||||
		memcpy(burst + 58, bi->burst + 87, 58);
 | 
							memcpy(burst + 58, bi->burst + 87, 58);
 | 
				
			||||||
@@ -130,17 +130,20 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
		return 0; /* TODO: send BFI */
 | 
							return 0; /* TODO: send BFI */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* decode
 | 
						/* TCH/F: speech and signalling frames are interleaved over 8 bursts, while
 | 
				
			||||||
	 * also shift buffer by 4 bursts for interleaving */
 | 
						 * CSD frames are interleaved over 22 bursts.  Unless we're in CSD mode,
 | 
				
			||||||
 | 
						 * decode only the last 8 bursts to avoid introducing additional delays. */
 | 
				
			||||||
	switch (tch_mode) {
 | 
						switch (tch_mode) {
 | 
				
			||||||
	case GSM48_CMODE_SIGN:
 | 
						case GSM48_CMODE_SIGN:
 | 
				
			||||||
	case GSM48_CMODE_SPEECH_V1: /* FR */
 | 
						case GSM48_CMODE_SPEECH_V1: /* FR */
 | 
				
			||||||
		rc = gsm0503_tch_fr_decode(tch_data, bursts_p, 1, 0, &n_errors, &n_bits_total);
 | 
							rc = gsm0503_tch_fr_decode(tch_data, BUFTAIL8(bursts_p),
 | 
				
			||||||
 | 
										   1, 0, &n_errors, &n_bits_total);
 | 
				
			||||||
		if (rc == GSM_FR_BYTES) /* only for valid *speech* frames */
 | 
							if (rc == GSM_FR_BYTES) /* only for valid *speech* frames */
 | 
				
			||||||
			lchan_set_marker(osmo_fr_is_any_sid(tch_data), lchan); /* DTXu */
 | 
								lchan_set_marker(osmo_fr_is_any_sid(tch_data), lchan); /* DTXu */
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case GSM48_CMODE_SPEECH_EFR: /* EFR */
 | 
						case GSM48_CMODE_SPEECH_EFR: /* EFR */
 | 
				
			||||||
		rc = gsm0503_tch_fr_decode(tch_data, bursts_p, 1, 1, &n_errors, &n_bits_total);
 | 
							rc = gsm0503_tch_fr_decode(tch_data, BUFTAIL8(bursts_p),
 | 
				
			||||||
 | 
										   1, 1, &n_errors, &n_bits_total);
 | 
				
			||||||
		if (rc == GSM_EFR_BYTES) /* only for valid *speech* frames */
 | 
							if (rc == GSM_EFR_BYTES) /* only for valid *speech* frames */
 | 
				
			||||||
			lchan_set_marker(osmo_efr_is_any_sid(tch_data), lchan); /* DTXu */
 | 
								lchan_set_marker(osmo_efr_is_any_sid(tch_data), lchan); /* DTXu */
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -166,7 +169,7 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
		 * we receive an FACCH frame instead of a voice frame (we
 | 
							 * we receive an FACCH frame instead of a voice frame (we
 | 
				
			||||||
		 * do not know this before we actually decode the frame) */
 | 
							 * do not know this before we actually decode the frame) */
 | 
				
			||||||
		amr = sizeof(struct amr_hdr);
 | 
							amr = sizeof(struct amr_hdr);
 | 
				
			||||||
		rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, bursts_p,
 | 
							rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, BUFTAIL8(bursts_p),
 | 
				
			||||||
			amr_is_cmr, chan_state->codec, chan_state->codecs, &chan_state->ul_ft,
 | 
								amr_is_cmr, chan_state->codec, chan_state->codecs, &chan_state->ul_ft,
 | 
				
			||||||
			&chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
 | 
								&chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -218,6 +221,33 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
			        ft, AMR_GOOD);
 | 
								        ft, AMR_GOOD);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						/* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_12k0:
 | 
				
			||||||
 | 
							rc = gsm0503_tch_fr96_decode(&tch_data[0], BUFPOS(bursts_p, 0),
 | 
				
			||||||
 | 
										     &n_errors, &n_bits_total);
 | 
				
			||||||
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						/* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_6k0:
 | 
				
			||||||
 | 
							rc = gsm0503_tch_fr48_decode(&tch_data[0], BUFPOS(bursts_p, 0),
 | 
				
			||||||
 | 
										     &n_errors, &n_bits_total);
 | 
				
			||||||
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						/* TODO: CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_3k6:
 | 
				
			||||||
 | 
							/* TCH/F2.4 employs the same interleaving as TCH/FS (8 bursts) */
 | 
				
			||||||
 | 
							rc = gsm0503_tch_fr24_decode(&tch_data[0], BUFTAIL8(bursts_p),
 | 
				
			||||||
 | 
										     &n_errors, &n_bits_total);
 | 
				
			||||||
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S8N8;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						/* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_14k5:
 | 
				
			||||||
 | 
							rc = gsm0503_tch_fr144_decode(&tch_data[0], BUFPOS(bursts_p, 0),
 | 
				
			||||||
 | 
										      &n_errors, &n_bits_total);
 | 
				
			||||||
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S24N22;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
 | 
							LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
 | 
				
			||||||
@@ -271,7 +301,7 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
		rc = 0;
 | 
							rc = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
 | 
						if (rsl_cmode == RSL_CMOD_SPD_SIGN)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TCH or BFI */
 | 
						/* TCH or BFI */
 | 
				
			||||||
@@ -406,6 +436,29 @@ struct msgb *tch_dl_dequeue(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br
 | 
				
			|||||||
			msg_tch->l2h += sizeof(struct amr_hdr);
 | 
								msg_tch->l2h += sizeof(struct amr_hdr);
 | 
				
			||||||
			len -= sizeof(struct amr_hdr);
 | 
								len -= sizeof(struct amr_hdr);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case GSM48_CMODE_DATA_14k5: /* TCH/F14.4 */
 | 
				
			||||||
 | 
								if (OSMO_UNLIKELY(br->chan != TRXC_TCHF))
 | 
				
			||||||
 | 
									goto inval_mode2;
 | 
				
			||||||
 | 
								len = 290;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case GSM48_CMODE_DATA_12k0: /* TCH/F9.6 */
 | 
				
			||||||
 | 
								if (OSMO_UNLIKELY(br->chan != TRXC_TCHF))
 | 
				
			||||||
 | 
									goto inval_mode2;
 | 
				
			||||||
 | 
								len = 4 * 60;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case GSM48_CMODE_DATA_6k0: /* TCH/[FH]4.8 */
 | 
				
			||||||
 | 
								if (br->chan == TRXC_TCHF)
 | 
				
			||||||
 | 
									len = 2 * 60;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									len = 4 * 60;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case GSM48_CMODE_DATA_3k6: /* TCH/[FH]2.4 */
 | 
				
			||||||
 | 
								/* FIXME: TCH/F2.4 is not supported */
 | 
				
			||||||
 | 
								if (br->chan == TRXC_TCHF)
 | 
				
			||||||
 | 
									goto inval_mode2; /* 2 * 36 */
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									len = 4 * 36;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
inval_mode2:
 | 
					inval_mode2:
 | 
				
			||||||
			LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
 | 
								LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
 | 
				
			||||||
@@ -446,8 +499,8 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
 | 
				
			|||||||
	/* BURST BYPASS */
 | 
						/* BURST BYPASS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	 /* shift buffer by 4 bursts for interleaving */
 | 
						 /* shift buffer by 4 bursts for interleaving */
 | 
				
			||||||
	memcpy(bursts_p, bursts_p + 464, 464);
 | 
						memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 4), 20 * BPLEN);
 | 
				
			||||||
	memset(bursts_p + 464, 0, 464);
 | 
						memset(BUFPOS(bursts_p, 20), 0, 4 * BPLEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* dequeue a message to be transmitted */
 | 
						/* dequeue a message to be transmitted */
 | 
				
			||||||
	msg = tch_dl_dequeue(l1ts, br);
 | 
						msg = tch_dl_dequeue(l1ts, br);
 | 
				
			||||||
@@ -485,23 +538,48 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
 | 
				
			|||||||
		goto send_burst;
 | 
							goto send_burst;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* populate the buffer with bursts */
 | 
						if (msgb_l2len(msg) == GSM_MACBLOCK_LEN)
 | 
				
			||||||
	if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) {
 | 
					 | 
				
			||||||
		gsm0503_tch_fr_encode(bursts_p, msg->l2h, msgb_l2len(msg), 1);
 | 
					 | 
				
			||||||
		chan_state->dl_facch_bursts = 8;
 | 
							chan_state->dl_facch_bursts = 8;
 | 
				
			||||||
	} else if (tch_mode == GSM48_CMODE_SPEECH_AMR) {
 | 
					
 | 
				
			||||||
 | 
						/* populate the buffer with bursts */
 | 
				
			||||||
 | 
						switch (tch_mode) {
 | 
				
			||||||
 | 
						case GSM48_CMODE_SIGN:
 | 
				
			||||||
 | 
						case GSM48_CMODE_SPEECH_V1:
 | 
				
			||||||
 | 
						case GSM48_CMODE_SPEECH_EFR:
 | 
				
			||||||
 | 
							gsm0503_tch_fr_encode(BUFPOS(bursts_p, 0), msg->l2h, msgb_l2len(msg), 1);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case GSM48_CMODE_SPEECH_AMR:
 | 
				
			||||||
		/* the first FN 4,13,21 defines that CMI is included in frame,
 | 
							/* the first FN 4,13,21 defines that CMI is included in frame,
 | 
				
			||||||
		 * the first FN 0,8,17 defines that CMR is included in frame.
 | 
							 * the first FN 0,8,17 defines that CMR is included in frame.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		gsm0503_tch_afs_encode(bursts_p,
 | 
							gsm0503_tch_afs_encode(BUFPOS(bursts_p, 0),
 | 
				
			||||||
				       msgb_l2(msg), msgb_l2len(msg),
 | 
									       msgb_l2(msg), msgb_l2len(msg),
 | 
				
			||||||
				       !sched_tchf_dl_amr_cmi_map[br->fn % 26],
 | 
									       !sched_tchf_dl_amr_cmi_map[br->fn % 26],
 | 
				
			||||||
				       chan_state->codec,
 | 
									       chan_state->codec,
 | 
				
			||||||
				       chan_state->codecs,
 | 
									       chan_state->codecs,
 | 
				
			||||||
				       chan_state->dl_ft,
 | 
									       chan_state->dl_ft,
 | 
				
			||||||
				       chan_state->dl_cmr);
 | 
									       chan_state->dl_cmr);
 | 
				
			||||||
	} else {
 | 
							break;
 | 
				
			||||||
		gsm0503_tch_fr_encode(bursts_p, msg->l2h, msgb_l2len(msg), 1);
 | 
						/* CSD (TCH/F9.6): 12.0 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_12k0:
 | 
				
			||||||
 | 
							gsm0503_tch_fr96_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						/* CSD (TCH/F4.8): 6.0 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_6k0:
 | 
				
			||||||
 | 
							gsm0503_tch_fr48_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						/* TODO: CSD (TCH/F2.4): 3.6 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_3k6:
 | 
				
			||||||
 | 
							gsm0503_tch_fr24_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						/* CSD (TCH/F14.4): 14.5 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_14k5:
 | 
				
			||||||
 | 
							gsm0503_tch_fr144_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* free message */
 | 
						/* free message */
 | 
				
			||||||
@@ -509,7 +587,7 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
send_burst:
 | 
					send_burst:
 | 
				
			||||||
	/* compose burst */
 | 
						/* compose burst */
 | 
				
			||||||
	burst = bursts_p + br->bid * 116;
 | 
						burst = BUFPOS(bursts_p, br->bid);
 | 
				
			||||||
	memcpy(br->burst + 3, burst, 58);
 | 
						memcpy(br->burst + 3, burst, 58);
 | 
				
			||||||
	memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
 | 
						memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
 | 
				
			||||||
	memcpy(br->burst + 87, burst + 58, 58);
 | 
						memcpy(br->burst + 87, burst + 58, 58);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
 | 
					 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
 | 
				
			||||||
 * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
 | 
					 * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * Contributions by sysmocom - s.f.m.c. GmbH
 | 
					 * (C) 2020-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * All Rights Reserved
 | 
					 * All Rights Reserved
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -91,16 +91,51 @@ static const uint8_t sched_tchh_ul_facch_map[26] = {
 | 
				
			|||||||
/* TDMA frame number of burst 'a' is used as the table index. */
 | 
					/* TDMA frame number of burst 'a' is used as the table index. */
 | 
				
			||||||
extern const uint8_t sched_tchh_dl_facch_map[26];
 | 
					extern const uint8_t sched_tchh_dl_facch_map[26];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 3GPP TS 45.002, table 2 in clause 7: Mapping tables for TCH/H2.4 and TCH/H4.8.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 | 
				
			||||||
 | 
					 * | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v |
 | 
				
			||||||
 | 
					 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TCH/H(0): B0(0,2,4,6,8,10,13,15,17,19,21,23,0,2,4,6,8,10,13,15,17,19)
 | 
				
			||||||
 | 
					 * TCH/H(1): B0(1,3,5,7,9,11,14,16,18,20,22,24,1,3,5,7,9,11,14,16,18,20)
 | 
				
			||||||
 | 
					 * TCH/H(0): B1(8,10,13,15,17,19,21,23,0,2,4,6,8,10,13,15,17,19,21,23,0,2)
 | 
				
			||||||
 | 
					 * TCH/H(1): B1(9,11,14,16,18,20,22,24,1,3,5,7,9,11,14,16,18,20,22,24,1,3)
 | 
				
			||||||
 | 
					 * TCH/H(0): B2(17,19,21,23,0,2,4,6,8,10,13,15,17,19,21,23,0,2,4,6,8,10)
 | 
				
			||||||
 | 
					 * TCH/H(1): B2(18,20,22,24,1,3,5,7,9,11,14,16,18,20,22,24,1,3,5,7,9,11)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TDMA frame number of burst 'v' % 26 is the table index.
 | 
				
			||||||
 | 
					 * This mapping is valid for both TCH/H(0) and TCH/H(1). */
 | 
				
			||||||
 | 
					static const uint8_t sched_tchh_ul_csd_map[26] = {
 | 
				
			||||||
 | 
						[19] = 1, /* TCH/H(0): B0(0  ... 19) */
 | 
				
			||||||
 | 
						[20] = 1, /* TCH/H(1): B0(1  ... 20) */
 | 
				
			||||||
 | 
						[2]  = 1, /* TCH/H(0): B1(8  ... 2) */
 | 
				
			||||||
 | 
						[3]  = 1, /* TCH/H(1): B1(9  ... 3) */
 | 
				
			||||||
 | 
						[10] = 1, /* TCH/H(0): B2(17 ... 10) */
 | 
				
			||||||
 | 
						[11] = 1, /* TCH/H(1): B2(18 ... 11) */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TDMA frame number of burst 'a' % 26 is the table index.
 | 
				
			||||||
 | 
					 * This mapping is valid for both TCH/H(0) and TCH/H(1). */
 | 
				
			||||||
 | 
					static const uint8_t sched_tchh_dl_csd_map[26] = {
 | 
				
			||||||
 | 
						[0]  = 1, /* TCH/H(0): B0(0  ... 19) */
 | 
				
			||||||
 | 
						[1]  = 1, /* TCH/H(1): B0(1  ... 20) */
 | 
				
			||||||
 | 
						[8]  = 1, /* TCH/H(0): B1(8  ... 2) */
 | 
				
			||||||
 | 
						[9]  = 1, /* TCH/H(1): B1(9  ... 3) */
 | 
				
			||||||
 | 
						[17] = 1, /* TCH/H(0): B2(17 ... 10) */
 | 
				
			||||||
 | 
						[18] = 1, /* TCH/H(1): B2(18 ... 11) */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! \brief a single TCH/H burst was received by the PHY, process it */
 | 
					/*! \brief a single TCH/H burst was received by the PHY, process it */
 | 
				
			||||||
int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
					int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
						struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
				
			||||||
	struct gsm_lchan *lchan = chan_state->lchan;
 | 
						struct gsm_lchan *lchan = chan_state->lchan;
 | 
				
			||||||
	sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
						sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
				
			||||||
	uint8_t *mask = &chan_state->ul_mask;
 | 
						uint32_t *mask = &chan_state->ul_mask;
 | 
				
			||||||
	uint8_t rsl_cmode = chan_state->rsl_cmode;
 | 
						uint8_t rsl_cmode = chan_state->rsl_cmode;
 | 
				
			||||||
	uint8_t tch_mode = chan_state->tch_mode;
 | 
						uint8_t tch_mode = chan_state->tch_mode;
 | 
				
			||||||
	uint8_t tch_data[128]; /* just to be safe */
 | 
						uint8_t tch_data[240]; /* large enough to hold 240 unpacked bits for CSD */
 | 
				
			||||||
	int rc = 0; /* initialize to make gcc happy */
 | 
						int rc = 0; /* initialize to make gcc happy */
 | 
				
			||||||
	int amr = 0;
 | 
						int amr = 0;
 | 
				
			||||||
	int n_errors = 0;
 | 
						int n_errors = 0;
 | 
				
			||||||
@@ -123,9 +158,8 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* shift the buffer by 2 bursts leftwards */
 | 
						/* shift the buffer by 2 bursts leftwards */
 | 
				
			||||||
	if (bi->bid == 0) {
 | 
						if (bi->bid == 0) {
 | 
				
			||||||
		memcpy(bursts_p, bursts_p + 232, 232);
 | 
							memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 2), 20 * BPLEN);
 | 
				
			||||||
		memcpy(bursts_p + 232, bursts_p + 464, 232);
 | 
							memset(BUFPOS(bursts_p, 20), 0, 2 * BPLEN);
 | 
				
			||||||
		memset(bursts_p + 464, 0, 232);
 | 
					 | 
				
			||||||
		*mask = *mask << 2;
 | 
							*mask = *mask << 2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -135,8 +169,8 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
	/* store measurements */
 | 
						/* store measurements */
 | 
				
			||||||
	trx_sched_meas_push(chan_state, bi);
 | 
						trx_sched_meas_push(chan_state, bi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* copy burst to end of buffer of 6 bursts */
 | 
						/* copy burst to end of buffer of 24 bursts */
 | 
				
			||||||
	burst = bursts_p + bi->bid * 116 + 464;
 | 
						burst = BUFPOS(bursts_p, 20 + bi->bid);
 | 
				
			||||||
	if (bi->burst_len > 0) {
 | 
						if (bi->burst_len > 0) {
 | 
				
			||||||
		memcpy(burst, bi->burst + 3, 58);
 | 
							memcpy(burst, bi->burst + 3, 58);
 | 
				
			||||||
		memcpy(burst + 58, bi->burst + 87, 58);
 | 
							memcpy(burst + 58, bi->burst + 87, 58);
 | 
				
			||||||
@@ -165,14 +199,16 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
		goto bfi;
 | 
							goto bfi;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* decode
 | 
						/* TCH/H: speech and signalling frames are interleaved over 4 and 6 bursts,
 | 
				
			||||||
	 * also shift buffer by 4 bursts for interleaving */
 | 
						 * respectively, while CSD frames are interleaved over 22 bursts.  Unless
 | 
				
			||||||
 | 
						 * we're in CSD mode, decode only the last 6 bursts to avoid introducing
 | 
				
			||||||
 | 
						 * additional delays. */
 | 
				
			||||||
	switch (tch_mode) {
 | 
						switch (tch_mode) {
 | 
				
			||||||
	case GSM48_CMODE_SIGN:
 | 
						case GSM48_CMODE_SIGN:
 | 
				
			||||||
		meas_avg_mode = SCHED_MEAS_AVG_M_S6N6;
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S6N6;
 | 
				
			||||||
		/* fall-through */
 | 
							/* fall-through */
 | 
				
			||||||
	case GSM48_CMODE_SPEECH_V1: /* HR or signalling */
 | 
						case GSM48_CMODE_SPEECH_V1: /* HR or signalling */
 | 
				
			||||||
		rc = gsm0503_tch_hr_decode2(tch_data, bursts_p,
 | 
							rc = gsm0503_tch_hr_decode2(tch_data, BUFTAIL8(bursts_p),
 | 
				
			||||||
					    !sched_tchh_ul_facch_map[bi->fn % 26],
 | 
										    !sched_tchh_ul_facch_map[bi->fn % 26],
 | 
				
			||||||
					    &n_errors, &n_bits_total);
 | 
										    &n_errors, &n_bits_total);
 | 
				
			||||||
		if (rc == GSM_HR_BYTES) { /* only for valid *speech* frames */
 | 
							if (rc == GSM_HR_BYTES) { /* only for valid *speech* frames */
 | 
				
			||||||
@@ -199,7 +235,7 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* See comment in function rx_tchf_fn() */
 | 
							/* See comment in function rx_tchf_fn() */
 | 
				
			||||||
		amr = sizeof(struct amr_hdr);
 | 
							amr = sizeof(struct amr_hdr);
 | 
				
			||||||
		rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, bursts_p,
 | 
							rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, BUFTAIL8(bursts_p),
 | 
				
			||||||
						!sched_tchh_ul_facch_map[bi->fn % 26],
 | 
											!sched_tchh_ul_facch_map[bi->fn % 26],
 | 
				
			||||||
						!fn_is_cmi, chan_state->codec,
 | 
											!fn_is_cmi, chan_state->codec,
 | 
				
			||||||
						chan_state->codecs, &chan_state->ul_ft,
 | 
											chan_state->codecs, &chan_state->ul_ft,
 | 
				
			||||||
@@ -254,6 +290,22 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
			        ft, AMR_GOOD);
 | 
								        ft, AMR_GOOD);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						/* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_6k0:
 | 
				
			||||||
 | 
							if (!sched_tchh_ul_csd_map[bi->fn % 26])
 | 
				
			||||||
 | 
								return 0; /* CSD: skip decoding attempt, need 2 more bursts */
 | 
				
			||||||
 | 
							rc = gsm0503_tch_hr48_decode(&tch_data[0], BUFPOS(bursts_p, 0),
 | 
				
			||||||
 | 
										     &n_errors, &n_bits_total);
 | 
				
			||||||
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S22N22;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						/* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_3k6:
 | 
				
			||||||
 | 
							if (!sched_tchh_ul_csd_map[bi->fn % 26])
 | 
				
			||||||
 | 
								return 0; /* CSD: skip decoding attempt, need 2 more bursts */
 | 
				
			||||||
 | 
							rc = gsm0503_tch_hr24_decode(&tch_data[0], BUFPOS(bursts_p, 0),
 | 
				
			||||||
 | 
										     &n_errors, &n_bits_total);
 | 
				
			||||||
 | 
							meas_avg_mode = SCHED_MEAS_AVG_M_S22N22;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
 | 
							LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
 | 
				
			||||||
@@ -308,7 +360,7 @@ bfi:
 | 
				
			|||||||
		rc = 0;
 | 
							rc = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
 | 
						if (rsl_cmode == RSL_CMOD_SPD_SIGN)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TCH or BFI */
 | 
						/* TCH or BFI */
 | 
				
			||||||
@@ -345,13 +397,14 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* BURST BYPASS */
 | 
						/* BURST BYPASS */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	 /* shift buffer by 2 bursts for interleaving */
 | 
						/* shift buffer by 2 bursts for interleaving */
 | 
				
			||||||
	memcpy(bursts_p, bursts_p + 232, 232);
 | 
						memmove(BUFPOS(bursts_p, 0), BUFPOS(bursts_p, 2), 20 * BPLEN);
 | 
				
			||||||
	if (chan_state->dl_ongoing_facch) {
 | 
						memset(BUFPOS(bursts_p, 20), 0, 2 * BPLEN);
 | 
				
			||||||
		memcpy(bursts_p + 232, bursts_p + 464, 232);
 | 
					
 | 
				
			||||||
		memset(bursts_p + 464, 0, 232);
 | 
						/* for half-rate CSD we dequeue every 4th burst */
 | 
				
			||||||
	} else {
 | 
						if (chan_state->rsl_cmode == RSL_CMOD_SPD_DATA) {
 | 
				
			||||||
		memset(bursts_p + 232, 0, 232);
 | 
							if (!sched_tchh_dl_csd_map[br->fn % 26])
 | 
				
			||||||
 | 
								goto send_burst;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* dequeue a message to be transmitted */
 | 
						/* dequeue a message to be transmitted */
 | 
				
			||||||
@@ -397,30 +450,45 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
 | 
				
			|||||||
			goto send_burst;
 | 
								goto send_burst;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		gsm0503_tch_hr_encode(bursts_p, dummy, sizeof(dummy));
 | 
							gsm0503_tch_hr_encode(BUFPOS(bursts_p, 0), dummy, sizeof(dummy));
 | 
				
			||||||
		chan_state->dl_ongoing_facch = 1;
 | 
							chan_state->dl_ongoing_facch = 1;
 | 
				
			||||||
		chan_state->dl_facch_bursts = 6;
 | 
							chan_state->dl_facch_bursts = 6;
 | 
				
			||||||
		goto send_burst;
 | 
							goto send_burst;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* populate the buffer with bursts */
 | 
					 | 
				
			||||||
	if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) {
 | 
						if (msgb_l2len(msg) == GSM_MACBLOCK_LEN) {
 | 
				
			||||||
		gsm0503_tch_hr_encode(bursts_p, msg->l2h, msgb_l2len(msg));
 | 
					 | 
				
			||||||
		chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */
 | 
							chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */
 | 
				
			||||||
		chan_state->dl_facch_bursts = 6;
 | 
							chan_state->dl_facch_bursts = 6;
 | 
				
			||||||
	} else if (tch_mode == GSM48_CMODE_SPEECH_AMR) {
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* populate the buffer with bursts */
 | 
				
			||||||
 | 
						switch (tch_mode) {
 | 
				
			||||||
 | 
						case GSM48_CMODE_SIGN:
 | 
				
			||||||
 | 
						case GSM48_CMODE_SPEECH_V1:
 | 
				
			||||||
 | 
							gsm0503_tch_hr_encode(BUFPOS(bursts_p, 0), msg->l2h, msgb_l2len(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case GSM48_CMODE_SPEECH_AMR:
 | 
				
			||||||
		/* the first FN 4,13,21 or 5,14,22 defines that CMI is included
 | 
							/* the first FN 4,13,21 or 5,14,22 defines that CMI is included
 | 
				
			||||||
		 * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
 | 
							 * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
 | 
				
			||||||
		 * included in frame. */
 | 
							 * included in frame. */
 | 
				
			||||||
		gsm0503_tch_ahs_encode(bursts_p,
 | 
							gsm0503_tch_ahs_encode(BUFPOS(bursts_p, 0),
 | 
				
			||||||
				       msgb_l2(msg), msgb_l2len(msg),
 | 
									       msgb_l2(msg), msgb_l2len(msg),
 | 
				
			||||||
				       !sched_tchh_dl_amr_cmi_map[br->fn % 26],
 | 
									       !sched_tchh_dl_amr_cmi_map[br->fn % 26],
 | 
				
			||||||
				       chan_state->codec,
 | 
									       chan_state->codec,
 | 
				
			||||||
				       chan_state->codecs,
 | 
									       chan_state->codecs,
 | 
				
			||||||
				       chan_state->dl_ft,
 | 
									       chan_state->dl_ft,
 | 
				
			||||||
				       chan_state->dl_cmr);
 | 
									       chan_state->dl_cmr);
 | 
				
			||||||
	} else {
 | 
							break;
 | 
				
			||||||
		gsm0503_tch_hr_encode(bursts_p, msg->l2h, msgb_l2len(msg));
 | 
						/* CSD (TCH/H4.8): 6.0 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_6k0:
 | 
				
			||||||
 | 
							gsm0503_tch_hr48_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						/* CSD (TCH/H2.4): 3.6 kbit/s radio interface rate */
 | 
				
			||||||
 | 
						case GSM48_CMODE_DATA_3k6:
 | 
				
			||||||
 | 
							gsm0503_tch_hr24_encode(BUFPOS(bursts_p, 0), msgb_l2(msg));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* free message */
 | 
						/* free message */
 | 
				
			||||||
@@ -428,7 +496,7 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
send_burst:
 | 
					send_burst:
 | 
				
			||||||
	/* compose burst */
 | 
						/* compose burst */
 | 
				
			||||||
	burst = bursts_p + br->bid * 116;
 | 
						burst = BUFPOS(bursts_p, br->bid);
 | 
				
			||||||
	memcpy(br->burst + 3, burst, 58);
 | 
						memcpy(br->burst + 3, burst, 58);
 | 
				
			||||||
	memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
 | 
						memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26);
 | 
				
			||||||
	memcpy(br->burst + 87, burst + 58, 58);
 | 
						memcpy(br->burst + 87, burst + 58, 58);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@ int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
 | 
				
			|||||||
	struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
						struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
 | 
				
			||||||
	sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
						sbit_t *burst, *bursts_p = chan_state->ul_bursts;
 | 
				
			||||||
	uint32_t *first_fn = &chan_state->ul_first_fn;
 | 
						uint32_t *first_fn = &chan_state->ul_first_fn;
 | 
				
			||||||
	uint8_t *mask = &chan_state->ul_mask;
 | 
						uint32_t *mask = &chan_state->ul_mask;
 | 
				
			||||||
	uint8_t l2[GSM_MACBLOCK_LEN], l2_len;
 | 
						uint8_t l2[GSM_MACBLOCK_LEN], l2_len;
 | 
				
			||||||
	struct l1sched_meas_set meas_avg;
 | 
						struct l1sched_meas_set meas_avg;
 | 
				
			||||||
	int n_errors = 0;
 | 
						int n_errors = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Burst Payload LENgth (short alias) */
 | 
				
			||||||
 | 
					#define BPLEN GSM_NBITS_NB_GMSK_PAYLOAD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Burst BUFfer capacity (in BPLEN units) */
 | 
				
			||||||
 | 
					#define BUFMAX 24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Burst BUFfer position macros */
 | 
				
			||||||
 | 
					#define BUFPOS(buf, n) &buf[(n) * BPLEN]
 | 
				
			||||||
 | 
					#define BUFTAIL8(buf) BUFPOS(buf, (BUFMAX - 8))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void *tall_bts_ctx;
 | 
					extern void *tall_bts_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compute the bit error rate in 1/10000 units */
 | 
					/* Compute the bit error rate in 1/10000 units */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -638,6 +638,8 @@ void trx_sched_meas_push(struct l1sched_chan_state *chan_state,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Measurement averaging mode sets: [MODE] = { SHIFT, NUM } */
 | 
					/* Measurement averaging mode sets: [MODE] = { SHIFT, NUM } */
 | 
				
			||||||
static const uint8_t trx_sched_meas_modeset[][2] = {
 | 
					static const uint8_t trx_sched_meas_modeset[][2] = {
 | 
				
			||||||
 | 
						[SCHED_MEAS_AVG_M_S24N22] = { 24, 22 },
 | 
				
			||||||
 | 
						[SCHED_MEAS_AVG_M_S22N22] = { 22, 22 },
 | 
				
			||||||
	[SCHED_MEAS_AVG_M_S4N4] = { 4, 4 },
 | 
						[SCHED_MEAS_AVG_M_S4N4] = { 4, 4 },
 | 
				
			||||||
	[SCHED_MEAS_AVG_M_S8N8] = { 8, 8 },
 | 
						[SCHED_MEAS_AVG_M_S8N8] = { 8, 8 },
 | 
				
			||||||
	[SCHED_MEAS_AVG_M_S6N4] = { 6, 4 },
 | 
						[SCHED_MEAS_AVG_M_S6N4] = { 6, 4 },
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user