aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-trx/sched_lchan_rach.c
blob: c3abf321fea7379eacb9ada0d9e1b190ba34de93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
 * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
 * (C) 2019 by Vadim Yanitskiy <axilirator@gmail.com>
 * 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/>.
 *
 */

#include <stdint.h>
#include <limits.h>
#include <errno.h>

#include <osmocom/core/bits.h>
#include <osmocom/core/utils.h>
#include <osmocom/coding/gsm0503_coding.h>

#include <osmo-bts/bts.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/logging.h>
#include <osmo-bts/scheduler.h>
#include <osmo-bts/scheduler_backend.h>

#include <sched_utils.h>

/* 3GPP TS 05.02, section 5.2.7 */
#define RACH_EXT_TAIL_LEN	8
#define RACH_SYNCH_SEQ_LEN	41

enum rach_synch_seq_t {
	RACH_SYNCH_SEQ_UNKNOWN = -1,
	RACH_SYNCH_SEQ_TS0, /* GSM, GMSK (default) */
	RACH_SYNCH_SEQ_TS1, /* EGPRS, 8-PSK */
	RACH_SYNCH_SEQ_TS2, /* EGPRS, GMSK */
	RACH_SYNCH_SEQ_NUM
};

static struct value_string rach_synch_seq_names[] = {
	{ RACH_SYNCH_SEQ_UNKNOWN,	"UNKNOWN" },
	{ RACH_SYNCH_SEQ_TS0,		"TS0: GSM, GMSK" },
	{ RACH_SYNCH_SEQ_TS1,		"TS1: EGPRS, 8-PSK" },
	{ RACH_SYNCH_SEQ_TS2,		"TS2: EGPRS, GMSK" },
	{ 0, NULL },
};

static enum rach_synch_seq_t rach_get_synch_seq(sbit_t *bits, int *best_score)
{
	sbit_t *synch_seq_burst = bits + RACH_EXT_TAIL_LEN;
	enum rach_synch_seq_t seq = RACH_SYNCH_SEQ_TS0;
	int score[RACH_SYNCH_SEQ_NUM] = { 0 };
	int max_score = INT_MIN;
	int i, j;

	/* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
	static const char synch_seq_ref[RACH_SYNCH_SEQ_NUM][RACH_SYNCH_SEQ_LEN] = {
		[RACH_SYNCH_SEQ_TS0] = "01001011011111111001100110101010001111000",
		[RACH_SYNCH_SEQ_TS1] = "01010100111110001000011000101111001001101",
		[RACH_SYNCH_SEQ_TS2] = "11101111001001110101011000001101101110111",
	};

	/* Get a multiplier for j-th bit of i-th synch. sequence */
#define RACH_SYNCH_SEQ_MULT \
	(synch_seq_ref[i][j] == '1' ? -1 : 1)

	/* For each synch. sequence, count the bit match score. Since we deal with
	 * soft-bits (-127...127), we sum the absolute values of matching ones,
	 * and subtract the absolute values of different ones, so the resulting
	 * score is more accurate than it could be with hard-bits. */
	for (i = 0; i < RACH_SYNCH_SEQ_NUM; i++) {
		for (j = 0; j < RACH_SYNCH_SEQ_LEN; j++)
			score[i] += RACH_SYNCH_SEQ_MULT * synch_seq_burst[j];

		/* Keep the maximum value updated */
		if (score[i] > max_score) {
			max_score = score[i];
			seq = i;
		}
	}

	/* Calculate an approximate level of our confidence */
	if (best_score != NULL)
		*best_score = max_score;

	/* At least 1/3 of a synch. sequence shall match */
	if (max_score < (127 * RACH_SYNCH_SEQ_LEN / 3))
		return RACH_SYNCH_SEQ_UNKNOWN;

	return seq;
}

int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
{
	struct gsm_bts_trx *trx = l1ts->ts->trx;
	struct osmo_phsap_prim l1sap;
	int n_errors = 0;
	int n_bits_total = 0;
	uint16_t ra11;
	uint8_t ra;
	int rc;

	/* TSC (Training Sequence Code) is an optional parameter of the UL burst
	 * indication. We need this information in order to decide whether an
	 * Access Burst is 11-bit encoded or not (see OS#1854). If this information
	 * is absent, we try to correlate the received synch. sequence with the
	 * known ones (3GPP TS 05.02, section 5.2.7), and fall-back to the default
	 * TS0 if it fails. */
	enum rach_synch_seq_t synch_seq = RACH_SYNCH_SEQ_TS0;
	int best_score = 127 * RACH_SYNCH_SEQ_LEN;

	/* If logical channel is not either of RACH, PDTCH or PTCCH, this is a
	 * handover Access Burst, which is always encoded as 8-bit and shall
	 * contain the generic training sequence (TS0). */
	if (bi->chan == TRXC_RACH || bi->chan == TRXC_PDTCH || bi->chan == TRXC_PTCCH) {
		if (bi->flags & TRX_BI_F_TS_INFO)
			synch_seq = (enum rach_synch_seq_t) bi->tsc;
		else
			synch_seq = rach_get_synch_seq((sbit_t *) bi->burst, &best_score);
	}

	LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
	       "Received%s RACH (%s): rssi=%d toa256=%d",
	       (bi->chan != TRXC_RACH) ? " handover" : "",
	       get_value_string(rach_synch_seq_names, synch_seq),
	       bi->rssi, bi->toa256);
	if (bi->flags & TRX_BI_F_CI_CB)
		LOGPC(DL1P, LOGL_DEBUG, " C/I=%d cB", bi->ci_cb);
	else
		LOGPC(DL1P, LOGL_DEBUG, " match=%.1f%%",
		      best_score * 100.0 / (127 * RACH_SYNCH_SEQ_LEN));
	LOGPC(DL1P, LOGL_DEBUG, "\n");

	/* Compose a new L1SAP primitive */
	memset(&l1sap, 0x00, sizeof(l1sap));
	osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, NULL);
	l1sap.u.rach_ind.chan_nr = trx_chan_desc[bi->chan].chan_nr | bi->tn;
	l1sap.u.rach_ind.acc_delay = (bi->toa256 >= 0) ? bi->toa256 / 256 : 0;
	l1sap.u.rach_ind.acc_delay_256bits = bi->toa256;
	l1sap.u.rach_ind.rssi = bi->rssi;
	l1sap.u.rach_ind.fn = bi->fn;

	/* Link quality is defined by C/I (Carrier-to-Interference ratio),
	 * which has optional presence. If it's absent, report the
	 * minimum acceptable value to pass L1SAP checks. */
	if (bi->flags & TRX_BI_F_CI_CB)
		l1sap.u.rach_ind.lqual_cb = bi->ci_cb;
	else
		l1sap.u.rach_ind.lqual_cb = trx->bts->min_qual_rach;

	/* Decode RACH depending on its synch. sequence */
	switch (synch_seq) {
	case RACH_SYNCH_SEQ_TS1:
	case RACH_SYNCH_SEQ_TS2:
		rc = gsm0503_rach_ext_decode_ber(&ra11, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
						 trx->bts->bsic, &n_errors, &n_bits_total);
		if (rc) {
			LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad Access Burst\n");
			return 0;
		}

		if (synch_seq == RACH_SYNCH_SEQ_TS1)
			l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_1;
		else
			l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_2;

		l1sap.u.rach_ind.is_11bit = 1;
		l1sap.u.rach_ind.ra = ra11;
		break;

	case RACH_SYNCH_SEQ_TS0:
	default:
		/* Fall-back to the default TS0 if needed */
		if (synch_seq != RACH_SYNCH_SEQ_TS0) {
			LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Falling-back to the default TS0\n");
			synch_seq = RACH_SYNCH_SEQ_TS0;
		}

		rc = gsm0503_rach_decode_ber(&ra, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
					     trx->bts->bsic, &n_errors, &n_bits_total);
		if (rc) {
			LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad Access Burst\n");
			return 0;
		}

		l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;
		l1sap.u.rach_ind.is_11bit = 0;
		l1sap.u.rach_ind.ra = ra;
		break;
	}

	l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);

	/* forward primitive */
	l1sap_up(trx, &l1sap);

	return 0;
}