diff options
Diffstat (limited to 'openbsc/src/libbsc/system_information.c')
-rw-r--r-- | openbsc/src/libbsc/system_information.c | 136 |
1 files changed, 111 insertions, 25 deletions
diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index f48e586e9..c005b3c9a 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -2,6 +2,7 @@ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ /* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> + * (C) 2012 Holger Hans Peter Freyther * * All Rights Reserved * @@ -34,6 +35,7 @@ #include <openbsc/gsm_data.h> #include <openbsc/abis_rsl.h> #include <openbsc/rest_octets.h> +#include <openbsc/arfcn_range_encode.h> /* Frequency Lists as per TS 04.08 10.5.2.13 */ @@ -88,11 +90,105 @@ static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn) return 0; } +/* generate a variable bitmap */ +static int enc_freq_lst_var_bitmap(uint8_t *chan_list, + struct bitvec *bv, const struct gsm_bts *bts, + int bis, int ter, int min, int pgsm) +{ + int i; + + /* set it to 'Variable bitmap format' */ + chan_list[0] = 0x8e; + + chan_list[0] |= (min >> 9) & 1; + chan_list[1] = (min >> 1); + chan_list[2] = (min & 1) << 7; + + for (i = 0; i < bv->data_len*8; i++) { + /* see notes in bitvec2freq_list */ + if (bitvec_get_bit_pos(bv, i) + && ((!bis && !ter && gsm_arfcn2band(i) == bts->band) + || (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124)) + || (ter && gsm_arfcn2band(i) != bts->band))) { + int rc = freq_list_bmrel_set_arfcn(chan_list, i); + if (rc < 0) + return rc; + } + } + + return 0; +} + +/* generate a frequency list with the range 512 format */ +static int enc_freq_lst_range(uint8_t *chan_list, + struct bitvec *bv, const struct gsm_bts *bts, + int bis, int ter, int pgsm) +{ + int arfcns[RANGE_ENC_MAX_ARFCNS]; + int w[RANGE_ENC_MAX_ARFCNS]; + int f0_included = 0; + int arfcns_used = 0; + int i, rc, range, f0; + + /* + * Select ARFCNs according to the rules in bitvec2freq_list + */ + for (i = 0; i < bv->data_len * 8; ++i) { + /* More ARFCNs than the maximum */ + if (arfcns_used > ARRAY_SIZE(arfcns)) + return -1; + /* Check if we can select it? */ + if (bitvec_get_bit_pos(bv, i) + && ((!bis && !ter && gsm_arfcn2band(i) == bts->band) + || (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124)) + || (ter && gsm_arfcn2band(i) != bts->band))) { + arfcns[arfcns_used++] = i; + } + } + + /* + * Check if the given list of ARFCNs can be encoded. + */ + range = range_enc_determine_range(arfcns, arfcns_used, &f0); + if (range == ARFCN_RANGE_INVALID) + return -2; + + /* + * 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) + return -3; + + /* Select the range and the amount of bits needed */ + switch (range) { + case ARFCN_RANGE_128: + return range_enc_range128(chan_list, f0, w); + break; + case ARFCN_RANGE_256: + return range_enc_range256(chan_list, f0, w); + break; + case ARFCN_RANGE_512: + return range_enc_range512(chan_list, f0, w); + break; + case ARFCN_RANGE_1024: + return range_enc_range1024(chan_list, f0, f0_included, w); + break; + default: + return -4; + }; +} + /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, const struct gsm_bts *bts, int bis, int ter) { - int i, rc, min = -1, max = -1, pgsm = 0; + int i, rc, min = -1, max = -1, pgsm = 0, arfcns = 0; memset(chan_list, 0, 16); @@ -114,9 +210,6 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, return 0; } - /* We currently only support the 'Variable bitmap format' */ - chan_list[0] = 0x8e; - for (i = 0; i < bv->data_len*8; i++) { /* in case of SI2 or SI5 allow all neighbours in same band * in case of SI*bis, allow neighbours in same band ouside pgsm @@ -126,6 +219,9 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, && ((!bis && !ter && gsm_arfcn2band(i) == bts->band) || (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124)) || (ter && gsm_arfcn2band(i) != bts->band))) { + /* count the arfcns we want to carry */ + arfcns += 1; + /* 955..1023 < 0..885 */ if (min < 0) min = i; @@ -152,29 +248,19 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, return 0; } - if (((max - min) & 1023) > 111) { - LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, " - "distance > 111\n", min, max); - return -EINVAL; - } - - chan_list[0] |= (min >> 9) & 1; - chan_list[1] = (min >> 1); - chan_list[2] = (min & 1) << 7; + /* Now find the best encoding */ + if (((max - min) & 1023) <= 111) + return enc_freq_lst_var_bitmap(chan_list, bv, bts, bis, + ter, min, pgsm); - for (i = 0; i < bv->data_len*8; i++) { - /* see notes above */ - if (bitvec_get_bit_pos(bv, i) - && ((!bis && !ter && gsm_arfcn2band(i) == bts->band) - || (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124)) - || (ter && gsm_arfcn2band(i) != bts->band))) { - rc = freq_list_bmrel_set_arfcn(chan_list, i); - if (rc < 0) - return rc; - } - } + /* Attempt to do the range encoding */ + rc = enc_freq_lst_range(chan_list, bv, bts, bis, ter, pgsm); + if (rc == 0) + return 0; - return 0; + LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, arfcns=%d " + "can not generate ARFCN list", min, max, arfcns); + return -EINVAL; } /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ |