aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-03-14 07:56:05 +0100
committerHarald Welte <laforge@gnumonks.org>2015-09-06 14:47:33 +0200
commit7ece637e5b9547dbddd73e871d05b6d305ea1267 (patch)
tree464ee1d4157519efd07618f3979541ecc72d0056
parentfcb0b32373f7bbad3fb92b70f1467acc5e35cc55 (diff)
TRX: Code cleanup, prepare for other codecs than GSM full rate
-rw-r--r--src/osmo-bts-trx/gsm0503_coding.c49
-rw-r--r--src/osmo-bts-trx/gsm0503_conv.c4
-rw-r--r--src/osmo-bts-trx/gsm0503_interleaving.c3
-rw-r--r--src/osmo-bts-trx/gsm0503_mapping.c49
-rw-r--r--src/osmo-bts-trx/gsm0503_mapping.h4
-rw-r--r--src/osmo-bts-trx/gsm0503_tables.c12
-rw-r--r--src/osmo-bts-trx/l1_if.c12
-rw-r--r--src/osmo-bts-trx/l1_if.h12
-rw-r--r--src/osmo-bts-trx/loops.c6
-rw-r--r--src/osmo-bts-trx/loops.h14
-rw-r--r--src/osmo-bts-trx/scheduler.c277
-rw-r--r--src/osmo-bts-trx/scheduler.h2
12 files changed, 276 insertions, 168 deletions
diff --git a/src/osmo-bts-trx/gsm0503_coding.c b/src/osmo-bts-trx/gsm0503_coding.c
index c7fe28db..5ceb1d58 100644
--- a/src/osmo-bts-trx/gsm0503_coding.c
+++ b/src/osmo-bts-trx/gsm0503_coding.c
@@ -336,8 +336,6 @@ static void tch_fr_reassemble(uint8_t *tch_data, ubit_t *b_bits, int net_order)
i++;
j++;
}
-
- /* rearrange according to Table 2 of TS 05.03 */
}
static void tch_fr_disassemble(ubit_t *b_bits, uint8_t *tch_data, int net_order)
@@ -419,37 +417,38 @@ int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order)
int i, rv, len, steal = 0;
for (i=0; i<8; i++) {
- gsm0503_tch_fr_burst_unmap(&iB[i * 114], &bursts[i * 116], &h,
+ gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], &h,
i>>2);
steal -= h;
}
gsm0503_tch_fr_deinterleave(cB, iB);
- if (steal <= 0) {
- osmo_conv_decode(&gsm0503_conv_tch_fr, cB, conv);
+ if (steal > 0) {
+ rv = _xcch_decode_cB(tch_data, cB);
+ if (rv)
+ return -1;
- tch_fr_unreorder(d, p, conv);
+ return 23;
+ }
- for (i=0; i<78; i++)
- d[i+182] = (cB[i+378] < 0) ? 1:0;
+ osmo_conv_decode(&gsm0503_conv_tch_fr, cB, conv);
- rv = osmo_crc8gen_check_bits(&gsm0503_tch_fr_crc3, d, 50, p);
- if (rv)
- return -1;
+ tch_fr_unreorder(d, p, conv);
- tch_fr_d_to_b(b, d);
+ for (i=0; i<78; i++)
+ d[i+182] = (cB[i+378] < 0) ? 1:0;
- tch_fr_reassemble(tch_data, b, net_order);
+ rv = osmo_crc8gen_check_bits(&gsm0503_tch_fr_crc3, d, 50, p);
+ if (rv)
+ return -1;
- len = 33;
- } else {
- rv = _xcch_decode_cB(tch_data, cB);
- if (rv)
- return -1;
- len = 23;
- }
+ tch_fr_d_to_b(b, d);
+
+ tch_fr_reassemble(tch_data, b, net_order);
+
+ len = 33;
return len;
}
@@ -457,14 +456,14 @@ int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order)
int tch_fr_encode(ubit_t *bursts, uint8_t *tch_data, int len, int net_order)
{
ubit_t iB[912], cB[456], h;
- ubit_t conv[185], b[260], d[260], p[3];
+ ubit_t conv[185], w[260], d[260], p[8];
int i;
switch (len) {
case 33: /* TCH FR */
- tch_fr_disassemble(b, tch_data, net_order);
+ tch_fr_disassemble(w, tch_data, net_order);
- tch_fr_b_to_d(d, b);
+ tch_fr_b_to_d(d, w);
osmo_crc8gen_set_bits(&gsm0503_tch_fr_crc3, d, 50, p);
@@ -490,13 +489,11 @@ int tch_fr_encode(ubit_t *bursts, uint8_t *tch_data, int len, int net_order)
gsm0503_tch_fr_interleave(cB, iB);
for (i=0; i<8; i++)
- gsm0503_tch_fr_burst_map(&iB[i * 114], &bursts[i * 116], &h,
- i>>2);
+ gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116], &h, i>>2);
return 0;
}
-
/*
* GSM RACH transcoding
*/
diff --git a/src/osmo-bts-trx/gsm0503_conv.c b/src/osmo-bts-trx/gsm0503_conv.c
index 79667715..f9fcaa82 100644
--- a/src/osmo-bts-trx/gsm0503_conv.c
+++ b/src/osmo-bts-trx/gsm0503_conv.c
@@ -61,7 +61,7 @@ const struct osmo_conv_code gsm0503_conv_rach = {
.next_output = conv_xcch_next_output,
.next_state = conv_xcch_next_state,
};
-
+
const struct osmo_conv_code gsm0503_conv_sch = {
.N = 2,
@@ -70,7 +70,7 @@ const struct osmo_conv_code gsm0503_conv_sch = {
.next_output = conv_xcch_next_output,
.next_state = conv_xcch_next_state,
};
-
+
const struct osmo_conv_code gsm0503_conv_tch_fr = {
.N = 2,
diff --git a/src/osmo-bts-trx/gsm0503_interleaving.c b/src/osmo-bts-trx/gsm0503_interleaving.c
index f8a63625..7a721b57 100644
--- a/src/osmo-bts-trx/gsm0503_interleaving.c
+++ b/src/osmo-bts-trx/gsm0503_interleaving.c
@@ -3,6 +3,7 @@
#include <osmocom/core/bits.h>
+#include "gsm0503_tables.h"
#include "gsm0503_interleaving.h"
/*
@@ -55,7 +56,7 @@ void gsm0503_xcch_interleave(ubit_t *cB, ubit_t *iB)
* Interleaving:
*
* Given 456 coded input bits, form 8 blocks of 114 bits,
- * where event bits of the first 4 block and off bits of the last 4 block
+ * where even bits of the first 4 blocks and odd bits of the last 4 blocks
* are used:
*
* i(B, j) = c(n, k) k = 0, ..., 455
diff --git a/src/osmo-bts-trx/gsm0503_mapping.c b/src/osmo-bts-trx/gsm0503_mapping.c
index e5ee9206..bdaddcef 100644
--- a/src/osmo-bts-trx/gsm0503_mapping.c
+++ b/src/osmo-bts-trx/gsm0503_mapping.c
@@ -30,36 +30,43 @@ void gsm0503_xcch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *hl,
eB[58] = *hn;
}
-void gsm0503_tch_fr_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *h, int odd)
+void gsm0503_tch_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *h, int odd)
{
int i;
/* brainfuck: only copy even or odd bits */
- for (i=odd; i<57; i+=2)
- iB[i] = eB[i];
- for (i=58-odd; i<114; i+=2)
- iB[i] = eB[i+2];
-
- if (h && !odd)
- *h = eB[58];
-
- if (h && odd)
- *h = eB[57];
+ if (iB) {
+ for (i=odd; i<57; i+=2)
+ iB[i] = eB[i];
+ for (i=58-odd; i<114; i+=2)
+ iB[i] = eB[i+2];
+ }
+
+ if (h) {
+ if (!odd)
+ *h = eB[58];
+ else
+ *h = eB[57];
+ }
}
-void gsm0503_tch_fr_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd)
+void gsm0503_tch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd)
{
int i;
/* brainfuck: only copy even or odd bits */
- for (i=odd; i<57; i+=2)
- eB[i] = iB[i];
- for (i=58-odd; i<114; i+=2)
- eB[i+2] = iB[i];
-
- if (h && !odd)
- eB[58] = *h;
- if (h && odd)
- eB[57] = *h;
+ if (eB) {
+ for (i=odd; i<57; i+=2)
+ eB[i] = iB[i];
+ for (i=58-odd; i<114; i+=2)
+ eB[i+2] = iB[i];
+ }
+
+ if (h) {
+ if (!odd)
+ eB[58] = *h;
+ else
+ eB[57] = *h;
+ }
}
diff --git a/src/osmo-bts-trx/gsm0503_mapping.h b/src/osmo-bts-trx/gsm0503_mapping.h
index 6123266e..a693b354 100644
--- a/src/osmo-bts-trx/gsm0503_mapping.h
+++ b/src/osmo-bts-trx/gsm0503_mapping.h
@@ -4,7 +4,7 @@
void gsm0503_xcch_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *hl, sbit_t *hn);
void gsm0503_xcch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *hl,
const ubit_t *hn);
-void gsm0503_tch_fr_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *h, int odd);
-void gsm0503_tch_fr_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd);
+void gsm0503_tch_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *h, int odd);
+void gsm0503_tch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd);
#endif /* _0503_INTERLEAVING_H */
diff --git a/src/osmo-bts-trx/gsm0503_tables.c b/src/osmo-bts-trx/gsm0503_tables.c
index 0e3e0d05..8ab6060b 100644
--- a/src/osmo-bts-trx/gsm0503_tables.c
+++ b/src/osmo-bts-trx/gsm0503_tables.c
@@ -103,15 +103,9 @@ const uint8_t gsm0503_puncture_cs3[676] = {
/* this corresponds to the bit-lengths of the individual codec
* parameters as indicated in Table 1.1 of TS 06.10 */
const uint8_t gsm0503_gsm_fr_map[76] = {
- 6, 6, 5, 5, 4, 4, 3, 3,
- 7, 2, 2, 6, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 7, 2, 2, 6, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 7, 2, 2, 6, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 7, 2, 2, 6, 3,
- 3, 3, 3, 3, 3, 3, 3, 3,
+ 6, 6, 5, 5, 4, 4, 3, 3, 7, 2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 7, 2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 2, 2, 6, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3
};
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c
index 294d77c5..61c02cd4 100644
--- a/src/osmo-bts-trx/l1_if.c
+++ b/src/osmo-bts-trx/l1_if.c
@@ -471,11 +471,9 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
break;
}
/* activate dedicated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x00, 0, 1);
- trx_sched_set_lchan(l1h, chan_nr, 0x00, 1, 1);
+ trx_sched_set_lchan(l1h, chan_nr, 0x00, 1);
/* activate assoicated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x40, 0, 1);
- trx_sched_set_lchan(l1h, chan_nr, 0x40, 1, 1);
+ trx_sched_set_lchan(l1h, chan_nr, 0x40, 1);
/* set mode */
trx_sched_set_mode(l1h, chan_nr,
lchan->rsl_cmode, lchan->tch_mode);
@@ -498,12 +496,10 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
break;
}
/* deactivate assoicated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x40, 0, 0);
- trx_sched_set_lchan(l1h, chan_nr, 0x40, 1, 0);
+ trx_sched_set_lchan(l1h, chan_nr, 0x40, 0);
/* deactivate dedicated channel */
if (!l1sap->u.info.u.act_req.sacch_only) {
- trx_sched_set_lchan(l1h, chan_nr, 0x00, 0, 0);
- trx_sched_set_lchan(l1h, chan_nr, 0x00, 1, 0);
+ trx_sched_set_lchan(l1h, chan_nr, 0x00, 0);
/* confirm only on dedicated channel */
mph_info_chan_confirm(l1h, chan_nr,
PRIM_INFO_DEACTIVATE, 0);
diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index eea49639..459496f6 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -48,20 +48,28 @@ enum trx_chan_type {
/* States each channel on a multiframe */
struct trx_chan_state {
- uint8_t dl_active; /* Channel is active for TX */
- uint8_t ul_active; /* Channel is active for RX */
+ /* scheduler */
+ uint8_t active; /* Channel is active */
ubit_t *dl_bursts; /* burst buffer for TX */
sbit_t *ul_bursts; /* burst buffer for RX */
uint32_t ul_first_fn; /* fn of first burst */
uint8_t ul_mask; /* mask of received bursts */
+
+ /* loss detection */
uint8_t lost; /* (SACCH) loss detection */
+
+ /* mode */
uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */
+
+ /* encryption */
int ul_encr_algo; /* A5/x encry algo downlink */
int dl_encr_algo; /* A5/x encry algo uplink */
int ul_encr_key_len;
int dl_encr_key_len;
uint8_t ul_encr_key[8];
uint8_t dl_encr_key[8];
+
+ /* measurements */
struct {
uint8_t clock; /* cyclic clock counter */
int8_t rssi[32]; /* last RSSI values */
diff --git a/src/osmo-bts-trx/loops.c b/src/osmo-bts-trx/loops.c
index c8815286..ee12e8bd 100644
--- a/src/osmo-bts-trx/loops.c
+++ b/src/osmo-bts-trx/loops.c
@@ -42,10 +42,6 @@
int trx_ms_power_loop = 0;
int8_t trx_target_rssi = -10;
-/* how much power levels do we raise/lower as maximum (1 level = 2 dB) */
-#define MS_RAISE_MAX 4
-#define MS_LOWER_MAX 4
-
static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan,
uint8_t chan_nr, struct trx_chan_state *chan_state, int8_t diff)
{
@@ -219,7 +215,7 @@ int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr,
return 0;
}
-int trx_loop_input(struct trx_l1h *l1h, uint8_t chan_nr,
+int trx_loop_sacch_input(struct trx_l1h *l1h, uint8_t chan_nr,
struct trx_chan_state *chan_state, int8_t rssi, float toa)
{
struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)]
diff --git a/src/osmo-bts-trx/loops.h b/src/osmo-bts-trx/loops.h
index 5449e41b..8b1d973d 100644
--- a/src/osmo-bts-trx/loops.h
+++ b/src/osmo-bts-trx/loops.h
@@ -1,11 +1,23 @@
#ifndef _TRX_LOOPS_H
#define _TRX_LOOPS_H
+/*
+ * calibration of loops
+ */
+
+/* how much power levels do we raise/lower as maximum (1 level = 2 dB) */
+#define MS_RAISE_MAX 4
+#define MS_LOWER_MAX 1
+
+/*
+ * loops api
+ */
+
extern int trx_ms_power_loop;
extern int8_t trx_target_rssi;
extern int trx_ta_loop;
-int trx_loop_input(struct trx_l1h *l1h, uint8_t chan_nr,
+int trx_loop_sacch_input(struct trx_l1h *l1h, uint8_t chan_nr,
struct trx_chan_state *chan_state, int8_t rssi, float toa);
int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c
index fde14fa8..023be372 100644
--- a/src/osmo-bts-trx/scheduler.c
+++ b/src/osmo-bts-trx/scheduler.c
@@ -71,7 +71,9 @@ typedef int trx_sched_ul_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
-static int rts_tch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan);
+static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
static ubit_t *tx_idle_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
@@ -159,9 +161,9 @@ struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
{ 0, TRXC_BCCH, 0x80, 0x00, "BCCH", rts_data_fn, tx_data_fn, NULL, 1 },
{ 0, TRXC_RACH, 0x88, 0x00, "RACH", NULL, NULL, rx_rach_fn, 1 },
{ 0, TRXC_CCCH, 0x90, 0x00, "CCCH", rts_data_fn, tx_data_fn, NULL, 1 },
- { 0, TRXC_TCHF, 0x08, 0x00, "TCH/F", rts_tch_fn, tx_tchf_fn, rx_tchf_fn, 0 },
- { 0, TRXC_TCHH_0, 0x10, 0x00, "TCH/H(0)", rts_tch_fn, tx_tchh_fn, rx_tchh_fn, 0 },
- { 0, TRXC_TCHH_1, 0x18, 0x00, "TCH/H(1)", rts_tch_fn, tx_tchh_fn, rx_tchh_fn, 0 },
+ { 0, TRXC_TCHF, 0x08, 0x00, "TCH/F", rts_tchf_fn, tx_tchf_fn, rx_tchf_fn, 0 },
+ { 0, TRXC_TCHH_0, 0x10, 0x00, "TCH/H(0)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 },
+ { 0, TRXC_TCHH_1, 0x18, 0x00, "TCH/H(1)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 },
{ 0, TRXC_SDCCH4_0, 0x20, 0x00, "SDCCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 },
{ 0, TRXC_SDCCH4_1, 0x28, 0x00, "SDCCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 },
{ 0, TRXC_SDCCH4_2, 0x30, 0x00, "SDCCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 },
@@ -215,9 +217,7 @@ int trx_sched_init(struct trx_l1h *l1h)
INIT_LLIST_HEAD(&l1h->dl_prims[tn]);
for (i = 0; i < _TRX_CHAN_MAX; i++) {
chan_state = &l1h->chan_states[tn][i];
- chan_state->dl_active = 0;
- chan_state->ul_active = 0;
- chan_state->ul_mask = 0x00;
+ chan_state->active = 0;
}
}
@@ -349,13 +349,13 @@ static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
return l1sap_up(l1h->trx, l1sap);
}
-/* RTS for traffic frame */
-static int rts_tch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan)
+static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan, int facch)
{
uint8_t chan_nr, link_id;
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
+ int rc = 0;
/* get data for RTS indication */
chan_nr = trx_chan_desc[chan].chan_nr | tn;
@@ -371,33 +371,55 @@ static int rts_tch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
"fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name,
chan_nr, fn, tn, l1h->trx->nr);
- /* generate prim */
- msg = l1sap_msgb_alloc(200);
- if (!msg)
- return -ENOMEM;
- l1sap = msgb_l1sap_prim(msg);
- osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS,
- PRIM_OP_INDICATION, msg);
- l1sap->u.data.chan_nr = chan_nr;
- l1sap->u.data.link_id = link_id;
- l1sap->u.data.fn = fn;
+ /* only send, if FACCH is selected */
+ if (facch) {
+ /* generate prim */
+ msg = l1sap_msgb_alloc(200);
+ if (!msg)
+ return -ENOMEM;
+ l1sap = msgb_l1sap_prim(msg);
+ osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS,
+ PRIM_OP_INDICATION, msg);
+ l1sap->u.data.chan_nr = chan_nr;
+ l1sap->u.data.link_id = link_id;
+ l1sap->u.data.fn = fn;
+
+ rc = l1sap_up(l1h->trx, l1sap);
+ }
+
+ /* dont send, if TCH is in signalling only mode */
+ if (l1h->chan_states[tn][chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
+ /* generate prim */
+ msg = l1sap_msgb_alloc(200);
+ if (!msg)
+ return -ENOMEM;
+ l1sap = msgb_l1sap_prim(msg);
+ osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS,
+ PRIM_OP_INDICATION, msg);
+ l1sap->u.tch.chan_nr = chan_nr;
+ l1sap->u.tch.fn = fn;
- /* stop here, if TCH is in signalling only mode */
- if (l1h->chan_states[tn][chan].rsl_cmode == RSL_CMOD_SPD_SIGN)
return l1sap_up(l1h->trx, l1sap);
- l1sap_up(l1h->trx, l1sap);
+ }
- /* generate prim */
- msg = l1sap_msgb_alloc(200);
- if (!msg)
- return -ENOMEM;
- l1sap = msgb_l1sap_prim(msg);
- osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS,
- PRIM_OP_INDICATION, msg);
- l1sap->u.tch.chan_nr = chan_nr;
- l1sap->u.tch.fn = fn;
+ return rc;
+}
- return l1sap_up(l1h->trx, l1sap);
+/* RTS for full rate traffic frame */
+static int rts_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan)
+{
+ /* TCH/F may include FACCH on every 4th burst */
+ return rts_tch_common(l1h, tn, fn, chan, 1);
+}
+
+
+/* RTS for half rate traffic frame */
+static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan)
+{
+ // FIXME
+ return 0;
}
@@ -732,32 +754,38 @@ send_burst:
return bits;
}
-static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid)
+static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch,
+ struct msgb **_msg_facch)
{
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
- ubit_t *burst, **bursts_p = &l1h->chan_states[tn][chan].dl_bursts;
- static ubit_t bits[148];
+ struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ uint8_t rsl_cmode = chan_state->rsl_cmode;
+ uint8_t tch_mode = chan_state->tch_mode;
struct osmo_phsap_prim *l1sap;
- /* send burst, if we already got a frame */
- if (bid > 0) {
- if (!*bursts_p)
- return NULL;
- goto send_burst;
- }
-
/* handle loss detection of received TCH frames */
- if (++(l1h->chan_states[tn][chan].lost) > 5) {
+ if (rsl_cmode == RSL_CMOD_SPD_SPEECH
+ && ++(l1h->chan_states[tn][chan].lost) > 5) {
uint8_t tch_data[33];
+ int len;
LOGP(DL1C, LOGL_NOTICE, "Missing TCH bursts detected, sending "
"BFI for %s\n", trx_chan_desc[chan].name);
/* indicate bad frame */
- memset(tch_data, 0, sizeof(tch_data));
- // FIXME length depends on codec
- compose_tch_ind(l1h, tn, 0, chan, tch_data, 33);
+ switch (tch_mode) {
+ case GSM48_CMODE_SPEECH_V1: /* FR / HR */
+ memset(tch_data, 0, 33);
+ len = 33;
+ break;
+ default:
+ LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please "
+ "fix!\n");
+ len = 0;
+ }
+ if (len)
+ compose_tch_ind(l1h, tn, 0, chan, tch_data, len);
}
/* get frame and unlink from queue */
@@ -797,13 +825,6 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
/* check validity of message */
- if (msg_tch && msgb_l2len(msg_tch) != 33) {
- LOGP(DL1C, LOGL_FATAL, "Prim not 33 bytes, please FIX! "
- "(len=%d)\n", msgb_l2len(msg_tch));
- /* free message */
- msgb_free(msg_tch);
- msg_tch = NULL;
- }
if (msg_facch && msgb_l2len(msg_facch) != 23) {
LOGP(DL1C, LOGL_FATAL, "Prim not 23 bytes, please FIX! "
"(len=%d)\n", msgb_l2len(msg_facch));
@@ -812,6 +833,69 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
msg_facch = NULL;
}
+ /* check validity of message */
+ if (!msg_facch && msg_tch) {
+ int len;
+
+ if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
+ LOGP(DL1C, LOGL_NOTICE, "%s Dropping speech frame, "
+ "because we are not in speech mode trx=%u "
+ "ts=%u at fn=%u.\n", trx_chan_desc[chan].name,
+ l1h->trx->nr, tn, fn);
+ goto free_bad_msg;
+ }
+
+ switch (tch_mode) {
+ case GSM48_CMODE_SPEECH_V1: /* FR / HR */
+ len = 33;
+ if (msgb_l2len(msg_tch) >= 1
+ && (msg_tch->l2h[0] >> 4) != 0xd) {
+ LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad "
+ "FR frame' trx=%u ts=%u at fn=%u.\n",
+ trx_chan_desc[chan].name,
+ l1h->trx->nr, tn, fn);
+ goto free_bad_msg;
+ }
+ break;
+ default:
+ LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please "
+ "fix!\n");
+ goto free_bad_msg;
+ }
+ if (msgb_l2len(msg_tch) != len) {
+ LOGP(DL1C, LOGL_ERROR, "Cannot send payload with "
+ "invalid length! (expecing %d, received %d)\n",
+ len, msgb_l2len(msg_tch));
+free_bad_msg:
+ /* free message */
+ msgb_free(msg_tch);
+ msg_tch = NULL;
+ goto send_frame;
+ }
+ }
+
+send_frame:
+ *_msg_tch = msg_tch;
+ *_msg_facch = msg_facch;
+}
+
+static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan, uint8_t bid)
+{
+ struct msgb *msg_tch = NULL, *msg_facch = NULL;
+ struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
+ static ubit_t bits[148];
+
+ /* send burst, if we already got a frame */
+ if (bid > 0) {
+ if (!*bursts_p)
+ return NULL;
+ goto send_burst;
+ }
+
+ tx_tch_common(l1h, tn, fn, chan, bid, &msg_tch, &msg_facch);
+
/* alloc burst memory, if not already,
* otherwise shift buffer by 4 bursts for interleaving */
if (!*bursts_p) {
@@ -831,14 +915,6 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
goto send_burst;
}
- /* bad frame */
- if (msg_tch && !msg_facch && (msg_tch->l2h[0] >> 4) != 0xd) {
- LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad frame' trx=%u "
- "ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1h->trx->nr, tn, fn);
- goto send_burst;
- }
-
/* encode bursts (priorize FACCH) */
if (msg_facch)
tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch),
@@ -846,7 +922,7 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
else
tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1);
- /* unlink and free message */
+ /* free message */
if (msg_tch)
msgb_free(msg_tch);
if (msg_facch)
@@ -956,7 +1032,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* send burst information to loops process */
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
- trx_loop_input(l1h, trx_chan_desc[chan].chan_nr | tn,
+ trx_loop_sacch_input(l1h, trx_chan_desc[chan].chan_nr | tn,
chan_state, rssi, toa);
}
@@ -1062,7 +1138,9 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
uint8_t *mask = &chan_state->ul_mask;
- uint8_t tch_data[33];
+ uint8_t rsl_cmode = chan_state->rsl_cmode;
+ uint8_t tch_mode = chan_state->tch_mode;
+ uint8_t tch_data[128]; /* just to be safe */
int rc;
LOGP(DL1C, LOGL_DEBUG, "TCH/F received %s fn=%u ts=%u trx=%u bid=%u\n",
@@ -1104,25 +1182,52 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* decode
* also shift buffer by 4 bursts for interleaving */
- rc = tch_fr_decode(tch_data, *bursts_p, 1);
+ switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
+ : tch_mode) {
+ case GSM48_CMODE_SPEECH_V1: /* FR */
+ rc = tch_fr_decode(tch_data, *bursts_p, 1);
+ break;
+ default:
+ LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n",
+ tch_mode);
+ return -EINVAL;
+ }
memcpy(*bursts_p, *bursts_p + 464, 464);
if (rc < 0) {
LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at "
"fn=%u for %s\n", fn, trx_chan_desc[chan].name);
goto bfi;
}
+ if (rc < 4) {
+ LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at "
+ "fn=%u for %s with codec mode %d (out of range)\n",
+ fn, trx_chan_desc[chan].name, rc);
+ goto bfi;
+ }
/* FACCH */
if (rc == 23) {
compose_ph_data_ind(l1h, tn, (fn + 2715648 - 7) % 2715648, chan,
tch_data, 23);
bfi:
- // FIXME length depends on codec
- rc = 33;
- /* indicate bad tch frame */
- memset(tch_data, 0, sizeof(tch_data));
+ if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
+ /* indicate bad frame */
+ switch (tch_mode) {
+ case GSM48_CMODE_SPEECH_V1: /* FR */
+ memset(tch_data, 0, 33);
+ rc = 33;
+ break;
+ default:
+ LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, "
+ "please fix!\n");
+ return -EINVAL;
+ }
+ }
}
+ if (rsl_cmode != RSL_CMOD_SPD_SPEECH)
+ return 0;
+
/* TCH or BFI */
return compose_tch_ind(l1h, tn, (fn + 2715648 - 7) % 2715648, chan,
tch_data, rc);
@@ -1925,7 +2030,7 @@ int trx_sched_set_pchan(struct trx_l1h *l1h, uint8_t tn,
/* setting all logical channels given attributes to active/inactive */
int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
- int downlink, int active)
+ int active)
{
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
int i;
@@ -1942,23 +2047,15 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)
&& trx_chan_desc[i].link_id == link_id) {
chan_state = &l1h->chan_states[tn][i];
- LOGP(DL1C, LOGL_NOTICE, "%s %s %s on trx=%d ts=%d\n",
+ rc = 0;
+ if (chan_state->active == active)
+ continue;
+ LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n",
(active) ? "Activating" : "Deactivating",
- (downlink) ? "downlink" : "uplink",
trx_chan_desc[i].name, l1h->trx->nr, tn);
- if (downlink) {
- chan_state->dl_active = active;
- chan_state->dl_active = active;
- } else {
- chan_state->ul_active = active;
- chan_state->ul_active = active;
- }
- chan_state->lost = 0;
- if (L1SAP_IS_LINK_SACCH(link_id)) {
- memset(&chan_state->meas, 0,
- sizeof(chan_state->meas));
- }
- rc = 0;
+ if (active)
+ memset(chan_state, 0, sizeof(*chan_state));
+ chan_state->active = active;
}
}
@@ -2062,7 +2159,7 @@ static int trx_sched_rts(struct trx_l1h *l1h, uint8_t tn, uint32_t fn)
/* check if channel is active */
if (!trx_chan_desc[chan].auto_active
- && !l1h->chan_states[tn][chan].dl_active)
+ && !l1h->chan_states[tn][chan].active)
return -EINVAL;
return func(l1h, tn, fn, frame->dl_chan);
@@ -2092,7 +2189,7 @@ static const ubit_t *trx_sched_dl_burst(struct trx_l1h *l1h, uint8_t tn,
/* check if channel is active */
if (!trx_chan_desc[chan].auto_active
- && !l1h->chan_states[tn][chan].dl_active)
+ && !l1h->chan_states[tn][chan].active)
goto no_data;
/* get burst from function */
@@ -2159,7 +2256,7 @@ int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn,
/* check if channel is active */
if (!trx_chan_desc[chan].auto_active
- && !l1h->chan_states[tn][chan].ul_active)
+ && !l1h->chan_states[tn][chan].active)
goto next_frame;
/* omit bursts which have no handler, like IDLE bursts */
diff --git a/src/osmo-bts-trx/scheduler.h b/src/osmo-bts-trx/scheduler.h
index ab185f3b..6e7c5293 100644
--- a/src/osmo-bts-trx/scheduler.h
+++ b/src/osmo-bts-trx/scheduler.h
@@ -24,7 +24,7 @@ int trx_sched_set_pchan(struct trx_l1h *l1h, uint8_t tn,
/* setting all logical channels given attributes to active/inactive */
int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
- int downlink, int active);
+ int downlink);
/* setting all logical channels given attributes to active/inactive */
int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode,