blob: 808103d28a6d7873882ce1ac28d075b28bfab791 [file] [log] [blame]
Harald Welte38fe2a62009-12-21 09:26:17 +01001/* Measurement Report Processing */
2
3/* (C) 2009 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
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Harald Welte38fe2a62009-12-21 09:26:17 +010010 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Harald Welte38fe2a62009-12-21 09:26:17 +010016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte38fe2a62009-12-21 09:26:17 +010019 *
20 */
21
Harald Welte38fe2a62009-12-21 09:26:17 +010022
23#include <openbsc/gsm_data.h>
24#include <openbsc/meas_rep.h>
25
26static int get_field(const struct gsm_meas_rep *rep,
27 enum meas_rep_field field)
28{
29 switch (field) {
30 case MEAS_REP_DL_RXLEV_FULL:
31 return rep->dl.full.rx_lev;
32 case MEAS_REP_DL_RXLEV_SUB:
33 return rep->dl.sub.rx_lev;
34 case MEAS_REP_DL_RXQUAL_FULL:
35 return rep->dl.full.rx_qual;
36 case MEAS_REP_DL_RXQUAL_SUB:
37 return rep->dl.sub.rx_qual;
38 case MEAS_REP_UL_RXLEV_FULL:
39 return rep->ul.full.rx_lev;
40 case MEAS_REP_UL_RXLEV_SUB:
41 return rep->ul.sub.rx_lev;
42 case MEAS_REP_UL_RXQUAL_FULL:
43 return rep->ul.full.rx_qual;
44 case MEAS_REP_UL_RXQUAL_SUB:
45 return rep->ul.sub.rx_qual;
46 }
47
48 return 0;
49}
50
51
52unsigned int calc_initial_idx(unsigned int array_size,
53 unsigned int meas_rep_idx,
54 unsigned int num_values)
55{
56 int offs, idx;
57
58 /* from which element do we need to start if we're interested
59 * in an average of 'num' elements */
60 offs = meas_rep_idx - num_values;
61
62 if (offs < 0)
63 idx = array_size + offs;
64 else
65 idx = offs;
66
67 return idx;
68}
69
70/* obtain an average over the last 'num' fields in the meas reps */
71int get_meas_rep_avg(const struct gsm_lchan *lchan,
72 enum meas_rep_field field, unsigned int num)
73{
74 unsigned int i, idx;
75 int avg = 0;
76
Holger Hans Peter Freyther6e95c5f2010-07-23 19:46:04 +080077 if (num < 1)
78 return 0;
79
Harald Welte38fe2a62009-12-21 09:26:17 +010080 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
81 lchan->meas_rep_idx, num);
82
83 for (i = 0; i < num; i++) {
84 int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep);
85
86 avg += get_field(&lchan->meas_rep[j], field);
87 }
88
89 return avg / num;
90}
91
92/* Check if N out of M last values for FIELD are >= bd */
93int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
94 enum meas_rep_field field,
95 unsigned int n, unsigned int m, int be)
96{
97 unsigned int i, idx;
98 int count = 0;
99
100 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
101 lchan->meas_rep_idx, m);
102
103 for (i = 0; i < m; i++) {
104 int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep);
105 int val = get_field(&lchan->meas_rep[j], field);
106
107 if (val >= be)
108 count++;
109
110 if (count >= n)
111 return 1;
112 }
113
114 return 0;
115}