blob: fbd15156dec95f0daec810a60deda5f960c57539 [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
Andreas Eversberg970b4342013-06-01 16:46:39 +020022#include <errno.h>
Harald Welte38fe2a62009-12-21 09:26:17 +010023
Neels Hofmeyrc0164792017-09-04 15:15:32 +020024#include <osmocom/bsc/gsm_data.h>
25#include <osmocom/bsc/meas_rep.h>
Harald Welte38fe2a62009-12-21 09:26:17 +010026
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)
Andreas Eversberg970b4342013-06-01 16:46:39 +020079 return -EINVAL;
80
81 if (num > lchan->meas_rep_count)
82 return -EINVAL;
Holger Hans Peter Freyther6e95c5f2010-07-23 19:46:04 +080083
Harald Welte38fe2a62009-12-21 09:26:17 +010084 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
85 lchan->meas_rep_idx, num);
86
87 for (i = 0; i < num; i++) {
88 int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep);
89
90 avg += get_field(&lchan->meas_rep[j], field);
91 }
92
93 return avg / num;
94}
95
96/* Check if N out of M last values for FIELD are >= bd */
97int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
98 enum meas_rep_field field,
99 unsigned int n, unsigned int m, int be)
100{
101 unsigned int i, idx;
102 int count = 0;
103
104 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
105 lchan->meas_rep_idx, m);
106
107 for (i = 0; i < m; i++) {
108 int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep);
109 int val = get_field(&lchan->meas_rep[j], field);
110
111 if (val >= be)
112 count++;
113
114 if (count >= n)
115 return 1;
116 }
117
118 return 0;
119}