blob: 9d81558b1717b51c96874d1be2ca73039038765e [file] [log] [blame]
Eric Wildd40300e2022-05-07 15:36:47 +02001#include <complex.h>
2#include <stdio.h>
3#include <math.h>
4#include <string.h>
5
6#include <osmocom/core/bits.h>
7#include <osmocom/core/conv.h>
8#include <osmocom/core/utils.h>
9#include <osmocom/core/crcgen.h>
Eric935c8cb2022-06-06 00:48:09 +020010#include <osmocom/coding/gsm0503_coding.h>
11#include <osmocom/coding/gsm0503_parity.h>
Eric Wildd40300e2022-05-07 15:36:47 +020012
13#include "sch.h"
14
15/* GSM 04.08, 9.1.30 Synchronization channel information */
16struct sch_packed_info {
17 ubit_t t1_hi[2];
18 ubit_t bsic[6];
19 ubit_t t1_md[8];
20 ubit_t t3p_hi[2];
21 ubit_t t2[5];
22 ubit_t t1_lo[1];
23 ubit_t t3p_lo[1];
24} __attribute__((packed));
25
26struct sch_burst {
27 sbit_t tail0[3];
28 sbit_t data0[39];
29 sbit_t etsc[64];
30 sbit_t data1[39];
31 sbit_t tail1[3];
32 sbit_t guard[8];
33} __attribute__((packed));
34
35static const uint8_t sch_next_output[][2] = {
36 { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
37 { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
38 { 3, 0 }, { 2, 1 }, { 3, 0 }, { 2, 1 },
39 { 0, 3 }, { 1, 2 }, { 0, 3 }, { 1, 2 },
40};
41
42static const uint8_t sch_next_state[][2] = {
43 { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
44 { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
45 { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
46 { 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
47};
48
49static const struct osmo_conv_code gsm_conv_sch = {
50 .N = 2,
51 .K = 5,
52 .len = GSM_SCH_UNCODED_LEN,
53 .next_output = sch_next_output,
54 .next_state = sch_next_state,
55};
56
Eric Wildd40300e2022-05-07 15:36:47 +020057#define GSM_MAX_BURST_LEN 157 * 4
58#define GSM_SYM_RATE (1625e3 / 6) * 4
59
60/* Pre-generated FCCH measurement tone */
61static complex float fcch_ref[GSM_MAX_BURST_LEN];
62
63int float_to_sbit(const float *in, sbit_t *out, float scale, int len)
64{
65 int i;
66
67 for (i = 0; i < len; i++) {
68 out[i] = (in[i] - 0.5f) * scale;
69 }
70
71 return 0;
72}
73
74/* Check if FN contains a FCCH burst */
75int gsm_fcch_check_fn(int fn)
76{
77 int fn51 = fn % 51;
78
79 switch (fn51) {
80 case 0:
81 case 10:
82 case 20:
83 case 30:
84 case 40:
85 return 1;
86 }
87
88 return 0;
89}
90
91/* Check if FN contains a SCH burst */
92int gsm_sch_check_fn(int fn)
93{
94 int fn51 = fn % 51;
95
96 switch (fn51) {
97 case 1:
98 case 11:
99 case 21:
100 case 31:
101 case 41:
102 return 1;
103 }
104
105 return 0;
106}
107
108/* SCH (T1, T2, T3p) to full FN value */
109int gsm_sch_to_fn(struct sch_info *sch)
110{
111 int t1 = sch->t1;
112 int t2 = sch->t2;
113 int t3p = sch->t3p;
114
115 if ((t1 < 0) || (t2 < 0) || (t3p < 0))
116 return -1;
117 int tt;
118 int t3 = t3p * 10 + 1;
119
120 if (t3 < t2)
121 tt = (t3 + 26) - t2;
122 else
123 tt = (t3 - t2) % 26;
124
125 return t1 * 51 * 26 + tt * 51 + t3;
126}
127
128/* Parse encoded SCH message */
129int gsm_sch_parse(const uint8_t *info, struct sch_info *desc)
130{
131 struct sch_packed_info *p = (struct sch_packed_info *) info;
132
133 desc->bsic = (p->bsic[0] << 0) | (p->bsic[1] << 1) |
134 (p->bsic[2] << 2) | (p->bsic[3] << 3) |
135 (p->bsic[4] << 4) | (p->bsic[5] << 5);
136
137 desc->t1 = (p->t1_lo[0] << 0) | (p->t1_md[0] << 1) |
138 (p->t1_md[1] << 2) | (p->t1_md[2] << 3) |
139 (p->t1_md[3] << 4) | (p->t1_md[4] << 5) |
140 (p->t1_md[5] << 6) | (p->t1_md[6] << 7) |
141 (p->t1_md[7] << 8) | (p->t1_hi[0] << 9) |
142 (p->t1_hi[1] << 10);
143
144 desc->t2 = (p->t2[0] << 0) | (p->t2[1] << 1) |
145 (p->t2[2] << 2) | (p->t2[3] << 3) |
146 (p->t2[4] << 4);
147
148 desc->t3p = (p->t3p_lo[0] << 0) | (p->t3p_hi[0] << 1) |
149 (p->t3p_hi[1] << 2);
150
151 return 0;
152}
153
154/* From osmo-bts */
Eric935c8cb2022-06-06 00:48:09 +0200155__attribute__((xray_always_instrument)) __attribute__((noinline)) int gsm_sch_decode(uint8_t *info, sbit_t *data)
Eric Wildd40300e2022-05-07 15:36:47 +0200156{
157 int rc;
158 ubit_t uncoded[GSM_SCH_UNCODED_LEN];
159
160 osmo_conv_decode(&gsm_conv_sch, data, uncoded);
161
162 rc = osmo_crc16gen_check_bits(&gsm0503_sch_crc10,
163 uncoded, GSM_SCH_INFO_LEN,
164 uncoded + GSM_SCH_INFO_LEN);
165 if (rc)
166 return -1;
167
168 memcpy(info, uncoded, GSM_SCH_INFO_LEN * sizeof(ubit_t));
169
170 return 0;
171}
172
173#define FCCH_TAIL_BITS_LEN 3*4
174#define FCCH_DATA_LEN 100*4// 142
175#if 1
176/* Compute FCCH frequency offset */
177double org_gsm_fcch_offset(float *burst, int len)
178{
179 int i, start, end;
180 float a, b, c, d, ang, avg = 0.0f;
181 double freq;
182
183 if (len > GSM_MAX_BURST_LEN)
184 len = GSM_MAX_BURST_LEN;
185
186 for (i = 0; i < len; i++) {
187 a = burst[2 * i + 0];
188 b = burst[2 * i + 1];
189 c = crealf(fcch_ref[i]);
190 d = cimagf(fcch_ref[i]);
191
192 burst[2 * i + 0] = a * c - b * d;
193 burst[2 * i + 1] = a * d + b * c;
194 }
195
196 start = FCCH_TAIL_BITS_LEN;
197 end = start + FCCH_DATA_LEN;
198
199 for (i = start; i < end; i++) {
200 a = cargf(burst[2 * (i - 1) + 0] +
201 burst[2 * (i - 1) + 1] * I);
202 b = cargf(burst[2 * i + 0] +
203 burst[2 * i + 1] * I);
204
205 ang = b - a;
206
207 if (ang > M_PI)
208 ang -= 2 * M_PI;
209 else if (ang < -M_PI)
210 ang += 2 * M_PI;
211
212 avg += ang;
213 }
214
215 avg /= (float) (end - start);
216 freq = avg / (2 * M_PI) * GSM_SYM_RATE;
217
218 return freq;
219}
220
221
222static const int L1 = 3;
223static const int L2 = 32;
224static const int N1 = 92;
225static const int N2 = 92;
226
227static struct { int8_t r; int8_t s; } P_inv_table[3+32];
228
229void pinv(int P, int8_t* r, int8_t* s, int L1, int L2) {
230 for (int i = 0; i < L1; i++)
231 for (int j = 0; j < L2; j++)
232 if (P == L2 * i - L1 * j) {
233 *r = i;
234 *s = j;
235 return;
236 }
237}
238
239
240float ac_sum_with_lag( complex float* in, int lag, int offset, int N) {
241 complex float v = 0 + 0*I;
242 int total_offset = offset + lag;
243 for (int s = 0; s < N; s++)
244 v += in[s + total_offset] * conjf(in[s + total_offset - lag]);
245 return cargf(v);
246}
247
248
249double gsm_fcch_offset(float *burst, int len)
250{
251 int start;
252
253 const float fs = 13. / 48. * 1e6 * 4;
254 const float expected_fcch_val = ((2 * M_PI) / (fs)) * 67700;
255
256 if (len > GSM_MAX_BURST_LEN)
257 len = GSM_MAX_BURST_LEN;
258
259 start = FCCH_TAIL_BITS_LEN+10 * 4;
260 float alpha_one = ac_sum_with_lag((complex float*)burst, L1, start, N1);
261 float alpha_two = ac_sum_with_lag((complex float*)burst, L2, start, N2);
262
263 float P_unrounded = (L1 * alpha_two - L2 * alpha_one) / (2 * M_PI);
264 int P = roundf(P_unrounded);
265
266 int8_t r = 0, s = 0;
267 pinv(P, &r, &s, L1, L2);
268
269 float omegal1 = (alpha_one + 2 * M_PI * r) / L1;
270 float omegal2 = (alpha_two + 2 * M_PI * s) / L2;
271
272 float rv = org_gsm_fcch_offset(burst, len);
273 //return rv;
274
275 float reval = GSM_SYM_RATE / (2 * M_PI) * (expected_fcch_val - (omegal1+omegal2)/2);
276 //fprintf(stderr, "XX rv %f %f %f %f\n", rv, reval, omegal1 / (2 * M_PI) * fs, omegal2 / (2 * M_PI) * fs);
277
278 //fprintf(stderr, "XX rv %f %f\n", rv, reval);
279
280 return -reval;
281}
282#endif
283/* Generate FCCH measurement tone */
284static __attribute__((constructor)) void init()
285{
286 int i;
287 double freq = 0.25;
288
289 for (i = 0; i < GSM_MAX_BURST_LEN; i++) {
290 fcch_ref[i] = sin(2 * M_PI * freq * (double) i) +
291 cos(2 * M_PI * freq * (double) i) * I;
292 }
293
294}