summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-01-10 17:46:51 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2014-01-16 12:04:30 +0100
commitf8f72e23caae9a1954d86db5242ad764c33e6eff (patch)
tree3e5b7a820bd6ef4e8725418c5b945fd53cb1a4d8
parent45014a0cadfd1f28d68d61b5160ee18fa391c4ba (diff)
si: Add generic range w(k) encoder
Currently the encoding of the chan_list is done by a hard-coded sequence of macros that closely resembles figure 10.5.16 in 3GPP TS 04.08. This patch replaces this by an algorithmic solution that can be used for all range encodings and is based on the property W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present (see section 10.5.2.13 in TS 04.08). Ticket: OW#1061 Sponsored-by: On-Waves ehf
-rw-r--r--openbsc/src/libbsc/arfcn_range_encode.c141
1 files changed, 83 insertions, 58 deletions
diff --git a/openbsc/src/libbsc/arfcn_range_encode.c b/openbsc/src/libbsc/arfcn_range_encode.c
index a047a06ea..1a26523e9 100644
--- a/openbsc/src/libbsc/arfcn_range_encode.c
+++ b/openbsc/src/libbsc/arfcn_range_encode.c
@@ -176,16 +176,6 @@ int range_enc_determine_range(const int *arfcns, const int size, int *f0)
return ARFCN_RANGE_INVALID;
}
-/*
- * The below is easier is to write in four methods than
- * to use the max_bits. The encoding is so screwed.. as
- * the bits need to be put in place in the wrong order..
- */
-#define HIGH_BITS(w, index, bits, offset) \
- (w[index - 1] >> (bits - offset))
-#define LOW_BITS(w, index, bits, offset) \
- (w[index - 1])
-
static void write_orig_arfcn(uint8_t *chan_list, int f0)
{
chan_list[0] |= (f0 >> 9) & 1;
@@ -193,6 +183,88 @@ static void write_orig_arfcn(uint8_t *chan_list, int f0)
chan_list[2] = (f0 & 1) << 7;
}
+static void write_all_wn(uint8_t *chan_list, int bit_offs,
+ int *w, int w_size, int w1_len)
+{
+ int octet_offs = 0; /* offset into chan_list */
+ int wk_len = w1_len; /* encoding size in bits of w[k] */
+ int k; /* 1 based */
+ int level = 0; /* tree level, top level = 0 */
+ int lvl_left = 1; /* nodes per tree level */
+
+ /* W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present */
+
+ for (k = 1; k <= w_size; k++) {
+ int wk_left = wk_len;
+ DEBUGP(DRR,
+ "k=%d, wk_len=%d, offs=%d:%d, level=%d, "
+ "lvl_left=%d\n",
+ k, wk_len, octet_offs, bit_offs, level, lvl_left);
+
+ while (wk_left > 0) {
+ int cur_bits = 8 - bit_offs;
+ int cur_mask;
+ int wk_slice;
+
+ if (cur_bits > wk_left)
+ cur_bits = wk_left;
+
+ cur_mask = ((1 << cur_bits) - 1);
+
+ DEBUGP(DRR,
+ " wk_left=%d, cur_bits=%d, offs=%d:%d\n",
+ wk_left, cur_bits, octet_offs, bit_offs);
+
+ /* advance */
+ wk_left -= cur_bits;
+ bit_offs += cur_bits;
+
+ /* right aligned wk data for current out octet */
+ wk_slice = (w[k-1] >> wk_left) & cur_mask;
+
+ /* cur_bits now contains the number of bits
+ * that are to be copied from wk to the chan_list.
+ * wk_left is set to the number of bits that must
+ * not yet be copied.
+ * bit_offs points after the bit area that is going to
+ * be overwritten:
+ *
+ * wk_left
+ * |
+ * v
+ * wk: WWWWWWWWWWW
+ * |||||<-- wk_slice, cur_bits=5
+ * --WWWWW-
+ * ^
+ * |
+ * bit_offs
+ */
+
+ DEBUGP(DRR,
+ " wk=%02x, slice=%02x/%02x, cl=%02x\n",
+ w[k-1], wk_slice, cur_mask, wk_slice << (8 - bit_offs));
+
+ chan_list[octet_offs] &= ~(cur_mask << (8 - bit_offs));
+ chan_list[octet_offs] |= wk_slice << (8 - bit_offs);
+
+ /* adjust output */
+ if (bit_offs == 8) {
+ bit_offs = 0;
+ octet_offs += 1;
+ }
+ }
+
+ /* adjust bit sizes */
+ lvl_left -= 1;
+ if (!lvl_left) {
+ /* completed tree level, advance to next */
+ level += 1;
+ lvl_left = 1 << level;
+ wk_len -= 1;
+ }
+ }
+}
+
int range_enc_range128(uint8_t *chan_list, int f0, int *w)
{
chan_list[0] = 0x8C;
@@ -213,57 +285,10 @@ int range_enc_range256(uint8_t *chan_list, int f0, int *w)
int range_enc_range512(uint8_t *chan_list, int f0, int *w)
{
- struct gsm48_range_512 *range512;
chan_list[0] = 0x88;
write_orig_arfcn(chan_list, f0);
- range512 = (struct gsm48_range_512 *) &chan_list[0];
-
- /* W(1) */
- range512->w1_hi = HIGH_BITS(w, 1, 9, 7);
- range512->w1_lo = LOW_BITS (w, 1, 9, 2);
- /* W(2) */
- range512->w2_hi = HIGH_BITS(w, 2, 8, 6);
- range512->w2_lo = LOW_BITS (w, 2, 8, 2);
- /* W(3) */
- range512->w3_hi = HIGH_BITS(w, 3, 8, 6);
- range512->w3_lo = LOW_BITS (w, 3, 8, 2);
- /* W(4) */
- range512->w4_hi = HIGH_BITS(w, 4, 7, 6);
- range512->w4_lo = LOW_BITS (w, 4, 7, 1);
- /* W(5) */
- range512->w5 = HIGH_BITS(w, 5, 7, 7);
- /* W(6) */
- range512->w6 = HIGH_BITS(w, 6, 7, 7);
- /* W(7) */
- range512->w7_hi = HIGH_BITS(w, 7, 7, 1);
- range512->w7_lo = LOW_BITS (w, 7, 7, 6);
- /* W(8) */
- range512->w8_hi = HIGH_BITS(w, 8, 6, 2);
- range512->w8_lo = LOW_BITS (w, 8, 6, 4);
- /* W(9) */
- range512->w9_hi = HIGH_BITS(w, 9, 6, 4);
- range512->w9_lo = LOW_BITS(w, 9, 6, 2);
- /* W(10) */
- range512->w10 = HIGH_BITS(w, 10, 6, 6);
- /* W(11) */
- range512->w11 = HIGH_BITS(w, 11, 6, 6);
- /* W(12) */
- range512->w12_hi = HIGH_BITS(w, 12, 6, 2);
- range512->w12_lo = LOW_BITS (w, 12, 6, 4);
- /* W(13) */
- range512->w13_hi = HIGH_BITS(w, 13, 6, 4);
- range512->w13_lo = LOW_BITS(w, 13, 6, 2);
- /* W(14) */
- range512->w14 = HIGH_BITS(w, 14, 6, 6);
- /* W(15) */
- range512->w15 = HIGH_BITS(w, 15, 6, 6);
- /* W(16) */
- range512->w16_hi = HIGH_BITS(w, 16, 5, 2);
- range512->w16_lo = LOW_BITS(w, 16, 5, 3);
- /* W(17) */
- range512->w17 = HIGH_BITS(w, 17, 5, 5);
-
+ write_all_wn(&chan_list[2], 1, w, 17, 9);
return 0;
}