src: use new libosmogsm and include/osmocom/[gsm|core] path to headers
[osmocom-bb.git] / src / target / firmware / layer1 / rfch.c
1 /* RF Channel utilities */
2
3 /* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24
25 #include <osmocom/gsm/gsm_utils.h>
26
27 #include <layer1/sync.h>
28
29
30 /*
31  * Hopping sequence generation
32  *
33  * The algorithm is explained in GSM 05.02 Section 6.2.3
34  *
35  *      if HSN = 0 (cyclic hopping) then:
36  *              MAI, integer (0 .. N-1) :
37  *                      MAI = (FN + MAIO) modulo N
38  *
39  *      else:
40  *              M, integer (0 .. 152) :
41  *                      M = T2 + RNTABLE((HSN xor T1R) + T3)
42  *
43  *              S, integer (0 .. N-1) :
44  *                      M' = M modulo (2 ^ NBIN)
45  *                      T' = T3 modulo (2 ^ NBIN)
46  *
47  *                      if M' < N then:
48  *                              S = M'
49  *                      else:
50  *                              S = (M'+T') modulo N
51  *
52  *              MAI, integer (0 .. N-1) :
53  *                      MAI = (S + MAIO) modulo N
54  */
55
56 static uint8_t rn_table[114] = {
57          48,  98,  63,   1,  36,  95,  78, 102,  94,  73,
58           0,  64,  25,  81,  76,  59, 124,  23, 104, 100,
59         101,  47, 118,  85,  18,  56,  96,  86,  54,   2,
60          80,  34, 127,  13,   6,  89,  57, 103,  12,  74,
61          55, 111,  75,  38, 109,  71, 112,  29,  11,  88,
62          87,  19,   3,  68, 110,  26,  33,  31,   8,  45,
63          82,  58,  40, 107,  32,   5, 106,  92,  62,  67,
64          77, 108, 122,  37,  60,  66, 121,  42,  51, 126,
65         117, 114,   4,  90,  43,  52,  53, 113, 120,  72,
66          16,  49,   7,  79, 119,  61,  22,  84,   9,  97,
67          91,  15,  21,  24,  46,  39,  93, 105,  65,  70,
68         125,  99,  17, 123,
69 };
70
71
72 static int pow_nbin_mask(int n)
73 {
74         int x;
75         x =     (n     ) |
76                 (n >> 1) |
77                 (n >> 2) |
78                 (n >> 3) |
79                 (n >> 4) |
80                 (n >> 5) |
81                 (n >> 6);
82         return x;
83 }
84
85 static int16_t rfch_hop_seq_gen(struct gsm_time *t,
86                                 uint8_t hsn, uint8_t maio,
87                                 uint8_t n, uint16_t *arfcn_tbl)
88 {
89         int mai;
90
91         if (!hsn) {
92                 /* cyclic hopping */
93                 mai = (t->fn + maio) % n;
94         } else {
95                 /* pseudo random hopping */
96                 int m, mp, tp, s, pnm;
97
98                 pnm = pow_nbin_mask(n);
99
100                 m = t->t2 + rn_table[(hsn ^ (t->t1 & 63)) + t->t3];
101                 mp = m & pnm;
102
103                 if (mp < n)
104                         s = mp;
105                 else {
106                         tp = t->t3 & pnm;
107                         s = (mp + tp) % n;
108                 }
109
110                 mai = (s + maio) % n;
111         }
112
113         return arfcn_tbl ? arfcn_tbl[mai] : mai;
114 }
115
116
117 /* RF Channel parameters */
118 void rfch_get_params(struct gsm_time *t,
119                      uint16_t *arfcn_p, uint8_t *tsc_p, uint8_t *tn_p)
120 {
121         if (l1s.dedicated.type == GSM_DCHAN_NONE) {
122                 /* Serving cell only */
123                 if (arfcn_p)
124                         *arfcn_p = l1s.serving_cell.arfcn;
125
126                 if (tsc_p)
127                         *tsc_p = l1s.serving_cell.bsic & 0x7;
128
129                 if (tn_p)
130                         *tn_p = 0;
131         } else {
132                 /* Dedicated channel */
133                 if (arfcn_p) {
134                         if (l1s.dedicated.h) {
135                                 *arfcn_p = rfch_hop_seq_gen(t,
136                                                 l1s.dedicated.h1.hsn,
137                                                 l1s.dedicated.h1.maio,
138                                                 l1s.dedicated.h1.n,
139                                                 l1s.dedicated.h1.ma);
140                         } else {
141                                 *arfcn_p = l1s.dedicated.h0.arfcn;
142                         }
143                 }
144
145                 if (tsc_p)
146                         *tsc_p = l1s.dedicated.tsc;
147
148                 if (tn_p)
149                         *tn_p = l1s.dedicated.tn;
150         }
151 }
152