aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/measurement.c266
-rw-r--r--tests/meas/meas_test.c22
-rw-r--r--tests/meas/meas_test.ok148
-rw-r--r--tests/meas/meas_testcases.h519
4 files changed, 859 insertions, 96 deletions
diff --git a/src/common/measurement.c b/src/common/measurement.c
index d7580e6e..59f5d834 100644
--- a/src/common/measurement.c
+++ b/src/common/measurement.c
@@ -16,6 +16,21 @@ static const uint8_t ts45008_83_tch_f[] = { 52, 53, 54, 55, 56, 57, 58, 59 };
static const uint8_t ts45008_83_tch_hs0[] = { 0, 2, 4, 6, 52, 54, 56, 58 };
static const uint8_t ts45008_83_tch_hs1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
+/* In cases where we less measurements than we expect we must assume that we
+ * just did not receive the block because it was lost due to bad channel
+ * conditions. We set up a dummy measurement result here that reflects the
+ * worst possible result. In our* calculation we will use this dummy to replace
+ * the missing measurements */
+#define MEASUREMENT_DUMMY_BER 10000 /* 100% BER */
+#define MEASUREMENT_DUMMY_IRSSI 109 /* noise floor in -dBm */
+static const struct bts_ul_meas measurement_dummy = (struct bts_ul_meas) {
+ .ber10k = MEASUREMENT_DUMMY_BER,
+ .ta_offs_256bits = 0,
+ .c_i = 0,
+ .is_sub = 0,
+ .inv_rssi = MEASUREMENT_DUMMY_IRSSI
+};
+
/* find out if an array contains a given key as element */
#define ARRAY_CONTAINS(arr, val) array_contains(arr, ARRAY_SIZE(arr), val)
static bool array_contains(const uint8_t *arr, unsigned int len, uint8_t val) {
@@ -468,6 +483,64 @@ static uint8_t ber10k_to_rxqual(uint32_t ber10k)
return 7;
}
+/* Get the number of measurements that we expect for a specific lchan.
+ * (This is a static number that is defined by the specific slot layout of
+ * the channel) */
+static unsigned int lchan_meas_num_expected(const struct gsm_lchan *lchan)
+{
+ enum gsm_phys_chan_config pchan = ts_pchan(lchan->ts);
+
+ switch (pchan) {
+ case GSM_PCHAN_TCH_F:
+ /* 24 for TCH + 1 for SACCH */
+ return 25;
+ case GSM_PCHAN_TCH_H:
+ /* 24 half-blocks for TCH + 1 for SACCH */
+ return 25;
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ /* 2 for SDCCH + 1 for SACCH */
+ return 3;
+ case GSM_PCHAN_CCCH_SDCCH4:
+ case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+ /* 2 for SDCCH + 1 for SACCH */
+ return 3;
+ default:
+ return lchan->meas.num_ul_meas;
+ }
+}
+
+/* In DTX a subset of blocks must always be transmitted
+ * See also: GSM 05.08, chapter 8.3 Aspects of discontinuous transmission (DTX) */
+static unsigned int lchan_meas_sub_num_expected(const struct gsm_lchan *lchan)
+{
+ enum gsm_phys_chan_config pchan = ts_pchan(lchan->ts);
+
+ /* AMR is using a more elaborated model with a dymanic amount of
+ * DTX blocks so this function is not applicable to determine the
+ * amount of expected SUB Measurements when AMR is used */
+ OSMO_ASSERT(lchan->tch_mode != GSM48_CMODE_SPEECH_AMR)
+
+ switch (pchan) {
+ case GSM_PCHAN_TCH_F:
+ /* 1 block SDCCH, 2 blocks TCH */
+ return 3;
+ case GSM_PCHAN_TCH_H:
+ /* 1 block SDCCH, 4 half-blocks TCH */
+ return 5;
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+ /* no DTX here, all blocks must be present! */
+ return 3;
+ case GSM_PCHAN_CCCH_SDCCH4:
+ case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+ /* no DTX here, all blocks must be present! */
+ return 3;
+ default:
+ return 0;
+ }
+}
+
/* if we clip the TOA value to 12 bits, i.e. toa256=3200,
* -> the maximum deviation can be 2*3200 = 6400
* -> the maximum squared deviation can be 6400^2 = 40960000
@@ -482,6 +555,10 @@ static uint8_t ber10k_to_rxqual(uint32_t ber10k)
/* compute Osmocom extended measurements for the given lchan */
static void lchan_meas_compute_extended(struct gsm_lchan *lchan)
{
+ unsigned int num_ul_meas;
+ unsigned int num_ul_meas_excess = 0;
+ unsigned int num_ul_meas_expect;
+
/* we assume that lchan_meas_check_compute() has already computed the mean value
* and we can compute the min/max/variance/stddev from this */
int i;
@@ -489,19 +566,47 @@ static void lchan_meas_compute_extended(struct gsm_lchan *lchan)
/* each measurement is an int32_t, so the squared difference value must fit in 32bits */
/* the sum of the squared values (each up to 32bit) can very easily exceed 32 bits */
u_int64_t sq_diff_sum = 0;
+
+ /* In case we do not have any measurement values collected there is no
+ * computation possible. We just skip the whole computation here, the
+ * lchan->meas.flags will not get the LC_UL_M_F_OSMO_EXT_VALID flag set
+ * so no extended measurement results will be reported back via RSL.
+ * this is ok, since we have nothing to report anyway and apart of that
+ * we also just lost the signal (otherwise we would have at least some
+ * measurements). */
+ if (!lchan->meas.num_ul_meas)
+ return;
+
/* initialize min/max values with their counterpart */
lchan->meas.ext.toa256_min = INT16_MAX;
lchan->meas.ext.toa256_max = INT16_MIN;
- OSMO_ASSERT(lchan->meas.num_ul_meas);
+ /* Determine the number of measurement values we need to take into the
+ * computation. In this case we only compute over the measurements we
+ * have indeed received. Since this computation is about timing
+ * information it does not make sense to approach missing measurement
+ * samples the TOA with 0. This would bend the average towards 0. What
+ * counts is the average TOA of the properly received blocks so that
+ * the TA logic can make a proper decision. */
+ num_ul_meas_expect = lchan_meas_num_expected(lchan);
+ if (lchan->meas.num_ul_meas > num_ul_meas_expect) {
+ num_ul_meas = num_ul_meas_expect;
+ num_ul_meas_excess = lchan->meas.num_ul_meas - num_ul_meas_expect;
+ }
+ else
+ num_ul_meas = lchan->meas.num_ul_meas;
/* all computations are done on the relative arrival time of the burst, relative to the
* beginning of its slot. This is of course excluding the TA value that the MS has already
* compensated/pre-empted its transmission */
/* step 1: compute the sum of the squared difference of each value to mean */
- for (i = 0; i < lchan->meas.num_ul_meas; i++) {
- struct bts_ul_meas *m = &lchan->meas.uplink[i];
+ for (i = 0; i < num_ul_meas; i++) {
+ const struct bts_ul_meas *m;
+
+ OSMO_ASSERT(i < lchan->meas.num_ul_meas);
+ m = &lchan->meas.uplink[i+num_ul_meas_excess];
+
int32_t diff = (int32_t)m->ta_offs_256bits - (int32_t)lchan->meas.ms_toa256;
/* diff can now be any value of +65535 to -65535, so we can safely square it,
* but only in unsigned math. As squaring looses the sign, we can simply drop
@@ -517,7 +622,7 @@ static void lchan_meas_compute_extended(struct gsm_lchan *lchan)
lchan->meas.ext.toa256_min = m->ta_offs_256bits;
}
/* step 2: compute the variance (mean of sum of squared differences) */
- sq_diff_sum = sq_diff_sum / lchan->meas.num_ul_meas;
+ sq_diff_sum = sq_diff_sum / num_ul_meas;
/* as the individual summed values can each not exceed 2^32, and we're
* dividing by the number of summands, the resulting value can also not exceed 2^32 */
OSMO_ASSERT(sq_diff_sum <= UINT32_MAX);
@@ -535,54 +640,137 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
uint32_t irssi_sub_sum = 0;
int32_t ta256b_sum = 0;
unsigned int num_meas_sub = 0;
+ unsigned int num_meas_sub_actual = 0;
+ unsigned int num_meas_sub_subst = 0;
+ unsigned int num_meas_sub_expect;
+ unsigned int num_ul_meas;
+ unsigned int num_ul_meas_actual = 0;
+ unsigned int num_ul_meas_subst = 0;
+ unsigned int num_ul_meas_expect;
+ unsigned int num_ul_meas_excess = 0;
int i;
/* if measurement period is not complete, abort */
if (!is_meas_complete(lchan, fn))
return 0;
- /* if there are no measurements, skip computation */
- if (lchan->meas.num_ul_meas == 0)
- return 0;
+ LOGP(DMEAS, LOGL_DEBUG, "%s Calculating measurement results for physical channel:%s\n",
+ gsm_lchan_name(lchan), gsm_pchan_name(ts_pchan(lchan->ts)));
+
+ /* Note: Some phys will send no measurement indication at all
+ * when a block is lost. Also in DTX mode blocks are left out
+ * intentionally to save energy. It is not necessarly an error
+ * when we get less measurements as we expect. */
+ num_ul_meas_expect = lchan_meas_num_expected(lchan);
+
+ if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR)
+ num_meas_sub_expect = lchan_meas_sub_num_expected(lchan);
+ else {
+ /* FIXME: the amount of SUB Measurements is a dynamic parameter
+ * in AMR and can not be determined by using a lookup table.
+ * See also: OS#2978 */
+ num_meas_sub_expect = 0;
+ }
- /* compute the actual measurements */
+ if (lchan->meas.num_ul_meas > num_ul_meas_expect)
+ num_ul_meas_excess = lchan->meas.num_ul_meas - num_ul_meas_expect;
+ num_ul_meas = num_ul_meas_expect;
+
+ LOGP(DMEAS, LOGL_DEBUG, "%s received %u UL measurements, expected %u\n", gsm_lchan_name(lchan),
+ lchan->meas.num_ul_meas, num_ul_meas_expect);
+ if (num_ul_meas_excess)
+ LOGP(DMEAS, LOGL_DEBUG, "%s received %u excess UL measurements\n", gsm_lchan_name(lchan),
+ num_ul_meas_excess);
+
+ /* Measurement computation step 1: add up */
+ for (i = 0; i < num_ul_meas; i++) {
+ const struct bts_ul_meas *m;
+ bool is_sub = false;
+
+ /* Note: We will always compute over a full measurement,
+ * interval even when not enough measurement samples are in
+ * the buffer. As soon as we run out of measurement values
+ * we continue the calculation using dummy values. This works
+ * well for the BER, since there we can safely assume 100%
+ * since a missing measurement means that the data (block)
+ * is lost as well (some phys do not give us measurement
+ * reports for lost blocks or blocks that are spaced out for
+ * DTX). However, for RSSI and TA this does not work since
+ * there we would distort the calculation if we would replace
+ * them with a made up number. This means for those values we
+ * only compute over the data we have actually received. */
+
+ if (i < lchan->meas.num_ul_meas) {
+ m = &lchan->meas.uplink[i + num_ul_meas_excess];
+ if (m->is_sub) {
+ irssi_sub_sum += m->inv_rssi;
+ num_meas_sub_actual++;
+ is_sub = true;
+ }
+ irssi_full_sum += m->inv_rssi;
+ ta256b_sum += m->ta_offs_256bits;
+
+ num_ul_meas_actual++;
+ } else {
+ m = &measurement_dummy;
+ if (num_ul_meas_expect - i <= num_meas_sub_expect - num_meas_sub) {
+ num_meas_sub_subst++;
+ is_sub = true;
+ }
- /* step 1: add up */
- for (i = 0; i < lchan->meas.num_ul_meas; i++) {
- struct bts_ul_meas *m = &lchan->meas.uplink[i];
+ num_ul_meas_subst++;
+ }
ber_full_sum += m->ber10k;
- irssi_full_sum += m->inv_rssi;
- ta256b_sum += m->ta_offs_256bits;
-
- if (m->is_sub) {
+ if (is_sub) {
num_meas_sub++;
ber_sub_sum += m->ber10k;
- irssi_sub_sum += m->inv_rssi;
}
}
- /* step 2: divide */
- ber_full_sum = ber_full_sum / lchan->meas.num_ul_meas;
- irssi_full_sum = irssi_full_sum / lchan->meas.num_ul_meas;
- ta256b_sum = ta256b_sum / lchan->meas.num_ul_meas;
+ LOGP(DMEAS, LOGL_DEBUG, "%s received UL measurements contain %u SUB measurements, expected %u\n",
+ gsm_lchan_name(lchan), num_meas_sub_actual, num_meas_sub_expect);
+ LOGP(DMEAS, LOGL_DEBUG, "%s replaced %u measurements with dummy values, from which %u were SUB measurements\n",
+ gsm_lchan_name(lchan), num_ul_meas_subst, num_meas_sub_subst);
+
+ if (num_meas_sub != num_meas_sub_expect) {
+ LOGP(DMEAS, LOGL_ERROR, "%s Incorrect number of SUB measurements detected!\n", gsm_lchan_name(lchan));
+ /* Normally the logic above should make sure that there is
+ * always the exact amount of SUB measurements taken into
+ * account. If not then the logic that decides tags the received
+ * measurements as is_sub works incorrectly. Since the logic
+ * above only adds missing measurements during the calculation
+ * it can not remove excess SUB measurements or add missing SUB
+ * measurements when there is no more room in the interval. */
+ }
+
+ /* Measurement computation step 2: divide */
+ ber_full_sum = ber_full_sum / num_ul_meas;
+
+ if (!irssi_full_sum)
+ ber_full_sum = MEASUREMENT_DUMMY_IRSSI;
+ else
+ irssi_full_sum = irssi_full_sum / num_ul_meas_actual;
+
+ if (!num_ul_meas_actual)
+ ta256b_sum = lchan->meas.ms_toa256;
+ else
+ ta256b_sum = ta256b_sum / num_ul_meas_actual;
- if (num_meas_sub) {
+ if (!num_meas_sub)
+ ber_sub_sum = MEASUREMENT_DUMMY_BER;
+ else
ber_sub_sum = ber_sub_sum / num_meas_sub;
- irssi_sub_sum = irssi_sub_sum / num_meas_sub;
- } else {
- LOGP(DMEAS, LOGL_ERROR, "%s No measurements for SUB!!!\n", gsm_lchan_name(lchan));
- /* The only situation in which this can occur is if the related uplink burst/block was
- * missing, so let's set BER to 100% and level to lowest possible. */
- ber_sub_sum = 10000; /* 100% */
- irssi_sub_sum = 120; /* -120 dBm */
- }
+
+ if (!num_meas_sub_actual)
+ irssi_sub_sum = MEASUREMENT_DUMMY_IRSSI;
+ else
+ irssi_sub_sum = irssi_sub_sum / num_meas_sub_actual;
LOGP(DMEAS, LOGL_INFO, "%s Computed TA256(% 4d) BER-FULL(%2u.%02u%%), RSSI-FULL(-%3udBm), "
- "BER-SUB(%2u.%02u%%), RSSI-SUB(-%3udBm)\n", gsm_lchan_name(lchan),
- ta256b_sum, ber_full_sum/100,
- ber_full_sum%100, irssi_full_sum, ber_sub_sum/100, ber_sub_sum%100,
- irssi_sub_sum);
+ "BER-SUB(%2u.%02u%%), RSSI-SUB(-%3udBm)\n", gsm_lchan_name(lchan),
+ ta256b_sum, ber_full_sum / 100,
+ ber_full_sum % 100, irssi_full_sum, ber_sub_sum / 100, ber_sub_sum % 100, irssi_sub_sum);
/* store results */
mru = &lchan->meas.ul_res;
@@ -593,20 +781,18 @@ int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
lchan->meas.ms_toa256 = ta256b_sum;
LOGP(DMEAS, LOGL_INFO, "%s UL MEAS RXLEV_FULL(%u), RXLEV_SUB(%u),"
- "RXQUAL_FULL(%u), RXQUAL_SUB(%u), num_meas_sub(%u), num_ul_meas(%u) \n",
- gsm_lchan_name(lchan),
- mru->full.rx_lev,
- mru->sub.rx_lev,
- mru->full.rx_qual,
- mru->sub.rx_qual, num_meas_sub, lchan->meas.num_ul_meas);
+ "RXQUAL_FULL(%u), RXQUAL_SUB(%u), num_meas_sub(%u), num_ul_meas(%u) \n",
+ gsm_lchan_name(lchan),
+ mru->full.rx_lev, mru->sub.rx_lev, mru->full.rx_qual, mru->sub.rx_qual, num_meas_sub, num_ul_meas_expect);
lchan->meas.flags |= LC_UL_M_F_RES_VALID;
lchan_meas_compute_extended(lchan);
lchan->meas.num_ul_meas = 0;
- /* send a signal indicating computation is complete */
+ /* return 1 to indicte that the computation has been done and the next
+ * interval begins. */
return 1;
}
diff --git a/tests/meas/meas_test.c b/tests/meas/meas_test.c
index b90227a7..c397ddd1 100644
--- a/tests/meas/meas_test.c
+++ b/tests/meas/meas_test.c
@@ -24,6 +24,7 @@ struct fn_sample {
#include "sysmobts_fr_samples.h"
#include "meas_testcases.h"
+
void test_fn_sample(struct fn_sample *s, unsigned int len, uint8_t pchan, uint8_t tsmap)
{
int rc;
@@ -73,13 +74,16 @@ static void reset_lchan_meas(struct gsm_lchan *lchan)
static void test_meas_compute(const struct meas_testcase *mtc)
{
- struct gsm_lchan *lchan = &trx->ts[1].lchan[0];
+ struct gsm_lchan *lchan;
unsigned int i;
unsigned int fn = 0;
- printf("\nMeasurement Compute Test %s\n", mtc->name);
+ printf("\n\n");
+ printf("===========================================================\n");
+ printf("Measurement Compute Test: %s\n", mtc->name);
- lchan->ts->pchan = GSM_PCHAN_TCH_F;
+ lchan = &trx->ts[mtc->ts].lchan[0];
+ lchan->ts->pchan = mtc->pchan;
reset_lchan_meas(lchan);
/* feed uplink measurements into the code */
@@ -94,6 +98,8 @@ static void test_meas_compute(const struct meas_testcase *mtc)
OSMO_ASSERT(!(lchan->meas.flags & LC_UL_M_F_RES_VALID));
} else {
OSMO_ASSERT(lchan->meas.flags & (LC_UL_M_F_RES_VALID|LC_UL_M_F_OSMO_EXT_VALID));
+ printf("number of measurements: %u\n", mtc->ulm_count);
+ printf("parameter | actual | expected\n");
printf("meas.ext.toa256_min | %6d | %6d\n",
lchan->meas.ext.toa256_min, mtc->res.toa256_min);
printf("meas.ext.toa256_max | %6d | %6d\n",
@@ -113,6 +119,7 @@ static void test_meas_compute(const struct meas_testcase *mtc)
(lchan->meas.ext.toa256_std_dev != mtc->res.toa256_std_dev) ||
(lchan->meas.ul_res.full.rx_lev != mtc->res.rx_lev_full)) {
fprintf(stderr, "%s: Unexpected measurement result!\n", mtc->name);
+ OSMO_ASSERT(false);
}
}
@@ -1121,6 +1128,15 @@ int main(int argc, char **argv)
test_meas_compute(&mtc3);
test_meas_compute(&mtc4);
test_meas_compute(&mtc5);
+ test_meas_compute(&mtc_tch_f_complete);
+ test_meas_compute(&mtc_tch_f_dtx_with_lost_subs);
+ test_meas_compute(&mtc_tch_f_dtx);
+ test_meas_compute(&mtc_tch_h_complete);
+ test_meas_compute(&mtc_tch_h_dtx_with_lost_subs);
+ test_meas_compute(&mtc_tch_h_dtx);
+ test_meas_compute(&mtc_overrun);
+ test_meas_compute(&mtc_sdcch4_complete);
+ test_meas_compute(&mtc_sdcch8_complete);
printf("\n");
printf("***************************************************\n");
diff --git a/tests/meas/meas_test.ok b/tests/meas/meas_test.ok
index 58e527af..86d8d871 100644
--- a/tests/meas/meas_test.ok
+++ b/tests/meas/meas_test.ok
@@ -540,33 +540,167 @@ Testing: ts[7]->lchan[1], fn=15079=>015079/11/25/34/23, fn%104=103, rc=1, delta=
Testing: ts[7]->lchan[0], fn=15170=>015170/11/12/23/14, fn%104=90, rc=1, delta=91
Testing: ts[7]->lchan[1], fn=15183=>015183/11/25/36/27, fn%104=103, rc=1, delta=13
-Measurement Compute Test TOA256 Min-Max negative/positive
+
+===========================================================
+Measurement Compute Test: TOA256 Min-Max negative/positive
+number of measurements: 3
+parameter | actual | expected
meas.ext.toa256_min | -256 | -256
meas.ext.toa256_max | 256 | 256
meas.ms_toa256 | 0 | 0
meas.ext.toa256_std_dev | 209 | 209
meas.ul_res.full.rx_lev | 20 | 20
-meas.ul_res.full.rx_qual | 0 | 0
+meas.ul_res.full.rx_qual | 7 | 0
-Measurement Compute Test TOA256 small jitter around 256
+
+===========================================================
+Measurement Compute Test: TOA256 small jitter around 256
+number of measurements: 25
+parameter | actual | expected
meas.ext.toa256_min | 254 | 254
meas.ext.toa256_max | 258 | 258
meas.ms_toa256 | 256 | 256
meas.ext.toa256_std_dev | 1 | 1
meas.ul_res.full.rx_lev | 20 | 20
-meas.ul_res.full.rx_qual | 0 | 0
+meas.ul_res.full.rx_qual | 0 | 7
-Measurement Compute Test RxLEv averaging
+
+===========================================================
+Measurement Compute Test: RxLEv averaging
+number of measurements: 5
+parameter | actual | expected
meas.ext.toa256_min | 0 | 0
meas.ext.toa256_max | 0 | 0
meas.ms_toa256 | 0 | 0
meas.ext.toa256_std_dev | 0 | 0
meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 7 | 0
+
+
+===========================================================
+Measurement Compute Test: Empty measurements
+number of measurements: 0
+parameter | actual | expected
+meas.ext.toa256_min | 0 | 0
+meas.ext.toa256_max | 0 | 0
+meas.ms_toa256 | 0 | 0
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 63 | 63
+meas.ul_res.full.rx_qual | 3 | 3
+
+
+===========================================================
+Measurement Compute Test: TOA256 26 blocks with max TOA256
+number of measurements: 26
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 0 | 0
+
+
+===========================================================
+Measurement Compute Test: Complete TCH/F measurement period (26 measurements, 3 sub-frames)
+number of measurements: 25
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 0 | 0
+
+
+===========================================================
+Measurement Compute Test: Incomplete TCH/F measurement period (16 measurements, 1 sub-frame)
+number of measurements: 16
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 7 | 7
+
+
+===========================================================
+Measurement Compute Test: Incomplete but normal TCH/F measurement period (16 measurements, 3 sub-frames)
+number of measurements: 16
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 7 | 7
+
+
+===========================================================
+Measurement Compute Test: Complete TCH/H measurement period (26 measurements, 5 sub-frames)
+number of measurements: 25
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 0 | 0
+
+
+===========================================================
+Measurement Compute Test: Incomplete TCH/H measurement period (14 measurements, 3 sub-frames)
+number of measurements: 14
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 7 | 7
+
+
+===========================================================
+Measurement Compute Test: Incomplete but normal TCH/F measurement period (16 measurements, 5 sub-frames)
+number of measurements: 16
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 7 | 7
+
+
+===========================================================
+Measurement Compute Test: TCH/F measurement period with too much measurement values (overrun)
+number of measurements: 59
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
meas.ul_res.full.rx_qual | 0 | 0
-Measurement Compute Test Empty measurements
-Measurement Compute Test TOA256 26 blocks with max TOA256
+===========================================================
+Measurement Compute Test: Complete SDCCH4 measurement period (3 measurements)
+number of measurements: 3
+parameter | actual | expected
+meas.ext.toa256_min | 16384 | 16384
+meas.ext.toa256_max | 16384 | 16384
+meas.ms_toa256 | 16384 | 16384
+meas.ext.toa256_std_dev | 0 | 0
+meas.ul_res.full.rx_lev | 20 | 20
+meas.ul_res.full.rx_qual | 0 | 0
+
+
+===========================================================
+Measurement Compute Test: Complete SDCCH8 measurement period (3 measurements)
+number of measurements: 3
+parameter | actual | expected
meas.ext.toa256_min | 16384 | 16384
meas.ext.toa256_max | 16384 | 16384
meas.ms_toa256 | 16384 | 16384
diff --git a/tests/meas/meas_testcases.h b/tests/meas/meas_testcases.h
index ff74a207..fefa34f7 100644
--- a/tests/meas/meas_testcases.h
+++ b/tests/meas/meas_testcases.h
@@ -1,5 +1,5 @@
-#define ULM(ber, ta, neg_rssi) \
- { .ber10k = (ber), .ta_offs_256bits = (ta), .c_i = 1.0, .is_sub = 0, .inv_rssi = (neg_rssi) }
+#define ULM(ber, ta, sub, neg_rssi) \
+ { .ber10k = (ber), .ta_offs_256bits = (ta), .c_i = 1.0, .is_sub = sub, .inv_rssi = (neg_rssi) }
struct meas_testcase {
const char *name;
@@ -7,6 +7,8 @@ struct meas_testcase {
const struct bts_ul_meas *ulm;
unsigned int ulm_count;
uint32_t final_fn;
+ uint8_t ts;
+ enum gsm_phys_chan_config pchan;
/* results */
struct {
int success;
@@ -20,15 +22,21 @@ struct meas_testcase {
};
static struct bts_ul_meas ulm1[] = {
- ULM(0, 0, 90),
- ULM(0, 256, 90),
- ULM(0, -256, 90),
+ /* Note: The assumptions about the frame number and the subset
+ * allegiance is random since for the calculation only the amount
+ * is of relevance. This is true for all following testcases */
+ ULM(0, 0, 0, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, -256, 0, 90),
};
+
static const struct meas_testcase mtc1 = {
.name = "TOA256 Min-Max negative/positive",
.ulm = ulm1,
.ulm_count = ARRAY_SIZE(ulm1),
.final_fn = 25,
+ .ts = 1,
+ .pchan = GSM_PCHAN_TCH_F,
.res = {
.success = 1,
.rx_lev_full = 110-90,
@@ -41,22 +49,44 @@ static const struct meas_testcase mtc1 = {
};
static struct bts_ul_meas ulm2[] = {
- ULM(0, 256, 90),
- ULM(0, 258, 90),
- ULM(0, 254, 90),
- ULM(0, 258, 90),
- ULM(0, 254, 90),
- ULM(0, 256, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 1, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 1, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 0, 90),
+ ULM(0, 256, 1, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 0, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 0, 90),
+ ULM(0, 258, 0, 90),
+ ULM(0, 254, 0, 90),
+ ULM(0, 256, 0, 90),
+ ULM(0, 256, 0, 90),
};
+
static const struct meas_testcase mtc2 = {
.name = "TOA256 small jitter around 256",
.ulm = ulm2,
.ulm_count = ARRAY_SIZE(ulm2),
.final_fn = 25,
+ .ts = 1,
+ .pchan = GSM_PCHAN_TCH_F,
.res = {
.success = 1,
.rx_lev_full = 110-90,
- .rx_qual_full = 0,
+ .rx_qual_full = 7,
.toa256_mean = 256,
.toa256_max = 258,
.toa256_min = 254,
@@ -65,17 +95,20 @@ static const struct meas_testcase mtc2 = {
};
static struct bts_ul_meas ulm3[] = {
- ULM(0, 0, 90),
- ULM(0, 0, 80),
- ULM(0, 0, 80),
- ULM(0, 0, 100),
- ULM(0, 0, 100),
+ ULM(0, 0, 0, 90),
+ ULM(0, 0, 0, 80),
+ ULM(0, 0, 0, 80),
+ ULM(0, 0, 0, 100),
+ ULM(0, 0, 0, 100),
};
+
static const struct meas_testcase mtc3 = {
.name = "RxLEv averaging",
.ulm = ulm3,
.ulm_count = ARRAY_SIZE(ulm3),
.final_fn = 25,
+ .ts = 1,
+ .pchan = GSM_PCHAN_TCH_F,
.res = {
.success = 1,
.rx_lev_full = 110-90,
@@ -88,15 +121,18 @@ static const struct meas_testcase mtc3 = {
};
static struct bts_ul_meas ulm4[] = {};
+
static const struct meas_testcase mtc4 = {
.name = "Empty measurements",
.ulm = ulm4,
.ulm_count = ARRAY_SIZE(ulm4),
.final_fn = 25,
+ .ts = 1,
+ .pchan = GSM_PCHAN_TCH_F,
.res = {
- .success = 0,
- .rx_lev_full = 0,
- .rx_qual_full = 0,
+ .success = 1,
+ .rx_lev_full = 63,
+ .rx_qual_full = 3,
.toa256_mean = 0,
.toa256_max = 0,
.toa256_min = 0,
@@ -107,38 +143,41 @@ static const struct meas_testcase mtc4 = {
static struct bts_ul_meas ulm5[] = {
/* one 104 multiframe can at max contain 26 blocks (TCH/F),
* each of which can at maximum be 64 bits in advance (TA range) */
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
- ULM(0, 64*256, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
};
+
static const struct meas_testcase mtc5 = {
.name = "TOA256 26 blocks with max TOA256",
.ulm = ulm5,
.ulm_count = ARRAY_SIZE(ulm5),
.final_fn = 25,
+ .ts = 1,
+ .pchan = GSM_PCHAN_TCH_F,
.res = {
.success = 1,
.rx_lev_full = 110-90,
@@ -149,3 +188,391 @@ static const struct meas_testcase mtc5 = {
.toa256_std_dev = 0,
},
};
+
+/* This testcase models a good case as we can see it when all TCH
+ * and SACCH blocks are received */
+static struct bts_ul_meas ulm_tch_f_complete[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+};
+
+static const struct meas_testcase mtc_tch_f_complete = {
+ .name = "Complete TCH/F measurement period (26 measurements, 3 sub-frames)",
+ .ulm = ulm_tch_f_complete,
+ .ulm_count = ARRAY_SIZE(ulm_tch_f_complete),
+ .final_fn = 38,
+ .ts = 2,
+ .pchan = GSM_PCHAN_TCH_F,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 0,
+ .toa256_mean = 64*256,
+ .toa256_max = 64*256,
+ .toa256_min = 64*256,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* This testcase models an error case where two of 3 expected sub measurements
+ * are lost. The calculation logic must detect this and replace those
+ * measurements. Note that this example also lacks some blocks due to DTX,
+ * which is normal. */
+static struct bts_ul_meas ulm_tch_f_dtx_with_lost_subs[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+};
+
+static const struct meas_testcase mtc_tch_f_dtx_with_lost_subs = {
+ /* This testcase models a good case as we can see it when all TCH
+ * and SACCH blocks are received */
+ .name = "Incomplete TCH/F measurement period (16 measurements, 1 sub-frame)",
+ .ulm = ulm_tch_f_dtx_with_lost_subs,
+ .ulm_count = ARRAY_SIZE(ulm_tch_f_dtx_with_lost_subs),
+ .final_fn = 38,
+ .ts = 2,
+ .pchan = GSM_PCHAN_TCH_F,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 7,
+ .toa256_mean = 16384,
+ .toa256_max = 16384,
+ .toa256_min = 16384,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* This testcase models a good-case with DTX. Some measurements are missing
+ * because no block was transmitted, all sub measurements are there. */
+static struct bts_ul_meas ulm_tch_f_dtx[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+};
+
+static const struct meas_testcase mtc_tch_f_dtx = {
+ .name = "Incomplete but normal TCH/F measurement period (16 measurements, 3 sub-frames)",
+ .ulm = ulm_tch_f_dtx,
+ .ulm_count = ARRAY_SIZE(ulm_tch_f_dtx),
+ .final_fn = 38,
+ .ts = 2,
+ .pchan = GSM_PCHAN_TCH_F,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 7,
+ .toa256_mean = 16384,
+ .toa256_max = 16384,
+ .toa256_min = 16384,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* This testcase models a good case as we can see it when all TCH
+ * and SACCH blocks are received */
+static struct bts_ul_meas ulm_tch_h_complete[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+};
+
+static const struct meas_testcase mtc_tch_h_complete = {
+ .name = "Complete TCH/H measurement period (26 measurements, 5 sub-frames)",
+ .ulm = ulm_tch_h_complete,
+ .ulm_count = ARRAY_SIZE(ulm_tch_h_complete),
+ .final_fn = 38,
+ .ts = 2,
+ .pchan = GSM_PCHAN_TCH_H,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 110 - 90,
+ .rx_qual_full = 0,
+ .toa256_mean = 64*256,
+ .toa256_max = 64*256,
+ .toa256_min = 64*256,
+ .toa256_std_dev = 0,
+ },
+};
+
+static struct bts_ul_meas ulm_tch_h_dtx_with_lost_subs[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+};
+
+static const struct meas_testcase mtc_tch_h_dtx_with_lost_subs = {
+ .name = "Incomplete TCH/H measurement period (14 measurements, 3 sub-frames)",
+ .ulm = ulm_tch_h_dtx_with_lost_subs,
+ .ulm_count = ARRAY_SIZE(ulm_tch_h_dtx_with_lost_subs),
+ .final_fn = 38,
+ .ts = 2,
+ .pchan = GSM_PCHAN_TCH_H,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 7,
+ .toa256_mean = 16384,
+ .toa256_max = 16384,
+ .toa256_min = 16384,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* This testcase models a good-case with DTX. Some measurements are missing
+ * because no block was transmitted, all sub measurements are there. */
+static struct bts_ul_meas ulm_tch_h_dtx[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+};
+
+static const struct meas_testcase mtc_tch_h_dtx = {
+ .name = "Incomplete but normal TCH/F measurement period (16 measurements, 5 sub-frames)",
+ .ulm = ulm_tch_h_dtx,
+ .ulm_count = ARRAY_SIZE(ulm_tch_h_dtx),
+ .final_fn = 38,
+ .ts = 2,
+ .pchan = GSM_PCHAN_TCH_H,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 7,
+ .toa256_mean = 16384,
+ .toa256_max = 16384,
+ .toa256_min = 16384,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* This testcase assumes that too many measurements were collected. This can
+ * happen when the measurement calculation for a previous cycle were not
+ * executed. In this case the older part of the excess data must be discarded.
+ * the calculation algorithm must make sure that the calculation only takes
+ * place on the last measurement interval */
+static struct bts_ul_meas ulm_overrun[] = {
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ /* All measurements above must be discarded */
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+ ULM(0, 64*256, 0, 90),
+};
+
+static const struct meas_testcase mtc_overrun = {
+ .name = "TCH/F measurement period with too much measurement values (overrun)",
+ .ulm = ulm_overrun,
+ .ulm_count = ARRAY_SIZE(ulm_overrun),
+ .final_fn = 25,
+ .ts = 1,
+ .pchan = GSM_PCHAN_TCH_F,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 110 - 90,
+ .rx_qual_full = 0,
+ .toa256_mean = 64*256,
+ .toa256_max = 64*256,
+ .toa256_min = 64*256,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* Test SDCCH4 with all frames received */
+static struct bts_ul_meas ulm_sdcch4_complete[] = {
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 1, 90),
+};
+
+static const struct meas_testcase mtc_sdcch4_complete = {
+ .name = "Complete SDCCH4 measurement period (3 measurements)",
+ .ulm = ulm_sdcch4_complete,
+ .ulm_count = ARRAY_SIZE(ulm_sdcch4_complete),
+ .final_fn = 88,
+ .ts = 0,
+ .pchan = GSM_PCHAN_CCCH_SDCCH4,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 0,
+ .toa256_mean = 16384,
+ .toa256_max = 16384,
+ .toa256_min = 16384,
+ .toa256_std_dev = 0,
+ },
+};
+
+/* Test SDCCH8 with all frames received */
+static struct bts_ul_meas ulm_sdcch8_complete[] = {
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 1, 90),
+ ULM(0, 64*256, 1, 90),
+};
+
+static const struct meas_testcase mtc_sdcch8_complete = {
+ .name = "Complete SDCCH8 measurement period (3 measurements)",
+ .ulm = ulm_sdcch8_complete,
+ .ulm_count = ARRAY_SIZE(ulm_sdcch8_complete),
+ .final_fn = 66,
+ .ts = 0,
+ .pchan = GSM_PCHAN_SDCCH8_SACCH8C,
+ .res = {
+ .success = 1,
+ .rx_lev_full = 20,
+ .rx_qual_full = 0,
+ .toa256_mean = 16384,
+ .toa256_max = 16384,
+ .toa256_min = 16384,
+ .toa256_std_dev = 0,
+ },
+};