1 /* BCCH Scanning code for OsmocomBB */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
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.
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.
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.
28 #include <l1a_l23_interface.h>
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>
41 #include <osmocom/l1ctl.h>
42 #include <osmocom/osmocom_data.h>
43 #include <osmocom/lapdm.h>
44 #include <osmocom/logging.h>
45 #include <osmocom/gsmtap_util.h>
47 /* somewhere in 05.08 */
48 #define MAX_CELLS_IN_BA 32
50 /* Information about a single cell / BCCH */
52 struct llist_head list;
59 uint16_t mcc; /* Mobile Country Code */
60 uint16_t mnc; /* Mobile Network Code */
61 uint16_t lac; /* Location Area Code */
62 uint16_t rac; /* Routing Area Code */
63 uint16_t cid; /* Cell ID */
65 uint16_t ba_arfcn[MAX_CELLS_IN_BA];
69 int32_t fn_delta; /* delta to current L1 fn */
75 #define AFS_F_PM_DONE 0x01
76 #define AFS_F_TESTED 0x02
77 #define AFS_F_BCCH 0x04
97 struct full_power_scan {
99 enum fps_state fps_state;
100 struct arfcn_state arfcn_state[1024];
102 struct osmocom_ms *ms;
105 enum bscan_state state;
106 struct llist_head cell_list;
107 struct cell_info *cur_cell;
109 struct timer_list timer;
112 static struct full_power_scan fps;
114 static int get_next_arfcn(struct full_power_scan *fps)
117 uint8_t best_rxlev = 0;
120 for (i = 0; i < ARRAY_SIZE(fps->arfcn_state); i++) {
121 struct arfcn_state *af = &fps->arfcn_state[i];
122 /* skip ARFCN's where we don't have a PM */
123 if (!(af->flags & AFS_F_PM_DONE))
125 /* skip ARFCN's that we already tested */
126 if (af->flags & AFS_F_TESTED)
128 /* if current arfcn_state is better than best so far,
130 if (af->rxlev > best_rxlev) {
131 best_rxlev = af->rxlev;
135 printf("arfcn=%d rxlev=%u\n", best_arfcn, best_rxlev);
139 static struct cell_info *cell_info_alloc(void)
141 struct cell_info *ci = talloc_zero(NULL, struct cell_info);
145 static void cell_info_free(struct cell_info *ci)
150 /* start to scan for one ARFCN */
151 static int _cinfo_start_arfcn(unsigned int band_arfcn)
155 /* ask L1 to try to tune to new ARFCN */
156 /* FIXME: decode band */
157 rc = l1ctl_tx_fbsb_req(fps.ms, band_arfcn,
158 L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_COMBINED);
162 /* allocate new cell info structure */
163 fps.cur_cell = cell_info_alloc();
164 fps.cur_arfcn = band_arfcn;
165 fps.cur_cell->band_arfcn = band_arfcn;
166 /* FIXME: start timer in case we never get a sync */
167 fps.state = BSCAN_S_WAIT_DATA;
168 bsc_schedule_timer(&fps.timer, 2, 0);
174 static void cinfo_next_cell(void *data)
178 /* we've been waiting for BCCH info */
179 fps.arfcn_state[fps.cur_arfcn].flags |= AFS_F_TESTED;
180 /* if there is a BCCH, we need to add the collected BCCH
181 * information to our list */
183 if (fps.arfcn_state[fps.cur_arfcn].flags & AFS_F_BCCH)
184 llist_add(&fps.cur_cell->list, &fps.cell_list);
186 cell_info_free(fps.cur_cell);
188 rc = get_next_arfcn(&fps);
190 fps.state = BSCAN_S_DONE;
193 /* start syncing to the next ARFCN */
194 _cinfo_start_arfcn(rc);
197 static void cinfo_timer_cb(void *data)
200 case BSCAN_S_WAIT_DATA:
201 cinfo_next_cell(data);
206 /* Update cell_info for current cell with received BCCH info */
207 static int rx_bcch_info(const uint8_t *data)
209 struct cell_info *ci = fps.cur_cell;
210 struct gsm48_system_information_type_header *si_hdr;
211 si_hdr = (struct gsm48_system_information_type_header *) data;;
213 /* we definitely have a BCCH on this channel */
214 fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH;
216 switch (si_hdr->system_information) {
217 case GSM48_MT_RR_SYSINFO_1:
218 /* FIXME: CA, RACH control */
220 case GSM48_MT_RR_SYSINFO_2:
221 /* FIXME: BA, NCC, RACH control */
223 case GSM48_MT_RR_SYSINFO_3:
224 /* FIXME: cell_id, LAI */
226 case GSM48_MT_RR_SYSINFO_4:
233 /* Update L1/SCH information (AFC/QBIT/FN offset, BSIC) */
234 static int rx_sch_info()
239 static int bscan_sig_cb(unsigned int subsys, unsigned int signal,
240 void *handler_data, void *signal_data)
242 struct cell_info *ci = fps.cur_cell;
243 struct osmocom_ms *ms;
244 struct osmobb_meas_res *mr;
248 if (subsys != SS_L1CTL)
254 /* check if PM result is for same MS */
255 if (fps.ms != mr->ms)
257 arfcn = mr->band_arfcn & 0x3ff;
258 /* update RxLev and notice that PM was done */
259 fps.arfcn_state[arfcn].rxlev = mr->rx_lev;
260 fps.arfcn_state[arfcn].flags |= AFS_F_PM_DONE;
262 case S_L1CTL_PM_DONE:
264 switch (fps.fps_state) {
265 case FPS_S_PM_GSM900:
266 fps.fps_state = FPS_S_PM_EGSM900;
267 return l1ctl_tx_pm_req_range(ms, 955, 1023);
268 case FPS_S_PM_EGSM900:
269 fps.fps_state = FPS_S_PM_GSM1800;
270 return l1ctl_tx_pm_req_range(ms, 512, 885);
271 case FPS_S_PM_GSM1800:
272 /* power measurement has finished, we can start
273 * to actually iterate over the ARFCN's and try
274 * to sync to BCCHs */
275 fps.fps_state = FPS_S_BINFO;
276 rc = get_next_arfcn(&fps);
278 fps.state = BSCAN_S_DONE;
281 _cinfo_start_arfcn(rc);
285 case S_L1CTL_FBSB_RESP:
286 /* We actually got a FCCH/SCH burst */
288 fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH;
293 case S_L1CTL_FBSB_ERR:
294 /* We timed out, move on */
295 if (fps.state == BSCAN_S_WAIT_DATA)
296 cinfo_next_cell(NULL);
302 /* start the full power scan */
303 int fps_start(struct osmocom_ms *ms)
305 memset(&fps, 0, sizeof(fps));
308 fps.timer.cb = cinfo_timer_cb;
309 fps.timer.data = &fps;
311 /* Start by scanning the good old GSM900 band */
312 fps.fps_state = FPS_S_PM_GSM900;
313 return l1ctl_tx_pm_req_range(ms, 0, 124);
318 return register_signal_handler(SS_L1CTL, &bscan_sig_cb, NULL);