diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h index 7eda5b9fb..fe5903dbb 100644 --- a/include/osmocom/gsm/gsm_utils.h +++ b/include/osmocom/gsm/gsm_utils.h @@ -161,7 +161,8 @@ static inline int rach_max_trans_raw2val(int raw) { #define ARFCN_UPLINK 0x4000 #define ARFCN_FLAG_MASK 0xf000 /* Reserve the upper 5 bits for flags */ -enum gsm_band gsm_arfcn2band(uint16_t arfcn); +int gsm_arfcn2band_rc(uint16_t arfcn, enum gsm_band *band); +enum gsm_band gsm_arfcn2band(uint16_t arfcn) OSMO_DEPRECATED("Use gsm_arfcn2band_rc() instead"); /* Convert an ARFCN to the frequency in MHz * 10 */ uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink); diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 7e6c7947b..8b4b55866 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -706,36 +706,61 @@ enum gsm_band gsm_band_parse(const char* mhz) } } -/*! Resolve GSM band from ARFCN +/*! Resolve GSM band from ARFCN. * In Osmocom, we use the highest bit of the \a arfcn to indicate PCS * \param[in] arfcn Osmocom ARFCN, highest bit determines PCS mode - * \returns GSM Band */ -enum gsm_band gsm_arfcn2band(uint16_t arfcn) + * \param[out] band GSM Band containing \arfcn if arfcn is valid, undetermined otherwise + * \returns 0 if arfcn is valid and \a band was set, negative on error */ +int gsm_arfcn2band_rc(uint16_t arfcn, enum gsm_band *band) { int is_pcs = arfcn & ARFCN_PCS; arfcn &= ~ARFCN_FLAG_MASK; - if (is_pcs) - return GSM_BAND_1900; - else if (arfcn <= 124) - return GSM_BAND_900; - else if (arfcn >= 955 && arfcn <= 1023) - return GSM_BAND_900; - else if (arfcn >= 128 && arfcn <= 251) - return GSM_BAND_850; - else if (arfcn >= 512 && arfcn <= 885) - return GSM_BAND_1800; - else if (arfcn >= 259 && arfcn <= 293) - return GSM_BAND_450; - else if (arfcn >= 306 && arfcn <= 340) - return GSM_BAND_480; - else if (arfcn >= 350 && arfcn <= 425) - return GSM_BAND_810; - else if (arfcn >= 438 && arfcn <= 511) - return GSM_BAND_750; - else - return GSM_BAND_1800; + if (is_pcs) { + *band = GSM_BAND_1900; + return 0; + } else if (arfcn <= 124) { + *band = GSM_BAND_900; + return 0; + } else if (arfcn >= 955 && arfcn <= 1023) { + *band = GSM_BAND_900; + return 0; + } else if (arfcn >= 128 && arfcn <= 251) { + *band = GSM_BAND_850; + return 0; + } else if (arfcn >= 512 && arfcn <= 885) { + *band = GSM_BAND_1800; + return 0; + } else if (arfcn >= 259 && arfcn <= 293) { + *band = GSM_BAND_450; + return 0; + } else if (arfcn >= 306 && arfcn <= 340) { + *band = GSM_BAND_480; + return 0; + } else if (arfcn >= 350 && arfcn <= 425) { + *band = GSM_BAND_810; + return 0; + } else if (arfcn >= 438 && arfcn <= 511) { + *band = GSM_BAND_750; + return 0; + } + return -1; +} + +/*! Resolve GSM band from ARFCN, aborts process on invalid ARFCN. + * In Osmocom, we use the highest bit of the \a arfcn to indicate PCS. + * DEPRECATED: Use gsm_arfcn2band_rc instead. + * \param[in] arfcn Osmocom ARFCN, highest bit determines PCS mode + * \returns GSM Band if ARFCN is valid (part of any valid band), aborts otherwise */ +enum gsm_band gsm_arfcn2band(uint16_t arfcn) +{ + enum gsm_band band; + if (gsm_arfcn2band_rc(arfcn, &band) == 0) + return band; + + osmo_panic("%s:%d Invalid arfcn %" PRIu16 " passed to gsm_arfcn2band\n", + __FILE__, __LINE__, arfcn); } struct gsm_freq_range { diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 217dcc39d..3fe9dfcfb 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -349,6 +349,7 @@ gsm_7bit_decode_n_hdr; gsm_7bit_encode_n; gsm_7bit_encode_n_ussd; +gsm_arfcn2band_rc; gsm_arfcn2band; gsm_arfcn2freq10; gsm_freq102arfcn; diff --git a/utils/osmo-arfcn.c b/utils/osmo-arfcn.c index 61108f8d7..aee132c7d 100644 --- a/utils/osmo-arfcn.c +++ b/utils/osmo-arfcn.c @@ -62,6 +62,7 @@ static int arfcn2freq(int arfcn) static int freq2arfcn(int freq10, int uplink) { uint16_t arfcn; + enum gsm_band band; if (uplink != 0 && uplink != 1) { fprintf(stderr, "Need to specify uplink or downlink\n"); @@ -75,8 +76,13 @@ static int freq2arfcn(int freq10, int uplink) return -EINVAL; } + if (gsm_arfcn2band_rc(arfcn, &band) < 0) { + fprintf(stderr, "ARFCN contains no valid band\n"); + return -EINVAL; + } + printf("%s: ARFCN %4d\n", - gsm_band_name(gsm_arfcn2band(arfcn)), + gsm_band_name(band), arfcn & ~ARFCN_FLAG_MASK); return 0; }