blob: 73d9a1f215ce978ccb021618c57fced0b3c2c1ba [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:
Andreas Eversberg83594842013-06-23 10:53:09 +020032 if (!(rep->flags & MEAS_REP_F_DL_VALID))
33 return -EINVAL;
Harald Welte38fe2a62009-12-21 09:26:17 +010034 return rep->dl.full.rx_lev;
35 case MEAS_REP_DL_RXLEV_SUB:
Andreas Eversberg83594842013-06-23 10:53:09 +020036 if (!(rep->flags & MEAS_REP_F_DL_VALID))
37 return -EINVAL;
Harald Welte38fe2a62009-12-21 09:26:17 +010038 return rep->dl.sub.rx_lev;
39 case MEAS_REP_DL_RXQUAL_FULL:
Andreas Eversberg83594842013-06-23 10:53:09 +020040 if (!(rep->flags & MEAS_REP_F_DL_VALID))
41 return -EINVAL;
Harald Welte38fe2a62009-12-21 09:26:17 +010042 return rep->dl.full.rx_qual;
43 case MEAS_REP_DL_RXQUAL_SUB:
Andreas Eversberg83594842013-06-23 10:53:09 +020044 if (!(rep->flags & MEAS_REP_F_DL_VALID))
45 return -EINVAL;
Harald Welte38fe2a62009-12-21 09:26:17 +010046 return rep->dl.sub.rx_qual;
47 case MEAS_REP_UL_RXLEV_FULL:
48 return rep->ul.full.rx_lev;
49 case MEAS_REP_UL_RXLEV_SUB:
50 return rep->ul.sub.rx_lev;
51 case MEAS_REP_UL_RXQUAL_FULL:
52 return rep->ul.full.rx_qual;
53 case MEAS_REP_UL_RXQUAL_SUB:
54 return rep->ul.sub.rx_qual;
55 }
56
57 return 0;
58}
59
60
61unsigned int calc_initial_idx(unsigned int array_size,
62 unsigned int meas_rep_idx,
63 unsigned int num_values)
64{
65 int offs, idx;
66
67 /* from which element do we need to start if we're interested
68 * in an average of 'num' elements */
69 offs = meas_rep_idx - num_values;
70
71 if (offs < 0)
72 idx = array_size + offs;
73 else
74 idx = offs;
75
76 return idx;
77}
78
79/* obtain an average over the last 'num' fields in the meas reps */
80int get_meas_rep_avg(const struct gsm_lchan *lchan,
81 enum meas_rep_field field, unsigned int num)
82{
83 unsigned int i, idx;
Andreas Eversberg83594842013-06-23 10:53:09 +020084 int avg = 0, valid_num = 0;
Harald Welte38fe2a62009-12-21 09:26:17 +010085
Holger Hans Peter Freyther6e95c5f2010-07-23 19:46:04 +080086 if (num < 1)
Andreas Eversberg970b4342013-06-01 16:46:39 +020087 return -EINVAL;
88
89 if (num > lchan->meas_rep_count)
90 return -EINVAL;
Holger Hans Peter Freyther6e95c5f2010-07-23 19:46:04 +080091
Harald Welte38fe2a62009-12-21 09:26:17 +010092 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
93 lchan->meas_rep_idx, num);
94
95 for (i = 0; i < num; i++) {
96 int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep);
Andreas Eversberg83594842013-06-23 10:53:09 +020097 int val = get_field(&lchan->meas_rep[j], field);
Harald Welte38fe2a62009-12-21 09:26:17 +010098
Andreas Eversberg83594842013-06-23 10:53:09 +020099 if (val >= 0) {
100 avg += val;
101 valid_num++;
102 }
Harald Welte38fe2a62009-12-21 09:26:17 +0100103 }
104
Andreas Eversberg83594842013-06-23 10:53:09 +0200105 if (valid_num == 0)
106 return -EINVAL;
107
108 return avg / valid_num;
Harald Welte38fe2a62009-12-21 09:26:17 +0100109}
110
111/* Check if N out of M last values for FIELD are >= bd */
112int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
113 enum meas_rep_field field,
114 unsigned int n, unsigned int m, int be)
115{
116 unsigned int i, idx;
117 int count = 0;
118
119 idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
120 lchan->meas_rep_idx, m);
121
122 for (i = 0; i < m; i++) {
123 int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep);
124 int val = get_field(&lchan->meas_rep[j], field);
125
Andreas Eversberg83594842013-06-23 10:53:09 +0200126 if (val >= be) /* implies that val < 0 will not count */
Harald Welte38fe2a62009-12-21 09:26:17 +0100127 count++;
128
129 if (count >= n)
130 return 1;
131 }
132
133 return 0;
134}