aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-02-24 11:09:19 +0100
committerHarald Welte <laforge@gnumonks.org>2015-09-06 14:47:32 +0200
commit4353d5aba542e1419989987fd108ddb5a80b87d1 (patch)
tree4da1d6a3abc1232230e2c83f50284328b3b33573
parent16f5eb055620842c7149650b11d44ddb90a7fd91 (diff)
TRX: Implementation of MS power and timing advance loops
-rw-r--r--include/osmo-bts/logging.h1
-rw-r--r--src/common/logging.c6
-rw-r--r--src/osmo-bts-trx/Makefile.am4
-rw-r--r--src/osmo-bts-trx/l1_if.h9
-rw-r--r--src/osmo-bts-trx/loops.c251
-rw-r--r--src/osmo-bts-trx/loops.h14
-rw-r--r--src/osmo-bts-trx/scheduler.c67
-rw-r--r--src/osmo-bts-trx/trx_if.c14
-rw-r--r--src/osmo-bts-trx/trx_vty.c50
9 files changed, 394 insertions, 22 deletions
diff --git a/include/osmo-bts/logging.h b/include/osmo-bts/logging.h
index b7c8a270..b1b44d54 100644
--- a/include/osmo-bts/logging.h
+++ b/include/osmo-bts/logging.h
@@ -17,6 +17,7 @@ enum {
DPCU,
DHO,
DTRX,
+ DLOOP,
DABIS,
DRTP,
DSUM,
diff --git a/src/common/logging.c b/src/common/logging.c
index b117ee04..5ce9b8b6 100644
--- a/src/common/logging.c
+++ b/src/common/logging.c
@@ -113,6 +113,12 @@ static struct log_info_cat bts_log_info_cat[] = {
.color = "\033[1;33m",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
+ [DLOOP] = {
+ .name = "DLOOP",
+ .description = "Control loops",
+ .color = "\033[0;34m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
#if 0
[DNS] = {
.name = "DNS",
diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am
index 28221d15..d9ddca1f 100644
--- a/src/osmo-bts-trx/Makefile.am
+++ b/src/osmo-bts-trx/Makefile.am
@@ -2,10 +2,10 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR)
AM_CFLAGS = -Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS)
LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) -lortp
-EXTRA_DIST = trx_if.h l1_if.h scheduler.h gsm0503_parity.h gsm0503_conv.h gsm0503_interleaving.h gsm0503_mapping.h gsm0503_coding.h gsm0503_tables.h
+EXTRA_DIST = trx_if.h l1_if.h scheduler.h gsm0503_parity.h gsm0503_conv.h gsm0503_interleaving.h gsm0503_mapping.h gsm0503_coding.h gsm0503_tables.h loops.h
bin_PROGRAMS = osmobts-trx
-osmobts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler.c trx_vty.c gsm0503_parity.c gsm0503_conv.c gsm0503_interleaving.c gsm0503_mapping.c gsm0503_coding.c gsm0503_tables.c
+osmobts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler.c trx_vty.c gsm0503_parity.c gsm0503_conv.c gsm0503_interleaving.c gsm0503_mapping.c gsm0503_coding.c gsm0503_tables.c loops.c
osmobts_trx_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index 0f4e8113..eea49639 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -62,6 +62,15 @@ struct trx_chan_state {
int dl_encr_key_len;
uint8_t ul_encr_key[8];
uint8_t dl_encr_key[8];
+ struct {
+ uint8_t clock; /* cyclic clock counter */
+ int8_t rssi[32]; /* last RSSI values */
+ int rssi_count; /* received RSSI values */
+ int rssi_valid_count; /* number of stored value */
+ int rssi_got_burst; /* any burst received so far */
+ float toa_sum; /* sum of TOA values */
+ int toa_num; /* number of TOA value */
+ } meas;
};
struct trx_config {
diff --git a/src/osmo-bts-trx/loops.c b/src/osmo-bts-trx/loops.c
new file mode 100644
index 00000000..c8815286
--- /dev/null
+++ b/src/osmo-bts-trx/loops.c
@@ -0,0 +1,251 @@
+/* Loop control for OsmoBTS-TRX */
+
+/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/l1sap.h>
+#include <osmocom/core/bits.h>
+
+#include "trx_if.h"
+#include "l1_if.h"
+#include "loops.h"
+
+#define MS_PWR_DBM(lvl) ms_pwr_dbm(gsm_arfcn2band(l1h->config.arfcn), lvl)
+
+/*
+ * MS Power loop
+ */
+
+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)
+{
+ int8_t new_power;
+
+ new_power = lchan->ms_power - (diff >> 1);
+
+ if (diff == 0)
+ return 0;
+
+ if (new_power < 0)
+ new_power = 0;
+
+ // FIXME: to go above 1W, we need to know classmark of MS
+ if (l1h->config.arfcn >= 512 && l1h->config.arfcn <= 885) {
+ if (new_power > 15)
+ new_power = 15;
+ } else {
+ if (new_power > 19)
+ new_power = 19;
+ }
+
+ /* a higher value means a lower level (and vice versa) */
+ if (new_power > lchan->ms_power + MS_LOWER_MAX)
+ new_power = lchan->ms_power + MS_LOWER_MAX;
+ else if (new_power < lchan->ms_power - MS_RAISE_MAX)
+ new_power = lchan->ms_power - MS_RAISE_MAX;
+
+ if (lchan->ms_power == new_power) {
+ LOGP(DLOOP, LOGL_INFO, "Keeping MS new_power of trx=%u "
+ "chan_nr=0x%02x at control level %d (%d dBm)\n",
+ l1h->trx->nr, chan_nr, new_power,
+ MS_PWR_DBM(new_power));
+
+ return 0;
+ }
+
+ LOGP(DLOOP, LOGL_INFO, "%s MS new_power of trx=%u chan_nr=0x%02x from "
+ "control level %d (%d dBm) to %d (%d dBm)\n",
+ (diff > 0) ? "Raising" : "Lowering",
+ l1h->trx->nr, chan_nr, lchan->ms_power,
+ MS_PWR_DBM(lchan->ms_power), new_power, MS_PWR_DBM(new_power));
+
+ lchan->ms_power = new_power;
+
+ return 0;
+}
+
+static int ms_power_val(struct trx_l1h *l1h, struct gsm_lchan *lchan,
+ uint8_t chan_nr, struct trx_chan_state *chan_state, int8_t rssi)
+{
+ /* ignore inserted dummy frames, treat as lost frames */
+ if (rssi < -127)
+ return 0;
+
+ LOGP(DLOOP, LOGL_DEBUG, "Got RSSI value of %d\n", rssi);
+
+ chan_state->meas.rssi_count++;
+
+ /* check if the current L1 header compares to the current ordered TA */
+// if ((lchan->meas.l1_info[0] >> 3) != lchan->ms_power)
+// return 0;
+
+ chan_state->meas.rssi_got_burst = 1;
+
+ /* store and process RSSI */
+ if (chan_state->meas.rssi_valid_count
+ == ARRAY_SIZE(chan_state->meas.rssi))
+ return 0;
+ chan_state->meas.rssi[chan_state->meas.rssi_valid_count++] = rssi;
+ chan_state->meas.rssi_valid_count++;
+
+ return 0;
+}
+
+static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan,
+ uint8_t chan_nr, struct trx_chan_state *chan_state)
+{
+ int rssi;
+ int i;
+
+ /* skip every second clock, to prevent oscillating due to roundtrip
+ * delay */
+ if (!(chan_state->meas.clock & 1))
+ return 0;
+
+ LOGP(DLOOP, LOGL_DEBUG, "Got SACCH master clock at RSSI count %d\n",
+ chan_state->meas.rssi_count);
+
+ /* wait for initial burst */
+ if (!chan_state->meas.rssi_got_burst)
+ return 0;
+
+ /* if no burst was received from MS at clock */
+ if (chan_state->meas.rssi_count == 0) {
+ LOGP(DLOOP, LOGL_NOTICE, "LOST SACCH frame of trx=%u "
+ "chan_nr=0x%02x, so we raise MS power\n",
+ l1h->trx->nr, chan_nr);
+ return ms_power_diff(l1h, lchan, chan_nr, chan_state,
+ MS_RAISE_MAX);
+ }
+
+ /* reset total counter */
+ chan_state->meas.rssi_count = 0;
+
+ /* check the minimum level received after MS acknowledged the ordered
+ * power level */
+ if (chan_state->meas.rssi_valid_count == 0)
+ return 0;
+ for (rssi = 999, i = 0; i < chan_state->meas.rssi_valid_count; i++) {
+ if (rssi > chan_state->meas.rssi[i])
+ rssi = chan_state->meas.rssi[i];
+ }
+
+ /* reset valid counter */
+ chan_state->meas.rssi_valid_count = 0;
+
+ /* change RSSI */
+ LOGP(DLOOP, LOGL_DEBUG, "Lowest RSSI: %d Target RSSI: %d Current "
+ "MS power: %d (%d dBm) of trx=%u chan_nr=0x%02x\n", rssi,
+ trx_target_rssi, lchan->ms_power, MS_PWR_DBM(lchan->ms_power),
+ l1h->trx->nr, chan_nr);
+ ms_power_diff(l1h, lchan, chan_nr, chan_state, trx_target_rssi - rssi);
+
+ return 0;
+}
+
+
+/*
+ * Timing Advance loop
+ */
+
+int trx_ta_loop = 1;
+
+int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr,
+ struct trx_chan_state *chan_state, float toa)
+{
+ /* check if the current L1 header acks to the current ordered TA */
+ if (lchan->meas.l1_info[1] != lchan->rqd_ta)
+ return 0;
+
+ /* sum measurement */
+ chan_state->meas.toa_sum += toa;
+ if (++(chan_state->meas.toa_num) < 16)
+ return 0;
+
+ /* complete set */
+ toa = chan_state->meas.toa_sum / chan_state->meas.toa_num;
+
+ /* check for change of TOA */
+ if (toa < -0.9F && lchan->rqd_ta > 0) {
+ LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is too "
+ "early (%.2f), now lowering TA from %d to %d\n",
+ l1h->trx->nr, chan_nr, toa, lchan->rqd_ta,
+ lchan->rqd_ta - 1);
+ lchan->rqd_ta--;
+ } else if (toa > 0.9F && lchan->rqd_ta < 63) {
+ LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is too "
+ "late (%.2f), now raising TA from %d to %d\n",
+ l1h->trx->nr, chan_nr, toa, lchan->rqd_ta,
+ lchan->rqd_ta + 1);
+ lchan->rqd_ta++;
+ } else
+ LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is "
+ "correct (%.2f), keeping current TA of %d\n",
+ l1h->trx->nr, chan_nr, toa, lchan->rqd_ta);
+
+ chan_state->meas.toa_num = 0;
+ chan_state->meas.toa_sum = 0;
+
+ return 0;
+}
+
+int trx_loop_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)]
+ .lchan[l1sap_chan2ss(chan_nr)];
+
+ if (trx_ms_power_loop)
+ ms_power_val(l1h, lchan, chan_nr, chan_state, rssi);
+
+ if (trx_ta_loop)
+ ta_val(l1h, lchan, chan_nr, chan_state, toa);
+
+ return 0;
+}
+
+int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
+ struct trx_chan_state *chan_state)
+{
+ struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)]
+ .lchan[l1sap_chan2ss(chan_nr)];
+
+ if (trx_ms_power_loop)
+ ms_power_clock(l1h, lchan, chan_nr, chan_state);
+
+ /* count the number of SACCH clocks */
+ chan_state->meas.clock++;
+
+ return 0;
+}
+
diff --git a/src/osmo-bts-trx/loops.h b/src/osmo-bts-trx/loops.h
new file mode 100644
index 00000000..5449e41b
--- /dev/null
+++ b/src/osmo-bts-trx/loops.h
@@ -0,0 +1,14 @@
+#ifndef _TRX_LOOPS_H
+#define _TRX_LOOPS_H
+
+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,
+ struct trx_chan_state *chan_state, int8_t rssi, float toa);
+
+int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
+ struct trx_chan_state *chan_state);
+
+#endif /* _TRX_LOOPS_H */
diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c
index 057d5c2e..a0ffe163 100644
--- a/src/osmo-bts-trx/scheduler.c
+++ b/src/osmo-bts-trx/scheduler.c
@@ -38,6 +38,7 @@
#include "scheduler.h"
#include "gsm0503_coding.h"
#include "trx_if.h"
+#include "loops.h"
/* Enable this to multiply TOA of RACH by 10.
* This usefull to check tenth of timing advances with RSSI test tool.
@@ -65,7 +66,8 @@ typedef int trx_sched_rts_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
typedef ubit_t *trx_sched_dl_func(struct trx_l1h *l1h, uint8_t tn,
uint32_t fn, enum trx_chan_type chan, uint8_t bid);
typedef int trx_sched_ul_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa);
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa);
static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
@@ -86,15 +88,20 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa);
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa);
static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa);
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa);
static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa);
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa);
static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa);
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa);
static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa);
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa);
static ubit_t dummy_burst[148] = {
0,0,0,
@@ -324,6 +331,10 @@ static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
"link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name,
chan_nr, link_id, fn, tn, l1h->trx->nr);
+ /* send clock information to loops process */
+ if (L1SAP_IS_LINK_SACCH(link_id))
+ trx_loop_sacch_clock(l1h, chan_nr, &l1h->chan_states[tn][chan]);
+
/* generate prim */
msg = l1sap_msgb_alloc(200);
if (!msg)
@@ -869,7 +880,8 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
*/
static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa)
{
struct osmo_phsap_prim l1sap;
uint8_t ra;
@@ -906,7 +918,8 @@ static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa)
{
struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
@@ -940,6 +953,12 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
memcpy(burst, bits + 3, 58);
memcpy(burst + 58, bits + 87, 58);
+ /* 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,
+ chan_state, rssi, toa);
+ }
+
/* wait until complete set of bursts */
if (bid != 3)
return 0;
@@ -950,6 +969,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
"fn=%u (%u/%u) for %s\n", *first_fn,
(*first_fn) % l1h->mf_period[tn], l1h->mf_period[tn],
trx_chan_desc[chan].name);
+
/* we require first burst to have correct FN */
if (!(*mask & 0x1)) {
*mask = 0x0;
@@ -973,7 +993,8 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa)
{
struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
@@ -1034,7 +1055,8 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa)
{
struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
@@ -1106,7 +1128,8 @@ bfi:
}
static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
+ enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
+ float toa)
{
LOGP(DL1C, LOGL_DEBUG, "TCH/H Received %s fn=%u ts=%u trx=%u bid=%u\n",
trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
@@ -1906,6 +1929,7 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
int i;
int rc = -EINVAL;
+ struct trx_chan_state *chan_state;
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
@@ -1916,18 +1940,23 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
continue;
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",
(active) ? "Activating" : "Deactivating",
(downlink) ? "downlink" : "uplink",
trx_chan_desc[i].name, l1h->trx->nr, tn);
if (downlink) {
- l1h->chan_states[tn][i].dl_active = active;
- l1h->chan_states[tn][i].dl_active = active;
+ chan_state->dl_active = active;
+ chan_state->dl_active = active;
} else {
- l1h->chan_states[tn][i].ul_active = active;
- l1h->chan_states[tn][i].ul_active = active;
+ 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));
}
- l1h->chan_states[tn][i].lost = 0;
rc = 0;
}
}
@@ -2154,12 +2183,12 @@ int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn,
}
}
- func(l1h, tn, fn, chan, bid, bits, toa);
- } else {
+ func(l1h, tn, fn, chan, bid, bits, rssi, toa);
+ } else if (chan != TRXC_RACH) {
sbit_t spare[148];
memset(spare, 0, 148);
- func(l1h, tn, fn, chan, bid, spare, toa);
+ func(l1h, tn, fn, chan, bid, spare, -128, 0);
}
next_frame:
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index 6420fdb4..bca9cdca 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -41,6 +41,9 @@
#include "trx_if.h"
#include "scheduler.h"
+/* enable to print RSSI level graph */
+//#define TOA_RSSI_DEBUG
+
int tranceiver_available = 0;
const char *tranceiver_ip = "127.0.0.1";
@@ -384,7 +387,7 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
}
tn = buf[0];
fn = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
- rssi = (int8_t)buf[5];
+ rssi = -(int8_t)buf[5];
toa = ((int16_t)(buf[6] << 8) | buf[7]) / 256.0F;
/* copy and convert bits {254..0} to sbits {-127..127} */
@@ -407,6 +410,15 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
LOGP(DTRX, LOGL_DEBUG, "RX burst tn=%u fn=%u rssi=%d toa=%.2f\n",
tn, fn, rssi, toa);
+#ifdef TOA_RSSI_DEBUG
+ char deb[128];
+
+ sprintf(deb, "| 0 "
+ " | rssi=%4d toa=%4.2f fn=%u", rssi, toa, fn);
+ deb[1 + (128 + rssi) / 4] = '*';
+ fprintf(stderr, "%s\n", deb);
+#endif
+
trx_sched_ul_burst(l1h, tn, fn, bits, rssi, toa);
return 0;
diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c
index 720f3538..fa08df4d 100644
--- a/src/osmo-bts-trx/trx_vty.c
+++ b/src/osmo-bts-trx/trx_vty.c
@@ -43,6 +43,7 @@
#include "l1_if.h"
#include "scheduler.h"
#include "trx_if.h"
+#include "loops.h"
static struct gsm_bts *vty_bts;
@@ -126,6 +127,43 @@ DEFUN(cfg_bts_fn_advance, cfg_bts_fn_advance_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_ms_power_loop, cfg_bts_ms_power_loop_cmd,
+ "ms-power-loop <-127-127>",
+ "Enable MS power control loop\nTarget RSSI value (tranceiver specific, "
+ "should be 6dB or more above noise floor)\n")
+{
+ trx_ms_power_loop = 1;
+ trx_target_rssi = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_ms_power_loop, cfg_bts_no_ms_power_loop_cmd,
+ "no ms-power-loop",
+ NO_STR "Disable MS power control loop\n")
+{
+ trx_ms_power_loop = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_timing_advance_loop, cfg_bts_timing_advance_loop_cmd,
+ "timing-advance-loop",
+ "Enable timing advance control loop\n")
+{
+ trx_ta_loop = 1;
+
+ return CMD_SUCCESS;
+}
+DEFUN(cfg_bts_no_timing_advance_loop, cfg_bts_no_timing_advance_loop_cmd,
+ "no timing-advance-loop",
+ NO_STR "Disable timing advance control loop\n")
+{
+ trx_ta_loop = 0;
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_trx_rxgain, cfg_trx_rxgain_cmd,
"rxgain <0-50>",
"Set the receiver gain in dB\n"
@@ -236,6 +274,14 @@ DEFUN(cfg_trx_no_maxdly, cfg_trx_no_maxdly_cmd,
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
vty_out(vty, " fn-advance %d%s", trx_clock_advance, VTY_NEWLINE);
+
+ if (trx_ms_power_loop)
+ vty_out(vty, " ms-power-loop %d%s", trx_target_rssi,
+ VTY_NEWLINE);
+ else
+ vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE);
+ vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ",
+ VTY_NEWLINE);
}
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
@@ -268,6 +314,10 @@ int bts_model_vty_init(struct gsm_bts *bts)
install_element_ve(&show_tranceiver_cmd);
install_element(BTS_NODE, &cfg_bts_fn_advance_cmd);
+ install_element(BTS_NODE, &cfg_bts_ms_power_loop_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_ms_power_loop_cmd);
+ install_element(BTS_NODE, &cfg_bts_timing_advance_loop_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_timing_advance_loop_cmd);
install_element(TRX_NODE, &cfg_trx_rxgain_cmd);
install_element(TRX_NODE, &cfg_trx_power_cmd);