diff options
Diffstat (limited to 'src/osmo-bsc/meas_rep.c')
-rw-r--r-- | src/osmo-bsc/meas_rep.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/osmo-bsc/meas_rep.c b/src/osmo-bsc/meas_rep.c new file mode 100644 index 000000000..73d9a1f21 --- /dev/null +++ b/src/osmo-bsc/meas_rep.c @@ -0,0 +1,134 @@ +/* Measurement Report Processing */ + +/* (C) 2009 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <errno.h> + +#include <osmocom/bsc/gsm_data.h> +#include <osmocom/bsc/meas_rep.h> + +static int get_field(const struct gsm_meas_rep *rep, + enum meas_rep_field field) +{ + switch (field) { + case MEAS_REP_DL_RXLEV_FULL: + if (!(rep->flags & MEAS_REP_F_DL_VALID)) + return -EINVAL; + return rep->dl.full.rx_lev; + case MEAS_REP_DL_RXLEV_SUB: + if (!(rep->flags & MEAS_REP_F_DL_VALID)) + return -EINVAL; + return rep->dl.sub.rx_lev; + case MEAS_REP_DL_RXQUAL_FULL: + if (!(rep->flags & MEAS_REP_F_DL_VALID)) + return -EINVAL; + return rep->dl.full.rx_qual; + case MEAS_REP_DL_RXQUAL_SUB: + if (!(rep->flags & MEAS_REP_F_DL_VALID)) + return -EINVAL; + return rep->dl.sub.rx_qual; + case MEAS_REP_UL_RXLEV_FULL: + return rep->ul.full.rx_lev; + case MEAS_REP_UL_RXLEV_SUB: + return rep->ul.sub.rx_lev; + case MEAS_REP_UL_RXQUAL_FULL: + return rep->ul.full.rx_qual; + case MEAS_REP_UL_RXQUAL_SUB: + return rep->ul.sub.rx_qual; + } + + return 0; +} + + +unsigned int calc_initial_idx(unsigned int array_size, + unsigned int meas_rep_idx, + unsigned int num_values) +{ + int offs, idx; + + /* from which element do we need to start if we're interested + * in an average of 'num' elements */ + offs = meas_rep_idx - num_values; + + if (offs < 0) + idx = array_size + offs; + else + idx = offs; + + return idx; +} + +/* obtain an average over the last 'num' fields in the meas reps */ +int get_meas_rep_avg(const struct gsm_lchan *lchan, + enum meas_rep_field field, unsigned int num) +{ + unsigned int i, idx; + int avg = 0, valid_num = 0; + + if (num < 1) + return -EINVAL; + + if (num > lchan->meas_rep_count) + return -EINVAL; + + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, num); + + for (i = 0; i < num; i++) { + int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep); + int val = get_field(&lchan->meas_rep[j], field); + + if (val >= 0) { + avg += val; + valid_num++; + } + } + + if (valid_num == 0) + return -EINVAL; + + return avg / valid_num; +} + +/* Check if N out of M last values for FIELD are >= bd */ +int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan, + enum meas_rep_field field, + unsigned int n, unsigned int m, int be) +{ + unsigned int i, idx; + int count = 0; + + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, m); + + for (i = 0; i < m; i++) { + int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep); + int val = get_field(&lchan->meas_rep[j], field); + + if (val >= be) /* implies that val < 0 will not count */ + count++; + + if (count >= n) + return 1; + } + + return 0; +} |