dff4dc9b3878716e74d528540ccaf85d3194270f
[osmocom-bb.git] / src / host / layer23 / src / misc / bcch_scan.c
1 /* BCCH Scanning code for OsmocomBB */
2
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
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 <stdio.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <l1ctl_proto.h>
29
30 #include <osmocore/logging.h>
31 #include <osmocore/talloc.h>
32 #include <osmocore/signal.h>
33 #include <osmocore/timer.h>
34 #include <osmocore/msgb.h>
35 #include <osmocore/tlv.h>
36 #include <osmocore/gsm_utils.h>
37 #include <osmocore/protocol/gsm_04_08.h>
38 #include <osmocore/protocol/gsm_08_58.h>
39 #include <osmocore/rsl.h>
40
41 #include <osmocom/bb/common/l1ctl.h>
42 #include <osmocom/bb/common/osmocom_data.h>
43 #include <osmocom/bb/common/lapdm.h>
44 #include <osmocom/bb/common/logging.h>
45
46 /* somewhere in 05.08 */
47 #define MAX_CELLS_IN_BA 32
48
49 /* Information about a single cell / BCCH */
50 struct cell_info {
51         struct llist_head list;
52
53         uint16_t band_arfcn;
54         uint8_t bsic;
55         uint8_t rxlev;
56
57         struct {
58                 uint16_t mcc;   /* Mobile Country Code */
59                 uint16_t mnc;   /* Mobile Network Code */
60                 uint16_t lac;   /* Location Area Code */
61                 uint16_t rac;   /* Routing Area Code */
62                 uint16_t cid;   /* Cell ID */
63         } id;
64         uint16_t ba_arfcn[MAX_CELLS_IN_BA];
65         uint8_t ba_arfcn_num;
66
67         struct {
68                 int32_t fn_delta;       /* delta to current L1 fn */
69                 int16_t qbit_delta;
70                 int16_t afc_delta;
71         } l1_sync;
72 };
73
74 #define AFS_F_PM_DONE   0x01
75 #define AFS_F_TESTED    0x02
76 #define AFS_F_BCCH      0x04
77 struct arfcn_state {
78         uint8_t rxlev;
79         uint8_t flags;
80 };
81
82 enum bscan_state {
83         BSCAN_S_NONE,
84         BSCAN_S_WAIT_DATA,
85         BSCAN_S_DONE,
86 };
87
88 enum fps_state {
89         FPS_S_NONE,
90         FPS_S_PM_GSM900,
91         FPS_S_PM_EGSM900,
92         FPS_S_PM_GSM1800,
93         FPS_S_BINFO,
94 };
95
96 struct full_power_scan {
97         /* Full Power Scan */
98         enum fps_state fps_state;
99         struct arfcn_state arfcn_state[1024];
100
101         struct osmocom_ms *ms;
102
103         /* BCCH info part */
104         enum bscan_state state;
105         struct llist_head cell_list;
106         struct cell_info *cur_cell;
107         uint16_t cur_arfcn;
108         struct timer_list timer;
109 };
110
111 static struct full_power_scan fps;
112
113 static int get_next_arfcn(struct full_power_scan *fps)
114 {
115         unsigned int i;
116         uint8_t best_rxlev = 0;
117         int best_arfcn = -1;
118
119         for (i = 0; i < ARRAY_SIZE(fps->arfcn_state); i++) {
120                 struct arfcn_state *af = &fps->arfcn_state[i];
121                 /* skip ARFCN's where we don't have a PM */
122                 if (!(af->flags & AFS_F_PM_DONE))
123                         continue;
124                 /* skip ARFCN's that we already tested */
125                 if (af->flags & AFS_F_TESTED)
126                         continue;
127                 /* if current arfcn_state is better than best so far,
128                  * select it */
129                 if (af->rxlev > best_rxlev) {
130                         best_rxlev = af->rxlev;
131                         best_arfcn = i;
132                 }
133         }
134         printf("arfcn=%d rxlev=%u\n", best_arfcn, best_rxlev);
135         return best_arfcn;
136 }
137
138 static struct cell_info *cell_info_alloc(void)
139 {
140         struct cell_info *ci = talloc_zero(NULL, struct cell_info);
141         return ci;
142 }
143
144 static void cell_info_free(struct cell_info *ci)
145 {
146         talloc_free(ci);
147 }
148
149 /* start to scan for one ARFCN */
150 static int _cinfo_start_arfcn(unsigned int band_arfcn)
151 {
152         int rc;
153
154         /* ask L1 to try to tune to new ARFCN */
155         /* FIXME: decode band */
156         rc = l1ctl_tx_fbsb_req(fps.ms, band_arfcn,
157                                L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_COMBINED);
158         if (rc < 0)
159                 return rc;
160
161         /* allocate new cell info structure */
162         fps.cur_cell = cell_info_alloc();
163         fps.cur_arfcn = band_arfcn;
164         fps.cur_cell->band_arfcn = band_arfcn;
165         /* FIXME: start timer in case we never get a sync */
166         fps.state = BSCAN_S_WAIT_DATA;
167         bsc_schedule_timer(&fps.timer, 2, 0);
168
169         return 0;
170 }
171
172
173 static void cinfo_next_cell(void *data)
174 {
175         int rc;
176
177         /* we've been waiting for BCCH info */
178         fps.arfcn_state[fps.cur_arfcn].flags |= AFS_F_TESTED;
179         /* if there is a BCCH, we need to add the collected BCCH
180          * information to our list */
181
182         if (fps.arfcn_state[fps.cur_arfcn].flags & AFS_F_BCCH)
183                 llist_add(&fps.cur_cell->list, &fps.cell_list);
184         else
185                 cell_info_free(fps.cur_cell);
186
187         rc = get_next_arfcn(&fps);
188         if (rc < 0) {
189                 fps.state = BSCAN_S_DONE;
190                 return;
191         }
192         /* start syncing to the next ARFCN */
193         _cinfo_start_arfcn(rc);
194 }
195
196 static void cinfo_timer_cb(void *data)
197 {
198         switch (fps.state) {
199         case BSCAN_S_WAIT_DATA:
200                 cinfo_next_cell(data);
201                 break;
202         }
203 }
204
205 /* Update cell_info for current cell with received BCCH info */
206 static int rx_bcch_info(const uint8_t *data)
207 {
208         struct cell_info *ci = fps.cur_cell;
209         struct gsm48_system_information_type_header *si_hdr;
210         si_hdr = (struct gsm48_system_information_type_header *) data;;
211
212         /* we definitely have a BCCH on this channel */
213         fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH;
214
215         switch (si_hdr->system_information) {
216         case GSM48_MT_RR_SYSINFO_1:
217                 /* FIXME: CA, RACH control */
218                 break;
219         case GSM48_MT_RR_SYSINFO_2:
220                 /* FIXME: BA, NCC, RACH control */
221                 break;
222         case GSM48_MT_RR_SYSINFO_3:
223                 /* FIXME: cell_id, LAI */
224                 break;
225         case GSM48_MT_RR_SYSINFO_4:
226                 /* FIXME: LAI */
227                 break;
228         }
229         return 0;
230 }
231
232 /* Update L1/SCH information (AFC/QBIT/FN offset, BSIC) */
233 static int rx_sch_info()
234 {
235         /* FIXME */
236 }
237
238 static int bscan_sig_cb(unsigned int subsys, unsigned int signal,
239                      void *handler_data, void *signal_data)
240 {
241         struct cell_info *ci = fps.cur_cell;
242         struct osmocom_ms *ms;
243         struct osmobb_meas_res *mr;
244         uint16_t arfcn;
245         int rc;
246
247         if (subsys != SS_L1CTL)
248                 return 0;
249
250         switch (signal) {
251         case S_L1CTL_PM_RES:
252                 mr = signal_data;
253                 /* check if PM result is for same MS */
254                 if (fps.ms != mr->ms)
255                         return 0;
256                 arfcn = mr->band_arfcn & 0x3ff;
257                 /* update RxLev and notice that PM was done */
258                 fps.arfcn_state[arfcn].rxlev = mr->rx_lev;
259                 fps.arfcn_state[arfcn].flags |= AFS_F_PM_DONE;
260                 break;
261         case S_L1CTL_PM_DONE:
262                 ms = signal_data;
263                 switch (fps.fps_state) {
264                 case FPS_S_PM_GSM900:
265                         fps.fps_state = FPS_S_PM_EGSM900;
266                         return l1ctl_tx_pm_req_range(ms, 955, 1023);
267                 case FPS_S_PM_EGSM900:
268                         fps.fps_state = FPS_S_PM_GSM1800;
269                         return l1ctl_tx_pm_req_range(ms, 512, 885);
270                 case FPS_S_PM_GSM1800:
271                         /* power measurement has finished, we can start
272                          * to actually iterate over the ARFCN's and try
273                          * to sync to BCCHs */
274                         fps.fps_state = FPS_S_BINFO;
275                         rc = get_next_arfcn(&fps);
276                         if (rc < 0) {
277                                 fps.state = BSCAN_S_DONE;
278                                 return;
279                         }
280                         _cinfo_start_arfcn(rc);
281                         break;
282                 }
283                 break;
284         case S_L1CTL_FBSB_RESP:
285                 /* We actually got a FCCH/SCH burst */
286 #if 0
287                 fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH;
288                 /* fallthrough */
289 #else
290                 break;
291 #endif
292         case S_L1CTL_FBSB_ERR:
293                 /* We timed out, move on */
294                 if (fps.state == BSCAN_S_WAIT_DATA)
295                         cinfo_next_cell(NULL);
296                 break;
297         }
298         return 0;
299 }
300
301 /* start the full power scan */
302 int fps_start(struct osmocom_ms *ms)
303 {
304         memset(&fps, 0, sizeof(fps));
305         fps.ms = ms;
306
307         fps.timer.cb = cinfo_timer_cb;
308         fps.timer.data = &fps;
309
310         /* Start by scanning the good old GSM900 band */
311         fps.fps_state = FPS_S_PM_GSM900;
312         return l1ctl_tx_pm_req_range(ms, 0, 124);
313 }
314
315 int fps_init(void)
316 {
317         return register_signal_handler(SS_L1CTL, &bscan_sig_cb, NULL);
318 }