summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-04-24 10:45:17 +0200
committerHarald Welte <laforge@gnumonks.org>2017-07-12 23:26:26 +0200
commit203f7e0c7fc9c40cb85ce4370f0e8fbd62888c04 (patch)
treef1404c812b3c8f924c24fa659ad0f3b3abf4a466
parent59cc3c3ab1efcaa8f44a3b76bd9b036018fea074 (diff)
VIRT-PHY: Configurable signal power reductions for multiple arfcns.
Model was expanded and holds now power management information consisting of an array of received power levels for all arfcns and one for the reduction of this signal in dbm. The reduction is configurable by commandline by --arfcn-sig-lev-red 666,12:888,13. The signal level is assumed to be max level (-63) if a packet from that arfcn is received within a timeframe (also configurable via cmd -- timeout-pm 5:800 == <seconds>:<microseconds>). After that timeout it will be reduced to min level (-110). Change-Id: I369ca26703f14bba4e9334b8f417deef640462f9
-rw-r--r--src/host/virt_phy/include/virtphy/l1ctl_sap.h8
-rw-r--r--src/host/virt_phy/include/virtphy/virt_l1_model.h12
-rw-r--r--src/host/virt_phy/src/gsmtapl1_if.c16
-rw-r--r--src/host/virt_phy/src/l1ctl_sap.c1
-rw-r--r--src/host/virt_phy/src/virt_l1_model.c1
-rw-r--r--src/host/virt_phy/src/virt_prim_fbsb.c2
-rw-r--r--src/host/virt_phy/src/virt_prim_pm.c53
-rw-r--r--src/host/virt_phy/src/virtphy.c58
8 files changed, 126 insertions, 25 deletions
diff --git a/src/host/virt_phy/include/virtphy/l1ctl_sap.h b/src/host/virt_phy/include/virtphy/l1ctl_sap.h
index a1261287..b84c3e9e 100644
--- a/src/host/virt_phy/include/virtphy/l1ctl_sap.h
+++ b/src/host/virt_phy/include/virtphy/l1ctl_sap.h
@@ -18,6 +18,14 @@
#define LID_SACCH 0x40
#define LID_DEDIC 0x00
+/* signature strengths for the ms */
+#define MIN_SIG_LEV_DBM -110
+#define MAX_SIG_LEV_DBM -63
+
+/* Ignore all flags of the arfcn */
+#define ARFCN_NO_FLAGS_MASK 0x0fff
+
+
void l1ctl_sap_init(struct l1_model_ms *model);
void prim_rach_init(struct l1_model_ms *model);
void prim_data_init(struct l1_model_ms *model);
diff --git a/src/host/virt_phy/include/virtphy/virt_l1_model.h b/src/host/virt_phy/include/virtphy/virt_l1_model.h
index d4969eb6..296931ab 100644
--- a/src/host/virt_phy/include/virtphy/virt_l1_model.h
+++ b/src/host/virt_phy/include/virtphy/virt_l1_model.h
@@ -3,6 +3,7 @@
#include <virtphy/virtual_um.h>
#include <virtphy/l1ctl_sock.h>
#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/core/timer.h>
#define L1S_NUM_NEIGH_CELL 6
#define A5_KEY_LEN 8
@@ -78,6 +79,17 @@ struct l1_state_ms {
struct {
uint32_t arfcn;
} fbsb;
+
+ /* power management state */
+ struct {
+ uint32_t timeout_us;
+ uint32_t timeout_s;
+ struct {
+ int16_t arfcn_sig_lev_dbm[1024];
+ uint8_t arfcn_sig_lev_red_dbm[1024];
+ struct osmo_timer_list arfcn_sig_lev_timers[1024];
+ } meas;
+ } pm;
};
struct l1_model_ms *l1_model_ms_init(void *ctx);
diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index 1a2c0850..2e1a2077 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -152,6 +152,11 @@ void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg)
extern void prim_fbsb_sync(struct msgb *msg);
/**
+ * @see virt_prim_pm.c
+ */
+extern uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev);
+
+/**
* Receive a gsmtap message from the virt um.
*
* As we do not have a downlink scheduler, but not all dl messages must be processed and thus forwarded to l2, this function also implements some message filtering.
@@ -166,16 +171,12 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
if (!msg) {
return;
}
- // we do not forward messages to l23 if we are in network search state
- if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING) {
- goto freemsg;
- }
struct gsmtap_hdr *gh = msgb_l1(msg);
uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the received msg
uint8_t gsmtap_chantype = gh->sub_type; // gsmtap channel type
- uint8_t signal_dbm = gh->signal_dbm; // signal strength, 63 is best
+ uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); // Power measurement with each received massage
uint8_t snr = gh->snr_db; // signal noise ratio, 63 is best
uint8_t subslot = gh->sub_slot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
uint8_t timeslot = gh->timeslot; // tdma timeslot to send in (0-7)
@@ -190,6 +191,11 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
goto freemsg;
}
+ // we do not forward messages to l23 if we are in network search state
+ if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING) {
+ goto freemsg;
+ }
+
// forward downlink msg to fbsb sync routine if we are in sync state
if (l1_model_ms->state->state == MS_STATE_IDLE_SYNCING) {
prim_fbsb_sync(msg);
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index f0f3f68f..9957bf3e 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -43,6 +43,7 @@ void l1ctl_sap_init(struct l1_model_ms *model)
prim_fbsb_init(model);
prim_data_init(model);
prim_traffic_init(model);
+ prim_pm_init(model);
}
/**
diff --git a/src/host/virt_phy/src/virt_l1_model.c b/src/host/virt_phy/src/virt_l1_model.c
index 1b1d0dfd..bcd67358 100644
--- a/src/host/virt_phy/src/virt_l1_model.c
+++ b/src/host/virt_phy/src/virt_l1_model.c
@@ -6,7 +6,6 @@ struct l1_model_ms* l1_model_ms_init(void *ctx)
struct l1_model_ms *model = talloc_zero(ctx, struct l1_model_ms);
model->state = talloc_zero(ctx, struct l1_state_ms);
return model;
-
}
void l1_model_ms_destroy(struct l1_model_ms *model)
diff --git a/src/host/virt_phy/src/virt_prim_fbsb.c b/src/host/virt_phy/src/virt_prim_fbsb.c
index f0c7f528..2c0f10cf 100644
--- a/src/host/virt_phy/src/virt_prim_fbsb.c
+++ b/src/host/virt_phy/src/virt_prim_fbsb.c
@@ -57,7 +57,7 @@ void prim_fbsb_sync(struct msgb *msg)
if (l1_model_ms->state->fbsb.arfcn != arfcn) {
talloc_free(msg);
// cancel sync if we did not receive a msg on dl from the requested arfcn that we can sync to
- if(sync_count++ > 100) {
+ if(sync_count++ > 20) {
sync_count = 0;
l1_model_ms->state->state = MS_STATE_IDLE_SEARCHING;
l1ctl_tx_fbsb_conf(1, (l1_model_ms->state->fbsb.arfcn));
diff --git a/src/host/virt_phy/src/virt_prim_pm.c b/src/host/virt_phy/src/virt_prim_pm.c
index c08ce03b..312461c4 100644
--- a/src/host/virt_phy/src/virt_prim_pm.c
+++ b/src/host/virt_phy/src/virt_prim_pm.c
@@ -13,8 +13,30 @@
#include <l1ctl_proto.h>
static struct l1_model_ms *l1_model_ms = NULL;
-// FIXME: ugly to configure that in code. Either make a config file or change power selection to automatically check which arfcns can be received.
-static uint16_t available_arfcns[] = {666};
+
+/**
+ * @brief Change the signal strength for a given arfcn.
+ *
+ * Should be called if a msg is received on the virtual layer. The configured signal level reduction is applied.
+ *
+ * @param [in] arfcn to change sig str for.
+ * @param [in] sig_lev the measured signal level value.
+ */
+uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev) {
+ if(l1_model_ms->state->pm.timeout_s > 0 || l1_model_ms->state->pm.timeout_us > 0) {
+ osmo_timer_schedule(&l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[arfcn], l1_model_ms->state->pm.timeout_s, l1_model_ms->state->pm.timeout_us);
+ }
+ l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn] = sig_lev - l1_model_ms->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn];
+ DEBUGP(DL1C, "Power measurement set for arfcn %u. Set signal level to %d (== rxlev: %u).\n", arfcn, l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn], dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn]));
+ return l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn];
+}
+
+void prim_pm_timer_cb(void *data) {
+ // reset the signal level to bad value if no messages have been received from that rfcn for a given time
+ DEBUGP(DL1C,
+ "Timeout occurred for arfcn, signal level reset to worst value.\n");
+ *((int16_t*)data) = MIN_SIG_LEV_DBM;
+}
/**
* @brief Handler for received L1CTL_PM_REQ from L23.
@@ -25,11 +47,8 @@ static uint16_t available_arfcns[] = {666};
*
* Process power measurement for a given range of arfcns to calculate signal power and connection quality.
*
- * Note: We do not need to calculate that for the virtual physical layer,
- * but l23 apps can expect a response. So this response is mocked here.
- * For available arfcns we always return a perfect link quality, for all other the worst.
+ * Note: This should only be called after a certain time so some messages have already been received.
*
- * TODO: Change PM so that we check the downlink first for for some time to get the arfcns we receive. Then return a good link for that and a bad for all others.
*/
void l1ctl_rx_pm_req(struct msgb *msg)
{
@@ -52,18 +71,10 @@ void l1ctl_rx_pm_req(struct msgb *msg)
struct l1ctl_pm_conf *pm_conf =
(struct l1ctl_pm_conf *)msgb_put(resp_msg,
sizeof(*pm_conf));
- int cnt, available = 0;
pm_conf->band_arfcn = htons(arfcn_next);
- // check if arfcn is available
- for(cnt = 0; cnt < sizeof(available_arfcns) / sizeof(uint16_t); cnt++) {
- if(arfcn_next == available_arfcns[cnt]) {
- available = 1;
- break;
- }
- }
- // rxlev 63 is great, 0 is bad the two values are min and max
- pm_conf->pm[0] = available ? 63 : 0;
- pm_conf->pm[1] = available ? 63 : 0;
+ // set min and max to the value calculated for that arfcn (IGNORE UPLINKK AND PCS AND OTHER FLAGS)
+ pm_conf->pm[0] = dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
+ pm_conf->pm[1] = dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
if (arfcn_next == pm_req->range.band_arfcn_to) {
struct l1ctl_hdr *resp_l1h = msgb_l1(resp_msg);
resp_l1h->flags |= L1CTL_F_DONE;
@@ -87,5 +98,13 @@ void l1ctl_rx_pm_req(struct msgb *msg)
*/
void prim_pm_init(struct l1_model_ms *model)
{
+ int i;
l1_model_ms = model;
+ // init the signal level of all arfcns with the lowest value possible
+ memset (model->state->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
+ // init timers
+ for(i = 0; i < 1024; ++i) {
+ l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[i].cb = prim_pm_timer_cb;
+ l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[i].data = &l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[i];
+ }
}
diff --git a/src/host/virt_phy/src/virtphy.c b/src/host/virt_phy/src/virtphy.c
index dd11c671..aaa9311d 100644
--- a/src/host/virt_phy/src/virtphy.c
+++ b/src/host/virt_phy/src/virtphy.c
@@ -3,6 +3,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <stdint.h>
+#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
@@ -22,6 +23,8 @@ static char* ul_tx_grp = DEFAULT_BTS_MCAST_GROUP;
static int port = DEFAULT_MCAST_PORT;
static char* log_mask = DEFAULT_LOG_MASK;
static char * l1ctl_sock_path = L1CTL_SOCK_PATH;
+static char * arfcn_sig_lev_red_mask = NULL;
+static char * pm_timeout = NULL;
static void handle_options(int argc, char **argv)
{
@@ -33,9 +36,11 @@ static void handle_options(int argc, char **argv)
{"port", required_argument, 0, 'x'},
{"log-mask", required_argument, 0, 'd'},
{"l1ctl-sock", required_argument, 0, 's'},
+ {"arfcn-sig-lev-red", required_argument, 0, 'r'},
+ {"pm-timeout", required_argument, 0, 't'},
{0, 0, 0, 0},
};
- c = getopt_long(argc, argv, "z:y:x:d:s:", long_options,
+ c = getopt_long(argc, argv, "z:y:x:d:s:r:t:", long_options,
&option_index);
if (c == -1)
break;
@@ -56,12 +61,59 @@ static void handle_options(int argc, char **argv)
case 's':
l1ctl_sock_path = optarg;
break;
+ case 'r':
+ arfcn_sig_lev_red_mask = optarg;
+ break;
+ case 't':
+ pm_timeout = optarg;
+ break;
default:
break;
}
}
}
+void parse_pm_timeout(struct l1_model_ms *model, char *pm_timeout) {
+
+ if(!pm_timeout || (strcmp(pm_timeout, "") == 0)) {
+ return;
+ }
+ // seconds
+ char *buf = strtok(pm_timeout, ":");
+ model->state->pm.timeout_s = atoi(buf);
+ // microseconds
+ buf = strtok(NULL, ":");
+ if(buf) {
+ model->state->pm.timeout_us = atoi(buf);
+ }
+}
+
+/**
+ * arfcn_sig_lev_red_mask has to be formatted like 666,12:888,43:176,22
+ */
+void parse_arfcn_sig_lev_red(struct l1_model_ms *model, char * arfcn_sig_lev_red_mask) {
+
+ if(!arfcn_sig_lev_red_mask || (strcmp(arfcn_sig_lev_red_mask, "") == 0)) {
+ return;
+ }
+ char *token = strtok(arfcn_sig_lev_red_mask, ":");
+ do {
+ char* colon = strstr(token, ",");
+ uint16_t arfcn;
+ uint8_t red;
+ if(!colon) {
+ continue;
+ }
+ colon[0] = '\0';
+
+ arfcn = atoi(token);
+ red = atoi(colon + 1);
+
+ //TODO: this may go wild if the token string is not properly formatted
+ model->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn] = red;
+ } while ((token = strtok(NULL, ":")));
+}
+
int main(int argc, char *argv[])
{
// init loginfo
@@ -84,6 +136,10 @@ int main(int argc, char *argv[])
l1ctl_sap_init(model);
virt_l1_sched_init(model);
+ // apply timeout and arfcn reduction value config to model
+ parse_pm_timeout(model, pm_timeout);
+ parse_arfcn_sig_lev_red(model, arfcn_sig_lev_red_mask);
+
LOGP(DVIRPHY, LOGL_INFO,
"Virtual physical layer ready...\n \
Waiting for l23 app on %s",