Merge commit '622b718195d607d7cfc8b9ec96f943ea0ce2d1dd'
authorHarald Welte <laforge@gnumonks.org>
Sun, 7 Mar 2010 16:51:35 +0000 (17:51 +0100)
committerHarald Welte <laforge@gnumonks.org>
Sun, 7 Mar 2010 16:51:35 +0000 (17:51 +0100)
src/shared/libosmocore/include/osmocore/Makefile.am
src/shared/libosmocore/include/osmocore/bitvec.h
src/shared/libosmocore/include/osmocore/gsm_utils.h
src/shared/libosmocore/include/osmocore/gsmtap.h
src/shared/libosmocore/include/osmocore/protocol/gsm_12_21.h
src/shared/libosmocore/include/osmocore/rxlev_stat.h [new file with mode: 0644]
src/shared/libosmocore/src/Makefile.am
src/shared/libosmocore/src/bitvec.c
src/shared/libosmocore/src/gsm_utils.c
src/shared/libosmocore/src/rxlev_stat.c [new file with mode: 0644]

index b45d023..9c4fc75 100644 (file)
@@ -1,6 +1,6 @@
 osmocore_HEADERS = signal.h linuxlist.h timer.h talloc.h msgb.h select.h \
                   tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
-                  gsmtap.h write_queue.h rsl.h gsm48.h
+                  gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h
 
 osmocoredir = $(includedir)/osmocore
 
index 11cb01e..7a26bce 100644 (file)
@@ -40,10 +40,10 @@ struct bitvec {
 };
 
 /* check if the bit is 0 or 1 for a given position inside a bitvec */
-enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr);
+enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr);
 
 /* get the Nth set bit inside the bit vector */
-unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n);
+unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n);
 
 /* Set a bit at given position */
 int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
index b611050..2536045 100644 (file)
 
 #include <stdint.h>
 
+struct gsm_time {
+       uint32_t        fn;     /* FN count */
+       uint16_t        t1;     /* FN div (26*51) */
+       uint8_t         t2;     /* FN modulo 26 */
+       uint8_t         t3;     /* FN modulo 51 */
+       uint8_t         tc;
+};
+
 enum gsm_band {
        GSM_BAND_850    = 1,
        GSM_BAND_900    = 2,
@@ -58,5 +66,19 @@ static inline int rach_max_trans_raw2val(int raw) {
        return tbl[raw & 3];
 }
 
+#define        ARFCN_PCS       0x8000
+#define        ARFCN_UPLINK    0x4000
+
+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 from frame number to GSM time */
+void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn);
+
+/* Convert from GSM time to frame number */
+uint32_t gsm_gsmtime2fn(struct gsm_time *time);
+
 void generate_backtrace();
 #endif
index d6d40ba..dcd64bd 100644 (file)
 #define GSMTAP_CHANNEL_TCH_H   0x0a
 #define GSMTAP_CHANNEL_ACCH    0x80
 
+#define GSMTAP_ARFCN_F_PCS     0x8000
+#define GSMTAP_ARFCN_F_UPLINK  0x4000
+#define GSMTAP_ARFCN_MASK      0x3fff
+
 #define GSMTAP_UDP_PORT                        4729
 
 struct gsmtap_hdr {
index ac6db4b..9cae45d 100644 (file)
@@ -671,7 +671,29 @@ enum ipac_eie {
        NM_IPAC_EIE_CHAN_USE_LIST       = 0x04,
        NM_IPAC_EIE_BCCH_INFO_TYPE      = 0x05,
        NM_IPAC_EIE_BCCH_INFO           = 0x06,
+       NM_IPAC_EIE_CONFIG              = 0x07,
+       NM_IPAC_EIE_RES_DETAILS         = 0x08,
+       NM_IPAC_EIE_RXLEV_THRESH        = 0x09,
+       NM_IPAC_EIE_FREQ_SYNC_OPTS      = 0x0a,
+       NM_IPAC_EIE_MAC_ADDR            = 0x0b,
+       NM_IPAC_EIE_HW_SW_COMPAT_NR     = 0x0c,
+       NM_IPAC_EIE_MANUF_SER_NR        = 0x0d,
+       NM_IPAC_EIE_OEM_ID              = 0x0e,
+       NM_IPAC_EIE_DATE_TIME_MANUF     = 0x0f,
+       NM_IPAC_EIE_DATE_TIME_CALIB     = 0x10,
+       NM_IPAC_EIE_BEACON_INFO         = 0x11,
+       NM_IPAC_EIE_FREQ_ERR            = 0x12,
        /* FIXME */
+       NM_IPAC_EIE_FREQ_BANDS          = 0x1c,
+       NM_IPAC_EIE_MAX_TA              = 0x1d,
+       NM_IPAC_EIE_CIPH_ALGOS          = 0x1e,
+       NM_IPAC_EIE_CHAN_TYPES          = 0x1f,
+       NM_IPAC_EIE_CHAN_MODES          = 0x20,
+       NM_IPAC_EIE_GPRS_CODING         = 0x21,
+       NM_IPAC_EIE_RTP_FEATURES        = 0x22,
+       NM_IPAC_EIE_RSL_FEATURES        = 0x23,
+       NM_IPAC_EIE_BTS_HW_CLASS        = 0x24,
+       NM_IPAC_EIE_BTS_ID              = 0x25,
 };
 
 enum ipac_bcch_info_type {
diff --git a/src/shared/libosmocore/include/osmocore/rxlev_stat.h b/src/shared/libosmocore/include/osmocore/rxlev_stat.h
new file mode 100644 (file)
index 0000000..415509d
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _OSMOCORE_RXLEV_STATS_H
+#define _OSMOCORE_RXLEV_STATS_H
+
+#define NUM_RXLEVS 32
+#define NUM_ARFCNS 1024
+
+struct rxlev_stats {
+       /* the maximum number of ARFCN's is 1024, and there are 32 RxLevels,
+        * so in we keep one 1024bit-bitvec for each RxLev */
+       uint8_t rxlev_buckets[NUM_RXLEVS][NUM_ARFCNS/8];
+};
+
+void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev);
+
+/* get the next ARFCN that has the specified Rxlev */
+int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn);
+
+void rxlev_stat_reset(struct rxlev_stats *st);
+
+void rxlev_stat_dump(const struct rxlev_stats *st);
+
+#endif /* _OSMOCORE_RXLEV_STATS_H */
index b6826ea..9942452 100644 (file)
@@ -9,4 +9,4 @@ lib_LTLIBRARIES = libosmocore.la
 
 libosmocore_la_SOURCES = msgb.c timer.c talloc.c select.c signal.c \
                         tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
-                        write_queue.c utils.c rsl.c gsm48.c
+                        write_queue.c utils.c rsl.c gsm48.c rxlev_stat.c
index 235c3ce..eb83ac6 100644 (file)
@@ -60,7 +60,7 @@ static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
 }
 
 /* check if the bit is 0 or 1 for a given position inside a bitvec */
-enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr)
+enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
 {
        unsigned int bytenum = bytenum_from_bitnum(bitnr);
        unsigned int bitnum = 7 - (bitnr % 8);
@@ -78,7 +78,7 @@ enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr)
 }
 
 /* get the Nth set bit inside the bit vector */
-unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n)
+unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
 {
        unsigned int i, k = 0;
 
index 174b2d4..4ee137c 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
  *
@@ -268,3 +268,94 @@ 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));
+}
diff --git a/src/shared/libosmocore/src/rxlev_stat.c b/src/shared/libosmocore/src/rxlev_stat.c
new file mode 100644 (file)
index 0000000..1bfd679
--- /dev/null
@@ -0,0 +1,94 @@
+/* Rx Level statistics */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <osmocore/bitvec.h>
+#include <osmocore/rxlev_stat.h>
+
+int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val)
+{
+       unsigned int i;
+
+       for (i = n; i < bv->data_len*8; i++) {
+               if (bitvec_get_bit_pos(bv, i) == val)
+                       return i;
+       }
+
+       return -1;
+}
+
+void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev)
+{
+       struct bitvec bv;
+
+       if (rxlev >= NUM_RXLEVS)
+               rxlev = NUM_RXLEVS-1;
+
+       bv.data_len = NUM_ARFCNS/8;
+       bv.data = st->rxlev_buckets[rxlev];
+
+       bitvec_set_bit_pos(&bv, arfcn, ONE);
+}
+
+/* get the next ARFCN that has the specified Rxlev */
+int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn)
+{
+       struct bitvec bv;
+
+       if (rxlev >= NUM_RXLEVS)
+               rxlev = NUM_RXLEVS-1;
+
+       bv.data_len = NUM_ARFCNS/8;
+
+       if (arfcn < 0)
+               arfcn = -1;
+
+       bv.data = st->rxlev_buckets[rxlev];
+
+       return bitvec_find_bit_pos(&bv, arfcn+1, ONE);
+}
+
+void rxlev_stat_reset(struct rxlev_stats *st)
+{
+       memset(st, 0, sizeof(*st));
+}
+
+void rxlev_stat_dump(const struct rxlev_stats *st)
+{
+       int i;
+
+       for (i = NUM_RXLEVS-1; i >= 0; i--) {
+               int16_t arfcn = -1;
+
+               printf("ARFCN with RxLev %u: ", i);
+               while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) {
+                       printf("%u ", arfcn);
+               }
+               printf("\n");
+       }
+}