aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmo-bts/bts.h2
-rw-r--r--include/osmo-bts/gsm_data_shared.h8
-rw-r--r--src/common/bts.c5
-rw-r--r--src/common/l1sap.c29
-rw-r--r--src/common/vty.c2
5 files changed, 46 insertions, 0 deletions
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index 970fb1b..4d13214 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -65,5 +65,7 @@ int bts_main(int argc, char **argv);
int bts_supports_cm(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
enum gsm48_chan_mode cm);
+int32_t bts_get_avg_fn_advance(struct gsm_bts *bts);
+
#endif /* _BTS_H */
diff --git a/include/osmo-bts/gsm_data_shared.h b/include/osmo-bts/gsm_data_shared.h
index 90772e2..f972a67 100644
--- a/include/osmo-bts/gsm_data_shared.h
+++ b/include/osmo-bts/gsm_data_shared.h
@@ -738,6 +738,14 @@ struct gsm_bts {
uint8_t tc4_ctr;
} si;
struct gsm_time gsm_time;
+ /* frame number statistics (FN in PH-RTS.ind vs. PH-DATA.ind */
+ struct {
+ int32_t min; /* minimum observed */
+ int32_t max; /* maximum observed */
+ int32_t avg256; /* accumulator */
+ uint32_t avg_count; /* number of samples accumulated in avg256 */
+ uint32_t avg_window; /* number of averages in avg_count */
+ } fn_stats;
/* Radio Link Timeout counter. -1 disables timeout for
* lab/measurement purpose */
int radio_link_timeout;
diff --git a/src/common/bts.c b/src/common/bts.c
index 596e5e0..c57d9f4 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -223,6 +223,11 @@ int bts_init(struct gsm_bts *bts)
rc = osmo_fsm_register(&dtx_dl_amr_fsm);
OSMO_ASSERT(rc == 0);
+ bts->fn_stats.min = INT32_MAX;
+ bts->fn_stats.max = INT32_MIN;
+ bts->fn_stats.avg_count = 0;
+ bts->fn_stats.avg_window = 256;
+
return rc;
}
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index 59d5b93..b730b85 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -719,6 +719,33 @@ int is_ccch_for_agch(struct gsm_bts_trx *trx, uint32_t fn) {
return l1sap_fn2ccch_block(fn) < num_agch(trx, "PH-RTS-IND");
}
+/* return the measured average of frame numbers that the RTS clock is running in advance */
+int32_t bts_get_avg_fn_advance(struct gsm_bts *bts)
+{
+ if (bts->fn_stats.avg_count == 0)
+ return 0;
+ return bts->fn_stats.avg256 / bts->fn_stats.avg_count;
+}
+
+static void l1sap_update_fnstats(struct gsm_bts *bts, uint32_t rts_fn)
+{
+ int32_t delta = (rts_fn + GSM_HYPERFRAME - bts->gsm_time.fn) % GSM_HYPERFRAME;
+
+ if (delta < bts->fn_stats.min)
+ bts->fn_stats.min = delta;
+ if (delta > bts->fn_stats.max)
+ bts->fn_stats.max = delta;
+
+ if (bts->fn_stats.avg_count > bts->fn_stats.avg_window) {
+ /* reset and start old average and new sample */
+ bts->fn_stats.avg256 = (bts->fn_stats.avg256 / bts->fn_stats.avg_count) + delta;
+ bts->fn_stats.avg_count = 2;
+ } else {
+ bts->fn_stats.avg256 += delta;
+ bts->fn_stats.avg_count++;
+ }
+}
+
/* PH-RTS-IND prim received from bts model */
static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind)
@@ -745,6 +772,8 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
DEBUGPGT(DL1P, &g_time, "Rx PH-RTS.ind chan_nr=%s link_id=0x%02xd\n", rsl_chan_nr_str(chan_nr), link_id);
+ l1sap_update_fnstats(trx->bts, fn);
+
/* reuse PH-RTS.ind for PH-DATA.req */
if (!msg) {
LOGPGT(DL1P, LOGL_FATAL, &g_time, "RTS without msg to be reused. Please fix!\n");
diff --git a/src/common/vty.c b/src/common/vty.c
index 1d25bfb..f4fc181 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -895,6 +895,8 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, " OML Link state: %s.%s",
bts->oml_link ? "connected" : "disconnected", VTY_NEWLINE);
+ vty_out(vty, " PH-RTS.ind FN advance average: %d, min: %d, max: %d%s",
+ bts_get_avg_fn_advance(bts), bts->fn_stats.min, bts->fn_stats.max, VTY_NEWLINE);
llist_for_each_entry(trx, &bts->trx_list, list) {
struct phy_instance *pinst = trx_phy_instance(trx);