diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2010-07-25 00:25:50 +0200 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2010-07-27 20:49:04 +0200 |
commit | de21ca4aaf999b15caca686b217708111117789b (patch) | |
tree | b2d8d5b5bfbc9aabe4ee17bea2ac58220a61e428 /src/host/layer23/src/misc/bcch_scan.c | |
parent | fb48f690d33d54951f7161060efb88835a1f378d (diff) |
layer23: Split [1/2] -> The source code
We split into :
- common: Everything that can be shared
- mobile: The real spec compliant mobile phones
- misc: Different test stuff
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'src/host/layer23/src/misc/bcch_scan.c')
-rw-r--r-- | src/host/layer23/src/misc/bcch_scan.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/host/layer23/src/misc/bcch_scan.c b/src/host/layer23/src/misc/bcch_scan.c new file mode 100644 index 00000000..d0383231 --- /dev/null +++ b/src/host/layer23/src/misc/bcch_scan.c @@ -0,0 +1,318 @@ +/* BCCH Scanning code for OsmocomBB */ + +/* (C) 2010 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <l1a_l23_interface.h> + +#include <osmocore/logging.h> +#include <osmocore/talloc.h> +#include <osmocore/signal.h> +#include <osmocore/timer.h> +#include <osmocore/msgb.h> +#include <osmocore/tlv.h> +#include <osmocore/gsm_utils.h> +#include <osmocore/protocol/gsm_04_08.h> +#include <osmocore/protocol/gsm_08_58.h> +#include <osmocore/rsl.h> + +#include <osmocom/l1ctl.h> +#include <osmocom/osmocom_data.h> +#include <osmocom/lapdm.h> +#include <osmocom/logging.h> + +/* somewhere in 05.08 */ +#define MAX_CELLS_IN_BA 32 + +/* Information about a single cell / BCCH */ +struct cell_info { + struct llist_head list; + + uint16_t band_arfcn; + uint8_t bsic; + uint8_t rxlev; + + struct { + uint16_t mcc; /* Mobile Country Code */ + uint16_t mnc; /* Mobile Network Code */ + uint16_t lac; /* Location Area Code */ + uint16_t rac; /* Routing Area Code */ + uint16_t cid; /* Cell ID */ + } id; + uint16_t ba_arfcn[MAX_CELLS_IN_BA]; + uint8_t ba_arfcn_num; + + struct { + int32_t fn_delta; /* delta to current L1 fn */ + int16_t qbit_delta; + int16_t afc_delta; + } l1_sync; +}; + +#define AFS_F_PM_DONE 0x01 +#define AFS_F_TESTED 0x02 +#define AFS_F_BCCH 0x04 +struct arfcn_state { + uint8_t rxlev; + uint8_t flags; +}; + +enum bscan_state { + BSCAN_S_NONE, + BSCAN_S_WAIT_DATA, + BSCAN_S_DONE, +}; + +enum fps_state { + FPS_S_NONE, + FPS_S_PM_GSM900, + FPS_S_PM_EGSM900, + FPS_S_PM_GSM1800, + FPS_S_BINFO, +}; + +struct full_power_scan { + /* Full Power Scan */ + enum fps_state fps_state; + struct arfcn_state arfcn_state[1024]; + + struct osmocom_ms *ms; + + /* BCCH info part */ + enum bscan_state state; + struct llist_head cell_list; + struct cell_info *cur_cell; + uint16_t cur_arfcn; + struct timer_list timer; +}; + +static struct full_power_scan fps; + +static int get_next_arfcn(struct full_power_scan *fps) +{ + unsigned int i; + uint8_t best_rxlev = 0; + int best_arfcn = -1; + + for (i = 0; i < ARRAY_SIZE(fps->arfcn_state); i++) { + struct arfcn_state *af = &fps->arfcn_state[i]; + /* skip ARFCN's where we don't have a PM */ + if (!(af->flags & AFS_F_PM_DONE)) + continue; + /* skip ARFCN's that we already tested */ + if (af->flags & AFS_F_TESTED) + continue; + /* if current arfcn_state is better than best so far, + * select it */ + if (af->rxlev > best_rxlev) { + best_rxlev = af->rxlev; + best_arfcn = i; + } + } + printf("arfcn=%d rxlev=%u\n", best_arfcn, best_rxlev); + return best_arfcn; +} + +static struct cell_info *cell_info_alloc(void) +{ + struct cell_info *ci = talloc_zero(NULL, struct cell_info); + return ci; +} + +static void cell_info_free(struct cell_info *ci) +{ + talloc_free(ci); +} + +/* start to scan for one ARFCN */ +static int _cinfo_start_arfcn(unsigned int band_arfcn) +{ + int rc; + + /* ask L1 to try to tune to new ARFCN */ + /* FIXME: decode band */ + rc = l1ctl_tx_fbsb_req(fps.ms, band_arfcn, + L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_COMBINED); + if (rc < 0) + return rc; + + /* allocate new cell info structure */ + fps.cur_cell = cell_info_alloc(); + fps.cur_arfcn = band_arfcn; + fps.cur_cell->band_arfcn = band_arfcn; + /* FIXME: start timer in case we never get a sync */ + fps.state = BSCAN_S_WAIT_DATA; + bsc_schedule_timer(&fps.timer, 2, 0); + + return 0; +} + + +static void cinfo_next_cell(void *data) +{ + int rc; + + /* we've been waiting for BCCH info */ + fps.arfcn_state[fps.cur_arfcn].flags |= AFS_F_TESTED; + /* if there is a BCCH, we need to add the collected BCCH + * information to our list */ + + if (fps.arfcn_state[fps.cur_arfcn].flags & AFS_F_BCCH) + llist_add(&fps.cur_cell->list, &fps.cell_list); + else + cell_info_free(fps.cur_cell); + + rc = get_next_arfcn(&fps); + if (rc < 0) { + fps.state = BSCAN_S_DONE; + return; + } + /* start syncing to the next ARFCN */ + _cinfo_start_arfcn(rc); +} + +static void cinfo_timer_cb(void *data) +{ + switch (fps.state) { + case BSCAN_S_WAIT_DATA: + cinfo_next_cell(data); + break; + } +} + +/* Update cell_info for current cell with received BCCH info */ +static int rx_bcch_info(const uint8_t *data) +{ + struct cell_info *ci = fps.cur_cell; + struct gsm48_system_information_type_header *si_hdr; + si_hdr = (struct gsm48_system_information_type_header *) data;; + + /* we definitely have a BCCH on this channel */ + fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH; + + switch (si_hdr->system_information) { + case GSM48_MT_RR_SYSINFO_1: + /* FIXME: CA, RACH control */ + break; + case GSM48_MT_RR_SYSINFO_2: + /* FIXME: BA, NCC, RACH control */ + break; + case GSM48_MT_RR_SYSINFO_3: + /* FIXME: cell_id, LAI */ + break; + case GSM48_MT_RR_SYSINFO_4: + /* FIXME: LAI */ + break; + } + return 0; +} + +/* Update L1/SCH information (AFC/QBIT/FN offset, BSIC) */ +static int rx_sch_info() +{ + /* FIXME */ +} + +static int bscan_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct cell_info *ci = fps.cur_cell; + struct osmocom_ms *ms; + struct osmobb_meas_res *mr; + uint16_t arfcn; + int rc; + + if (subsys != SS_L1CTL) + return 0; + + switch (signal) { + case S_L1CTL_PM_RES: + mr = signal_data; + /* check if PM result is for same MS */ + if (fps.ms != mr->ms) + return 0; + arfcn = mr->band_arfcn & 0x3ff; + /* update RxLev and notice that PM was done */ + fps.arfcn_state[arfcn].rxlev = mr->rx_lev; + fps.arfcn_state[arfcn].flags |= AFS_F_PM_DONE; + break; + case S_L1CTL_PM_DONE: + ms = signal_data; + switch (fps.fps_state) { + case FPS_S_PM_GSM900: + fps.fps_state = FPS_S_PM_EGSM900; + return l1ctl_tx_pm_req_range(ms, 955, 1023); + case FPS_S_PM_EGSM900: + fps.fps_state = FPS_S_PM_GSM1800; + return l1ctl_tx_pm_req_range(ms, 512, 885); + case FPS_S_PM_GSM1800: + /* power measurement has finished, we can start + * to actually iterate over the ARFCN's and try + * to sync to BCCHs */ + fps.fps_state = FPS_S_BINFO; + rc = get_next_arfcn(&fps); + if (rc < 0) { + fps.state = BSCAN_S_DONE; + return; + } + _cinfo_start_arfcn(rc); + break; + } + break; + case S_L1CTL_FBSB_RESP: + /* We actually got a FCCH/SCH burst */ +#if 0 + fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH; + /* fallthrough */ +#else + break; +#endif + case S_L1CTL_FBSB_ERR: + /* We timed out, move on */ + if (fps.state == BSCAN_S_WAIT_DATA) + cinfo_next_cell(NULL); + break; + } + return 0; +} + +/* start the full power scan */ +int fps_start(struct osmocom_ms *ms) +{ + memset(&fps, 0, sizeof(fps)); + fps.ms = ms; + + fps.timer.cb = cinfo_timer_cb; + fps.timer.data = &fps; + + /* Start by scanning the good old GSM900 band */ + fps.fps_state = FPS_S_PM_GSM900; + return l1ctl_tx_pm_req_range(ms, 0, 124); +} + +int fps_init(void) +{ + return register_signal_handler(SS_L1CTL, &bscan_sig_cb, NULL); +} |