#define ULM(ber, ta, sub, neg_rssi) \ { .ber10k = (ber), .ta_offs_256bits = (ta), .ci_cb = 10, .is_sub = sub, .inv_rssi = (neg_rssi) } struct meas_testcase { const char *name; /* input data */ 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; uint8_t rx_lev_full; uint8_t rx_qual_full; int16_t toa256_mean; int16_t toa256_min; int16_t toa256_max; uint16_t toa256_std_dev; } res; }; static struct bts_ul_meas ulm1[] = { /* 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, .rx_qual_full = 0, .toa256_mean = 0, .toa256_max = 256, .toa256_min = -256, .toa256_std_dev = 209, }, }; static struct bts_ul_meas ulm2[] = { 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 = 7, .toa256_mean = 256, .toa256_max = 258, .toa256_min = 254, .toa256_std_dev = 1, }, }; static struct bts_ul_meas ulm3[] = { 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, .rx_qual_full = 0, .toa256_mean = 0, .toa256_max = 0, .toa256_min = 0, .toa256_std_dev = 0, }, }; 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 = 1, .rx_lev_full = 1, .rx_qual_full = 7, .toa256_mean = 0, .toa256_max = 0, .toa256_min = 0, .toa256_std_dev = 0, }, }; 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, 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, .rx_qual_full = 0, .toa256_mean = 64*256, .toa256_max = 64*256, .toa256_min = 64*256, .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, }, };