blob: 4c08c6664a83a34781699884c24969b1fd602e37 [file] [log] [blame]
Harald Welte8d77b952009-12-17 00:31:10 +01001/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This
2 * only implements the handover algorithm/decision, but not execution
3 * of it */
4
5/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <stdlib.h>
26#include <errno.h>
27
28#include <openbsc/msgb.h>
29#include <openbsc/debug.h>
30#include <openbsc/gsm_data.h>
31#include <openbsc/meas_rep.h>
32#include <openbsc/signal.h>
33#include <openbsc/talloc.h>
34#include <openbsc/handover.h>
35
36static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
37 u_int16_t arfcn, u_int8_t bsic)
38{
39 struct gsm_bts *new_bts;
40
41 /* resolve the gsm_bts structure for the best neighbor */
42 new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic);
43 if (!new_bts) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +010044 LOGP(DHO, LOGL_NOTICE, "unable to determine neighbor BTS "
45 "for ARFCN %u BSIC %u ?!?\n", arfcn, bsic);
Harald Welte8d77b952009-12-17 00:31:10 +010046 return -EINVAL;
47 }
48
49 /* and actually try to handover to that cell */
50 return bsc_handover_start(lchan, new_bts);
51}
52
53#define RXLEV_HYST 3
54
55/* process an already parsed measurement report */
56static int process_meas_rep(struct gsm_meas_rep *mr)
57{
58 struct gsm_meas_rep_cell *mr_cell = NULL;
59 unsigned int best_better_db;
60 int i;
61
Harald Welte386cd2b2009-12-18 11:49:20 +010062 /* we currently only do handover for TCH channels */
63 switch (mr->lchan->type) {
64 case GSM_LCHAN_TCH_F:
65 case GSM_LCHAN_TCH_H:
66 break;
67 default:
68 return 0;
69 }
70
Harald Welte8d77b952009-12-17 00:31:10 +010071 /* FIXME: implement actual averaging over multiple measurement
72 * reports */
73
Harald Weltee786c322009-12-19 21:29:19 +010074 if (mr->num_cell > 6)
75 return 0;
76
Harald Welte8d77b952009-12-17 00:31:10 +010077 /* find the best cell in this report that is at least RXLEV_HYST
78 * better than the current serving cell */
79 for (i = 0; i < mr->num_cell; i++) {
80 unsigned int better;
81 if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST)
82 continue;
83
84 better = mr->cell[i].rxlev - mr->dl.full.rx_lev;
85 if (better > best_better_db) {
86 mr_cell = &mr->cell[i];
87 best_better_db = better;
88 }
89 }
90
Harald Weltebc814502009-12-19 21:41:52 +010091 if (!mr_cell) {
92 DEBUGPC(DHO, "No better cell\n");
93 return 0;
Harald Welte8d77b952009-12-17 00:31:10 +010094 }
95
Harald Weltebc814502009-12-19 21:41:52 +010096 LOGP(DHO, LOGL_INFO, "Cell on ARFCN %u is better: ", mr_cell->arfcn);
97 if (!mr->lchan->ts->trx->bts->network->handover.active) {
98 LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n");
99 return 0;
100 }
101
102 LOGPC(DHO, LOGL_INFO, "Starting handover\n");
103 return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, mr_cell->bsic);
Harald Welte8d77b952009-12-17 00:31:10 +0100104}
105
106static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal,
107 void *handler_data, void *signal_data)
108{
109 struct gsm_meas_rep *mr;
110
111 if (subsys != SS_LCHAN)
112 return 0;
113
114 switch (signal) {
115 case S_LCHAN_MEAS_REP:
116 mr = signal_data;
117 process_meas_rep(mr);
118 break;
119 }
120
121 return 0;
122}
123
124void on_dso_load_ho_dec(void)
125{
126 register_signal_handler(SS_LCHAN, ho_dec_sig_cb, NULL);
127}