aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsm
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2019-10-09 13:38:38 +0200
committerlaforge <laforge@osmocom.org>2019-10-28 19:43:14 +0000
commit69e00ccd6ff3a19b771070b78ed3d85dd219799f (patch)
treebf4914255ba3a4491423bd7e06f8f4efda1953ef /src/gsm
parenta0c8195ad37292ab800a6c777fc28383995b4b64 (diff)
gsm0508: add functions to calculate beginning of a block
The calculation of the beginning of a block for TCH/F, TCH/H and FACCH can be challenging since those channels are affected by the diagonal interleaving of the TCH channels. However, GSM 05.02 Section 7 Table 1 of 5 specifies how the blocks are distributed over the TDMA frame interval. Lets add a mapping function that is based on that table Related: OS#3803 Change-Id: I3d71c66f8c401f5afbad9b1c86c24580dab9e0ce
Diffstat (limited to 'src/gsm')
-rw-r--r--src/gsm/gsm0502.c157
-rw-r--r--src/gsm/libosmogsm.map1
2 files changed, 158 insertions, 0 deletions
diff --git a/src/gsm/gsm0502.c b/src/gsm/gsm0502.c
index 53259a42..1a71e617 100644
--- a/src/gsm/gsm0502.c
+++ b/src/gsm/gsm0502.c
@@ -27,6 +27,9 @@
#include <osmocom/gsm/gsm0502.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/logging.h>
+#include <inttypes.h>
unsigned int
gsm0502_calc_paging_group(struct gsm48_control_channel_descr *chan_desc, uint64_t imsi)
@@ -44,3 +47,157 @@ gsm0502_calc_paging_group(struct gsm48_control_channel_descr *chan_desc, uint64_
return group;
}
+
+/* Clause 7 Table 1 of 5 Mapping of logical channels onto physical channels */
+#define TCH_REPEAT_LENGTH 13
+#define FACCH_F_REPEAT_LENGTH 13
+#define FACCH_H_REPEAT_LENGTH 26
+
+static const uint8_t gsm0502_tch_f_traffic_block_map[3][8] = {
+ {0, 1, 2, 3, 4, 5, 6, 7},
+ {4, 5, 6, 7, 8, 9, 10, 11},
+ {8, 9, 10, 11, 0, 1, 2, 3}
+};
+
+static const uint8_t gsm0502_tch_h0_traffic_block_map[3][4] = {
+ {0, 2, 4, 6},
+ {4, 6, 8, 10},
+ {8, 10, 0, 2}
+};
+
+static const uint8_t gsm0502_tch_h1_traffic_block_map[3][4] = {
+ {1, 3, 5, 7},
+ {5, 7, 9, 11},
+ {9, 11, 1, 3}
+};
+
+static const uint8_t gsm0502_tch_f_facch_block_map[3][8] = {
+ {0, 1, 2, 3, 4, 5, 6, 7},
+ {4, 5, 6, 7, 8, 9, 10, 11},
+ {8, 9, 10, 11, 0, 1, 2, 3}
+};
+
+static const uint8_t gsm0502_tch_h0_facch_block_map[3][6] = {
+ {0, 2, 4, 6, 8, 10},
+ {8, 10, 13, 15, 17, 19},
+ {17, 19, 21, 23, 0, 2}
+};
+
+static const uint8_t gsm0502_tch_h1_facch_block_map[3][6] = {
+ {1, 3, 5, 7, 9, 11},
+ {9, 11, 14, 16, 18, 20},
+ {18, 20, 22, 24, 1, 3}
+};
+
+/* Struct to describe a remapping function for block frame nbumbers. The member
+ * blockend describes the ending of a block for which we want to determine the
+ * beginning frame number. The member distance describes the value we need to
+ * subtract from the blockend frame number in order to get the beginning of the
+ * the block. The member cycle describes the Repeat length in TDMA frames we
+ * are dealing with. For traffic channels this is always 13, for control
+ * channels it is different. The member len simply defines amount of
+ * blockendings and distances we store in the remap table */
+struct fn_remap_table {
+ unsigned int cycle;
+ unsigned int len;
+ uint8_t blockend[8];
+ uint8_t distance[8];
+};
+
+/* Memory to hold the remap tables we will automatically generate on startup */
+static struct fn_remap_table tch_f_remap_table;
+static struct fn_remap_table tch_h0_remap_table;
+static struct fn_remap_table tch_h1_remap_table;
+static struct fn_remap_table facch_f_remap_table;
+static struct fn_remap_table facch_h0_remap_table;
+static struct fn_remap_table facch_h1_remap_table;
+static struct fn_remap_table *fn_remap_table_ptr[FN_REMAP_MAX];
+
+/* Generate a remap table from a given block map. A block map lists the block
+ * layout as defined in GSM 05.02, Clause 7 Table 1 of 5, one block per row.
+ * Parameters:
+ * table: name of the remap table to output
+ * map: traffic block map input
+ * rows: length of the traffic block map
+ * cols: witdh of the traffic block map
+ * repeat: repeat length in TDMA frames (cycle) */
+#define fn_remap_table_from_traffic_block_map(table, map, rows, cols, repeat) \
+ for(i=0;i<rows;i++) { \
+ table.blockend[i] = map[i][cols-1]; \
+ if(map[i][0] <= map[i][cols-1]) \
+ table.distance[i] = map[i][cols-1] - map[i][0]; \
+ else \
+ table.distance[i] = repeat - map[i][0] + map[i][cols-1]; \
+ } \
+ table.cycle = repeat; \
+ table.len = rows;
+
+/* Automatically generate fn remap tables on startupmake */
+static __attribute__ ((constructor))
+void fn_remap_tables_build(void)
+{
+ /* Required by macro */
+ unsigned int i;
+
+ /* Generate tables */
+ fn_remap_table_from_traffic_block_map(tch_f_remap_table,
+ gsm0502_tch_f_traffic_block_map, 3, 8,
+ TCH_REPEAT_LENGTH);
+ fn_remap_table_from_traffic_block_map(tch_h0_remap_table,
+ gsm0502_tch_h0_traffic_block_map, 3, 4,
+ TCH_REPEAT_LENGTH);
+ fn_remap_table_from_traffic_block_map(tch_h1_remap_table,
+ gsm0502_tch_h1_traffic_block_map, 3, 4,
+ TCH_REPEAT_LENGTH);
+ fn_remap_table_from_traffic_block_map(facch_f_remap_table,
+ gsm0502_tch_f_facch_block_map, 3, 8,
+ FACCH_F_REPEAT_LENGTH);
+ fn_remap_table_from_traffic_block_map(facch_h0_remap_table,
+ gsm0502_tch_h0_facch_block_map, 3, 6,
+ FACCH_H_REPEAT_LENGTH);
+ fn_remap_table_from_traffic_block_map(facch_h1_remap_table,
+ gsm0502_tch_h1_facch_block_map, 3, 6,
+ FACCH_H_REPEAT_LENGTH);
+
+ fn_remap_table_ptr[FN_REMAP_TCH_F] = &tch_f_remap_table;
+ fn_remap_table_ptr[FN_REMAP_TCH_H0] = &tch_h0_remap_table;
+ fn_remap_table_ptr[FN_REMAP_TCH_H1] = &tch_h1_remap_table;
+ fn_remap_table_ptr[FN_REMAP_FACCH_F] = &facch_f_remap_table;
+ fn_remap_table_ptr[FN_REMAP_FACCH_H0] = &facch_h0_remap_table;
+ fn_remap_table_ptr[FN_REMAP_FACCH_H1] = &facch_h1_remap_table;
+}
+
+/*! Calculate the frame number of the beginning of a block.
+ * \param[in] fn frame number of the block ending.
+ * \param[in] channel channel type (see also enum fn_remap_channel).
+ * \returns frame number of the beginning of the block or input frame number if
+ * remapping was not possible. */
+uint32_t gsm0502_fn_remap(uint32_t fn, enum gsm0502_fn_remap_channel channel)
+{
+ uint8_t fn_cycle;
+ uint8_t i;
+ int sub = -1;
+ uint32_t fn_map;
+ struct fn_remap_table *table;
+
+ OSMO_ASSERT(channel < ARRAY_SIZE(fn_remap_table_ptr));
+ table = fn_remap_table_ptr[(uint8_t)channel];
+
+ fn_cycle = fn % table->cycle;
+
+ for (i = 0; i < table->len; i++) {
+ if (table->blockend[i] == fn_cycle) {
+ sub = table->distance[i];
+ break;
+ }
+ }
+
+ if (sub == -1) {
+ LOGP(DLGLOBAL, LOGL_ERROR, "could not remap frame number!, fn=%"PRIu32"\n", fn);
+ return fn;
+ }
+
+ fn_map = (fn + GSM_MAX_FN - sub) % GSM_MAX_FN;
+
+ return fn_map;
+}
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index ea1f759d..724fe5b1 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -107,6 +107,7 @@ gsm0480_gen_return_error;
gsm0480_gen_reject;
gsm0502_calc_paging_group;
+gsm0502_fn_remap;
gsm0503_xcch;
gsm0503_rach;