Merge commit '816e24cb4296d6b7110da4a89661bbac8dc7af21' into libosmocore
[osmocom-bb.git] / src / shared / libosmocore / src / gsm_utils.c
index b0a66a6..913946e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
  *
  * All Rights Reserved
  *
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
+#include <ctype.h>
 
 #include "../config.h"
 
@@ -192,6 +193,60 @@ uint8_t dbm2rxlev(int dbm)
        return rxlev;
 }
 
+const char *gsm_band_name(enum gsm_band band)
+{
+       switch (band) {
+       case GSM_BAND_450:
+               return "GSM450";
+       case GSM_BAND_480:
+               return "GSM450";
+       case GSM_BAND_750:
+               return "GSM750";
+       case GSM_BAND_810:
+               return "GSM810";
+       case GSM_BAND_850:
+               return "GSM850";
+       case GSM_BAND_900:
+               return "GSM900";
+       case GSM_BAND_1800:
+               return "DCS1800";
+       case GSM_BAND_1900:
+               return "PCS1900";
+       }
+       return "invalid";
+}
+
+enum gsm_band gsm_band_parse(const char* mhz)
+{
+       while (*mhz && !isdigit(*mhz))
+               mhz++;
+
+       if (*mhz == '\0')
+               return -EINVAL;
+
+       switch (strtol(mhz, NULL, 10)) {
+       case 450:
+               return GSM_BAND_450;
+       case 480:
+               return GSM_BAND_480;
+       case 750:
+               return GSM_BAND_750;
+       case 810:
+               return GSM_BAND_810;
+       case 850:
+               return GSM_BAND_850;
+       case 900:
+               return GSM_BAND_900;
+       case 1800:
+               return GSM_BAND_1800;
+       case 1900:
+               return GSM_BAND_1900;
+       default:
+               return -EINVAL;
+       }
+}
+
+
 #ifdef HAVE_EXECINFO_H
 #include <execinfo.h>
 void generate_backtrace()
@@ -213,3 +268,126 @@ void generate_backtrace()
        free(strings);
 }
 #endif
+
+enum gsm_band gsm_arfcn2band(uint16_t arfcn)
+{
+       if (arfcn & ARFCN_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;
+}
+
+/* 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;
+
+       if (arfcn & ARFCN_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;
+
+       if (uplink)
+               return freq10_ul;
+       else
+               return freq10_dl;
+}
+
+void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
+{
+       time->fn = fn;
+       time->t1 = time->fn / (26*51);
+       time->t2 = time->fn % 26;
+       time->t3 = time->fn % 51;
+       time->tc = (time->fn / 51) % 8;
+}
+
+uint32_t gsm_gsmtime2fn(struct gsm_time *time)
+{
+       /* TS 05.02 Chapter 4.3.3 TDMA frame number */
+       return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
+}
+
+/* TS 03.03 Chapter 2.6 */
+int gprs_tlli_type(uint32_t tlli)
+{
+       if ((tlli & 0xc0000000) == 0xc0000000)
+               return TLLI_LOCAL;
+       else if ((tlli & 0xc0000000) == 0x80000000)
+               return TLLI_FOREIGN;
+       else if ((tlli & 0xf8000000) == 0x78000000)
+               return TLLI_RANDOM;
+       else if ((tlli & 0xf8000000) == 0x70000000)
+               return TLLI_AUXILIARY;
+
+       return TLLI_RESERVED;
+}
+
+uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type)
+{
+       uint32_t tlli;
+       switch (type) {
+       case TLLI_LOCAL:
+               tlli = p_tmsi | 0xc0000000;
+               break;
+       case TLLI_FOREIGN:
+               tlli = (p_tmsi & 0x3fffffff) | 0x80000000;
+               break;
+       default:
+               tlli = 0;
+               break;
+       }
+       return tlli;
+}