blob: 788a9baede4b22d1e71dc3f17bf34dd70ad45d21 [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
22#include <sys/types.h>
23
24#include <openbsc/gsm_data.h>
25#include <openbsc/meas_rep.h>
26
27static int get_field(const struct gsm_meas_rep *rep,
28 enum meas_rep_field field)
29{
30 switch (field) {
31 case MEAS_REP_DL_RXLEV_FULL:
32 return rep->dl.full.rx_lev;
33 case MEAS_REP_DL_RXLEV_SUB:
34 return rep->dl.sub.rx_lev;
35 case MEAS_REP_DL_RXQUAL_FULL:
36 return rep->dl.full.rx_qual;
37 case MEAS_REP_DL_RXQUAL_SUB:
38 return rep->dl.sub.rx_qual;
39 case MEAS_REP_UL_RXLEV_FULL:
40 return rep->ul.full.rx_lev;
41 case MEAS_REP_UL_RXLEV_SUB:
42 return rep->ul.sub.rx_lev;
43 case MEAS_REP_UL_RXQUAL_FULL:
44 return rep->ul.full.rx_qual;
45 case MEAS_REP_UL_RXQUAL_SUB:
46 return rep->ul.sub.rx_qual;
47 }
48
49 return 0;
50}
51
52
53unsigned int calc_initial_idx(unsigned int array_size,
54 unsigned int meas_rep_idx,
55 unsigned int num_values)
56{
57 int offs, idx;
58
59 /* from which element do we need to start if we're interested
60 * in an average of 'num' elements */
61 offs = meas_rep_idx - num_values;
62
63 if (offs < 0)
64 idx = array_size + offs;
65 else
66 idx = offs;
67
68 return idx;
69}
70
71/* obtain an average over the last 'num' fields in the meas reps */
72int get_meas_rep_avg(const struct gsm_lchan *lchan,
73 enum meas_rep_field field, unsigned int num)
74{
75 unsigned int i, idx;
76 int avg = 0;
77
Holger Hans Peter Freyther6e95c5f2010-07-23 19:46:04 +080078 if (num < 1)
79 return 0;
80
Harald Welte38fe2a62009-12-21 09:26:17 +010081 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
82 lchan->meas_rep_idx, num);
83
84 for (i = 0; i < num; i++) {
85 int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep);
86
87 avg += get_field(&lchan->meas_rep[j], field);
88 }
89
90 return avg / num;
91}
92
93/* Check if N out of M last values for FIELD are >= bd */
94int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
95 enum meas_rep_field field,
96 unsigned int n, unsigned int m, int be)
97{
98 unsigned int i, idx;
99 int count = 0;
100
101 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
102 lchan->meas_rep_idx, m);
103
104 for (i = 0; i < m; i++) {
105 int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep);
106 int val = get_field(&lchan->meas_rep[j], field);
107
108 if (val >= be)
109 count++;
110
111 if (count >= n)
112 return 1;
113 }
114
115 return 0;
116}