[PATCH] osmocom-bb[master]: VIRT-PHY: Uplink scheduler implementation.

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Wed Jul 12 21:20:46 UTC 2017


Review at  https://gerrit.osmocom.org/3204

VIRT-PHY: Uplink scheduler implementation.

Implemented simple scheduler depending on frame number in downlink. It
will be executed each time we receive a msg on downlink and send out all
scheduled uplink msgs with a sched_fn smaller than the one of this
received downlink msg.

Further refactored l1ctl_sap by extracting rach and fbsb logic and
putting it to own files virt_prim_fbsb.c and virt_prim_rach.c

Added simple states to the ms layer 1 model, indicating if the ms is
currently searching for bts, syncing to or camping on a bts. Downlink
will be handled differently dependent of the state.

Change-Id: I8937b1d6568f5d3750bbdc5d77fa283074d5365e
---
M src/host/virt_phy/Makefile.am
M src/host/virt_phy/include/virtphy/gsmtapl1_if.h
M src/host/virt_phy/include/virtphy/l1ctl_sap.h
M src/host/virt_phy/include/virtphy/virt_l1_model.h
A src/host/virt_phy/include/virtphy/virt_l1_sched.h
M src/host/virt_phy/src/Makefile.am
M src/host/virt_phy/src/gsmtapl1_if.c
M src/host/virt_phy/src/l1ctl_sap.c
A src/host/virt_phy/src/virt_l1_sched_simple.c
A src/host/virt_phy/src/virt_prim_fbsb.c
A src/host/virt_phy/src/virt_prim_rach.c
M src/host/virt_phy/src/virtphy.c
12 files changed, 492 insertions(+), 155 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/04/3204/1

diff --git a/src/host/virt_phy/Makefile.am b/src/host/virt_phy/Makefile.am
index 515d51b..57b4571 100644
--- a/src/host/virt_phy/Makefile.am
+++ b/src/host/virt_phy/Makefile.am
@@ -1,2 +1,4 @@
 SUBDIRS = src
-dist_doc_DATA = README
\ No newline at end of file
+dist_doc_DATA = README
+
+CFLAGS = "-g -O0"
\ No newline at end of file
diff --git a/src/host/virt_phy/include/virtphy/gsmtapl1_if.h b/src/host/virt_phy/include/virtphy/gsmtapl1_if.h
index c511560..34cd9c8 100644
--- a/src/host/virt_phy/include/virtphy/gsmtapl1_if.h
+++ b/src/host/virt_phy/include/virtphy/gsmtapl1_if.h
@@ -10,8 +10,7 @@
 void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
                                       struct msgb *msg);
 void gsmtapl1_rx_from_virt_um(struct msgb *msg);
-void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint32_t fn,
-                                 struct msgb *msg);
-void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg);
+void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, struct msgb *msg);
+void gsmtapl1_tx_to_virt_um(struct msgb *msg);
 void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
                          uint8_t *link_id);
diff --git a/src/host/virt_phy/include/virtphy/l1ctl_sap.h b/src/host/virt_phy/include/virtphy/l1ctl_sap.h
index 902eb17..c11c5fe 100644
--- a/src/host/virt_phy/include/virtphy/l1ctl_sap.h
+++ b/src/host/virt_phy/include/virtphy/l1ctl_sap.h
@@ -19,6 +19,8 @@
 #define LID_DEDIC 		0x00
 
 void l1ctl_sap_init(struct l1_model_ms *model);
+void prim_rach_init(struct l1_model_ms *model);
+void prim_fbsb_init(struct l1_model_ms *model);
 void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg);
 void l1ctl_sap_tx_to_l23(struct msgb *msg);
 void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi,
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 561025e..69115f2 100644
--- a/src/host/virt_phy/include/virtphy/virt_l1_model.h
+++ b/src/host/virt_phy/include/virtphy/virt_l1_model.h
@@ -2,9 +2,18 @@
 
 #include <virtphy/virtual_um.h>
 #include <virtphy/l1ctl_sock.h>
+#include <osmocom/gsm/gsm_utils.h>
 
 #define L1S_NUM_NEIGH_CELL	6
 #define A5_KEY_LEN		8
+
+enum ms_state {
+	MS_STATE_IDLE_SEARCHING = 0,
+	MS_STATE_IDLE_SYNCING,
+	MS_STATE_IDLE_CAMPING,
+	MS_STATE_DEDICATED,
+};
+
 
 struct l1_model_ms {
 	struct l1ctl_sock_inst *lsi;
@@ -38,7 +47,10 @@
 
 struct l1_state_ms {
 
-	uint8_t camping; // are we currently camping on a cell
+	struct gsm_time	downlink_time;	/* current GSM time received on downlink */
+	struct gsm_time current_time; /* GSM time used internally for scheduling */
+
+	uint8_t state; // the ms state like in ms_state
 
 	/* the cell on which we are camping right now */
 	struct l1_cell_info serving_cell;
@@ -60,6 +72,11 @@
 		uint8_t tsc; // training sequence code (ununsed in virtual um)
 		uint8_t h; // hopping enabled flag (ununsed in virtual um)
 	} dedicated;
+
+	/* fbsb state */
+	struct {
+		uint32_t arfcn;
+	} fbsb;
 };
 
 struct l1_model_ms *l1_model_ms_init(void *ctx);
diff --git a/src/host/virt_phy/include/virtphy/virt_l1_sched.h b/src/host/virt_phy/include/virtphy/virt_l1_sched.h
new file mode 100644
index 0000000..a68c58d
--- /dev/null
+++ b/src/host/virt_phy/include/virtphy/virt_l1_sched.h
@@ -0,0 +1,32 @@
+#pragma once
+#include <osmocom/core/msgb.h>
+#include <virtphy/virt_l1_model.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <virtphy/virt_l1_sched.h>
+
+typedef void virt_l1_sched_cb(struct msgb * msg);
+
+/* bucket containing items to be executed for a specific mframe number */
+struct virt_l1_sched_mframe_item {
+	struct llist_head mframe_item_entry;
+	struct llist_head tdma_item_list; /* list of tdma sched items */
+	uint32_t fn; /* frame number of execution */
+};
+
+/* item to be be executed for a specific tdma timeslot of a framenumber */
+struct virt_l1_sched_tdma_item {
+	struct llist_head tdma_item_entry;
+	struct msgb * msg; /* the msg to be handled */
+	uint8_t ts; /* tdma timeslot of execution */
+	virt_l1_sched_cb * handler_cb; /* handler callback */
+};
+
+void virt_l1_sched_init(struct l1_model_ms * model);
+int virt_l1_sched_start(struct gsm_time time);
+int virt_l1_sched_restart(struct gsm_time time);
+void virt_l1_sched_sync_time(struct gsm_time time, uint8_t hard_reset);
+void virt_l1_sched_stop();
+void virt_l1_sched_execute(uint32_t fn);
+void virt_l1_sched_schedule(struct msgb * msg, uint32_t fn, uint8_t ts,
+                            virt_l1_sched_cb * handler_cb);
diff --git a/src/host/virt_phy/src/Makefile.am b/src/host/virt_phy/src/Makefile.am
index 8508509..fd8d5d9 100644
--- a/src/host/virt_phy/src/Makefile.am
+++ b/src/host/virt_phy/src/Makefile.am
@@ -1,9 +1,12 @@
 AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
 AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include  -I$(top_srcdir)/../layer23/include
 
+CFLAGS = "-g -O0"
+
 sbin_PROGRAMS = virtphy
-virtphy_SOURCES = virtphy.c l1ctl_sock.c l1ctl_sap.c gsmtapl1_if.c logging.c virt_l1_model.c shared/virtual_um.c shared/osmo_mcast_sock.c
-virtphy_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
+virtphy_SOURCES = virtphy.c l1ctl_sock.c gsmtapl1_if.c l1ctl_sap.c virt_prim_fbsb.c virt_prim_rach.c virt_l1_sched_simple.c logging.c virt_l1_model.c shared/virtual_um.c shared/osmo_mcast_sock.c
+virtphy_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) 
+virtphy_LDFLAGS = -pthread
 
 # debug output
 all:
diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index ebfb5b6..3762cdc 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -23,6 +23,7 @@
 #include <osmocom/core/gsmtap_util.h>
 #include <osmocom/core/utils.h>
 #include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/gsm_utils.h>
 #include <osmocom/gsm/protocol/gsm_08_58.h>
 #include <osmocom/core/msgb.h>
 #include <stddef.h>
@@ -35,6 +36,7 @@
 #include <virtphy/l1ctl_sap.h>
 #include <virtphy/gsmtapl1_if.h>
 #include <virtphy/logging.h>
+#include <virtphy/virt_l1_sched.h>
 
 static struct l1_model_ms *l1_model_ms = NULL;
 
@@ -88,13 +90,13 @@
 /**
  * Replace l11 header of given msgb by a gsmtap header and send it over the virt um.
  */
-void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, uint32_t fn,
-                                 struct msgb *msg)
+void gsmtapl1_tx_to_virt_um_inst(struct virt_um_inst *vui, struct msgb *msg)
 {
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
 	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
 	struct gsmtap_hdr *gh;
 	struct msgb *outmsg; // msg to send with gsmtap header prepended
+	uint32_t fn = gsm_gsmtime2fn(&l1_model_ms->state->downlink_time);
 	uint16_t arfcn = l1_model_ms->state->serving_cell.arfcn; // arfcn of the cell we currently camp on
 	uint8_t signal_dbm = 63; // signal strength, 63 is best
 	uint8_t snr = 63; // signal noise ratio, 63 is best
@@ -138,9 +140,9 @@
 /**
  * @see void gsmtapl1_tx_to_virt_um(struct virt_um_inst *vui, uint32_t fn, struct msgb *msg).
  */
-void gsmtapl1_tx_to_virt_um(uint32_t fn, struct msgb *msg)
+void gsmtapl1_tx_to_virt_um(struct msgb *msg)
 {
-	gsmtapl1_tx_to_virt_um_inst(l1_model_ms->vui, fn, msg);
+	gsmtapl1_tx_to_virt_um_inst(l1_model_ms->vui, msg);
 }
 
 /**
@@ -152,9 +154,15 @@
 	if (!msg) {
 		return;
 	}
-	// we assume we only receive msgs if we actually camp on a cell
-	if (!l1_model_ms->state->camping) {
+	// we do not forward messages to l23 if we are in network search state
+	if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING) {
 		talloc_free(msg);
+		return;
+	}
+
+	// forward 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);
 		return;
 	}
 
@@ -164,7 +172,7 @@
 	struct l1ctl_traffic_ind * l1ti;
 	struct l1ctl_data_ind * l1di;
 	uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
-	uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the cell we currently camp on
+	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 snr = gh->snr_db; // signal noise ratio, 63 is best
@@ -179,18 +187,23 @@
 	// see GSM 8.58 -> 9.3.1 for channel number encoding
 	chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot);
 
+	gsm_fn2gsmtime(&l1_model_ms->state->downlink_time, fn);
+	virt_l1_sched_sync_time(l1_model_ms->state->downlink_time, 0);
+	virt_l1_sched_execute(fn);
+
 	DEBUGP(DVIRPHY,
 	                "Receiving gsmtap msg from virt um - (arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
 	                arfcn, fn, get_value_string(gsmtap_types, gh->type),
 	                get_value_string(gsmtap_channels, gsmtap_chantype),
 	                timeslot, subslot, rsl_chantype, link_id, chan_nr);
 
-	// generally ignore all messages coming from another arfcn than the synced one
+	// generally ignore all messages coming from another arfcn than the camped one
 	if (l1_model_ms->state->serving_cell.arfcn != (arfcn & GSMTAP_ARFCN_MASK)) {
 		LOGP(DVIRPHY, LOGL_NOTICE,
 		                "Ignoring gsmtap msg from virt um - msg arfcn=%d not equal synced arfcn=%d!\n", arfcn & GSMTAP_ARFCN_MASK, l1_model_ms->state->serving_cell.arfcn);
 		goto nomessage;
 	}
+
 	// generally ignore all uplink messages received
 	if (arfcn & GSMTAP_ARFCN_F_UPLINK) {
 		LOGP(DVIRPHY, LOGL_NOTICE,
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index b89d963..6e42e5d 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -17,6 +17,7 @@
 #include <virtphy/l1ctl_sap.h>
 #include <virtphy/gsmtapl1_if.h>
 #include <virtphy/logging.h>
+#include <virtphy/virt_l1_sched.h>
 
 static struct l1_model_ms *l1_model_ms = NULL;
 
@@ -38,6 +39,8 @@
 void l1ctl_sap_init(struct l1_model_ms *model)
 {
 	l1_model_ms = model;
+	prim_rach_init(model);
+	prim_fbsb_init(model);
 }
 
 /**
@@ -193,11 +196,9 @@
 		break;
 	case L1CTL_RACH_REQ:
 		l1ctl_rx_rach_req(msg);
-		// msg is freed by rx routine
 		goto exit_nofree;
 	case L1CTL_DATA_REQ:
 		l1ctl_rx_data_req(msg);
-		/* we have to keep the msgb, not free it! */
 		goto exit_nofree;
 	case L1CTL_PM_REQ:
 		l1ctl_rx_pm_req(msg);
@@ -216,7 +217,6 @@
 		break;
 	case L1CTL_TRAFFIC_REQ:
 		l1ctl_rx_traffic_req(msg);
-		/* we have to keep the msgb, not free it! */
 		goto exit_nofree;
 	case L1CTL_SIM_REQ:
 		l1ctl_rx_sim_req(msg);
@@ -224,49 +224,14 @@
 	}
 
 	exit_msgbfree: msgb_free(msg);
-	exit_nofree: return;
+	exit_nofree: return; /* msg is scheduled for uplink and mustn't be freed here */
 }
 
 /***************************************************************
  * L1CTL RX ROUTINES *******************************************
+ * For more routines check the respective handler classes ******
+ * like virt_prim_rach.c ***************************************
  ***************************************************************/
-
-/**
- * @brief Handler for received L1CTL_FBSB_REQ from L23.
- *
- * -- frequency burst synchronisation burst request --
- *
- * @param [in] msg the received message.
- *
- * Transmit frequency control and synchronisation bursts on FCCH and SCH to calibrate transceiver and search for base stations.
- * Sync to a given arfcn.
- *
- * Note: ms will start receiving msgs on virtual um only after this req was received.
- * Note: virt bts does not broadcast freq and sync bursts.
- *
- * TODO: Could be used to bind/connect to different virtual_bts sockets with a arfcn-socket mapping.
- * TODO: Check flags if this is a sync or freq request and handle it accordingly.
- */
-void l1ctl_rx_fbsb_req(struct msgb *msg)
-{
-	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
-	struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *)l1h->data;
-
-	DEBUGP(DL1C,
-	                "Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
-	                ntohs(sync_req->band_arfcn), sync_req->flags);
-
-	l1_model_ms->state->camping = 1;
-	l1_model_ms->state->serving_cell.arfcn = ntohs(sync_req->band_arfcn); // freq req
-
-	// not needed in virt um
-	l1_model_ms->state->serving_cell.ccch_mode = sync_req->ccch_mode; // sync req
-	l1_model_ms->state->serving_cell.fn_offset = 0; // sync req
-	l1_model_ms->state->serving_cell.bsic = 0; // sync req
-	l1_model_ms->state->serving_cell.time_alignment = 0; // sync req
-
-	l1ctl_tx_fbsb_conf(0, l1_model_ms->state->serving_cell.arfcn);
-}
 
 /**
  * @brief Handler for received L1CTL_DM_EST_REQ from L23.
@@ -410,47 +375,6 @@
 }
 
 /**
- * @brief Handler for received L1CTL_RACH_REQ from L23.
- *
- * -- random access channel request --
- *
- * @param [in] msg the received message.
- *
- * Transmit RACH request on RACH. Refer to 04.08 - 9.1.8 - Channel request.
- *
- */
-void l1ctl_rx_rach_req(struct msgb *msg)
-{
-	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
-	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
-	struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *)ul->payload;
-	// FIXME: proper frame number
-	uint32_t fn_sched = 42;
-
-	DEBUGP(DL1C,
-	                "Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
-	                rach_req->ra, ntohs(rach_req->offset),
-	                rach_req->combined);
-
-	// for the rach channel request, there is no layer2 header, but only the one bit ra content to submit
-	// replace l1ctl_rach_req with ra data that rly shall be submitted
-	// ra on peer side is decoded as uint16_t, but we do not use the 11bit option and thus 8bits must be sufficient
-	msg->l2h = msgb_put(msg, sizeof(uint8_t));
-	*msg->l2h = rach_req->ra;
-
-	// chan_nr is not specified in info_ul for rach request coming from l23, but needed in gsmtapl1_tx_to_virt_um()
-	ul->chan_nr = rsl_enc_chan_nr(RSL_CHAN_RACH, 0, 0);
-	ul->link_id = LID_DEDIC;
-
-	// send rach over virt um
-	gsmtapl1_tx_to_virt_um(fn_sched, msg);
-
-	// send confirm to layer23
-	l1ctl_tx_rach_conf(fn_sched, l1_model_ms->state->serving_cell.arfcn);
-
-}
-
-/**
  * @brief Handler for received L1CTL_DATA_REQ from L23.
  *
  * -- data request --
@@ -466,8 +390,8 @@
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
 	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
 	struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *)ul->payload;
-	// FIXME: proper frame number
-	uint32_t fn_sched = 42;
+	// TODO: calc the scheduled fn
+	uint32_t fn_sched = l1_model_ms->state->downlink_time.fn;
 
 	DEBUGP(DL1C,
 	                "Received and handled from l23 - L1CTL_DATA_REQ (link_id=0x%02x, ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p)\n",
@@ -476,8 +400,8 @@
 
 	msg->l2h = data_ind->data;
 
-	// send msg over virt um
-	gsmtapl1_tx_to_virt_um(fn_sched, msg);
+	// TODO: append to scheduler queue instead of sending here directly
+	gsmtapl1_tx_to_virt_um(msg);
 
 	// send confirm to layer23
 	msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn_sched, 0, 0);
@@ -560,11 +484,12 @@
 	case L1CTL_RES_T_FULL:
 		DEBUGP(DL1C,
 		                "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
-		l1_model_ms->state->camping = 0;
-		// TODO: check if we also need to reset the dedicated channel state
+		l1_model_ms->state->state = MS_STATE_IDLE_SEARCHING;
+		virt_l1_sched_stop();
 		l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
 		break;
 	case L1CTL_RES_T_SCHED:
+		virt_l1_sched_restart(l1_model_ms->state->downlink_time);
 		DEBUGP(DL1C,
 		                "Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
 		l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
@@ -673,14 +598,15 @@
 	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
 	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
 	struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *)ul->payload;
-	uint32_t fn_sched = 42;
+	// TODO: calc the scheduled fn
+	uint32_t fn_sched = l1_model_ms->state->downlink_time.fn;
 
 	DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n");
 
 	msg->l2h = tr->data;
 
-	// send msg over virt um
-	gsmtapl1_tx_to_virt_um(fn_sched, msg);
+	// TODO: append to scheduler queue instead of sending here directly
+	gsmtapl1_tx_to_virt_um(msg);
 
 	// send confirm to layer23
 	msg = l1ctl_create_l2_msg(L1CTL_TRAFFIC_CONF, fn_sched, 0, 0);
@@ -719,6 +645,8 @@
 
 /***************************************************************
  * L1CTL TX ROUTINES *******************************************
+ * For more routines check the respective handler classes ******
+ * like virt_prim_rach.c ***************************************
  ***************************************************************/
 
 /**
@@ -742,23 +670,6 @@
 }
 
 /**
- * @brief Transmit L1CTL_RESET_IND or L1CTL_RESET_CONF to layer 23.
- *
- * -- reset indication / confirm --
- *
- * @param [in] msg_type L1CTL primitive message type.
- * @param [in] reset_type reset type (full, boot or just scheduler reset).
- */
-void l1ctl_tx_rach_conf(uint32_t fn, uint16_t arfcn)
-{
-	struct msgb * msg = l1ctl_create_l2_msg(L1CTL_RACH_CONF, fn, 0, arfcn);
-
-	DEBUGP(DL1C, "Sending to l23 - %s (fn: %u, arfcn: %u)\n",
-	                getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn);
-	l1ctl_sap_tx_to_l23(msg);
-}
-
-/**
  * @brief Transmit L1CTL msg of a given type to layer 23.
  *
  * @param [in] msg_type L1CTL primitive message type.
@@ -767,38 +678,6 @@
 {
 	struct msgb *msg = l1ctl_msgb_alloc(msg_type);
 	DEBUGP(DL1C, "Sending to l23 - %s\n", getL1ctlPrimName(msg_type));
-	l1ctl_sap_tx_to_l23(msg);
-}
-
-/**
- * @brief Transmit L1CTL_FBSB_CONF to l23.
- *
- * -- frequency burst synchronisation burst confirm --
- *
- * @param [in] res 0 -> success, 255 -> error.
- * @param [in] arfcn the arfcn we are synced to.
- *
- * No calculation needed for virtual pyh -> uses dummy values for a good link quality.
- */
-void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
-{
-	struct msgb *msg;
-	struct l1ctl_fbsb_conf *resp;
-	uint32_t fn = 0; // 0 should be okay here
-	uint16_t snr = 40; // signal noise ratio > 40db is best signal (unused in virt)
-	int16_t initial_freq_err = 0; // 0 means no error (unused in virt)
-	uint8_t bsic = 0; // bsci can be read from sync burst (unused in virt)
-
-	msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, snr, arfcn);
-
-	resp = (struct l1ctl_fbsb_conf *)msgb_put(msg, sizeof(*resp));
-	resp->initial_freq_err = htons(initial_freq_err);
-	resp->result = res;
-	resp->bsic = bsic;
-
-	DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n",
-	                getL1ctlPrimName(L1CTL_FBSB_CONF), res);
-
 	l1ctl_sap_tx_to_l23(msg);
 }
 
diff --git a/src/host/virt_phy/src/virt_l1_sched_simple.c b/src/host/virt_phy/src/virt_l1_sched_simple.c
new file mode 100644
index 0000000..8df88ec
--- /dev/null
+++ b/src/host/virt_phy/src/virt_l1_sched_simple.c
@@ -0,0 +1,135 @@
+#include <virtphy/virt_l1_sched.h>
+#include <osmocom/core/linuxlist.h>
+#include <virtphy/virt_l1_model.h>
+#include <virtphy/logging.h>
+#include <time.h>
+#include <talloc.h>
+
+static struct l1_model_ms *l1_model_ms = NULL;
+
+static LLIST_HEAD(mframe_item_list);
+
+/**
+ * @brief Initialize schedulers data structures.
+ */
+void virt_l1_sched_init(struct l1_model_ms * model)
+{
+	l1_model_ms = model;
+}
+
+/**
+ * @brief Clear scheduler queue and completely restart scheduler.
+ */
+int virt_l1_sched_restart(struct gsm_time time)
+{
+	virt_l1_sched_stop();
+	return virt_l1_sched_start(time);
+}
+
+/**
+ * @brief Start scheduler thread based on current gsm time from model
+ */
+int virt_l1_sched_start(struct gsm_time time)
+{
+	virt_l1_sched_sync_time(time, 1);
+	return 0;
+}
+
+/**
+ * @brief Sync scheduler with given time.
+ */
+void virt_l1_sched_sync_time(struct gsm_time time, uint8_t hard_reset)
+{
+	l1_model_ms->state->current_time = time;
+}
+
+/**
+ * @brief Stop the scheduler thread and cleanup mframe items queue
+ */
+void virt_l1_sched_stop()
+{
+	struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
+
+	/* Empty tdma and mframe sched items lists */
+	llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
+	{
+		struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
+		llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry)
+		{
+			talloc_free(ti_next->msg);
+			llist_del(&ti_next->tdma_item_entry);
+		}
+		llist_del(&mi_next->mframe_item_entry);
+		talloc_free(mi_next);
+	}
+}
+
+/**
+ * @brief Handle all pending scheduled items for the current frame number.
+ */
+void virt_l1_sched_execute(uint32_t fn)
+{
+	struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
+	// FIXME: change of hyperframe and thus restarting fn at 0 may cause messages in the queue that are never handled
+	llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
+	{
+		if (mi_next->fn <= fn) {
+			struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
+			// run through all scheduled tdma sched items for that frame number
+			llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry)
+			{
+				// exec tdma sched item's handler callback
+				// TODO: we do not have a tdma scheduler currently and execute alle scheduled tdma items here at once
+				ti_next->handler_cb(ti_next->msg);
+				// remove handled tdma sched item
+				llist_del(&ti_next->tdma_item_entry);
+			}
+			// remove handled mframe sched item
+			llist_del(&mi_next->mframe_item_entry);
+			talloc_free(mi_next);
+		} else if (mi_next->fn > fn) {
+			/* break the loop as our list is ordered */
+			break;
+		}
+	}
+}
+
+/**
+ * @brief Schedule a msg to the given framenumber and timeslot.
+ */
+void virt_l1_sched_schedule(struct msgb * msg, uint32_t fn, uint8_t ts,
+                            virt_l1_sched_cb * handler_cb)
+{
+	struct virt_l1_sched_mframe_item *mi_next = NULL, *mi_tmp = NULL,
+	                *mi_fn = NULL;
+	struct virt_l1_sched_tdma_item *ti_new = NULL;
+
+	llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
+	{
+		if (mi_next->fn == fn) {
+			mi_fn = mi_next;
+			break;
+		} else if (mi_next->fn > fn) {
+			break;
+		}
+	}
+	if (!mi_fn) {
+		// list did not contain mframe item with needed fn
+		mi_fn = talloc_zero(NULL, struct virt_l1_sched_mframe_item);
+		mi_fn->fn = fn;
+		// need to manually init the struct content.... no so happy
+		mi_fn->tdma_item_list.prev = &mi_fn->tdma_item_list;
+		mi_fn->tdma_item_list.next = &mi_fn->tdma_item_list;
+
+		// TODO: check if we get an error if list is empty...
+		llist_add(&mi_fn->mframe_item_entry,
+		          mi_next->mframe_item_entry.prev);
+
+	}
+	ti_new = talloc_zero(mi_fn, struct virt_l1_sched_tdma_item);
+	ti_new->msg = msg;
+	ti_new->handler_cb = handler_cb;
+	ti_new->ts = ts;
+	// simply add at end, no ordering for tdma sched items currently
+	llist_add_tail(&ti_new->tdma_item_entry, &mi_fn->tdma_item_list); // TODO: ordered insert needed if tdma scheduler should be implemented
+}
diff --git a/src/host/virt_phy/src/virt_prim_fbsb.c b/src/host/virt_phy/src/virt_prim_fbsb.c
new file mode 100644
index 0000000..6a678d0
--- /dev/null
+++ b/src/host/virt_phy/src/virt_prim_fbsb.c
@@ -0,0 +1,113 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/core/msgb.h>
+#include <virtphy/l1ctl_sap.h>
+#include <virtphy/virt_l1_sched.h>
+#include <osmocom/core/gsmtap.h>
+#include <virtphy/logging.h>
+#include <l1ctl_proto.h>
+
+static struct l1_model_ms *l1_model_ms = NULL;
+
+/**
+ * @brief Handler for received L1CTL_FBSB_REQ from L23.
+ *
+ * -- frequency burst synchronisation burst request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Transmit frequency control and synchronisation bursts on FCCH and SCH to calibrate transceiver and search for base stations.
+ * Sync to a given arfcn.
+ *
+ * Note: ms will start receiving msgs on virtual um only after this req was received.
+ * Note: virt bts does not broadcast freq and sync bursts.
+ *
+ */
+void l1ctl_rx_fbsb_req(struct msgb *msg)
+{
+	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+	struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *)l1h->data;
+
+	DEBUGP(DL1C,
+	       "Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
+	       ntohs(sync_req->band_arfcn), sync_req->flags);
+
+	l1_model_ms->state->state = MS_STATE_IDLE_SYNCING;
+	l1_model_ms->state->fbsb.arfcn = ntohs(sync_req->band_arfcn);
+}
+
+/**
+ * @brief A msg was received on l1 that can be used for synchronization.
+ *
+ * Note: for virtual layer 1 this can be a random downlink message, as we can parse the fn from the gsmtap header.
+ */
+void prim_fbsb_sync(struct msgb *msg)
+{
+	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
+
+	// ignore messages from other arfcns as the one requested to sync to by l23
+	if (l1_model_ms->state->fbsb.arfcn != (arfcn & GSMTAP_ARFCN_MASK)) {
+		talloc_free(msg);
+		return;
+	}
+	l1_model_ms->state->serving_cell.arfcn = (arfcn & GSMTAP_ARFCN_MASK);
+	l1_model_ms->state->state = MS_STATE_IDLE_CAMPING;
+	/* Not needed in virtual phy */
+	l1_model_ms->state->serving_cell.fn_offset = 0;
+	l1_model_ms->state->serving_cell.time_alignment = 0;
+	l1_model_ms->state->serving_cell.bsic = 0;
+	/* Update current gsm time each time we receive a message on the virt um */
+	gsm_fn2gsmtime(&l1_model_ms->state->downlink_time, fn);
+	/* Restart scheduler */
+	virt_l1_sched_restart(l1_model_ms->state->downlink_time);
+	talloc_free(msg);
+	l1ctl_tx_fbsb_conf(0, (arfcn & GSMTAP_ARFCN_MASK));
+}
+
+/**
+ * @brief Transmit L1CTL_FBSB_CONF to l23.
+ *
+ * -- frequency burst synchronisation burst confirm --
+ *
+ * @param [in] res 0 -> success, 255 -> error.
+ * @param [in] arfcn the arfcn we are synced to.
+ *
+ * No calculation needed for virtual pyh -> uses dummy values for a good link quality.
+ */
+void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
+{
+	struct msgb *msg;
+	struct l1ctl_fbsb_conf *resp;
+	uint32_t fn = 0; // 0 should be okay here
+	uint16_t snr = 40; // signal noise ratio > 40db is best signal (unused in virt)
+	int16_t initial_freq_err = 0; // 0 means no error (unused in virt)
+	uint8_t bsic = 0; // bsci can be read from sync burst (unused in virt)
+
+	msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, snr, arfcn);
+
+	resp = (struct l1ctl_fbsb_conf *)msgb_put(msg, sizeof(*resp));
+	resp->initial_freq_err = htons(initial_freq_err);
+	resp->result = res;
+	resp->bsic = bsic;
+
+	DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n",
+	       getL1ctlPrimName(L1CTL_FBSB_CONF), res);
+
+	l1ctl_sap_tx_to_l23(msg);
+}
+/**
+ * @brief Initialize virtual prim rach.
+ *
+ * @param [in] model the l1 model instance
+ */
+void prim_fbsb_init(struct l1_model_ms *model)
+{
+	l1_model_ms = model;
+}
diff --git a/src/host/virt_phy/src/virt_prim_rach.c b/src/host/virt_phy/src/virt_prim_rach.c
new file mode 100644
index 0000000..c558034
--- /dev/null
+++ b/src/host/virt_phy/src/virt_prim_rach.c
@@ -0,0 +1,140 @@
+/* Layer 1 Random Access Channel Burst */
+
+/* (C) 2010 by Dieter Spaar <spaar at mirider.augusta.de>
+ * (C) 2010 by Harald Welte <laforge at gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/core/msgb.h>
+#include <virtphy/l1ctl_sap.h>
+#include <virtphy/virt_l1_sched.h>
+#include <virtphy/logging.h>
+#include <virtphy/gsmtapl1_if.h>
+
+#include <l1ctl_proto.h>
+
+static struct l1_model_ms *l1_model_ms = NULL;
+static void virt_l1_sched_handler_cb(struct msgb * msg);
+
+// use if we have a combined uplink (RACH, SDCCH, ...) (see http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html)
+// if we have no combined channel config, uplink consists of only RACH
+static uint8_t t3_to_rach_comb[51] = {
+        0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+        11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 25, 25,
+        25, 25, 25, 25, 25, 26, 27, 27, 27, 27};
+static uint8_t rach_to_t3_comb[27] = {
+        4, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+        30, 31, 32, 33, 34, 35, 36, 45, 46};
+
+/**
+ * @brief Handler callback function for RACH request.
+ *
+ * @param [in] msg the msg to sent over virtual um.
+ */
+static void virt_l1_sched_handler_cb(struct msgb * msg)
+{
+	gsmtapl1_tx_to_virt_um(msg);
+	l1ctl_tx_rach_conf(l1_model_ms->state->current_time.fn,
+	                   l1_model_ms->state->serving_cell.arfcn);
+}
+
+/**
+ * @brief Handler for received L1CTL_RACH_REQ from L23.
+ *
+ * -- random access channel request --
+ *
+ * @param [in] msg the received message.
+ *
+ * Transmit RACH request on RACH. Refer to 04.08 - 9.1.8 - Channel request.
+ *
+ */
+void l1ctl_rx_rach_req(struct msgb *msg)
+{
+	struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+	struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
+	struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *)ul->payload;
+	uint32_t fn_sched;
+	uint8_t ts = 1; //FIXME mostly, ts 1 is used for rach, where can i get that info? System info?
+	uint16_t offset = ntohs(rach_req->offset);
+
+	DEBUGP(DL1C,
+	       "Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
+	       rach_req->ra, offset, rach_req->combined);
+
+	if (rach_req->ra == 0x03) {
+		fn_sched = 42;
+	}
+
+	// set ra data to msg (8bits, the 11bit option is not used)
+	msg->l2h = msgb_put(msg, sizeof(uint8_t));
+	*msg->l2h = rach_req->ra;
+
+	// chan_nr need to be encoded here, as it is not set by l23 for the rach request, but needed by virt um
+	ul->chan_nr = rsl_enc_chan_nr(RSL_CHAN_RACH, 0, ts);
+	ul->link_id = LID_DEDIC;
+
+	// sched fn calculation if we have a combined ccch channel configuration
+	if (rach_req->combined) {
+		/* add elapsed RACH slots to offset */
+		offset += t3_to_rach_comb[l1_model_ms->state->current_time.t3];
+		/* offset is the number of RACH slots in the future */
+		fn_sched = l1_model_ms->state->current_time.fn - l1_model_ms->state->current_time.t3;
+		fn_sched += offset / 27 * 51;
+		fn_sched += rach_to_t3_comb[offset % 27];
+	} else {
+		fn_sched = l1_model_ms->state->current_time.fn + offset;
+	}
+
+	virt_l1_sched_schedule(msg, fn_sched, ts, &virt_l1_sched_handler_cb);
+
+}
+
+/**
+ * @brief Transmit L1CTL_RACH_CONF to layer 23.
+ *
+ * -- rach confirm --
+ *
+ * @param [in] fn the fn on which the rach was sent
+ * @param [in] arfcn arfcn on which the rach was sent
+ */
+void l1ctl_tx_rach_conf(uint32_t fn, uint16_t arfcn)
+{
+	struct msgb * msg = l1ctl_create_l2_msg(L1CTL_RACH_CONF, fn, 0, arfcn);
+
+	DEBUGP(DL1C, "Sending to l23 - %s (fn: %u, arfcn: %u)\n",
+	       getL1ctlPrimName(L1CTL_RACH_CONF), fn, arfcn);
+	l1ctl_sap_tx_to_l23(msg);
+}
+
+/**
+ * @brief Initialize virtual prim rach.
+ *
+ * @param [in] model the l1 model instance
+ */
+void prim_rach_init(struct l1_model_ms *model)
+{
+	l1_model_ms = model;
+}
diff --git a/src/host/virt_phy/src/virtphy.c b/src/host/virt_phy/src/virtphy.c
index 977a358..c9e7bdd 100644
--- a/src/host/virt_phy/src/virtphy.c
+++ b/src/host/virt_phy/src/virtphy.c
@@ -11,6 +11,7 @@
 #include <virtphy/l1ctl_sap.h>
 #include <virtphy/gsmtapl1_if.h>
 #include <virtphy/logging.h>
+#include <virtphy/virt_l1_sched.h>
 
 int main( int argc, char *argv[] )
 {
@@ -40,6 +41,7 @@
 
 	gsmtapl1_init(model);
 	l1ctl_sap_init(model);
+	virt_l1_sched_init(model);
 
 	LOGP(DVIRPHY, LOGL_INFO, "Virtual physical layer ready...\n \
 			Waiting for l23 app on", l1ctl_sock_path);

-- 
To view, visit https://gerrit.osmocom.org/3204
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8937b1d6568f5d3750bbdc5d77fa283074d5365e
Gerrit-PatchSet: 1
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: BastusIII <sebastian.stumpf87 at googlemail.com>



More information about the gerrit-log mailing list