From 65d114fe434ec4fff9b9abfedade05ce21da994e Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Thu, 16 Jan 2014 11:02:14 +0100 Subject: [PATCH 1/7] si: Add a config option to disable SI2ter/SI2bis/SI5ter/SI5bis messages The iPhone5 (US) appears to have some issues with the SIs generated, or the nanoBTS is not sending them correctly. Add a configurable hack to put all bands into the SI2/SI5 message. It is enabled by the bts VTY command 'force-combined-si'. This is a quick change without much reflection and watching for side effects. I have verfied that a network with ARFCN 134 and neighbors ARFCN 130 and 512 do not get generate the SI2ter and announce everything inside the SI2. This patch is conceptually based on 'si: Add a hack to disable SI2ter/SI2bis/SI5ter/SI5bis messages' (692daaf2d2). Ticket: OW#1062 Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/gsm_data_shared.h | 3 +++ openbsc/src/libbsc/bsc_vty.c | 27 +++++++++++++++++++++++ openbsc/src/libbsc/system_information.c | 3 +++ openbsc/tests/vty_test_runner.py | 18 +++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 3bf05e4b3..ae9e7d867 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -676,6 +676,9 @@ struct gsm_bts { int num_trx; struct llist_head trx_list; + /* SI compatibility hacks */ + int force_combined_si; + #ifdef ROLE_BSC /* Abis NM queue */ struct llist_head abis_queue; diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index b27184be3..3b85892e0 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -645,6 +645,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) if (bts->excl_from_rf_lock) vty_out(vty, " rf-lock-exclude%s", VTY_NEWLINE); + vty_out(vty, " %sforce-combined-si%s", + bts->force_combined_si ? "" : "no ", VTY_NEWLINE); + config_write_bts_model(vty, bts); } @@ -2667,6 +2670,28 @@ DEFUN(cfg_bts_no_excl_rf_lock, return CMD_SUCCESS; } +#define FORCE_COMB_SI_STR "Force the generation of a single SI (no ter/bis)\n" + +DEFUN(cfg_bts_force_comb_si, + cfg_bts_force_comb_si_cmd, + "force-combined-si", + FORCE_COMB_SI_STR) +{ + struct gsm_bts *bts = vty->index; + bts->force_combined_si = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_no_force_comb_si, + cfg_bts_no_force_comb_si_cmd, + "no force-combined-si", + NO_STR FORCE_COMB_SI_STR) +{ + struct gsm_bts *bts = vty->index; + bts->force_combined_si = 0; + return CMD_SUCCESS; +} + static void _get_codec_from_arg(struct vty *vty, int argc, const char *argv[]) { struct gsm_bts *bts = vty->index; @@ -3331,6 +3356,8 @@ int bsc_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd); install_element(BTS_NODE, &cfg_bts_excl_rf_lock_cmd); install_element(BTS_NODE, &cfg_bts_no_excl_rf_lock_cmd); + install_element(BTS_NODE, &cfg_bts_force_comb_si_cmd); + install_element(BTS_NODE, &cfg_bts_no_force_comb_si_cmd); install_element(BTS_NODE, &cfg_bts_codec0_cmd); install_element(BTS_NODE, &cfg_bts_codec1_cmd); install_element(BTS_NODE, &cfg_bts_codec2_cmd); diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index c901a4ae6..aa1cb8d1b 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -70,8 +70,11 @@ static int is_dcs_net(const struct gsm_bts *bts) static int use_arfcn(const struct gsm_bts *bts, const int bis, const int ter, const int pgsm, const int arfcn) { + if (bts->force_combined_si) + return !bis && !ter; if (!bis && !ter && band_compatible(bts, arfcn)) return 1; + /* Correct but somehow broken with either the nanoBTS or the iPhone5 */ if (bis && pgsm && band_compatible(bts, arfcn) && (arfcn < 1 || arfcn > 124)) return 1; if (ter && !band_compatible(bts, arfcn)) diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py index 08c94b1b5..74f0fd21a 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -173,6 +173,24 @@ class TestVTYNITB(TestVTYGenericBSC): self.assertEquals(res.find('periodic location update 60'), -1) self.assert_(res.find('no periodic location update') > 0) + def testEnableDisableSiHacks(self): + self.vty.enable() + self.vty.command("configure terminal") + self.vty.command("network") + self.vty.command("bts 0") + + # Enable periodic lu.. + self.vty.verify("force-combined-si", ['']) + res = self.vty.command("write terminal") + self.assert_(res.find(' force-combined-si') > 0) + self.assertEquals(res.find('no force-combined-si'), -1) + + # Now disable it.. + self.vty.verify("no force-combined-si", ['']) + res = self.vty.command("write terminal") + self.assertEquals(res.find(' force-combined-si'), -1) + self.assert_(res.find('no force-combined-si') > 0) + def testRachAccessControlClass(self): self.vty.enable() self.vty.command("configure terminal") From 4b903b4afb5d593603b0d75a7d244f6c00e039ad Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 10 Jan 2014 17:43:41 +0100 Subject: [PATCH 2/7] si/test: Add tests for range encoding/decoding This commit adds test range encoding tests. They check the property decoding(encoding(L)) = L and optionally dump the results and encoded sequences to stdout. There a 2 test modes: - A list of fixed tests - A random number based test loop per ARFCN list size (only dumps the first failing test) Sponsored-by: On-Waves ehf --- openbsc/tests/gsm0408/Makefile.am | 1 + openbsc/tests/gsm0408/gsm0408_test.c | 216 ++++++++++++++++++++++++++ openbsc/tests/gsm0408/gsm0408_test.ok | 48 ++++++ 3 files changed, 265 insertions(+) diff --git a/openbsc/tests/gsm0408/Makefile.am b/openbsc/tests/gsm0408/Makefile.am index b000c0802..1c29ece12 100644 --- a/openbsc/tests/gsm0408/Makefile.am +++ b/openbsc/tests/gsm0408/Makefile.am @@ -8,4 +8,5 @@ gsm0408_test_SOURCES = gsm0408_test.c gsm0408_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libbsc/libbsc.a \ + $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -ldbi diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index 60a151faf..721b283bb 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #define COMPARE(result, op, value) \ if (!((result) op (value))) {\ @@ -94,10 +96,224 @@ static void test_mi_functionality(void) COMPARE_STR(mi_parsed, imsi_even); } +struct { + int range; + int arfcns_num; + int arfcns[RANGE_ENC_MAX_ARFCNS]; +} arfcn_test_ranges[] = { + {ARFCN_RANGE_512, 12, + { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }}, + {ARFCN_RANGE_512, 17, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }}, + {ARFCN_RANGE_512, 18, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }}, + {ARFCN_RANGE_512, 18, + { 1, 17, 31, 45, 58, 79, 81, 97, + 113, 127, 213, 277, 287, 311, 331, 391, + 417, 511 }}, + {ARFCN_RANGE_512, 6, + { 1, 17, 31, 45, 58, 79 }}, + {ARFCN_RANGE_512, 6, + { 10, 17, 31, 45, 58, 79 }}, + {ARFCN_RANGE_1024, 17, + { 0, 17, 31, 45, 58, 79, 81, 97, + 113, 127, 213, 277, 287, 311, 331, 391, + 1023 }}, + {ARFCN_RANGE_1024, 16, + { 17, 31, 45, 58, 79, 81, 97, 113, + 127, 213, 277, 287, 311, 331, 391, 1023 }}, + {-1} +}; + +static int test_single_range_encoding(int range, const int *orig_arfcns, + int arfcns_num, int silent) +{ + int arfcns[RANGE_ENC_MAX_ARFCNS]; + int w[RANGE_ENC_MAX_ARFCNS]; + int f0_included = 0; + int rc, f0; + uint8_t chan_list[16] = {0}; + struct gsm_sysinfo_freq dec_freq[1024] = {{0}}; + int dec_arfcns[RANGE_ENC_MAX_ARFCNS] = {0}; + int dec_arfcns_count = 0; + int arfcns_used = 0; + int i; + + arfcns_used = arfcns_num; + memmove(arfcns, orig_arfcns, sizeof(arfcns)); + + f0 = arfcns[0]; + /* + * Manipulate the ARFCN list according to the rules in J4 depending + * on the selected range. + */ + arfcns_used = range_enc_filter_arfcns(range, arfcns, arfcns_used, + f0, &f0_included); + + memset(w, 0, sizeof(w)); + rc = range_enc_arfcns(range, arfcns, arfcns_used, w, 0); + if (rc != 0) { + printf("Cannot compute range W(k), rc = %d\n", rc); + return 1; + } + + if (!silent) + fprintf(stderr, "range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", + range, arfcns_used, f0, f0_included); + + /* Select the range and the amount of bits needed */ + switch (range) { + case ARFCN_RANGE_128: + rc = range_enc_range128(chan_list, f0, w); + break; + case ARFCN_RANGE_256: + rc = range_enc_range256(chan_list, f0, w); + break; + case ARFCN_RANGE_512: + rc = range_enc_range512(chan_list, f0, w); + break; + case ARFCN_RANGE_1024: + rc = range_enc_range1024(chan_list, f0, f0_included, w); + break; + default: + return 1; + }; + if (rc != 0) { + printf("Cannot encode range, rc = %d\n", rc); + return 1; + } + + if (!silent) + printf("chan_list = %s\n", + osmo_hexdump(chan_list, sizeof(chan_list))); + + rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list), + 0xfe, 1); + if (rc != 0) { + printf("Cannot decode freq list, rc = %d\n", rc); + return 1; + } + + for (i = 0; i < ARRAY_SIZE(dec_freq); i++) { + if (dec_freq[i].mask && + dec_arfcns_count < ARRAY_SIZE(dec_arfcns)) + dec_arfcns[dec_arfcns_count++] = i; + } + + if (!silent) { + printf("Decoded freqs %d (expected %d)\n", + dec_arfcns_count, arfcns_num); + printf("Decoded: "); + for (i = 0; i < dec_arfcns_count; i++) { + printf("%d ", dec_arfcns[i]); + if (dec_arfcns[i] != orig_arfcns[i]) + printf("(!= %d) ", orig_arfcns[i]); + } + printf("\n"); + } + + if (dec_arfcns_count != arfcns_num) { + printf("Wrong number of arfcns\n"); + return 1; + } + + if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) { + printf("Decoding error, got wrong freqs\n"); + fprintf(stderr, " w = "); + for (i = 0; i < ARRAY_SIZE(w); i++) + fprintf(stderr, "%d ", w[i]); + fprintf(stderr, "\n"); + return 1; + } + + return 0; +} + +static void test_random_range_encoding(int range, int max_arfcn_num) +{ + int arfcns_num = 0; + int test_idx; + int rc, max_count; + int num_tests = 1024; + + printf("Random range test: range %d, max num ARFCNs %d\n", + range, max_arfcn_num); + + srandom(1); + + for (max_count = 1; max_count < max_arfcn_num; max_count++) { + for (test_idx = 0; test_idx < num_tests; test_idx++) { + int count; + int i; + int min_freq = 0; + + int rnd_arfcns[RANGE_ENC_MAX_ARFCNS] = {0}; + char rnd_arfcns_set[1024] = {0}; + + if (range < ARFCN_RANGE_1024) + min_freq = random() % (1023 - range); + + for (count = max_count; count; ) { + int arfcn = min_freq + random() % (range + 1); + OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set)); + + if (!rnd_arfcns_set[arfcn]) { + rnd_arfcns_set[arfcn] = 1; + count -= 1; + } + } + + arfcns_num = 0; + for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++) + if (rnd_arfcns_set[i]) + rnd_arfcns[arfcns_num++] = i; + + rc = test_single_range_encoding(range, rnd_arfcns, + arfcns_num, 1); + if (rc != 0) { + printf("Failed on test %d, range %d, num ARFCNs %d\n", + test_idx, range, max_count); + test_single_range_encoding(range, rnd_arfcns, + arfcns_num, 0); + return; + } + } + } +} + +static void test_range_encoding() +{ + int *arfcns; + int arfcns_num = 0; + int test_idx; + int range; + + for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++) + { + arfcns_num = arfcn_test_ranges[test_idx].arfcns_num; + arfcns = &arfcn_test_ranges[test_idx].arfcns[0]; + range = arfcn_test_ranges[test_idx].range; + + printf("Range test %d: range %d, num ARFCNs %d\n", + test_idx, range, arfcns_num); + + test_single_range_encoding(range, arfcns, arfcns_num, 0); + } + + test_random_range_encoding(ARFCN_RANGE_128, 29); + test_random_range_encoding(ARFCN_RANGE_256, 22); + test_random_range_encoding(ARFCN_RANGE_512, 18); + test_random_range_encoding(ARFCN_RANGE_1024, 16); +} + int main(int argc, char **argv) { + osmo_init_logging(&log_info); + log_set_log_level(osmo_stderr_target, LOGL_INFO); + test_location_area_identifier(); test_mi_functionality(); + test_range_encoding(); printf("Done.\n"); return EXIT_SUCCESS; diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok index 52c601e2d..a92b8792b 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.ok +++ b/openbsc/tests/gsm0408/gsm0408_test.ok @@ -2,4 +2,52 @@ Testing test location area identifier Testing parsing and generating TMSI/IMSI hex: 17 08 99 78 56 34 12 90 78 36 hex: 17 09 91 78 56 34 12 90 78 56 f4 +Range test 0: range 511, num ARFCNs 12 +chan_list = 88 00 98 34 85 36 7c 50 22 dc 5e ec 00 00 00 00 +Decoded freqs 12 (expected 12) +Decoded: 1 12 31 51 57 91 97 98 113 117 120 125 +Range test 1: range 511, num ARFCNs 17 +chan_list = 88 00 82 7f 01 3f 7e 04 0b ff ff fc 10 41 07 e0 +Decoded freqs 17 (expected 17) +Decoded: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +Range test 2: range 511, num ARFCNs 18 +chan_list = 88 00 82 7f 01 7f 7e 04 0b ff ff fc 10 41 07 ff +Decoded freqs 18 (expected 18) +Decoded: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 +Range test 3: range 511, num ARFCNs 18 +chan_list = 88 00 94 3a 44 32 d7 2a 43 2a 13 94 e5 38 39 76 +Decoded freqs 18 (expected 18) +Decoded: 1 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 417 507 (!= 511) +Decoding error, got wrong freqs +Range test 4: range 511, num ARFCNs 6 +chan_list = 88 00 8b 3c 88 b9 6b 00 00 00 00 00 00 00 00 00 +Decoded freqs 6 (expected 6) +Decoded: 1 17 31 45 58 79 +Range test 5: range 511, num ARFCNs 6 +chan_list = 88 05 08 fc 88 b9 6b 00 00 00 00 00 00 00 00 00 +Decoded freqs 6 (expected 6) +Decoded: 10 17 31 45 58 79 +Range test 6: range 1023, num ARFCNs 17 +Cannot encode range, rc = -1 +Range test 7: range 1023, num ARFCNs 16 +Cannot encode range, rc = -1 +Random range test: range 127, max num ARFCNs 29 +Cannot encode range, rc = -1 +Failed on test 0, range 127, num ARFCNs 1 +Cannot encode range, rc = -1 +Random range test: range 255, max num ARFCNs 22 +Cannot encode range, rc = -1 +Failed on test 0, range 255, num ARFCNs 1 +Cannot encode range, rc = -1 +Random range test: range 511, max num ARFCNs 18 +Decoding error, got wrong freqs +Failed on test 0, range 511, num ARFCNs 17 +chan_list = 88 21 55 fc da d7 76 03 31 2f ed 45 dc 93 d6 80 +Decoded freqs 17 (expected 17) +Decoded: 66 81 161 250 314 343 383 (!= 380) 395 396 397 409 429 505 506 516 518 545 +Decoding error, got wrong freqs +Random range test: range 1023, max num ARFCNs 16 +Cannot encode range, rc = -1 +Failed on test 0, range 1023, num ARFCNs 1 +Cannot encode range, rc = -1 Done. From 9444d4f8e264d425867d6430883afa754fe7bedc Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 13 Jan 2014 14:43:40 +0100 Subject: [PATCH 3/7] si/test: Merge si tests into gsm48 tests Currently tests covering features of the GSM 04.08 specification are spread over the si and gsm0408 subdirs in tests. This commit merges all tests from 'si' into 'gsm0408' and removes the 'si' test sub-directory. Sponsored-by: On-Waves ehf --- openbsc/configure.ac | 1 - openbsc/tests/Makefile.am | 2 +- openbsc/tests/gsm0408/gsm0408_test.c | 146 ++++++++++++++++++++++++ openbsc/tests/gsm0408/gsm0408_test.ok | 20 ++++ openbsc/tests/si/Makefile.am | 12 -- openbsc/tests/si/si_test.c | 156 -------------------------- openbsc/tests/si/si_test.ok | 20 ---- openbsc/tests/testsuite.at | 6 - 8 files changed, 167 insertions(+), 196 deletions(-) delete mode 100644 openbsc/tests/si/Makefile.am delete mode 100644 openbsc/tests/si/si_test.c delete mode 100644 openbsc/tests/si/si_test.ok diff --git a/openbsc/configure.ac b/openbsc/configure.ac index fe9956976..5d29af717 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -166,7 +166,6 @@ AC_OUTPUT( tests/mgcp/Makefile tests/gprs/Makefile tests/gbproxy/Makefile - tests/si/Makefile tests/abis/Makefile tests/smpp/Makefile tests/trau/Makefile diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index d4bb954a6..31b2bb4c7 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs si abis gbproxy trau +SUBDIRS = gsm0408 db channel mgcp gprs abis gbproxy trau if BUILD_NAT SUBDIRS += bsc-nat bsc-nat-trie diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index 721b283bb..3a6bbddff 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -42,6 +42,16 @@ exit(-1); \ } +#define DBG(...) + +#define VERIFY(res, cmp, wanted) \ + if (!(res cmp wanted)) { \ + printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \ + __FILE__, __LINE__, res, # cmp, wanted); \ + } + + + /* * Test Location Area Identifier formatting. Table 10.5.3 of 04.08 */ @@ -306,6 +316,138 @@ static void test_range_encoding() test_random_range_encoding(ARFCN_RANGE_1024, 16); } +static int freqs1[] = { + 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980 +}; + +static int freqs2[] = { + 402, 460, 1, 67, 131, 197, 272, 347, +}; + +static int freqs3[] = { + 68, 128, 198, 279, 353, 398, 452, + +}; + +static int w_out[] = { + 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9, +}; + +static int range128[] = { + 1, 1 + 127, +}; + +static int range256[] = { + 1, 1 + 128, +}; + +static int range512[] = { + 1, 1+ 511, +}; + + +static void test_arfcn_filter() +{ + int arfcns[50], i, res, f0_included; + for (i = 0; i < ARRAY_SIZE(arfcns); ++i) + arfcns[i] = (i + 1) * 2; + + /* check that the arfcn is taken out. f0_included is only set for Range1024 */ + f0_included = 24; + res = range_enc_filter_arfcns(ARFCN_RANGE_512, arfcns, ARRAY_SIZE(arfcns), + arfcns[0], &f0_included); + VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); + VERIFY(f0_included, ==, 0); + for (i = 0; i < res; ++i) + VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1)); + + /* check with range1024 */ + for (i = 0; i < ARRAY_SIZE(arfcns); ++i) + arfcns[i] = (i + 1) * 2; + res = range_enc_filter_arfcns(ARFCN_RANGE_1024, arfcns, ARRAY_SIZE(arfcns), + arfcns[0], &f0_included); + VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); + VERIFY(f0_included, ==, 1); + for (i = 0; i < res; ++i) + VERIFY(arfcns[i], ==, ((i + 2) * 2) - 1); + + /* check with range1024, not included */ + for (i = 0; i < ARRAY_SIZE(arfcns); ++i) + arfcns[i] = (i + 1) * 2; + res = range_enc_filter_arfcns(ARFCN_RANGE_1024, arfcns, ARRAY_SIZE(arfcns), + 11, &f0_included); + VERIFY(res, ==, ARRAY_SIZE(arfcns)); + VERIFY(f0_included, ==, 0); + for (i = 0; i < res; ++i) + VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1); +} + +static void test_print_encoding() +{ + int rc; + int w[17]; + uint8_t chan_list[16]; + memset(chan_list, 0x23, sizeof(chan_list)); + + for (rc = 0; rc < ARRAY_SIZE(w); ++rc) + switch (rc % 3) { + case 0: + w[rc] = 0xAAAA; + break; + case 1: + w[rc] = 0x5555; + break; + case 2: + w[rc] = 0x9696; + break; + } + + rc = range_enc_range512(chan_list, (1 << 9) | 0x96, w); + VERIFY(rc, ==, 0); + + printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list))); +} + +static void test_si_range_helpers() +{ + int ws[(sizeof(freqs1)/sizeof(freqs1[0]))]; + int i, f0 = 0xFFFFFF; + + memset(&ws[0], 0x23, sizeof(ws)); + + i = range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1)); + printf("Element is: %d => freqs[i] = %d\n", i, freqs1[i]); + VERIFY(i, ==, 2); + + i = range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2)); + printf("Element is: %d => freqs[i] = %d\n", i, freqs2[i]); + VERIFY(i, ==, 2); + + i = range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3)); + printf("Element is: %d => freqs[i] = %d\n", i, freqs3[i]); + VERIFY(i, ==, 0); + + i = range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0); + VERIFY(i, ==, 0); + + for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) { + printf("w[%d]=%d\n", i, ws[i]); + VERIFY(ws[i], ==, w_out[i]); + } + + i = range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0); + VERIFY(i, ==, ARFCN_RANGE_128); + VERIFY(f0, ==, 1); + + i = range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0); + VERIFY(i, ==, ARFCN_RANGE_256); + VERIFY(f0, ==, 1); + + i = range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0); + VERIFY(i, ==, ARFCN_RANGE_512); + VERIFY(f0, ==, 1); +} + int main(int argc, char **argv) { osmo_init_logging(&log_info); @@ -313,6 +455,10 @@ int main(int argc, char **argv) test_location_area_identifier(); test_mi_functionality(); + + test_si_range_helpers(); + test_arfcn_filter(); + test_print_encoding(); test_range_encoding(); printf("Done.\n"); diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok index a92b8792b..545866962 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.ok +++ b/openbsc/tests/gsm0408/gsm0408_test.ok @@ -2,6 +2,26 @@ Testing test location area identifier Testing parsing and generating TMSI/IMSI hex: 17 08 99 78 56 34 12 90 78 36 hex: 17 09 91 78 56 34 12 90 78 56 f4 +Element is: 2 => freqs[i] = 121 +Element is: 2 => freqs[i] = 1 +Element is: 0 => freqs[i] = 68 +w[0]=122 +w[1]=2 +w[2]=69 +w[3]=204 +w[4]=75 +w[5]=66 +w[6]=60 +w[7]=70 +w[8]=83 +w[9]=3 +w[10]=24 +w[11]=67 +w[12]=54 +w[13]=64 +w[14]=70 +w[15]=9 +Range512: 89 4b 2a 95 65 95 55 2c a9 55 aa 55 6a 95 59 55 Range test 0: range 511, num ARFCNs 12 chan_list = 88 00 98 34 85 36 7c 50 22 dc 5e ec 00 00 00 00 Decoded freqs 12 (expected 12) diff --git a/openbsc/tests/si/Makefile.am b/openbsc/tests/si/Makefile.am deleted file mode 100644 index 795bd3081..000000000 --- a/openbsc/tests/si/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(COVERAGE_CFLAGS) - -EXTRA_DIST = si_test.ok - -noinst_PROGRAMS = si_test - -si_test_SOURCES = si_test.c - -si_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) -lrt $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) diff --git a/openbsc/tests/si/si_test.c b/openbsc/tests/si/si_test.c deleted file mode 100644 index fd840f301..000000000 --- a/openbsc/tests/si/si_test.c +++ /dev/null @@ -1,156 +0,0 @@ - - -#include -#include -#include - -#include - -#include - -#define DBG(...) - -#define VERIFY(res, cmp, wanted) \ - if (!(res cmp wanted)) { \ - printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \ - __FILE__, __LINE__, res, # cmp, wanted); \ - } - - -static int freqs1[] = { - 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980 -}; - -static int freqs2[] = { - 402, 460, 1, 67, 131, 197, 272, 347, -}; - -static int freqs3[] = { - 68, 128, 198, 279, 353, 398, 452, - -}; - -static int w_out[] = { - 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9, -}; - -static int range128[] = { - 1, 1 + 127, -}; - -static int range256[] = { - 1, 1 + 128, -}; - -static int range512[] = { - 1, 1+ 511, -}; - - -static void test_arfcn_filter() -{ - int arfcns[50], i, res, f0_included; - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = (i + 1) * 2; - - /* check that the arfcn is taken out. f0_included is only set for Range1024 */ - f0_included = 24; - res = range_enc_filter_arfcns(ARFCN_RANGE_512, arfcns, ARRAY_SIZE(arfcns), - arfcns[0], &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); - VERIFY(f0_included, ==, 0); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1)); - - /* check with range1024 */ - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = (i + 1) * 2; - res = range_enc_filter_arfcns(ARFCN_RANGE_1024, arfcns, ARRAY_SIZE(arfcns), - arfcns[0], &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); - VERIFY(f0_included, ==, 1); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i + 2) * 2) - 1); - - /* check with range1024, not included */ - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = (i + 1) * 2; - res = range_enc_filter_arfcns(ARFCN_RANGE_1024, arfcns, ARRAY_SIZE(arfcns), - 11, &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns)); - VERIFY(f0_included, ==, 0); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1); -} - -static void test_print_encoding() -{ - int rc; - int w[17]; - uint8_t chan_list[16]; - memset(chan_list, 0x23, sizeof(chan_list)); - - for (rc = 0; rc < ARRAY_SIZE(w); ++rc) - switch (rc % 3) { - case 0: - w[rc] = 0xAAAA; - break; - case 1: - w[rc] = 0x5555; - break; - case 2: - w[rc] = 0x9696; - break; - } - - rc = range_enc_range512(chan_list, (1 << 9) | 0x96, w); - VERIFY(rc, ==, 0); - - printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list))); -} - -int main(int argc, char **argv) -{ - int ws[(sizeof(freqs1)/sizeof(freqs1[0]))]; - int i, f0 = 0xFFFFFF; - - memset(&ws[0], 0x23, sizeof(ws)); - - i = range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1)); - printf("Element is: %d => freqs[i] = %d\n", i, freqs1[i]); - VERIFY(i, ==, 2); - - i = range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2)); - printf("Element is: %d => freqs[i] = %d\n", i, freqs2[i]); - VERIFY(i, ==, 2); - - i = range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3)); - printf("Element is: %d => freqs[i] = %d\n", i, freqs3[i]); - VERIFY(i, ==, 0); - - i = range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0); - VERIFY(i, ==, 0); - - for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) { - printf("w[%d]=%d\n", i, ws[i]); - VERIFY(ws[i], ==, w_out[i]); - } - - i = range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0); - VERIFY(i, ==, ARFCN_RANGE_128); - VERIFY(f0, ==, 1); - - i = range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0); - VERIFY(i, ==, ARFCN_RANGE_256); - VERIFY(f0, ==, 1); - - i = range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0); - VERIFY(i, ==, ARFCN_RANGE_512); - VERIFY(f0, ==, 1); - - - test_arfcn_filter(); - test_print_encoding(); - - return 0; -} diff --git a/openbsc/tests/si/si_test.ok b/openbsc/tests/si/si_test.ok deleted file mode 100644 index 6a3ee513c..000000000 --- a/openbsc/tests/si/si_test.ok +++ /dev/null @@ -1,20 +0,0 @@ -Element is: 2 => freqs[i] = 121 -Element is: 2 => freqs[i] = 1 -Element is: 0 => freqs[i] = 68 -w[0]=122 -w[1]=2 -w[2]=69 -w[3]=204 -w[4]=75 -w[5]=66 -w[6]=60 -w[7]=70 -w[8]=83 -w[9]=3 -w[10]=24 -w[11]=67 -w[12]=54 -w[13]=64 -w[14]=70 -w[15]=9 -Range512: 89 4b 2a 95 65 95 55 2c a9 55 aa 55 6a 95 59 55 diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 652cfe96c..b2c551859 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -57,12 +57,6 @@ cat $abs_srcdir/bsc-nat-trie/bsc_nat_trie_test.ok > expout AT_CHECK([$abs_top_builddir/tests/bsc-nat-trie/bsc_nat_trie_test], [], [expout], [ignore]) AT_CLEANUP -AT_SETUP([si]) -AT_KEYWORDS([si]) -cat $abs_srcdir/si/si_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/si/si_test], [], [expout], [ignore]) -AT_CLEANUP - AT_SETUP([abis]) AT_KEYWORDS([abis]) cat $abs_srcdir/abis/abis_test.ok > expout From 131406c86dc1c589af8dea91e772eac01340ac94 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 13 Jan 2014 09:45:56 +0100 Subject: [PATCH 4/7] si: Fix range512 encoding This patch fixes a bug in the range encoder that leads to wrong encoding when 17 or more ARFCNs are encoded. Sponsored-by: On-Waves ehf --- openbsc/src/libbsc/arfcn_range_encode.c | 2 +- openbsc/tests/gsm0408/gsm0408_test.ok | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/openbsc/src/libbsc/arfcn_range_encode.c b/openbsc/src/libbsc/arfcn_range_encode.c index c52743e0d..917754623 100644 --- a/openbsc/src/libbsc/arfcn_range_encode.c +++ b/openbsc/src/libbsc/arfcn_range_encode.c @@ -256,7 +256,7 @@ int range_enc_range512(uint8_t *chan_list, int f0, int *w) range512->w15 = HIGH_BITS(w, 15, 6, 6); /* W(16) */ range512->w16_hi = HIGH_BITS(w, 16, 5, 2); - range512->w16_lo = HIGH_BITS(w, 16, 5, 3); + range512->w16_lo = LOW_BITS(w, 16, 5, 3); /* W(17) */ range512->w17 = HIGH_BITS(w, 17, 5, 5); diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok index 545866962..dab495d00 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.ok +++ b/openbsc/tests/gsm0408/gsm0408_test.ok @@ -35,10 +35,9 @@ chan_list = 88 00 82 7f 01 7f 7e 04 0b ff ff fc 10 41 07 ff Decoded freqs 18 (expected 18) Decoded: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Range test 3: range 511, num ARFCNs 18 -chan_list = 88 00 94 3a 44 32 d7 2a 43 2a 13 94 e5 38 39 76 +chan_list = 88 00 94 3a 44 32 d7 2a 43 2a 13 94 e5 38 39 f6 Decoded freqs 18 (expected 18) -Decoded: 1 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 417 507 (!= 511) -Decoding error, got wrong freqs +Decoded: 1 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 417 511 Range test 4: range 511, num ARFCNs 6 chan_list = 88 00 8b 3c 88 b9 6b 00 00 00 00 00 00 00 00 00 Decoded freqs 6 (expected 6) @@ -60,12 +59,6 @@ Cannot encode range, rc = -1 Failed on test 0, range 255, num ARFCNs 1 Cannot encode range, rc = -1 Random range test: range 511, max num ARFCNs 18 -Decoding error, got wrong freqs -Failed on test 0, range 511, num ARFCNs 17 -chan_list = 88 21 55 fc da d7 76 03 31 2f ed 45 dc 93 d6 80 -Decoded freqs 17 (expected 17) -Decoded: 66 81 161 250 314 343 383 (!= 380) 395 396 397 409 429 505 506 516 518 545 -Decoding error, got wrong freqs Random range test: range 1023, max num ARFCNs 16 Cannot encode range, rc = -1 Failed on test 0, range 1023, num ARFCNs 1 From 45014a0cadfd1f28d68d61b5160ee18fa391c4ba Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 14 Jan 2014 10:42:58 +0100 Subject: [PATCH 5/7] si: Fix range1024 encoding f0 is currently set to arfcns[0] in range_enc_determine_range(), while GSM 04.08 requires f0 to be ARFCN 0 in range1024 encoding. This patch modifies range_enc_determine_range() to force f0 to be 0 if this encoding is used. This way the case distinction in range_enc_filter_arfcns() is not longer necessary. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/arfcn_range_encode.h | 2 +- openbsc/src/libbsc/arfcn_range_encode.c | 42 +++++++++----------- openbsc/src/libbsc/system_information.c | 2 +- openbsc/tests/gsm0408/gsm0408_test.c | 34 ++++++++-------- 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/openbsc/include/openbsc/arfcn_range_encode.h b/openbsc/include/openbsc/arfcn_range_encode.h index 7a6fff000..bd85d6af4 100644 --- a/openbsc/include/openbsc/arfcn_range_encode.h +++ b/openbsc/include/openbsc/arfcn_range_encode.h @@ -16,7 +16,7 @@ enum { int range_enc_determine_range(const int *arfcns, int size, int *f0_out); int range_enc_arfcns(const int rng, const int *arfcns, int sze, int *out, int idx); int range_enc_find_index(const int rng, const int *arfcns, int size); -int range_enc_filter_arfcns(const int rng, int *arfcns, const int sze, const int f0, int *f0_included); +int range_enc_filter_arfcns(int *arfcns, const int sze, const int f0, int *f0_included); int range_enc_range128(uint8_t *chan_list, int f0, int *w); int range_enc_range256(uint8_t *chan_list, int f0, int *w); diff --git a/openbsc/src/libbsc/arfcn_range_encode.c b/openbsc/src/libbsc/arfcn_range_encode.c index 917754623..a047a06ea 100644 --- a/openbsc/src/libbsc/arfcn_range_encode.c +++ b/openbsc/src/libbsc/arfcn_range_encode.c @@ -144,7 +144,9 @@ int range_enc_arfcns(const int range, */ /** * This implements the range determination as described in GSM 04.08 J4. The - * result will be a base frequency f0 and the range to use. + * result will be a base frequency f0 and the range to use. Note that for range + * 1024 encoding f0 always refers to ARFCN 0 even if it is not an element of + * the arfcns list. * * \param[in] arfcns The input frequencies, they must be sorted, lowest number first * \param[in] size The length of the array @@ -166,8 +168,10 @@ int range_enc_determine_range(const int *arfcns, const int size, int *f0) return ARFCN_RANGE_256; if (max < 512 && size <= 18) return ARFCN_RANGE_512; - if (max < 1024 && size <= 17) + if (max < 1024 && size <= 17) { + *f0 = 0; return ARFCN_RANGE_1024; + } return ARFCN_RANGE_INVALID; } @@ -271,34 +275,24 @@ int range_enc_range1024(uint8_t *chan_list, int f0, int f0_included, int *w) return -1; } -int range_enc_filter_arfcns(const int range, int *arfcns, - const int size, const int f0, int *f0_included) +int range_enc_filter_arfcns(int *arfcns, + const int size, const int f0, int *f0_included) { int i, j = 0; *f0_included = 0; - if (range == ARFCN_RANGE_1024) { - for (i = 0; i < size; ++i) { - if (arfcns[i] == f0) { - *f0_included = 1; - continue; - } - - /* copy and subtract */ - arfcns[j++] = mod(arfcns[i] - 1, 1024); + for (i = 0; i < size; ++i) { + /* + * Appendix J.4 says the following: + * All frequencies except F(0), minus F(0) + 1. + * I assume we need to exclude it here. + */ + if (arfcns[i] == f0) { + *f0_included = 1; + continue; } - } else { - for (i = 0; i < size; ++i) { - /* - * Appendix J.4 says the following: - * All frequencies except F(0), minus F(0) + 1. - * I assume we need to exclude it here. - */ - if (arfcns[i] == f0) - continue; - arfcns[j++] = mod(arfcns[i] - (f0 + 1), 1024); - } + arfcns[j++] = mod(arfcns[i] - (f0 + 1), 1024); } return j; diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index aa1cb8d1b..a3deefc73 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -197,7 +197,7 @@ static int enc_freq_lst_range(uint8_t *chan_list, * Manipulate the ARFCN list according to the rules in J4 depending * on the selected range. */ - arfcns_used = range_enc_filter_arfcns(range, arfcns, arfcns_used, + arfcns_used = range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included); memset(w, 0, sizeof(w)); diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index 3a6bbddff..894eb0fb5 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -152,12 +152,12 @@ static int test_single_range_encoding(int range, const int *orig_arfcns, arfcns_used = arfcns_num; memmove(arfcns, orig_arfcns, sizeof(arfcns)); - f0 = arfcns[0]; + f0 = range == ARFCN_RANGE_1024 ? 0 : arfcns[0]; /* * Manipulate the ARFCN list according to the rules in J4 depending * on the selected range. */ - arfcns_used = range_enc_filter_arfcns(range, arfcns, arfcns_used, + arfcns_used = range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included); memset(w, 0, sizeof(w)); @@ -354,28 +354,28 @@ static void test_arfcn_filter() /* check that the arfcn is taken out. f0_included is only set for Range1024 */ f0_included = 24; - res = range_enc_filter_arfcns(ARFCN_RANGE_512, arfcns, ARRAY_SIZE(arfcns), - arfcns[0], &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); - VERIFY(f0_included, ==, 0); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1)); - - /* check with range1024 */ - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = (i + 1) * 2; - res = range_enc_filter_arfcns(ARFCN_RANGE_1024, arfcns, ARRAY_SIZE(arfcns), + res = range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), arfcns[0], &f0_included); VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); VERIFY(f0_included, ==, 1); for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i + 2) * 2) - 1); + VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1)); - /* check with range1024, not included */ + /* check with range1024, ARFCN 0 is included */ + for (i = 0; i < ARRAY_SIZE(arfcns); ++i) + arfcns[i] = i * 2; + res = range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), + 0, &f0_included); + VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); + VERIFY(f0_included, ==, 1); + for (i = 0; i < res; ++i) + VERIFY(arfcns[i], ==, (i + 1) * 2 - 1); + + /* check with range1024, ARFCN 0 not included */ for (i = 0; i < ARRAY_SIZE(arfcns); ++i) arfcns[i] = (i + 1) * 2; - res = range_enc_filter_arfcns(ARFCN_RANGE_1024, arfcns, ARRAY_SIZE(arfcns), - 11, &f0_included); + res = range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), + 0, &f0_included); VERIFY(res, ==, ARRAY_SIZE(arfcns)); VERIFY(f0_included, ==, 0); for (i = 0; i < res; ++i) From f8f72e23caae9a1954d86db5242ad764c33e6eff Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 10 Jan 2014 17:46:51 +0100 Subject: [PATCH 6/7] si: Add generic range w(k) encoder Currently the encoding of the chan_list is done by a hard-coded sequence of macros that closely resembles figure 10.5.16 in 3GPP TS 04.08. This patch replaces this by an algorithmic solution that can be used for all range encodings and is based on the property W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present (see section 10.5.2.13 in TS 04.08). Ticket: OW#1061 Sponsored-by: On-Waves ehf --- openbsc/src/libbsc/arfcn_range_encode.c | 141 ++++++++++++++---------- 1 file changed, 83 insertions(+), 58 deletions(-) diff --git a/openbsc/src/libbsc/arfcn_range_encode.c b/openbsc/src/libbsc/arfcn_range_encode.c index a047a06ea..1a26523e9 100644 --- a/openbsc/src/libbsc/arfcn_range_encode.c +++ b/openbsc/src/libbsc/arfcn_range_encode.c @@ -176,16 +176,6 @@ int range_enc_determine_range(const int *arfcns, const int size, int *f0) return ARFCN_RANGE_INVALID; } -/* - * The below is easier is to write in four methods than - * to use the max_bits. The encoding is so screwed.. as - * the bits need to be put in place in the wrong order.. - */ -#define HIGH_BITS(w, index, bits, offset) \ - (w[index - 1] >> (bits - offset)) -#define LOW_BITS(w, index, bits, offset) \ - (w[index - 1]) - static void write_orig_arfcn(uint8_t *chan_list, int f0) { chan_list[0] |= (f0 >> 9) & 1; @@ -193,6 +183,88 @@ static void write_orig_arfcn(uint8_t *chan_list, int f0) chan_list[2] = (f0 & 1) << 7; } +static void write_all_wn(uint8_t *chan_list, int bit_offs, + int *w, int w_size, int w1_len) +{ + int octet_offs = 0; /* offset into chan_list */ + int wk_len = w1_len; /* encoding size in bits of w[k] */ + int k; /* 1 based */ + int level = 0; /* tree level, top level = 0 */ + int lvl_left = 1; /* nodes per tree level */ + + /* W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present */ + + for (k = 1; k <= w_size; k++) { + int wk_left = wk_len; + DEBUGP(DRR, + "k=%d, wk_len=%d, offs=%d:%d, level=%d, " + "lvl_left=%d\n", + k, wk_len, octet_offs, bit_offs, level, lvl_left); + + while (wk_left > 0) { + int cur_bits = 8 - bit_offs; + int cur_mask; + int wk_slice; + + if (cur_bits > wk_left) + cur_bits = wk_left; + + cur_mask = ((1 << cur_bits) - 1); + + DEBUGP(DRR, + " wk_left=%d, cur_bits=%d, offs=%d:%d\n", + wk_left, cur_bits, octet_offs, bit_offs); + + /* advance */ + wk_left -= cur_bits; + bit_offs += cur_bits; + + /* right aligned wk data for current out octet */ + wk_slice = (w[k-1] >> wk_left) & cur_mask; + + /* cur_bits now contains the number of bits + * that are to be copied from wk to the chan_list. + * wk_left is set to the number of bits that must + * not yet be copied. + * bit_offs points after the bit area that is going to + * be overwritten: + * + * wk_left + * | + * v + * wk: WWWWWWWWWWW + * |||||<-- wk_slice, cur_bits=5 + * --WWWWW- + * ^ + * | + * bit_offs + */ + + DEBUGP(DRR, + " wk=%02x, slice=%02x/%02x, cl=%02x\n", + w[k-1], wk_slice, cur_mask, wk_slice << (8 - bit_offs)); + + chan_list[octet_offs] &= ~(cur_mask << (8 - bit_offs)); + chan_list[octet_offs] |= wk_slice << (8 - bit_offs); + + /* adjust output */ + if (bit_offs == 8) { + bit_offs = 0; + octet_offs += 1; + } + } + + /* adjust bit sizes */ + lvl_left -= 1; + if (!lvl_left) { + /* completed tree level, advance to next */ + level += 1; + lvl_left = 1 << level; + wk_len -= 1; + } + } +} + int range_enc_range128(uint8_t *chan_list, int f0, int *w) { chan_list[0] = 0x8C; @@ -213,57 +285,10 @@ int range_enc_range256(uint8_t *chan_list, int f0, int *w) int range_enc_range512(uint8_t *chan_list, int f0, int *w) { - struct gsm48_range_512 *range512; chan_list[0] = 0x88; write_orig_arfcn(chan_list, f0); - range512 = (struct gsm48_range_512 *) &chan_list[0]; - - /* W(1) */ - range512->w1_hi = HIGH_BITS(w, 1, 9, 7); - range512->w1_lo = LOW_BITS (w, 1, 9, 2); - /* W(2) */ - range512->w2_hi = HIGH_BITS(w, 2, 8, 6); - range512->w2_lo = LOW_BITS (w, 2, 8, 2); - /* W(3) */ - range512->w3_hi = HIGH_BITS(w, 3, 8, 6); - range512->w3_lo = LOW_BITS (w, 3, 8, 2); - /* W(4) */ - range512->w4_hi = HIGH_BITS(w, 4, 7, 6); - range512->w4_lo = LOW_BITS (w, 4, 7, 1); - /* W(5) */ - range512->w5 = HIGH_BITS(w, 5, 7, 7); - /* W(6) */ - range512->w6 = HIGH_BITS(w, 6, 7, 7); - /* W(7) */ - range512->w7_hi = HIGH_BITS(w, 7, 7, 1); - range512->w7_lo = LOW_BITS (w, 7, 7, 6); - /* W(8) */ - range512->w8_hi = HIGH_BITS(w, 8, 6, 2); - range512->w8_lo = LOW_BITS (w, 8, 6, 4); - /* W(9) */ - range512->w9_hi = HIGH_BITS(w, 9, 6, 4); - range512->w9_lo = LOW_BITS(w, 9, 6, 2); - /* W(10) */ - range512->w10 = HIGH_BITS(w, 10, 6, 6); - /* W(11) */ - range512->w11 = HIGH_BITS(w, 11, 6, 6); - /* W(12) */ - range512->w12_hi = HIGH_BITS(w, 12, 6, 2); - range512->w12_lo = LOW_BITS (w, 12, 6, 4); - /* W(13) */ - range512->w13_hi = HIGH_BITS(w, 13, 6, 4); - range512->w13_lo = LOW_BITS(w, 13, 6, 2); - /* W(14) */ - range512->w14 = HIGH_BITS(w, 14, 6, 6); - /* W(15) */ - range512->w15 = HIGH_BITS(w, 15, 6, 6); - /* W(16) */ - range512->w16_hi = HIGH_BITS(w, 16, 5, 2); - range512->w16_lo = LOW_BITS(w, 16, 5, 3); - /* W(17) */ - range512->w17 = HIGH_BITS(w, 17, 5, 5); - + write_all_wn(&chan_list[2], 1, w, 17, 9); return 0; } From 64277e6514d5b305af97d6cfe07601ba00d8afaa Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 10 Jan 2014 17:47:43 +0100 Subject: [PATCH 7/7] si: Implement range 128, 256, 1024 encoding This commit adds the implementation of these range formats to the encoder. In addition, the work-around that tried range 512 first is removed, so that the selection is primarily based on the max distance between frequencies. Ticket: OW#1061 Sponsored-by: On-Waves ehf --- openbsc/src/libbsc/arfcn_range_encode.c | 12 ++++++------ openbsc/tests/gsm0408/gsm0408_test.ok | 17 ++++++----------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/openbsc/src/libbsc/arfcn_range_encode.c b/openbsc/src/libbsc/arfcn_range_encode.c index 1a26523e9..e67bf0a70 100644 --- a/openbsc/src/libbsc/arfcn_range_encode.c +++ b/openbsc/src/libbsc/arfcn_range_encode.c @@ -270,8 +270,8 @@ int range_enc_range128(uint8_t *chan_list, int f0, int *w) chan_list[0] = 0x8C; write_orig_arfcn(chan_list, f0); - LOGP(DRR, LOGL_ERROR, "Range128 encoding is not implemented.\n"); - return -1; + write_all_wn(&chan_list[2], 1, w, 28, 7); + return 0; } int range_enc_range256(uint8_t *chan_list, int f0, int *w) @@ -279,8 +279,8 @@ int range_enc_range256(uint8_t *chan_list, int f0, int *w) chan_list[0] = 0x8A; write_orig_arfcn(chan_list, f0); - LOGP(DRR, LOGL_ERROR, "Range256 encoding is not implemented.\n"); - return -1; + write_all_wn(&chan_list[2], 1, w, 21, 8); + return 0; } int range_enc_range512(uint8_t *chan_list, int f0, int *w) @@ -296,8 +296,8 @@ int range_enc_range1024(uint8_t *chan_list, int f0, int f0_included, int *w) { chan_list[0] = 0x80 | (f0_included << 2); - LOGP(DRR, LOGL_ERROR, "Range1024 encoding is not implemented.\n"); - return -1; + write_all_wn(&chan_list[0], 6, w, 16, 10); + return 0; } int range_enc_filter_arfcns(int *arfcns, diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok index dab495d00..3d3c4e6a1 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.ok +++ b/openbsc/tests/gsm0408/gsm0408_test.ok @@ -47,20 +47,15 @@ chan_list = 88 05 08 fc 88 b9 6b 00 00 00 00 00 00 00 00 00 Decoded freqs 6 (expected 6) Decoded: 10 17 31 45 58 79 Range test 6: range 1023, num ARFCNs 17 -Cannot encode range, rc = -1 +chan_list = 84 71 e4 ab b9 58 05 cb 39 17 fd b0 75 62 0f 2f +Decoded freqs 17 (expected 17) +Decoded: 0 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 1023 Range test 7: range 1023, num ARFCNs 16 -Cannot encode range, rc = -1 +chan_list = 80 71 e4 ab b9 58 05 cb 39 17 fd b0 75 62 0f 2f +Decoded freqs 16 (expected 16) +Decoded: 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 1023 Random range test: range 127, max num ARFCNs 29 -Cannot encode range, rc = -1 -Failed on test 0, range 127, num ARFCNs 1 -Cannot encode range, rc = -1 Random range test: range 255, max num ARFCNs 22 -Cannot encode range, rc = -1 -Failed on test 0, range 255, num ARFCNs 1 -Cannot encode range, rc = -1 Random range test: range 511, max num ARFCNs 18 Random range test: range 1023, max num ARFCNs 16 -Cannot encode range, rc = -1 -Failed on test 0, range 1023, num ARFCNs 1 -Cannot encode range, rc = -1 Done.