summaryrefslogtreecommitdiffstats
path: root/src/host/virt_phy
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2022-08-15 17:59:49 +0700
committerfixeria <vyanitskiy@sysmocom.de>2023-03-17 12:15:29 +0000
commit2b462dd89db851148c154e30f570a1d2ea4c6567 (patch)
treedda38e2dda3ecee1cb1797c12917fb522803eed8 /src/host/virt_phy
parente15996378f102b801868f5e5edd687ba9c72c69b (diff)
{trxcon,virt_phy}: shared GPRS L1 (MAC) implementation
Diffstat (limited to 'src/host/virt_phy')
-rw-r--r--src/host/virt_phy/include/osmocom/bb/Makefile.am1
l---------src/host/virt_phy/include/osmocom/bb/l1gprs.h1
-rw-r--r--src/host/virt_phy/include/osmocom/bb/virtphy/l1ctl_sap.h4
-rw-r--r--src/host/virt_phy/include/osmocom/bb/virtphy/logging.h1
-rw-r--r--src/host/virt_phy/include/osmocom/bb/virtphy/virt_l1_model.h12
-rw-r--r--src/host/virt_phy/src/Makefile.am2
-rw-r--r--src/host/virt_phy/src/gsmtapl1_if.c94
-rw-r--r--src/host/virt_phy/src/l1ctl_sap.c163
l---------src/host/virt_phy/src/l1gprs.c1
-rw-r--r--src/host/virt_phy/src/logging.c15
-rw-r--r--src/host/virt_phy/src/virt_prim_pdch.c106
-rw-r--r--src/host/virt_phy/src/virtphy.c4
12 files changed, 157 insertions, 247 deletions
diff --git a/src/host/virt_phy/include/osmocom/bb/Makefile.am b/src/host/virt_phy/include/osmocom/bb/Makefile.am
index c52fb937..9a4b939a 100644
--- a/src/host/virt_phy/include/osmocom/bb/Makefile.am
+++ b/src/host/virt_phy/include/osmocom/bb/Makefile.am
@@ -4,4 +4,5 @@ SUBDIRS = \
noinst_HEADERS = \
l1ctl_proto.h \
+ l1gprs.h \
$(NULL)
diff --git a/src/host/virt_phy/include/osmocom/bb/l1gprs.h b/src/host/virt_phy/include/osmocom/bb/l1gprs.h
new file mode 120000
index 00000000..3bf85176
--- /dev/null
+++ b/src/host/virt_phy/include/osmocom/bb/l1gprs.h
@@ -0,0 +1 @@
+../../../../../../include/l1gprs.h \ No newline at end of file
diff --git a/src/host/virt_phy/include/osmocom/bb/virtphy/l1ctl_sap.h b/src/host/virt_phy/include/osmocom/bb/virtphy/l1ctl_sap.h
index 724d238b..e756c140 100644
--- a/src/host/virt_phy/include/osmocom/bb/virtphy/l1ctl_sap.h
+++ b/src/host/virt_phy/include/osmocom/bb/virtphy/l1ctl_sap.h
@@ -57,6 +57,8 @@ void l1ctl_rx_tch_mode_req(struct l1_model_ms *ms, struct msgb *msg);
void l1ctl_rx_neigh_pm_req(struct l1_model_ms *ms, struct msgb *msg);
void l1ctl_rx_traffic_req(struct l1_model_ms *ms, struct msgb *msg);
void l1ctl_rx_sim_req(struct l1_model_ms *ms, struct msgb *msg);
+void l1ctl_rx_gprs_uldl_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg);
+void l1ctl_rx_gprs_ul_block_req(struct l1_model_ms *ms, struct msgb *msg);
/* transmit routines */
void l1ctl_tx_reset(struct l1_model_ms *ms, uint8_t msg_type, uint8_t reset_type);
@@ -75,6 +77,8 @@ void l1ctl_tx_pm_conf(struct l1_model_ms *ms, struct l1ctl_pm_req *pm_req);
void l1ctl_tx_fbsb_conf(struct l1_model_ms *ms, uint8_t res, uint16_t arfcn);
void l1ctl_tx_ccch_mode_conf(struct l1_model_ms *ms, uint8_t ccch_mode);
void l1ctl_tx_tch_mode_conf(struct l1_model_ms *ms, uint8_t tch_mode, uint8_t audio_mode);
+void l1ctl_tx_gprs_dl_block_ind(struct l1_model_ms *ms, const struct msgb *msg,
+ uint32_t fn, uint8_t tn, uint8_t rxlev);
/* scheduler functions */
uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
diff --git a/src/host/virt_phy/include/osmocom/bb/virtphy/logging.h b/src/host/virt_phy/include/osmocom/bb/virtphy/logging.h
index b22db992..48f7ed55 100644
--- a/src/host/virt_phy/include/osmocom/bb/virtphy/logging.h
+++ b/src/host/virt_phy/include/osmocom/bb/virtphy/logging.h
@@ -7,6 +7,7 @@ enum virtphy_log_cat {
DL1C,
DL1P,
DVIRPHY,
+ DGPRS,
DMAIN
};
diff --git a/src/host/virt_phy/include/osmocom/bb/virtphy/virt_l1_model.h b/src/host/virt_phy/include/osmocom/bb/virtphy/virt_l1_model.h
index b729c443..94581f61 100644
--- a/src/host/virt_phy/include/osmocom/bb/virtphy/virt_l1_model.h
+++ b/src/host/virt_phy/include/osmocom/bb/virtphy/virt_l1_model.h
@@ -16,7 +16,6 @@ enum ms_state {
MS_STATE_IDLE_SYNCING,
MS_STATE_IDLE_CAMPING,
MS_STATE_DEDICATED,
- MS_STATE_TBF
};
@@ -77,15 +76,6 @@ struct l1_state_ms {
uint8_t tsc; // training sequence code (unused in virtual um)
uint8_t h; // hopping enabled flag (unused in virtual um)
} dedicated;
- struct {
- struct {
- uint8_t usf[8];
- struct llist_head tx_queue;
- } ul;
- struct {
- uint8_t tfi[8];
- } dl;
- } tbf;
/* fbsb state */
struct {
@@ -116,6 +106,8 @@ struct l1_model_ms {
struct l1ctl_sock_client *lsc;
/* pointer to the (shared) GSMTAP/VirtUM socket to talk to BTS(s) */
struct virt_um_inst *vui;
+ /* GPRS state (MAC layer) */
+ struct l1gprs_state *gprs;
/* actual per-MS state */
struct l1_state_ms state;
};
diff --git a/src/host/virt_phy/src/Makefile.am b/src/host/virt_phy/src/Makefile.am
index 902284d0..f10639f5 100644
--- a/src/host/virt_phy/src/Makefile.am
+++ b/src/host/virt_phy/src/Makefile.am
@@ -5,6 +5,7 @@ bin_PROGRAMS = virtphy
virtphy_SOURCES = \
virtphy.c \
+ l1gprs.c \
logging.c \
gsmtapl1_if.c \
l1ctl_sock.c \
@@ -13,6 +14,7 @@ virtphy_SOURCES = \
virt_prim_fbsb.c \
virt_prim_rach.c \
virt_prim_data.c \
+ virt_prim_pdch.c \
virt_prim_traffic.c \
virt_l1_sched_simple.c \
virt_l1_model.c \
diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index f5c49af4..ef8d6840 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -94,23 +94,16 @@ void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, uint8_t tn
uint8_t timeslot; /* tdma timeslot to send in (0-7) */
uint8_t gsmtap_chan; /* the gsmtap channel */
- switch (ms->state.state) {
- case MS_STATE_DEDICATED:
- case MS_STATE_TBF:
+ if (ms->state.state == MS_STATE_DEDICATED)
arfcn = ms->state.dedicated.band_arfcn;
- break;
- default:
+ else
arfcn = ms->state.serving_cell.arfcn;
- break;
- }
switch (l1h->msg_type) {
- case L1CTL_DATA_TBF_REQ:
- ul = NULL;
- rsl_chantype = RSL_CHAN_OSMO_PDCH;
+ case L1CTL_GPRS_UL_BLOCK_REQ:
+ gsmtap_chan = GSMTAP_CHANNEL_PDCH;
timeslot = tn;
subslot = 0;
- gsmtap_chan = chantype_rsl2gsmtap2(rsl_chantype, 0, false);
break;
case L1CTL_TRAFFIC_REQ:
ul = (struct l1ctl_info_ul *)l1h->data;
@@ -165,77 +158,6 @@ extern void prim_fbsb_sync(struct l1_model_ms *ms, struct msgb *msg);
*/
extern uint16_t prim_pm_set_sig_strength(struct l1_model_ms *ms, uint16_t arfcn, int16_t sig_lev);
-/* determine if a received Downlink RLC/MAC block matches the current MS configuration */
-static bool gprs_dl_block_matches_ms(struct l1_model_ms *ms, struct msgb *msg, uint8_t timeslot)
-{
- uint8_t payload_type;
- uint8_t tfi;
-
- if (msgb_length(msg) < 1)
- return false;
-
- /* FIXME: Ensure this will also work for EGPRS! */
- payload_type = msg->data[0] >> 6;
- switch (payload_type) {
- case 0: /* RLC Data Block */
- /* forward all RLD Data Blocks destined for TFI of MS */
- tfi = (msg->data[1] >> 1) & 0x1f;
- if (ms->state.state == MS_STATE_TBF && ms->state.tbf.dl.tfi[timeslot] == tfi)
- return true;
- break;
- case 1: /* RLC/MAC Control without optional octets */
- /* forward all RLC/MAC control blocks without optional octets, i.e. not addressed
- * to a specific TFI */
- return true;
- case 2: /* RLC/MAC with optional control octets */
- /* forward all RLD Control Blocks destined for TFI of MS */
- tfi = (msg->data[2] >> 1) & 0x1f;
- if (ms->state.state == MS_STATE_TBF && ms->state.tbf.dl.tfi[timeslot] == tfi)
- return true;
- break;
- default:
- break;
- }
- return false;
-}
-
-/* determine if given USF at given timeslot is relevant to given MS or not */
-static bool usf_matches_ms(struct l1_model_ms *ms, uint8_t usf, uint8_t timeslot)
-{
- if (ms->state.state == MS_STATE_TBF && ms->state.tbf.ul.usf[timeslot] == usf)
- return true;
-
- return false;
-}
-
-/* extract USF from (E)GPRS RLC/MAC block */
-static uint8_t get_usf_from_block(struct msgb *msg)
-{
- /* FIXME: Ensure this will also work for EGPRS! */
- return msg->data[0] & 0x7;
-}
-
-/* MS is authorized to transmit a block in uplink for given USF on timeslot+arfcn at FN */
-static void ms_ul_tbf_may_transmit(struct l1_model_ms *ms, uint16_t arfcn, uint8_t timeslot,
- uint32_t fn, uint8_t usf)
-{
- struct msgb *msg;
-
- /* If USF is not for us, bail out */
- if (!usf_matches_ms(ms, usf, timeslot))
- return;
-
- /* attempt to de-queue pending msgb for this UL TBF and transmit it */
- msg = msgb_dequeue(&ms->state.tbf.ul.tx_queue);
- if (!msg) {
- printf("FN=%u, TN=%u, USF=%u: empty tx_queue, not transmitting\n", fn, timeslot, usf);
- /* FIXME: send some dummy control frame? */
- } else {
- printf("FN=%u, TN=%u, USF=%u: transmitting queued msg\n", fn, timeslot, usf);
- gsmtapl1_tx_to_virt_um_inst(ms, fn, timeslot, msg);
- }
-}
-
static void l1ctl_from_virt_um(struct l1ctl_sock_client *lsc, struct msgb *msg, uint32_t fn,
uint16_t arfcn, uint8_t timeslot, uint8_t subslot,
uint8_t gsmtap_chantype, uint8_t chan_nr, uint8_t link_id,
@@ -243,7 +165,6 @@ static void l1ctl_from_virt_um(struct l1ctl_sock_client *lsc, struct msgb *msg,
{
struct l1_model_ms *ms = lsc->priv;
uint8_t rxlev = dbm2rxlev(prim_pm_set_sig_strength(ms, arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM));
- uint8_t usf;
gsm_fn2gsmtime(&ms->state.downlink_time, fn);
@@ -310,16 +231,13 @@ static void l1ctl_from_virt_um(struct l1ctl_sock_client *lsc, struct msgb *msg,
case GSMTAP_CHANNEL_RACH:
LOGPMS(DVIRPHY, LOGL_NOTICE, ms, "Ignoring unexpected RACH in downlink ?!?\n");
break;
+ case GSMTAP_CHANNEL_PTCCH:
case GSMTAP_CHANNEL_PACCH:
case GSMTAP_CHANNEL_PDCH:
- if (gprs_dl_block_matches_ms(ms, msg, timeslot))
- l1ctl_tx_data_ind(ms, msg, arfcn, link_id, chan_nr, fn, snr_db, rxlev, 0, 0);
- usf = get_usf_from_block(msg);
- ms_ul_tbf_may_transmit(ms, arfcn, timeslot, fn, usf);
+ l1ctl_tx_gprs_dl_block_ind(ms, msg, fn, timeslot, rxlev);
break;
case GSMTAP_CHANNEL_SDCCH:
case GSMTAP_CHANNEL_CCCH:
- case GSMTAP_CHANNEL_PTCCH:
LOGPMS(DVIRPHY, LOGL_NOTICE, ms, "Ignoring unsupported channel type %s\n",
get_value_string(gsmtap_gsm_channel_names, gsmtap_chantype));
break;
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index ab917c6a..7e4540df 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -30,7 +30,6 @@
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/rsl.h>
-#include <osmocom/gprs/gprs_rlc.h>
#include <osmocom/bb/virtphy/virtual_um.h>
#include <osmocom/bb/virtphy/l1ctl_sock.h>
@@ -40,9 +39,7 @@
#include <osmocom/bb/virtphy/logging.h>
#include <osmocom/bb/virtphy/virt_l1_sched.h>
#include <osmocom/bb/l1ctl_proto.h>
-
-static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg);
-static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg);
+#include <osmocom/bb/l1gprs.h>
static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode)
{
@@ -60,7 +57,6 @@ static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode)
void l1ctl_sap_init(struct l1_model_ms *model)
{
INIT_LLIST_HEAD(&model->state.sched.mframe_items);
- INIT_LLIST_HEAD(&model->state.tbf.ul.tx_queue);
prim_pm_init(model);
}
@@ -163,8 +159,8 @@ static bool is_l1ctl_control(uint8_t msg_type)
switch (msg_type) {
case L1CTL_DATA_REQ:
case L1CTL_DATA_CONF:
- case L1CTL_DATA_TBF_REQ:
- case L1CTL_DATA_TBF_CONF:
+ case L1CTL_GPRS_UL_BLOCK_REQ:
+ case L1CTL_GPRS_DL_BLOCK_IND:
case L1CTL_TRAFFIC_REQ:
case L1CTL_TRAFFIC_CONF:
case L1CTL_TRAFFIC_IND:
@@ -247,11 +243,12 @@ void l1ctl_sap_handler(struct l1_model_ms *ms, struct msgb *msg)
case L1CTL_SIM_REQ:
l1ctl_rx_sim_req(ms, msg);
break;
- case L1CTL_TBF_CFG_REQ:
- l1ctl_rx_tbf_cfg_req(ms, msg);
+ case L1CTL_GPRS_UL_TBF_CFG_REQ:
+ case L1CTL_GPRS_DL_TBF_CFG_REQ:
+ l1ctl_rx_gprs_uldl_tbf_cfg_req(ms, msg);
break;
- case L1CTL_DATA_TBF_REQ:
- l1ctl_rx_data_tbf_req(ms, msg);
+ case L1CTL_GPRS_UL_BLOCK_REQ:
+ l1ctl_rx_gprs_ul_block_req(ms, msg);
goto exit_nofree;
}
@@ -297,6 +294,12 @@ void l1ctl_rx_dm_est_req(struct l1_model_ms *ms, struct msgb *msg)
ms->state.dedicated.subslot = subslot;
ms->state.state = MS_STATE_DEDICATED;
+ if (rsl_chantype == RSL_CHAN_OSMO_PDCH) {
+ OSMO_ASSERT(ms->gprs == NULL);
+ ms->gprs = l1gprs_state_alloc(ms, NULL, ms);
+ OSMO_ASSERT(ms->gprs != NULL);
+ }
+
/* TCH config */
if (rsl_chantype == RSL_CHAN_Bm_ACCHs || rsl_chantype == RSL_CHAN_Lm_ACCHs) {
ms->state.tch_mode = est_req->tch_mode;
@@ -381,6 +384,9 @@ void l1ctl_rx_dm_rel_req(struct l1_model_ms *ms, struct msgb *msg)
ms->state.tch_mode = GSM48_CMODE_SIGN;
ms->state.state = MS_STATE_IDLE_CAMPING;
+ l1gprs_state_free(ms->gprs);
+ ms->gprs = NULL;
+
/* TODO: disable ciphering */
/* TODO: disable audio recording / playing */
}
@@ -429,6 +435,8 @@ void l1ctl_rx_reset_req(struct l1_model_ms *ms, struct msgb *msg)
DEBUGPMS(DL1C, ms, "Rx L1CTL_RESET_REQ (type=FULL)\n");
ms->state.state = MS_STATE_IDLE_SEARCHING;
virt_l1_sched_stop(ms);
+ l1gprs_state_free(ms->gprs);
+ ms->gprs = NULL;
l1ctl_tx_reset(ms, L1CTL_RESET_CONF, reset_req->type);
break;
case L1CTL_RES_T_SCHED:
@@ -547,145 +555,12 @@ void l1ctl_rx_sim_req(struct l1_model_ms *ms, struct msgb *msg)
}
-static void l1ctl_tx_tbf_cfg_conf(struct l1_model_ms *ms, const struct l1ctl_tbf_cfg_req *in);
-
-static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg)
-{
- struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
- struct l1ctl_tbf_cfg_req *cfg_req = (struct l1ctl_tbf_cfg_req *) l1h->data;
- unsigned int i;
-
- LOGPMS(DL1C, LOGL_INFO, ms, "Rx L1CTL_TBF_CFG_REQ (tbf_id=%u, dir=%s, "
- "usf=[%d,%d,%d,%d,%d,%d,%d,%d]\n", cfg_req->tbf_nr,
- cfg_req->is_uplink ? "UL" : "DL", cfg_req->usf[0], cfg_req->usf[1],
- cfg_req->usf[2], cfg_req->usf[3], cfg_req->usf[4], cfg_req->usf[5],
- cfg_req->usf[6], cfg_req->usf[7]);
-
- if (cfg_req->tbf_nr != 0) {
- LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n");
- return;
- }
-
- if (ms->state.state == MS_STATE_DEDICATED)
- LOGPMS(DL1C, LOGL_NOTICE, ms, "Hard termination of DEDICATED mode, fix L23!\n");
-
- if (cfg_req->is_uplink) {
- for (i = 0; i < 8; i++)
- ms->state.tbf.ul.usf[i] = cfg_req->usf[i];
- } else {
- for (i = 0; i < 8; i++)
- ms->state.tbf.dl.tfi[i] = cfg_req->usf[i];
- }
- ms->state.state = MS_STATE_TBF;
-
- l1ctl_tx_tbf_cfg_conf(ms, cfg_req);
-}
-
-#if 0
-static const enum osmo_gprs_cs osmo_cs_by_l1ctl[] = {
- [L1CTL_CS_NONE] = OSMO_GPRS_CS_NONE,
- [L1CTL_CS1] = OSMO_GPRS_CS1,
- [L1CTL_CS2] = OSMO_GPRS_CS2,
- [L1CTL_CS3] = OSMO_GPRS_CS3,
- [L1CTL_CS4] = OSMO_GPRS_CS4,
- [L1CTL_MCS1] = OSMO_GPRS_MCS1,
- [L1CTL_MCS2] = OSMO_GPRS_MCS2,
- [L1CTL_MCS3] = OSMO_GPRS_MCS3,
- [L1CTL_MCS4] = OSMO_GPRS_MCS4,
- [L1CTL_MCS5] = OSMO_GPRS_MCS5,
- [L1CTL_MCS6] = OSMO_GPRS_MCS6,
- [L1CTL_MCS7] = OSMO_GPRS_MCS7,
- [L1CTL_MCS8] = OSMO_GPRS_MCS8,
- [L1CTL_MCS9] = OSMO_GPRS_MCS9,
-};
-
-static int get_osmo_cs_by_l1ctl(enum l1ctl_coding_scheme l1)
-{
- if (l1 >= ARRAY_SIZE(osmo_cs_by_l1ctl))
- return -1;
- return osmo_cs_by_l1ctl[l1];
-}
-#endif
-
-static const enum l1ctl_coding_scheme l1ctl_cs_by_osmo[] = {
- [OSMO_GPRS_CS_NONE] = L1CTL_CS_NONE,
- [OSMO_GPRS_CS1] = L1CTL_CS1,
- [OSMO_GPRS_CS2] = L1CTL_CS2,
- [OSMO_GPRS_CS3] = L1CTL_CS3,
- [OSMO_GPRS_CS4] = L1CTL_CS4,
- [OSMO_GPRS_MCS1] = L1CTL_MCS1,
- [OSMO_GPRS_MCS2] = L1CTL_MCS2,
- [OSMO_GPRS_MCS3] = L1CTL_MCS3,
- [OSMO_GPRS_MCS4] = L1CTL_MCS4,
- [OSMO_GPRS_MCS5] = L1CTL_MCS5,
- [OSMO_GPRS_MCS6] = L1CTL_MCS6,
- [OSMO_GPRS_MCS7] = L1CTL_MCS7,
- [OSMO_GPRS_MCS8] = L1CTL_MCS8,
- [OSMO_GPRS_MCS9] = L1CTL_MCS9,
-};
-
-static int get_l1ctl_cs_by_osmo(enum osmo_gprs_cs in)
-{
- if (in >= ARRAY_SIZE(l1ctl_cs_by_osmo))
- return -1;
- return l1ctl_cs_by_osmo[in];
-}
-
-static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg)
-{
- struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
- struct l1ctl_info_ul_tbf *udt = (struct l1ctl_info_ul_tbf *) l1h->data;
- enum osmo_gprs_cs osmo_cs;
- int block_size;
-
- msg->l2h = udt->payload;
-
- LOGPMS(DL1P, LOGL_ERROR, ms, "Rx L1CTL_DATA_TBF_REQ (tbf_id=%d, data=%s)\n",
- udt->tbf_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
- if (udt->tbf_nr != 0) {
- LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n");
- return;
- }
-
- if (ms->state.state != MS_STATE_TBF) {
- LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_TBF_REQ in state != TBF\n");
- return;
- }
-
- osmo_cs = get_l1ctl_cs_by_osmo(udt->coding_scheme);
- if (osmo_cs < 0) {
- LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_RBF_REQ with invalid CS\n");
- return;
- }
- block_size = osmo_gprs_ul_block_size_bytes(osmo_cs);
-
- if (msgb_l2len(msg) < block_size) {
- int pad_len = block_size - msgb_l2len(msg);
- uint8_t *pad = msgb_put(msg, pad_len);
- memset(pad, GSM_MACBLOCK_PADDING, pad_len);
- }
-
- msgb_enqueue(&ms->state.tbf.ul.tx_queue, msg);
-}
-
/***************************************************************
* L1CTL TX ROUTINES *******************************************
* For more routines check the respective handler classes ******
* like virt_prim_rach.c ***************************************
***************************************************************/
-static void l1ctl_tx_tbf_cfg_conf(struct l1_model_ms *ms, const struct l1ctl_tbf_cfg_req *in)
-{
- struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TBF_CFG_CONF);
- struct l1ctl_tbf_cfg_req *out;
-
- /* copy over the data from the request */
- out = (struct l1ctl_tbf_cfg_req *) msgb_put(msg, sizeof(*out));
- *out = *in;
-
- l1ctl_sap_tx_to_l23_inst(ms, msg);
-}
-
/**
* @brief Transmit L1CTL_RESET_IND or L1CTL_RESET_CONF to layer 23.
*
diff --git a/src/host/virt_phy/src/l1gprs.c b/src/host/virt_phy/src/l1gprs.c
new file mode 120000
index 00000000..0185f68b
--- /dev/null
+++ b/src/host/virt_phy/src/l1gprs.c
@@ -0,0 +1 @@
+../../../shared/l1gprs.c \ No newline at end of file
diff --git a/src/host/virt_phy/src/logging.c b/src/host/virt_phy/src/logging.c
index 04667d1f..0a1b2a41 100644
--- a/src/host/virt_phy/src/logging.c
+++ b/src/host/virt_phy/src/logging.c
@@ -54,10 +54,10 @@ static const char* l1ctlPrimNames[] = {
"L1CTL_TRAFFIC_CONF",
"L1CTL_TRAFFIC_IND",
"L1CTL_BURST_IND",
- "L1CTL_TBF_CFG_REQ",
- "L1CTL_TBF_CFG_CONF",
- "L1CTL_DATA_TBF_REQ",
- "L1CTL_DATA_TBF_CONF"
+ "L1CTL_GPRS_UL_TBF_CFG_REQ",
+ "L1CTL_GPRS_DL_TBF_CFG_REQ",
+ "L1CTL_GPRS_UL_BLOCK_REQ",
+ "L1CTL_GPRS_DL_BLOCK_IND",
};
static const struct log_info_cat default_categories[] = {
@@ -82,6 +82,13 @@ static const struct log_info_cat default_categories[] = {
.enabled = 1,
.loglevel = LOGL_NOTICE,
},
+ [DGPRS] = {
+ .name = "DGPRS",
+ .description = "L1 GPRS (MAC leyer)",
+ .color = "\033[1;31m",
+ .enabled = 1,
+ .loglevel = LOGL_NOTICE,
+ },
[DMAIN] = {
.name = "DMAIN",
.description = "Main Program / Data Structures",
diff --git a/src/host/virt_phy/src/virt_prim_pdch.c b/src/host/virt_phy/src/virt_prim_pdch.c
new file mode 100644
index 00000000..7125a70b
--- /dev/null
+++ b/src/host/virt_phy/src/virt_prim_pdch.c
@@ -0,0 +1,106 @@
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
+ *
+ * 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.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+
+#include <osmocom/bb/virtphy/l1ctl_sap.h>
+#include <osmocom/bb/virtphy/virt_l1_sched.h>
+#include <osmocom/bb/virtphy/gsmtapl1_if.h>
+#include <osmocom/bb/virtphy/logging.h>
+
+#include <osmocom/bb/l1ctl_proto.h>
+#include <osmocom/bb/l1gprs.h>
+
+void l1ctl_rx_gprs_uldl_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg)
+{
+ const struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+
+ if (OSMO_UNLIKELY(ms->gprs == NULL)) {
+ LOGPMS(DL1C, LOGL_ERROR, ms, "l1gprs is not initialized\n");
+ return;
+ }
+
+ msg->l1h = msgb_pull(msg, sizeof(*l1h));
+
+ if (l1h->msg_type == L1CTL_GPRS_UL_TBF_CFG_REQ)
+ l1gprs_handle_ul_tbf_cfg_req(ms->gprs, msg);
+ else
+ l1gprs_handle_dl_tbf_cfg_req(ms->gprs, msg);
+}
+
+void l1ctl_rx_gprs_ul_block_req(struct l1_model_ms *ms, struct msgb *msg)
+{
+ const struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
+ struct l1gprs_prim_ul_block_req req;
+ uint32_t fn_sched;
+
+ if (OSMO_UNLIKELY(ms->gprs == NULL)) {
+ LOGPMS(DL1P, LOGL_ERROR, ms, "l1gprs is not initialized\n");
+ return;
+ }
+
+ msg->l1h = (void *)l1h->data;
+ if (l1gprs_handle_ul_block_req(ms->gprs, &req, msg) != 0)
+ return;
+ msg->l2h = (void *)&req.data[0];
+
+ fn_sched = sched_fn_ul(ms->state.current_time,
+ RSL_CHAN_OSMO_PDCH | req.hdr.tn, 0x00);
+ if (OSMO_UNLIKELY(fn_sched != req.hdr.fn)) {
+ LOGPMS(DL1P, LOGL_ERROR, ms,
+ "GPRS UL BLOCK.req: fn_sched(%u) != fn_req(%u)\n",
+ fn_sched, req.hdr.fn);
+ /* FIXME: return; */
+ }
+
+ virt_l1_sched_schedule(ms, msg, fn_sched, req.hdr.tn,
+ &gsmtapl1_tx_to_virt_um_inst);
+}
+
+void l1ctl_tx_gprs_dl_block_ind(struct l1_model_ms *ms, const struct msgb *msg,
+ uint32_t fn, uint8_t tn, uint8_t rxlev)
+{
+ struct l1gprs_prim_dl_block_ind ind;
+ struct msgb *nmsg;
+
+ if (ms->gprs == NULL)
+ return;
+
+ ind = (struct l1gprs_prim_dl_block_ind) {
+ .hdr = {
+ .fn = fn,
+ .tn = tn,
+ },
+ .meas = {
+ .ber10k = 0, /* perfect Um, no errors */
+ .ci_cb = 180, /* 18 dB */
+ .rx_lev = rxlev,
+ },
+ .data = msgb_data(msg),
+ .data_len = msgb_length(msg),
+ };
+
+ nmsg = l1gprs_handle_dl_block_ind(ms->gprs, &ind);
+ if (nmsg != NULL)
+ l1ctl_sap_tx_to_l23_inst(ms, nmsg);
+}
diff --git a/src/host/virt_phy/src/virtphy.c b/src/host/virt_phy/src/virtphy.c
index ad09a53c..005ae2dd 100644
--- a/src/host/virt_phy/src/virtphy.c
+++ b/src/host/virt_phy/src/virtphy.c
@@ -40,8 +40,9 @@
#include <osmocom/bb/virtphy/gsmtapl1_if.h>
#include <osmocom/bb/virtphy/logging.h>
#include <osmocom/bb/virtphy/virt_l1_sched.h>
+#include <osmocom/bb/l1gprs.h>
-#define DEFAULT_LOG_MASK "DL1C,2:DL1P,2:DVIRPHY,2:DMAIN,1"
+#define DEFAULT_LOG_MASK "DL1C,2:DL1P,2:DVIRPHY,2:DGPRS,1:DMAIN,1"
/* this exists once in the program, and contains the state that we
* only keep once: L1CTL server socket, GSMTAP/VirtUM socket */
@@ -242,6 +243,7 @@ int main(int argc, char *argv[])
handle_options(argc, argv);
ms_log_init(log_mask);
+ l1gprs_logging_init(DGPRS);
LOGP(DVIRPHY, LOGL_INFO, "Virtual physical layer starting up...\n");