summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2023-06-09 21:58:48 +0700
committerPau Espin Pedrol <pespin@sysmocom.de>2023-07-24 14:00:41 +0200
commit3f0f1a421497657589268e5f4a37811232b05474 (patch)
treece27b13a1caec6849ae2be28634bdc6c63c17d05
parent19450eb435e07649b1f48201526ffda17f1e0219 (diff)
layer23: modem: implement GPRS-RR FSM
-rw-r--r--src/host/layer23/include/osmocom/bb/common/ms.h1
-rw-r--r--src/host/layer23/include/osmocom/bb/modem/grr.h23
-rw-r--r--src/host/layer23/src/modem/app_modem.c41
-rw-r--r--src/host/layer23/src/modem/grr.c338
-rw-r--r--src/host/layer23/src/modem/rlcmac.c60
-rw-r--r--src/host/layer23/src/modem/vty.c11
6 files changed, 341 insertions, 133 deletions
diff --git a/src/host/layer23/include/osmocom/bb/common/ms.h b/src/host/layer23/include/osmocom/bb/common/ms.h
index bfbf879a..8d1ffc4e 100644
--- a/src/host/layer23/include/osmocom/bb/common/ms.h
+++ b/src/host/layer23/include/osmocom/bb/common/ms.h
@@ -100,6 +100,7 @@ struct osmocom_ms {
/* GPRS */
struct gprs_settings gprs;
struct osmobb_ms_gmm_layer gmmlayer;
+ struct osmo_fsm_inst *grr_fi;
/* Audio I/O */
struct gapk_io_state *gapk_io;
diff --git a/src/host/layer23/include/osmocom/bb/modem/grr.h b/src/host/layer23/include/osmocom/bb/modem/grr.h
index 1f2b08c0..3472a103 100644
--- a/src/host/layer23/include/osmocom/bb/modem/grr.h
+++ b/src/host/layer23/include/osmocom/bb/modem/grr.h
@@ -6,7 +6,28 @@
struct msgb;
struct osmocom_ms;
struct lapdm_entity;
+struct osmo_fsm;
+
+enum grr_fsm_state {
+ GRR_ST_PACKET_NOT_READY,
+ GRR_ST_PACKET_IDLE,
+ GRR_ST_PACKET_TRANSFER,
+};
+
+enum grr_fsm_event {
+ GRR_EV_BCCH_BLOCK_IND,
+ GRR_EV_PCH_AGCH_BLOCK_IND,
+ GRR_EV_RACH_REQ,
+ GRR_EV_RACH_CNF,
+ GRR_EV_PDCH_ESTABLISH_REQ,
+ GRR_EV_PDCH_RELEASE_REQ,
+ GRR_EV_PDCH_UL_TBF_CFG_REQ,
+ GRR_EV_PDCH_DL_TBF_CFG_REQ,
+ GRR_EV_PDCH_BLOCK_REQ,
+ GRR_EV_PDCH_BLOCK_IND,
+};
+
+extern struct osmo_fsm grr_fsm_def;
int modem_grr_rslms_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx);
-int modem_grr_tx_chan_req(struct osmocom_ms *ms, uint8_t chan_req);
uint8_t modem_grr_gen_chan_req(bool single_block);
diff --git a/src/host/layer23/src/modem/app_modem.c b/src/host/layer23/src/modem/app_modem.c
index fdb38212..6871384e 100644
--- a/src/host/layer23/src/modem/app_modem.c
+++ b/src/host/layer23/src/modem/app_modem.c
@@ -62,34 +62,6 @@
struct modem_app app_data;
-static bool modem_can_gprs_attach(const struct osmocom_ms *ms)
-{
- const struct gsm_subscriber *subscr = &ms->subscr;
- const struct gsm322_cellsel *cs = &ms->cellsel;
- const struct gsm48_sysinfo *si = &cs->sel_si;
-
- if (!subscr->sim_valid)
- goto ret_false;
-
- if (!si->si1 || !si->si3 || !si->si4 || !si->si13)
- goto ret_false;
-
- if (!si->gprs.supported)
- goto ret_false;
-
- return true;
-
-ret_false:
- LOGP(DRLCMAC, LOGL_INFO, "Delaying GPRS attach, waiting for:%s%s%s%s%s%s\n",
- subscr->sim_valid ? "" : " imsi",
- si->si1 ? "" : " si1",
- si->si3 ? "" : " si3",
- si->si4 ? "" : " si4",
- si->si13 ? "" : " si13",
- si->gprs.supported ? "" : " GprsIndicator");
- return false;
-}
-
int modem_gprs_attach_if_needed(struct osmocom_ms *ms)
{
int rc;
@@ -97,7 +69,10 @@ int modem_gprs_attach_if_needed(struct osmocom_ms *ms)
if (app_data.modem_state != MODEM_ST_IDLE)
return 0;
- if (!modem_can_gprs_attach(ms))
+ if (ms->grr_fi->state == GRR_ST_PACKET_NOT_READY)
+ return 0;
+
+ if (!ms->subscr.sim_valid)
return 0;
app_data.modem_state = MODEM_ST_ATTACHING;
@@ -201,6 +176,8 @@ static int global_signal_cb(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_L1CTL_RESET:
ms = signal_data;
+ if (ms->started)
+ break;
layer3_app_reset();
app_data.ms = ms;
@@ -285,6 +262,12 @@ int l23_app_init(void)
return rc;
}
+ /* TODO: move to a separate function */
+ app_data.ms->grr_fi = osmo_fsm_inst_alloc(&grr_fsm_def, NULL,
+ app_data.ms, LOGL_DEBUG,
+ app_data.ms->name);
+ OSMO_ASSERT(app_data.ms->grr_fi != NULL);
+
osmo_signal_register_handler(SS_L1CTL, &global_signal_cb, NULL);
osmo_signal_register_handler(SS_L23_SUBSCR, &modem_l23_subscr_signal_cb, NULL);
lapdm_channel_set_l3(&app_data.ms->lapdm_channel, &modem_grr_rslms_cb, app_data.ms);
diff --git a/src/host/layer23/src/modem/grr.c b/src/host/layer23/src/modem/grr.c
index bd55f300..a7185fe3 100644
--- a/src/host/layer23/src/modem/grr.c
+++ b/src/host/layer23/src/modem/grr.c
@@ -1,5 +1,8 @@
/*
* (C) 2022-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
+ *
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +26,7 @@
#include <string.h>
#include <errno.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
@@ -41,6 +45,7 @@
#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/common/ms.h>
#include <osmocom/bb/modem/modem.h>
+#include <osmocom/bb/modem/grr.h>
#include <osmocom/bb/mobile/gsm322.h>
#include <osmocom/bb/mobile/gsm48_rr.h>
@@ -87,29 +92,6 @@ static bool grr_match_req_ref(struct osmocom_ms *ms,
return false;
}
-int modem_grr_tx_chan_req(struct osmocom_ms *ms, uint8_t chan_req)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm48_rrlayer *rr = &ms->rrlayer;
-
- OSMO_ASSERT(rr->state == GSM48_RR_ST_IDLE);
-
- if (!cs->sel_si.si1 || !cs->sel_si.si13)
- return -EAGAIN;
- if (!cs->sel_si.gprs.supported)
- return -ENOTSUP;
-
- rr->cr_ra = chan_req;
- memset(&rr->cr_hist[0], 0x00, sizeof(rr->cr_hist));
-
- LOGP(DRR, LOGL_NOTICE, "Sending CHANNEL REQUEST (0x%02x)\n", rr->cr_ra);
- l1ctl_tx_rach_req(ms, RSL_CHAN_RACH, 0x00, rr->cr_ra, 0,
- cs->ccch_mode == CCCH_MODE_COMBINED);
-
- rr->state = GSM48_RR_ST_CONN_PEND;
- return 0;
-}
-
static int forward_to_rlcmac(struct osmocom_ms *ms, struct msgb *msg)
{
struct osmo_gprs_rlcmac_prim *rlcmac_prim;
@@ -135,7 +117,6 @@ static int grr_handle_si1(struct osmocom_ms *ms, struct msgb *msg)
return rc;
}
- modem_gprs_attach_if_needed(ms);
return 0;
}
@@ -171,7 +152,6 @@ static int grr_handle_si3(struct osmocom_ms *ms, struct msgb *msg)
LOGP(DRR, LOGL_NOTICE, "Found GPRS Indicator (RA Colour %u, SI13 on BCCH %s)\n",
cs->sel_si.gprs.ra_colour, cs->sel_si.gprs.si13_pos ? "Ext" : "Norm");
- modem_gprs_attach_if_needed(ms);
return 0;
}
@@ -199,7 +179,6 @@ static int grr_handle_si4(struct osmocom_ms *ms, struct msgb *msg)
LOGP(DRR, LOGL_NOTICE, "Found GPRS Indicator (RA Colour %u, SI13 on BCCH %s)\n",
cs->sel_si.gprs.ra_colour, cs->sel_si.gprs.si13_pos ? "Ext" : "Norm");
- modem_gprs_attach_if_needed(ms);
return 0;
}
@@ -218,10 +197,7 @@ static int grr_handle_si13(struct osmocom_ms *ms, struct msgb *msg)
return rc;
/* Forward SI13 to RLC/MAC layer */
- rc = forward_to_rlcmac(ms, msg);
-
- modem_gprs_attach_if_needed(ms);
- return rc;
+ return forward_to_rlcmac(ms, msg);
}
static int grr_rx_bcch(struct osmocom_ms *ms, struct msgb *msg)
@@ -299,6 +275,11 @@ static int grr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
return -EINVAL;
}
+ /* FIXME: this event should be triggered by the RLC/MAC layers itself */
+ rc = osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_PDCH_ESTABLISH_REQ, NULL);
+ if (rc != 0)
+ return rc;
+
if (!ia->chan_desc.h0.h) {
/* Non-hopping */
uint16_t arfcn;
@@ -349,7 +330,6 @@ static int grr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
if (rc < 0)
return rc;
- rr->state = GSM48_RR_ST_DEDICATED;
return 0;
}
@@ -461,9 +441,9 @@ static int grr_rx_rslms_rll_ud(struct osmocom_ms *ms, struct msgb *msg)
switch (rllh->chan_nr) {
case RSL_CHAN_PCH_AGCH:
- return grr_rx_ccch(ms, msg);
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_PCH_AGCH_BLOCK_IND, msg);
case RSL_CHAN_BCCH:
- return grr_rx_bcch(ms, msg);
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_BCCH_BLOCK_IND, msg);
default:
return 0;
}
@@ -486,25 +466,11 @@ static int grr_rx_rslms_rll(struct osmocom_ms *ms, struct msgb *msg)
static int grr_rx_rslms_cchan(struct osmocom_ms *ms, struct msgb *msg)
{
const struct abis_rsl_cchan_hdr *ch = msgb_l2(msg);
- struct gsm48_rrlayer *rr = &ms->rrlayer;
switch (ch->c.msg_type) {
case RSL_MT_CHAN_CONF: /* RACH.conf */
- if (rr->state == GSM48_RR_ST_CONN_PEND) {
- const struct gsm48_req_ref *ref = (void *)&ch->data[1];
- LOGP(DRSL, LOGL_NOTICE,
- "Rx RACH.conf (RA=0x%02x, T1=%u, T3=%u, T2=%u, FN=%u)\n",
- rr->cr_ra, ref->t1, ref->t3_high << 3 | ref->t3_low, ref->t2,
- _gsm48_req_ref2fn(ref));
- /* shift the CHANNEL REQUEST history buffer */
- memmove(&rr->cr_hist[1], &rr->cr_hist[0], ARRAY_SIZE(rr->cr_hist) - 1);
- /* store the new entry */
- rr->cr_hist[0].ref = *ref;
- rr->cr_hist[0].ref.ra = rr->cr_ra;
- rr->cr_hist[0].valid = 1;
- return 0;
- }
- /* fall-through */
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_RACH_CNF,
+ (void *)&ch->data[1]);
default:
LOGP(DRSL, LOGL_NOTICE, "Unhandled RSLms CCHAN message "
"(msg_type 0x%02x)\n", ch->c.msg_type);
@@ -534,3 +500,277 @@ int modem_grr_rslms_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
msgb_free(msg);
return rc;
}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define S(x) (1 << (x))
+
+#include <osmocom/gsm/gsm0502.h> // XXX
+
+static void handle_pdch_block_ind(struct osmocom_ms *ms, struct msgb *msg)
+{
+ const struct l1ctl_gprs_dl_block_ind *ind = (void *)msg->l1h;
+ const uint32_t fn = osmo_load32be(&ind->hdr.fn);
+ struct osmo_gprs_rlcmac_prim *prim;
+
+ /* FIXME: sadly, rlcmac_prim_l1ctl_alloc() is not exposed */
+ prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_data_ind(0, 0, 0, 0, 0, NULL, 0);
+ prim->l1ctl = (struct osmo_gprs_rlcmac_l1ctl_prim) {
+ .pdch_data_ind = {
+ .fn = fn,
+ .ts_nr = ind->hdr.tn,
+ .rx_lev = ind->meas.rx_lev,
+ .ber10k = osmo_load16be(&ind->meas.ber10k),
+ .ci_cb = osmo_load16be(&ind->meas.ci_cb),
+ .data_len = msgb_l2len(msg),
+ .data = msgb_l2(msg),
+ }
+ };
+ osmo_gprs_rlcmac_prim_lower_up(prim);
+
+ /* Do not send RTS.ind if we got PTCCH/D */
+ if (fn % 104 == 12)
+ return;
+
+ /* Every fn % 13 == 12 we have either a PTCCH or an IDLE slot, thus
+ * every fn % 13 == 8 we add 5 frames, or 4 frames othrwise. The
+ * resulting value is first fn of the next block. */
+ const uint32_t rts_fn = GSM_TDMA_FN_SUM(fn, (fn % 13 == 8) ? 5 : 4);
+ prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_rts_ind(ind->hdr.tn, rts_fn, ind->usf);
+ osmo_gprs_rlcmac_prim_lower_up(prim);
+}
+
+static bool grr_cell_is_usable(const struct osmocom_ms *ms)
+{
+ const struct gsm322_cellsel *cs = &ms->cellsel;
+ const struct gsm48_sysinfo *si = &cs->sel_si;
+
+ if (!si->si1 || !si->si3 || !si->si4 || !si->si13)
+ return false;
+ if (!si->gprs.supported)
+ return false;
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void grr_st_packet_not_ready_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct osmocom_ms *ms = fi->priv;
+
+ switch (event) {
+ case GRR_EV_BCCH_BLOCK_IND:
+ grr_rx_bcch(ms, (struct msgb *)data);
+ if (grr_cell_is_usable(ms)) {
+ LOGPFSML(fi, LOGL_NOTICE, "Cell is usable, GRR becomes ready\n");
+ osmo_fsm_inst_state_chg(fi, GRR_ST_PACKET_IDLE, 0, 0);
+ }
+ break;
+ case GRR_EV_PCH_AGCH_BLOCK_IND:
+ grr_rx_ccch(ms, (struct msgb *)data);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void grr_st_packet_idle_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct osmocom_ms *ms = fi->priv;
+
+ modem_gprs_attach_if_needed(ms);
+}
+
+static void grr_st_packet_idle_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct osmocom_ms *ms = fi->priv;
+
+ switch (event) {
+ case GRR_EV_BCCH_BLOCK_IND:
+ grr_rx_bcch(ms, (struct msgb *)data);
+ if (!grr_cell_is_usable(ms)) {
+ LOGPFSML(fi, LOGL_NOTICE, "Cell is not usable, GRR becomes not ready\n");
+ osmo_fsm_inst_state_chg(fi, GRR_ST_PACKET_NOT_READY, 0, 0);
+ }
+ break;
+ case GRR_EV_PCH_AGCH_BLOCK_IND:
+ grr_rx_ccch(ms, (struct msgb *)data);
+ break;
+ case GRR_EV_RACH_REQ:
+ {
+ const struct osmo_gprs_rlcmac_l1ctl_prim *lp = data;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+
+ if (lp->rach_req.is_11bit) { /* TODO: implement 11-bit RACH */
+ LOGPFSML(fi, LOGL_ERROR, "11-bit RACH is not supported\n");
+ return;
+ }
+
+ rr->cr_ra = lp->rach_req.ra;
+ memset(&rr->cr_hist[0], 0x00, sizeof(rr->cr_hist));
+
+ LOGPFSML(fi, LOGL_INFO, "Sending CHANNEL REQUEST (0x%02x)\n", rr->cr_ra);
+ l1ctl_tx_rach_req(ms, RSL_CHAN_RACH, 0x00, rr->cr_ra, 0,
+ ms->cellsel.ccch_mode == CCCH_MODE_COMBINED);
+
+ rr->state = GSM48_RR_ST_CONN_PEND;
+ break;
+ }
+ case GRR_EV_RACH_CNF:
+ {
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ const struct gsm48_req_ref *ref = data;
+
+ LOGPFSML(fi, LOGL_NOTICE,
+ "Rx RACH.conf (RA=0x%02x, T1=%u, T3=%u, T2=%u, FN=%u)\n",
+ rr->cr_ra, ref->t1, ref->t3_high << 3 | ref->t3_low, ref->t2,
+ _gsm48_req_ref2fn(ref));
+
+ if (ms->rrlayer.state != GSM48_RR_ST_CONN_PEND) {
+ LOGPFSML(fi, LOGL_ERROR, "Rx unexpected RACH.conf\n");
+ return;
+ }
+
+ /* shift the CHANNEL REQUEST history buffer */
+ memmove(&rr->cr_hist[1], &rr->cr_hist[0], ARRAY_SIZE(rr->cr_hist) - 1);
+ /* store the new entry */
+ rr->cr_hist[0].ref = *ref;
+ rr->cr_hist[0].ref.ra = rr->cr_ra;
+ rr->cr_hist[0].valid = 1;
+ break;
+ }
+ case GRR_EV_PDCH_ESTABLISH_REQ:
+ /* TODO: send L1CTL_DM_EST_REQ here */
+ osmo_fsm_inst_state_chg(fi, GRR_ST_PACKET_TRANSFER, 0, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void grr_st_packet_transfer_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct osmocom_ms *ms = fi->priv;
+
+ ms->rrlayer.state = GSM48_RR_ST_DEDICATED;
+}
+
+static void grr_st_packet_transfer_onleave(struct osmo_fsm_inst *fi, uint32_t next_state)
+{
+ struct osmocom_ms *ms = fi->priv;
+
+ ms->rrlayer.state = GSM48_RR_ST_IDLE;
+}
+
+static void grr_st_packet_transfer_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct osmocom_ms *ms = fi->priv;
+
+ switch (event) {
+ case GRR_EV_PDCH_UL_TBF_CFG_REQ:
+ {
+ const struct osmo_gprs_rlcmac_l1ctl_prim *lp = data;
+ l1ctl_tx_gprs_ul_tbf_cfg_req(ms,
+ lp->cfg_ul_tbf_req.ul_tbf_nr,
+ lp->cfg_ul_tbf_req.ul_slotmask);
+ break;
+ }
+ case GRR_EV_PDCH_DL_TBF_CFG_REQ:
+ {
+ const struct osmo_gprs_rlcmac_l1ctl_prim *lp = data;
+ l1ctl_tx_gprs_dl_tbf_cfg_req(ms,
+ lp->cfg_dl_tbf_req.dl_tbf_nr,
+ lp->cfg_dl_tbf_req.dl_slotmask,
+ lp->cfg_dl_tbf_req.dl_tfi);
+ break;
+ }
+ case GRR_EV_PDCH_BLOCK_REQ:
+ {
+ const struct osmo_gprs_rlcmac_l1ctl_prim *lp = data;
+ l1ctl_tx_gprs_ul_block_req(ms,
+ lp->pdch_data_req.fn,
+ lp->pdch_data_req.ts_nr,
+ lp->pdch_data_req.data,
+ lp->pdch_data_req.data_len);
+ break;
+ }
+ case GRR_EV_PDCH_BLOCK_IND:
+ handle_pdch_block_ind(ms, (struct msgb *)data);
+ break;
+ case GRR_EV_PDCH_RELEASE_REQ:
+ l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
+ l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
+ L1CTL_FBSB_F_FB01SB, 100, 0,
+ ms->cellsel.ccch_mode, dbm2rxlev(-85));
+ osmo_fsm_inst_state_chg(fi, GRR_ST_PACKET_IDLE, 0, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static const struct osmo_fsm_state grr_fsm_states[] = {
+ [GRR_ST_PACKET_NOT_READY] = {
+ .name = "PACKET_NOT_READY",
+ .out_state_mask = S(GRR_ST_PACKET_IDLE),
+ .in_event_mask = S(GRR_EV_BCCH_BLOCK_IND)
+ | S(GRR_EV_PCH_AGCH_BLOCK_IND),
+ .action = &grr_st_packet_not_ready_action,
+ },
+ [GRR_ST_PACKET_IDLE] = {
+ .name = "PACKET_IDLE",
+ .out_state_mask = S(GRR_ST_PACKET_NOT_READY)
+ | S(GRR_ST_PACKET_TRANSFER),
+ .in_event_mask = S(GRR_EV_BCCH_BLOCK_IND)
+ | S(GRR_EV_PCH_AGCH_BLOCK_IND)
+ | S(GRR_EV_RACH_REQ)
+ | S(GRR_EV_RACH_CNF)
+ | S(GRR_EV_PDCH_ESTABLISH_REQ),
+ .action = &grr_st_packet_idle_action,
+ .onenter = &grr_st_packet_idle_onenter,
+ },
+ [GRR_ST_PACKET_TRANSFER] = {
+ .name = "PACKET_TRANSFER",
+ .out_state_mask = S(GRR_ST_PACKET_NOT_READY)
+ | S(GRR_ST_PACKET_IDLE),
+ .in_event_mask = S(GRR_EV_PDCH_UL_TBF_CFG_REQ)
+ | S(GRR_EV_PDCH_DL_TBF_CFG_REQ)
+ | S(GRR_EV_PDCH_BLOCK_REQ)
+ | S(GRR_EV_PDCH_BLOCK_IND)
+ | S(GRR_EV_PDCH_RELEASE_REQ),
+ .action = &grr_st_packet_transfer_action,
+ .onenter = &grr_st_packet_transfer_onenter,
+ .onleave = &grr_st_packet_transfer_onleave,
+ },
+};
+
+static const struct value_string grr_fsm_event_names[] = {
+ OSMO_VALUE_STRING(GRR_EV_BCCH_BLOCK_IND),
+ OSMO_VALUE_STRING(GRR_EV_PCH_AGCH_BLOCK_IND),
+ OSMO_VALUE_STRING(GRR_EV_RACH_REQ),
+ OSMO_VALUE_STRING(GRR_EV_RACH_CNF),
+ OSMO_VALUE_STRING(GRR_EV_PDCH_ESTABLISH_REQ),
+ OSMO_VALUE_STRING(GRR_EV_PDCH_RELEASE_REQ),
+ OSMO_VALUE_STRING(GRR_EV_PDCH_UL_TBF_CFG_REQ),
+ OSMO_VALUE_STRING(GRR_EV_PDCH_DL_TBF_CFG_REQ),
+ OSMO_VALUE_STRING(GRR_EV_PDCH_BLOCK_REQ),
+ OSMO_VALUE_STRING(GRR_EV_PDCH_BLOCK_IND),
+ { 0, NULL }
+};
+
+struct osmo_fsm grr_fsm_def = {
+ .name = "GPRS-RR",
+ .log_subsys = DRR,
+ .states = grr_fsm_states,
+ .num_states = ARRAY_SIZE(grr_fsm_states),
+ .event_names = grr_fsm_event_names,
+};
+
+static __attribute__((constructor)) void on_dso_load(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&grr_fsm_def) == 0);
+}
diff --git a/src/host/layer23/src/modem/rlcmac.c b/src/host/layer23/src/modem/rlcmac.c
index fcd2b2ea..d209ec49 100644
--- a/src/host/layer23/src/modem/rlcmac.c
+++ b/src/host/layer23/src/modem/rlcmac.c
@@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/prim.h>
@@ -38,13 +39,10 @@
#include <osmocom/gprs/gmm/gmm_prim.h>
#include <osmocom/bb/common/logging.h>
-#include <osmocom/bb/common/l1ctl.h>
#include <osmocom/bb/common/ms.h>
#include <osmocom/bb/modem/rlcmac.h>
#include <osmocom/bb/modem/grr.h>
-#include <l1ctl_proto.h>
-
static int modem_rlcmac_handle_grr(struct osmo_gprs_rlcmac_prim *rlcmac_prim)
{
int rc;
@@ -141,33 +139,19 @@ static int modem_rlcmac_prim_up_cb(struct osmo_gprs_rlcmac_prim *rlcmac_prim, vo
static int modem_rlcmac_prim_down_cb(struct osmo_gprs_rlcmac_prim *prim, void *user_data)
{
- const struct osmo_gprs_rlcmac_l1ctl_prim *lp = &prim->l1ctl;
+ struct osmo_gprs_rlcmac_l1ctl_prim *lp = &prim->l1ctl;
const char *pdu_name = osmo_gprs_rlcmac_prim_name(prim);
struct osmocom_ms *ms = user_data;
switch (OSMO_PRIM_HDR(&prim->oph)) {
case OSMO_PRIM(OSMO_GPRS_RLCMAC_L1CTL_RACH, PRIM_OP_REQUEST):
- if (lp->rach_req.is_11bit) {
- LOGP(DRLCMAC, LOGL_NOTICE,
- "%s(): 11-bit RACH is not supported\n", __func__);
- return -ENOTSUP;
- }
- return modem_grr_tx_chan_req(ms, lp->rach_req.ra);
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_RACH_REQ, lp);
case OSMO_PRIM(OSMO_GPRS_RLCMAC_L1CTL_PDCH_DATA, PRIM_OP_REQUEST):
- return l1ctl_tx_gprs_ul_block_req(ms,
- lp->pdch_data_req.fn,
- lp->pdch_data_req.ts_nr,
- lp->pdch_data_req.data,
- lp->pdch_data_req.data_len);
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_PDCH_BLOCK_REQ, lp);
case OSMO_PRIM(OSMO_GPRS_RLCMAC_L1CTL_CFG_UL_TBF, PRIM_OP_REQUEST):
- return l1ctl_tx_gprs_ul_tbf_cfg_req(ms,
- lp->cfg_ul_tbf_req.ul_tbf_nr,
- lp->cfg_ul_tbf_req.ul_slotmask);
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_PDCH_UL_TBF_CFG_REQ, lp);
case OSMO_PRIM(OSMO_GPRS_RLCMAC_L1CTL_CFG_DL_TBF, PRIM_OP_REQUEST):
- return l1ctl_tx_gprs_dl_tbf_cfg_req(ms,
- lp->cfg_dl_tbf_req.dl_tbf_nr,
- lp->cfg_dl_tbf_req.dl_slotmask,
- lp->cfg_dl_tbf_req.dl_tfi);
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_PDCH_DL_TBF_CFG_REQ, lp);
default:
LOGP(DRLCMAC, LOGL_DEBUG, "%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
@@ -176,37 +160,7 @@ static int modem_rlcmac_prim_down_cb(struct osmo_gprs_rlcmac_prim *prim, void *u
static int l1ctl_dl_block_cb(struct osmocom_ms *ms, struct msgb *msg)
{
- const struct l1ctl_gprs_dl_block_ind *ind = (void *)msg->l1h;
- const uint32_t fn = osmo_load32be(&ind->hdr.fn);
- struct osmo_gprs_rlcmac_prim *prim;
-
- /* FIXME: sadly, rlcmac_prim_l1ctl_alloc() is not exposed */
- prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_data_ind(0, 0, 0, 0, 0, NULL, 0);
- prim->l1ctl = (struct osmo_gprs_rlcmac_l1ctl_prim) {
- .pdch_data_ind = {
- .fn = fn,
- .ts_nr = ind->hdr.tn,
- .rx_lev = ind->meas.rx_lev,
- .ber10k = osmo_load16be(&ind->meas.ber10k),
- .ci_cb = osmo_load16be(&ind->meas.ci_cb),
- .data_len = msgb_l2len(msg),
- .data = msgb_l2(msg),
- }
- };
- osmo_gprs_rlcmac_prim_lower_up(prim);
-
- /* Do not send RTS.ind if we got PTCCH/D */
- if (fn % 104 == 12)
- return 0;
-
- /* Every fn % 13 == 12 we have either a PTCCH or an IDLE slot, thus
- * every fn % 13 == 8 we add 5 frames, or 4 frames othrwise. The
- * resulting value is first fn of the next block. */
- const uint32_t rts_fn = GSM_TDMA_FN_SUM(fn, (fn % 13 == 8) ? 5 : 4);
- prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_rts_ind(ind->hdr.tn, rts_fn, ind->usf);
- osmo_gprs_rlcmac_prim_lower_up(prim);
-
- return 0;
+ return osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_PDCH_BLOCK_IND, msg);
}
int modem_rlcmac_init(struct osmocom_ms *ms)
diff --git a/src/host/layer23/src/modem/vty.c b/src/host/layer23/src/modem/vty.c
index d827993e..da291658 100644
--- a/src/host/layer23/src/modem/vty.c
+++ b/src/host/layer23/src/modem/vty.c
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/linuxlist.h>
@@ -27,6 +28,7 @@
#include <osmocom/gprs/llc/llc_prim.h>
#include <osmocom/gprs/gmm/gmm_prim.h>
#include <osmocom/gprs/sm/sm_prim.h>
+#include <osmocom/gprs/rlcmac/rlcmac_prim.h>
#include <osmocom/vty/vty.h>
@@ -84,7 +86,14 @@ DEFUN_HIDDEN(test_grr_tx_chan_req,
return CMD_WARNING;
chan_req = modem_grr_gen_chan_req(argv[1][0] == '2');
- if (modem_grr_tx_chan_req(ms, chan_req) != 0) {
+ const struct osmo_gprs_rlcmac_l1ctl_prim lp = {
+ .rach_req = {
+ .is_11bit = false,
+ .ra = chan_req,
+ }
+ };
+
+ if (osmo_fsm_inst_dispatch(ms->grr_fi, GRR_EV_RACH_REQ, (void *)&lp)) {
vty_out(vty, "Failed to send a CHANNEL REQUEST%s", VTY_NEWLINE);
return CMD_WARNING;
}