pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/libosmocore/+/34145 )


Change subject: gsm: Introduce functions to convert between FN and RFN (Reduced 
FN)
......................................................................

gsm: Introduce functions to convert between FN and RFN (Reduced FN)

Implementation ported from osmo-pcu.git
e98b315d12fb009359410809f4169f9380f3d933, function bts_rfn_to_fn().

This functionality can be used by osmo-pcu, libosmo-gprs or any other
related code which needs to handle RFNs.

Change-Id: Ib71e8da976f6cc84c3a4ab17b0a8c2101492e243
---
M include/osmocom/gsm/gsm_utils.h
M src/gsm/gsm_utils.c
M src/gsm/libosmogsm.map
M tests/gsm0408/gsm0408_test.c
4 files changed, 90 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/45/34145/1

diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h
index 721456d..b250c59 100644
--- a/include/osmocom/gsm/gsm_utils.h
+++ b/include/osmocom/gsm/gsm_utils.h
@@ -188,6 +188,14 @@
 char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time 
*tm);
 char *osmo_dump_gsmtime_c(const void *ctx, const struct gsm_time *tm);

+/* Reduced Frame Number (3GPP TS 44.018 ยง10.5.2.38) */
+#define GSM_RFN_MODULUS 42432
+uint32_t gsm_rfn2fn(uint16_t rfn, uint32_t curr_fn);
+static inline uint16_t gsm_fn2rfn(uint32_t fn)
+{
+       return fn % GSM_RFN_MODULUS;
+}
+
 /* GSM TS 03.03 Chapter 2.6 */
 enum gprs_tlli_type {
        TLLI_LOCAL,
diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c
index 06b2406..bb40339 100644
--- a/src/gsm/gsm_utils.c
+++ b/src/gsm/gsm_utils.c
@@ -80,6 +80,7 @@
 #include <osmocom/gsm/gsm_utils.h>
 #include <osmocom/gsm/meas_rep.h>
 #include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm0502.h>

 #include <stdlib.h>
 #include <stdint.h>
@@ -924,6 +925,45 @@
        return osmo_dump_gsmtime_buf(buf, 64, tm);
 }

+#define GSM_RFN_THRESHOLD (GSM_RFN_MODULUS / 2)
+uint32_t gsm_rfn2fn(uint16_t rfn, uint32_t curr_fn)
+{
+       uint32_t curr_rfn;
+       uint32_t fn_rounded;
+       const uint32_t rfn32 = rfn; /* used as 32bit for calculations */
+
+       /* Ensure that all following calculations are performed with the
+        * relative frame number */
+       OSMO_ASSERT(rfn32 < GSM_RFN_MODULUS);
+
+       /* Compute an internal relative frame number from the full internal
+          frame number */
+       curr_rfn = gsm_fn2rfn(curr_fn);
+
+       /* Compute a "rounded" version of the internal frame number, which
+        * exactly fits in the RFN_MODULUS raster */
+       fn_rounded = GSM_TDMA_FN_SUB(curr_fn, curr_rfn);
+
+       /* If the delta between the internal and the external relative frame
+        * number exceeds a certain limit, we need to assume that the incoming
+        * request belongs to a the previous rfn period. To correct this,
+        * we roll back the rounded frame number by one RFN_MODULUS */
+       if (GSM_TDMA_FN_DIFF(rfn32, curr_rfn) > GSM_RFN_THRESHOLD) {
+               /* Race condition between rfn and curr_fn detected:  rfn belongs
+               to the previous RFN_MODULUS cycle, wrapping... */
+               if (fn_rounded < GSM_RFN_MODULUS) {
+                       /* Corner case detected: wrapping crosses GSM_MAX_FN 
border */
+                       fn_rounded = GSM_TDMA_FN_SUB(GSM_MAX_FN, 
(GSM_TDMA_FN_SUB(GSM_RFN_MODULUS, fn_rounded)));
+               } else {
+                       fn_rounded = GSM_TDMA_FN_SUB(fn_rounded, 
GSM_RFN_MODULUS);
+               }
+       }
+
+       /* The real frame number is the sum of the rounded frame number and the
+        * relative framenumber computed via RACH */
+       return GSM_TDMA_FN_SUM(fn_rounded, rfn32);
+}
+
 /*! append range1024 encoded data to bit vector
  *  \param[out] bv Caller-provided output bit-vector
  *  \param[in] r Input Range1024 sructure */
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 951cbcb..49db282 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -544,6 +544,7 @@
 osmo_dump_gsmtime;
 osmo_dump_gsmtime_buf;
 osmo_dump_gsmtime_c;
+gsm_rfn2fn;

 gsm_milenage;
 gsm_septet_encode;
diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c
index f4353e2..5b3f5cd 100644
--- a/tests/gsm0408/gsm0408_test.c
+++ b/tests/gsm0408/gsm0408_test.c
@@ -1946,6 +1946,31 @@
        }
 }

+static void test_gsm_rfn2fn(void)
+{
+       unsigned int i;
+       struct {
+               uint32_t curr_fn;
+               uint16_t rfn;
+               uint32_t exp_fn;
+       } input[] = {
+               { .curr_fn = 0,         .rfn = 0,       .exp_fn = 0 },
+               { .curr_fn = 0,         .rfn = 4,       .exp_fn = 4 },
+               { .curr_fn = 2229729,   .rfn = 23322,   .exp_fn = 2229786 },
+               { .curr_fn = 2229777,   .rfn = 23322,   .exp_fn = 2229786 },
+               { .curr_fn = 1320458,   .rfn = 5070,    .exp_fn = 1320462 },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(input); i++) {
+               uint32_t fn = gsm_rfn2fn(input[i].rfn, input[i].curr_fn);
+               if (fn != input[i].exp_fn) {
+                       printf("Wrong frame number computed! curr_fn=%u, rfn=%u 
==> fn=%u, expected fn=%u\n",
+                              input[i].curr_fn, input[i].rfn, fn, 
input[i].exp_fn);
+                       OSMO_ASSERT(false);
+               }
+       }
+}
+
 int main(int argc, char **argv)
 {
        test_bearer_cap();
@@ -1967,6 +1992,7 @@
        test_power_ctrl();
        test_rach_tx_integer_raw2val();
        test_gsm_gsmtime2fn();
+       test_gsm_rfn2fn();

        return EXIT_SUCCESS;
 }

--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/34145
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ib71e8da976f6cc84c3a4ab17b0a8c2101492e243
Gerrit-Change-Number: 34145
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <[email protected]>
Gerrit-MessageType: newchange

Reply via email to