From 5572031749ffa4cdfa15e9c73b8897e39c3ddb0b Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Tue, 11 Dec 2012 23:44:41 +0100 Subject: gsm: Add method to find ARFCN based on frequency Signed-off-by: Sylvain Munaut --- include/osmocom/gsm/gsm_utils.h | 3 ++ src/gsm/gsm_utils.c | 110 ++++++++++++++++++++++++---------------- src/gsm/libosmogsm.map | 1 + 3 files changed, 69 insertions(+), 45 deletions(-) diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h index 6d316727..17678981 100644 --- a/include/osmocom/gsm/gsm_utils.h +++ b/include/osmocom/gsm/gsm_utils.h @@ -101,6 +101,9 @@ enum gsm_band gsm_arfcn2band(uint16_t arfcn); /* Convert an ARFCN to the frequency in MHz * 10 */ uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink); +/* Convert a Frequency in MHz * 10 to ARFCN */ +uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink); + /* Convert from frame number to GSM time */ void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn); diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 8b1fae08..ecebde80 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -503,59 +503,79 @@ enum gsm_band gsm_arfcn2band(uint16_t arfcn) return GSM_BAND_1800; } +struct gsm_freq_range { + uint16_t arfcn_first; + uint16_t arfcn_last; + uint16_t freq_ul_first; + uint16_t freq_dl_offset; + uint16_t flags; +}; + +static struct gsm_freq_range gsm_ranges[] = { + { 512, 810, 18502, 800, ARFCN_PCS }, /* PCS 1900 */ + { 0, 124, 8900, 450, 0 }, /* P-GSM + E-GSM ARFCN 0 */ + { 955, 1023, 8762, 450, 0 }, /* E-GSM + R-GSM */ + { 128, 251, 8242, 450, 0 }, /* GSM 850 */ + { 512, 885, 17102, 950, 0 }, /* DCS 1800 */ + { 259, 293, 4506, 100, 0 }, /* GSM 450 */ + { 306, 340, 4790, 100, 0 }, /* GSM 480 */ + { 350, 425, 8060, 450, 0 }, /* GSM 810 */ + { 438, 511, 7472, 300, 0 }, /* GSM 750 */ + { /* Guard */ } +}; + /* Convert an ARFCN to the frequency in MHz * 10 */ uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink) { - uint16_t freq10_ul; - uint16_t freq10_dl; - int is_pcs = arfcn & ARFCN_PCS; + struct gsm_freq_range *r; + uint16_t flags = arfcn & ARFCN_FLAG_MASK; + uint16_t freq10_ul = 0xffff; + uint16_t freq10_dl = 0xffff; arfcn &= ~ARFCN_FLAG_MASK; - if (is_pcs) { - /* DCS 1900 */ - arfcn &= ~ARFCN_PCS; - freq10_ul = 18502 + 2 * (arfcn-512); - freq10_dl = freq10_ul + 800; - } else if (arfcn <= 124) { - /* Primary GSM + ARFCN 0 of E-GSM */ - freq10_ul = 8900 + 2 * arfcn; - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 955 && arfcn <= 1023) { - /* E-GSM and R-GSM */ - freq10_ul = 8900 + 2 * (arfcn - 1024); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 128 && arfcn <= 251) { - /* GSM 850 */ - freq10_ul = 8242 + 2 * (arfcn - 128); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 512 && arfcn <= 885) { - /* DCS 1800 */ - freq10_ul = 17102 + 2 * (arfcn - 512); - freq10_dl = freq10_ul + 950; - } else if (arfcn >= 259 && arfcn <= 293) { - /* GSM 450 */ - freq10_ul = 4506 + 2 * (arfcn - 259); - freq10_dl = freq10_ul + 100; - } else if (arfcn >= 306 && arfcn <= 340) { - /* GSM 480 */ - freq10_ul = 4790 + 2 * (arfcn - 306); - freq10_dl = freq10_ul + 100; - } else if (arfcn >= 350 && arfcn <= 425) { - /* GSM 810 */ - freq10_ul = 8060 + 2 * (arfcn - 350); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 438 && arfcn <= 511) { - /* GSM 750 */ - freq10_ul = 7472 + 2 * (arfcn - 438); - freq10_dl = freq10_ul + 300; - } else - return 0xffff; + for (r=gsm_ranges; r->freq_ul_first>0; r++) { + if ((flags == r->flags) && + (arfcn >= r->arfcn_first) && + (arfcn <= r->arfcn_last)) + { + freq10_ul = r->freq_ul_first + 2 * (arfcn - r->arfcn_first); + freq10_dl = freq10_ul + r->freq_dl_offset; + break; + } + } + + return uplink ? freq10_ul : freq10_dl; +} + +/* Convert a Frequency in MHz * 10 to ARFCN */ +uint16_t gsm_freq102arfcn(uint16_t freq10, int uplink) +{ + struct gsm_freq_range *r; + uint16_t freq10_lo, freq10_hi; + uint16_t arfcn = 0xffff; + + for (r=gsm_ranges; r->freq_ul_first>0; r++) { + /* Generate frequency limits */ + freq10_lo = r->freq_ul_first; + freq10_hi = freq10_lo + 2 * (r->arfcn_last - r->arfcn_first); + if (!uplink) { + freq10_lo += r->freq_dl_offset; + freq10_hi += r->freq_dl_offset; + } + + /* Check if this fits */ + if (freq10 >= freq10_lo && freq10 <= freq10_hi) { + arfcn = r->arfcn_first + ((freq10 - freq10_lo) >> 1); + arfcn |= r->flags; + break; + } + } if (uplink) - return freq10_ul; - else - return freq10_dl; + arfcn |= ARFCN_UPLINK; + + return arfcn; } void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn) diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 33738881..b2278f15 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -137,6 +137,7 @@ gsm_7bit_encode; gsm_arfcn2band; gsm_arfcn2freq10; +gsm_freq102arfcn; gsm_band_name; gsm_band_parse; gsm_fn2gsmtime; -- cgit v1.2.3