fixeria has submitted this change. (
https://gerrit.osmocom.org/c/osmocom-bb/+/28809 )
Change subject: trxcon: rework trxcon_fsm, move into a separate file
......................................................................
trxcon: rework trxcon_fsm, move into a separate file
The original trxcon_fsm I wrote back in 2017 [1] was more like
a boolean flag, as there were only two states: IDLE and MANAGED.
Not surprising, given that until recently handling of multiple
L1CTL connections was not supported. Now that we have this
implemented, lifetime of a trxcon_fsm instance is limited by
lifetime of a L1CTL connection, what renders the FSM useless.
This change removes the old 'boolean' trxcon_fsm and introduces
the new one, which will allows us to abstract the L1CTL interface
from the TRXC/TRXD interfaces, as well as the scheduler. The new
FSM will also simplify development of the RLC/MAC layer for GPRS.
Change-Id: Ifaf63ead9dd180181358e771367b2a686ba159ca
Related: [1] I7ee6fc891abe5f775f5b7ebbf093181a97950dea
Related: OS#5599
---
M src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
M src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h
M src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
M src/host/trxcon/src/Makefile.am
M src/host/trxcon/src/l1ctl.c
M src/host/trxcon/src/trx_if.c
M src/host/trxcon/src/trxcon.c
A src/host/trxcon/src/trxcon_fsm.c
8 files changed, 787 insertions(+), 411 deletions(-)
Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
pespin: Looks good to me, but someone else must approve
fixeria: Looks good to me, approved
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
index 2c48eae..3f7dae0 100644
--- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
+++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <stdbool.h>
+#include <arpa/inet.h>
+
#include <osmocom/core/bits.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h
b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h
index e15d5a2..9518bb9 100644
--- a/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h
+++ b/src/host/trxcon/include/osmocom/bb/trxcon/l1ctl.h
@@ -9,8 +9,8 @@
/* Event handlers */
int l1ctl_rx_cb(struct l1ctl_client *l1c, struct msgb *msg);
-int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint8_t result,
- const struct l1ctl_info_dl *dl_info, uint8_t bsic);
+int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint16_t band_arfcn, uint8_t bsic);
+int l1ctl_tx_fbsb_fail(struct l1ctl_client *l1c, uint16_t band_arfcn);
int l1ctl_tx_ccch_mode_conf(struct l1ctl_client *l1c, uint8_t mode);
int l1ctl_tx_pm_conf(struct l1ctl_client *l1c, uint16_t band_arfcn,
int dbm, int last);
diff --git a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
index da47f8b..b982193 100644
--- a/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
+++ b/src/host/trxcon/include/osmocom/bb/trxcon/trxcon.h
@@ -4,19 +4,127 @@
struct trx_instance;
struct l1ctl_client;
+extern struct osmo_fsm trxcon_fsm_def;
+
enum trxcon_fsm_states {
- TRXCON_STATE_IDLE = 0,
- TRXCON_STATE_MANAGED,
+ TRXCON_ST_RESET,
+ TRXCON_ST_FULL_POWER_SCAN,
+ TRXCON_ST_FBSB_SEARCH,
+ TRXCON_ST_BCCH_CCCH,
+ TRXCON_ST_DEDICATED,
};
enum trxcon_fsm_events {
- /* L1CTL specific events */
- L1CTL_EVENT_CONNECT,
- L1CTL_EVENT_DISCONNECT,
+ TRXCON_EV_L1IF_FAILURE,
+ TRXCON_EV_L2IF_FAILURE,
+ TRXCON_EV_RESET_FULL_REQ,
+ TRXCON_EV_RESET_SCHED_REQ,
+ TRXCON_EV_FULL_POWER_SCAN_REQ,
+ TRXCON_EV_FULL_POWER_SCAN_RES,
+ TRXCON_EV_FBSB_SEARCH_REQ,
+ TRXCON_EV_FBSB_SEARCH_RES,
+ TRXCON_EV_SET_CCCH_MODE_REQ,
+ TRXCON_EV_SET_TCH_MODE_REQ,
+ TRXCON_EV_SET_CONFIG_REQ,
+ TRXCON_EV_TX_ACCESS_BURST_REQ,
+ TRXCON_EV_DEDICATED_ESTABLISH_REQ,
+ TRXCON_EV_DEDICATED_RELEASE_REQ,
+ TRXCON_EV_TX_TRAFFIC_REQ,
+ TRXCON_EV_RX_TRAFFIC_IND,
+ TRXCON_EV_TX_DATA_REQ,
+ TRXCON_EV_RX_DATA_IND,
+ TRXCON_EV_CRYPTO_REQ,
+};
- /* TRX specific events */
- TRX_EVENT_RSP_ERROR,
- TRX_EVENT_OFFLINE,
+/* param of TRXCON_EV_FULL_POWER_SCAN_REQ */
+struct trxcon_param_full_power_scan_req {
+ uint16_t band_arfcn_start;
+ uint16_t band_arfcn_stop;
+};
+
+/* param of TRXCON_EV_FULL_POWER_SCAN_RES */
+struct trxcon_param_full_power_scan_res {
+ bool last_result;
+ uint16_t band_arfcn;
+ int dbm;
+};
+
+/* param of TRXCON_EV_FBSB_SEARCH_REQ */
+struct trxcon_param_fbsb_search_req {
+ uint16_t band_arfcn;
+ uint16_t timeout_ms;
+ uint8_t pchan_config;
+};
+
+/* param of TRXCON_EV_SET_{CCCH,TCH}_MODE_REQ */
+struct trxcon_param_set_ccch_tch_mode_req {
+ uint8_t mode;
+ bool applied;
+};
+
+/* param of TRXCON_EV_SET_CONFIG_REQ */
+struct trxcon_param_set_config_req {
+ uint8_t timing_advance;
+ uint8_t tx_power;
+};
+
+/* param of TRXCON_EV_TX_{TRAFFIC,DATA}_REQ */
+struct trxcon_param_tx_traffic_data_req {
+ uint8_t chan_nr;
+ uint8_t link_id;
+ size_t data_len;
+ const uint8_t *data;
+};
+
+/* param of TRXCON_EV_RX_{TRAFFIC,DATA}_IND */
+struct trxcon_param_rx_traffic_data_ind {
+ uint8_t chan_nr;
+ uint8_t link_id;
+ uint32_t frame_nr;
+ int16_t toa256;
+ int8_t rssi;
+ int n_errors;
+ int n_bits_total;
+ size_t data_len;
+ const uint8_t *data;
+};
+
+/* param of TRXCON_EV_TX_ACCESS_BURST_REQ */
+struct trxcon_param_tx_access_burst_req {
+ uint8_t chan_nr;
+ uint8_t link_id;
+ uint8_t offset;
+ uint8_t synch_seq;
+ uint16_t ra;
+ bool is_11bit;
+};
+
+/* param of TRXCON_EV_DEDICATED_ESTABLISH_REQ */
+struct trxcon_param_dedicated_establish_req {
+ uint8_t chan_nr;
+ uint8_t tch_mode;
+ uint8_t tsc;
+
+ bool hopping;
+ union {
+ struct { /* hopping=false */
+ uint16_t band_arfcn;
+ } h0;
+ struct { /* hopping=true */
+ uint8_t hsn;
+ uint8_t maio;
+ uint8_t n;
+ uint16_t ma[64];
+ } h1;
+ };
+};
+
+/* param of TRXCON_EV_CRYPTO_REQ */
+struct trxcon_param_crypto_req {
+ uint8_t chan_nr;
+ uint8_t a5_algo; /* 0 is A5/0 */
+ uint8_t key_len;
+ const uint8_t *key;
};
struct trxcon_inst {
@@ -31,10 +139,6 @@
/* L1/L2 interfaces */
struct trx_instance *trx;
struct l1ctl_client *l1c;
-
- /* TODO: implement this as an FSM state with timeout */
- struct osmo_timer_list fbsb_timer;
- bool fbsb_conf_sent;
};
struct trxcon_inst *trxcon_inst_alloc(void *ctx, unsigned int id);
diff --git a/src/host/trxcon/src/Makefile.am b/src/host/trxcon/src/Makefile.am
index cf1357f..3af004d 100644
--- a/src/host/trxcon/src/Makefile.am
+++ b/src/host/trxcon/src/Makefile.am
@@ -42,6 +42,7 @@
l1ctl.c \
trx_if.c \
logging.c \
+ trxcon_fsm.c \
trxcon.c \
$(NULL)
diff --git a/src/host/trxcon/src/l1ctl.c b/src/host/trxcon/src/l1ctl.c
index 5e40af5..96dde73 100644
--- a/src/host/trxcon/src/l1ctl.c
+++ b/src/host/trxcon/src/l1ctl.c
@@ -30,18 +30,18 @@
#include <arpa/inet.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
+
+#include <osmocom/gsm/gsm0502.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/bb/trxcon/logging.h>
#include <osmocom/bb/trxcon/l1ctl_server.h>
#include <osmocom/bb/trxcon/l1ctl_proto.h>
-
-#include <osmocom/bb/trxcon/trx_if.h>
-#include <osmocom/bb/l1sched/l1sched.h>
#include <osmocom/bb/trxcon/trxcon.h>
static const char *arfcn2band_name(uint16_t arfcn)
@@ -166,33 +166,52 @@
return conf;
}
-int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint8_t result,
- const struct l1ctl_info_dl *dl_info, uint8_t bsic)
+int l1ctl_tx_fbsb_fail(struct l1ctl_client *l1c, uint16_t band_arfcn)
{
struct trxcon_inst *trxcon = l1c->priv;
- struct l1ctl_fbsb_conf *conf;
+ struct l1ctl_info_dl *dl;
struct msgb *msg;
msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
if (msg == NULL)
return -ENOMEM;
- put_dl_info_hdr(msg, dl_info);
+ dl = put_dl_info_hdr(msg, NULL);
- conf = fbsb_conf_make(msg, result, bsic);
+ /* Fill in current ARFCN */
+ dl->band_arfcn = htons(band_arfcn);
+
+ fbsb_conf_make(msg, 255, 0);
+
+ LOGPFSMSL(trxcon->fi, DL1C, LOGL_DEBUG, "Send FBSB Conf (timeout)\n");
+
+ return l1ctl_client_send(l1c, msg);
+}
+
+int l1ctl_tx_fbsb_conf(struct l1ctl_client *l1c, uint16_t band_arfcn, uint8_t bsic)
+{
+ struct trxcon_inst *trxcon = l1c->priv;
+ struct l1ctl_fbsb_conf *conf;
+ struct l1ctl_info_dl *dl;
+ struct msgb *msg;
+
+ msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
+ if (msg == NULL)
+ return -ENOMEM;
+
+ dl = put_dl_info_hdr(msg, NULL);
+
+ /* Fill in current ARFCN */
+ dl->band_arfcn = htons(band_arfcn);
+
+ conf = fbsb_conf_make(msg, 0, bsic);
/* FIXME: set proper value */
conf->initial_freq_err = 0;
- /* Ask SCH handler not to send L1CTL_FBSB_CONF anymore */
- trxcon->fbsb_conf_sent = true;
-
- /* Abort FBSB expire timer */
- osmo_timer_del(&trxcon->fbsb_timer);
-
LOGPFSMSL(trxcon->fi, DL1C, LOGL_DEBUG,
"Send FBSB Conf (result=%u, bsic=%u)\n",
- result, bsic);
+ conf->result, conf->bsic);
return l1ctl_client_send(l1c, msg);
}
@@ -299,44 +318,10 @@
}
}
-/* FBSB expire timer */
-static void fbsb_timer_cb(void *data)
-{
- struct l1ctl_client *l1c = (struct l1ctl_client *) data;
- struct trxcon_inst *trxcon = l1c->priv;
- struct l1ctl_info_dl *dl;
- struct msgb *msg;
-
- msg = l1ctl_alloc_msg(L1CTL_FBSB_CONF);
- if (msg == NULL)
- return;
-
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
- "FBSB timer fired for ARFCN %u\n",
- trxcon->trx->band_arfcn & ~ARFCN_FLAG_MASK);
-
- dl = put_dl_info_hdr(msg, NULL);
-
- /* Fill in current ARFCN */
- dl->band_arfcn = htons(trxcon->trx->band_arfcn);
-
- fbsb_conf_make(msg, 255, 0);
-
- /* Ask SCH handler not to send L1CTL_FBSB_CONF anymore */
- trxcon->fbsb_conf_sent = true;
-
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_DEBUG, "Send FBSB Conf (timeout)\n");
-
- l1ctl_client_send(l1c, msg);
-}
-
static int l1ctl_rx_fbsb_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1c->priv;
- enum gsm_phys_chan_config ch_config;
struct l1ctl_fbsb_req *fbsb;
- uint16_t band_arfcn;
- uint16_t timeout;
int rc = 0;
fbsb = (struct l1ctl_fbsb_req *) msg->l1h;
@@ -348,44 +333,19 @@
goto exit;
}
- ch_config = l1ctl_ccch_mode2pchan_config(fbsb->ccch_mode);
- band_arfcn = ntohs(fbsb->band_arfcn);
- timeout = ntohs(fbsb->timeout);
+ struct trxcon_param_fbsb_search_req req = {
+ .pchan_config = l1ctl_ccch_mode2pchan_config(fbsb->ccch_mode),
+ .timeout_ms = ntohs(fbsb->timeout) * GSM_TDMA_FN_DURATION_uS / 1000,
+ .band_arfcn = ntohs(fbsb->band_arfcn),
+ };
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE, "Received FBSB request (%s
%d)\n",
- arfcn2band_name(band_arfcn), band_arfcn & ~ARFCN_FLAG_MASK);
+ LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
+ "Received FBSB request (%s %d, timeout %u ms)\n",
+ arfcn2band_name(req.band_arfcn),
+ req.band_arfcn & ~ARFCN_FLAG_MASK,
+ req.timeout_ms);
- /* Reset scheduler and clock counter */
- l1sched_reset(trxcon->sched, true);
-
- /* Configure a single timeslot */
- l1sched_configure_ts(trxcon->sched, 0, ch_config);
-
- /* Ask SCH handler to send L1CTL_FBSB_CONF */
- trxcon->fbsb_conf_sent = false;
-
- /* Only if current ARFCN differs */
- if (trxcon->trx->band_arfcn != band_arfcn) {
- /* Update current ARFCN */
- trxcon->trx->band_arfcn = band_arfcn;
-
- /* Tune transceiver to required ARFCN */
- trx_if_cmd_rxtune(trxcon->trx, band_arfcn);
- trx_if_cmd_txtune(trxcon->trx, band_arfcn);
- }
-
- /* Transceiver might have been powered on before, e.g.
- * in case of sending L1CTL_FBSB_REQ due to signal loss. */
- if (!trxcon->trx->powered_up)
- trx_if_cmd_poweron(trxcon->trx);
-
- /* Start FBSB expire timer */
- trxcon->fbsb_timer.data = l1c;
- trxcon->fbsb_timer.cb = fbsb_timer_cb;
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_INFO, "Starting FBSB timer %u ms\n",
- timeout * GSM_TDMA_FN_DURATION_uS / 1000);
- osmo_timer_schedule(&trxcon->fbsb_timer, 0,
- timeout * GSM_TDMA_FN_DURATION_uS);
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_FBSB_SEARCH_REQ, &req);
exit:
msgb_free(msg);
@@ -394,7 +354,6 @@
static int l1ctl_rx_pm_req(struct l1ctl_client *l1c, struct msgb *msg)
{
- uint16_t band_arfcn_start, band_arfcn_stop;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_pm_req *pmr;
int rc = 0;
@@ -408,17 +367,18 @@
goto exit;
}
- band_arfcn_start = ntohs(pmr->range.band_arfcn_from);
- band_arfcn_stop = ntohs(pmr->range.band_arfcn_to);
+ struct trxcon_param_full_power_scan_req req = {
+ .band_arfcn_start = ntohs(pmr->range.band_arfcn_from),
+ .band_arfcn_stop = ntohs(pmr->range.band_arfcn_to),
+ };
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"Received power measurement request (%s: %d -> %d)\n",
- arfcn2band_name(band_arfcn_start),
- band_arfcn_start & ~ARFCN_FLAG_MASK,
- band_arfcn_stop & ~ARFCN_FLAG_MASK);
+ arfcn2band_name(req.band_arfcn_start),
+ req.band_arfcn_start & ~ARFCN_FLAG_MASK,
+ req.band_arfcn_stop & ~ARFCN_FLAG_MASK);
- /* Send measurement request to transceiver */
- rc = trx_if_cmd_measure(trxcon->trx, band_arfcn_start, band_arfcn_stop);
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_FULL_POWER_SCAN_REQ, &req);
exit:
msgb_free(msg);
@@ -445,13 +405,10 @@
switch (res->type) {
case L1CTL_RES_T_FULL:
- /* TODO: implement trx_if_reset() */
- trx_if_cmd_poweroff(trxcon->trx);
- trx_if_cmd_echo(trxcon->trx);
-
- /* Fall through */
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_RESET_FULL_REQ, NULL);
+ break;
case L1CTL_RES_T_SCHED:
- l1sched_reset(trxcon->sched, true);
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_RESET_SCHED_REQ, NULL);
break;
default:
LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR,
@@ -486,13 +443,11 @@
static int l1ctl_rx_ccch_mode_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1c->priv;
- enum gsm_phys_chan_config ch_config;
- struct l1ctl_ccch_mode_req *req;
- struct l1sched_ts *ts;
- int rc = 0;
+ struct l1ctl_ccch_mode_req *mode_req;
+ int rc;
- req = (struct l1ctl_ccch_mode_req *) msg->l1h;
- if (msgb_l1len(msg) < sizeof(*req)) {
+ mode_req = (struct l1ctl_ccch_mode_req *)msg->l1h;
+ if (msgb_l1len(msg) < sizeof(*mode_req)) {
LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR,
"MSG too short Reset Req: %u\n",
msgb_l1len(msg));
@@ -501,26 +456,16 @@
}
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE, "Received CCCH mode request
(%u)\n",
- req->ccch_mode); /* TODO: add value-string for ccch_mode */
+ mode_req->ccch_mode); /* TODO: add value-string for ccch_mode */
- /* Make sure that TS0 is allocated and configured */
- ts = trxcon->sched->ts[0];
- if (ts == NULL || ts->mf_layout == NULL) {
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR, "TS0 is not configured");
- rc = -EINVAL;
- goto exit;
- }
+ struct trxcon_param_set_ccch_tch_mode_req req = {
+ /* Choose corresponding channel combination */
+ .mode = l1ctl_ccch_mode2pchan_config(mode_req->ccch_mode),
+ };
- /* Choose corresponding channel combination */
- ch_config = l1ctl_ccch_mode2pchan_config(req->ccch_mode);
-
- /* Do nothing if the current mode matches required */
- if (ts->mf_layout->chan_config != ch_config)
- rc = l1sched_configure_ts(trxcon->sched, 0, ch_config);
-
- /* Confirm reconfiguration */
- if (!rc)
- rc = l1ctl_tx_ccch_mode_conf(l1c, req->ccch_mode);
+ rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_SET_CCCH_MODE_REQ, &req);
+ if (rc == 0 && req.applied)
+ l1ctl_tx_ccch_mode_conf(l1c, mode_req->ccch_mode);
exit:
msgb_free(msg);
@@ -529,40 +474,38 @@
static int l1ctl_rx_rach_req(struct l1ctl_client *l1c, struct msgb *msg, bool ext)
{
+ struct trxcon_param_tx_access_burst_req req;
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_info_ul *ul;
- struct l1sched_ts_prim *prim;
- struct l1sched_ts_prim_rach rach;
- enum l1sched_ts_prim_type prim_type;
- int rc;
ul = (struct l1ctl_info_ul *) msg->l1h;
/* Is it extended (11-bit) RACH or not? */
if (ext) {
- const struct l1ctl_ext_rach_req *req = (void *)ul->payload;
+ const struct l1ctl_ext_rach_req *rr = (void *)ul->payload;
- rach = (struct l1sched_ts_prim_rach) {
- .ra = ntohs(req->ra11),
- .synch_seq = req->synch_seq,
- .offset = ntohs(req->offset),
+ req = (struct trxcon_param_tx_access_burst_req) {
+ .offset = ntohs(rr->offset),
+ .synch_seq = rr->synch_seq,
+ .ra = ntohs(rr->ra11),
+ .is_11bit = true,
};
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"Received extended (11-bit) RACH request "
"(offset=%u, synch_seq=%u, ra11=0x%02hx)\n",
- rach.offset, rach.synch_seq, rach.ra);
+ req.offset, req.synch_seq, req.ra);
} else {
- const struct l1ctl_rach_req *req = (void *)ul->payload;
+ const struct l1ctl_rach_req *rr = (void *)ul->payload;
- rach = (struct l1sched_ts_prim_rach) {
- .ra = req->ra,
- .offset = ntohs(req->offset),
+ req = (struct trxcon_param_tx_access_burst_req) {
+ .offset = ntohs(rr->offset),
+ .ra = rr->ra,
};
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"Received regular (8-bit) RACH request "
- "(offset=%u, ra=0x%02x)\n", rach.offset, rach.ra);
+ "(offset=%u, ra=0x%02x)\n", req.offset, req.ra);
}
/* The controlling L1CTL side always does include the UL info header,
@@ -570,55 +513,38 @@
if (ul->chan_nr == 0x00) {
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"The UL info header is empty, assuming RACH is on TS0\n");
- ul->chan_nr = RSL_CHAN_RACH;
+ req.chan_nr = RSL_CHAN_RACH;
+ req.link_id = 0x00;
+ } else {
+ req.chan_nr = ul->chan_nr;
+ req.link_id = ul->link_id;
}
- /**
- * Push this primitive to the transmit queue.
- * Indicated timeslot needs to be configured.
- */
- prim_type = ext ? L1SCHED_PRIM_RACH11 : L1SCHED_PRIM_RACH8;
- prim = l1sched_prim_push(trxcon->sched, prim_type, ul->chan_nr, ul->link_id,
- (const uint8_t *)&rach, sizeof(rach));
- if (prim == NULL)
- rc = -ENOMEM;
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_ACCESS_BURST_REQ, &req);
msgb_free(msg);
- return rc;
+ return 0;
}
-static int l1ctl_proc_est_req_h0(struct trxcon_inst *trxcon, struct l1ctl_h0 *h)
+static int l1ctl_proc_est_req_h0(struct trxcon_inst *trxcon,
+ struct trxcon_param_dedicated_establish_req *req,
+ const struct l1ctl_h0 *h)
{
- struct trx_instance *trx = trxcon->trx;
- uint16_t band_arfcn;
- int rc = 0;
-
- band_arfcn = ntohs(h->band_arfcn);
+ req->h0.band_arfcn = ntohs(h->band_arfcn);
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
- "L1CTL_DM_EST_REQ indicates a single ARFCN=%u\n",
- band_arfcn & ~ARFCN_FLAG_MASK);
-
- /* Do we need to retune? */
- if (trx->band_arfcn == band_arfcn)
- return 0;
-
- /* Tune transceiver to required ARFCN */
- rc |= trx_if_cmd_rxtune(trx, band_arfcn);
- rc |= trx_if_cmd_txtune(trx, band_arfcn);
- if (rc)
- return rc;
-
- /* Update current ARFCN */
- trx->band_arfcn = band_arfcn;
+ "L1CTL_DM_EST_REQ indicates single ARFCN %s %u\n",
+ arfcn2band_name(req->h0.band_arfcn),
+ req->h0.band_arfcn & ~ARFCN_FLAG_MASK);
return 0;
}
-static int l1ctl_proc_est_req_h1(struct trxcon_inst *trxcon, struct l1ctl_h1 *h)
+static int l1ctl_proc_est_req_h1(struct trxcon_inst *trxcon,
+ struct trxcon_param_dedicated_establish_req *req,
+ const struct l1ctl_h1 *h)
{
- uint16_t ma[64];
- int i, rc;
+ unsigned int i;
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"L1CTL_DM_EST_REQ indicates a Frequency "
@@ -630,7 +556,7 @@
LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR,
"No channels in mobile allocation?!?\n");
return -EINVAL;
- } else if (h->n > ARRAY_SIZE(ma)) {
+ } else if (h->n > ARRAY_SIZE(h->ma)) {
LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR,
"More than 64 channels in mobile allocation?!?\n");
return -EINVAL;
@@ -638,75 +564,45 @@
/* Convert from network to host byte order */
for (i = 0; i < h->n; i++)
- ma[i] = ntohs(h->ma[i]);
+ req->h1.ma[i] = ntohs(h->ma[i]);
+ req->h1.n = h->n;
+ req->h1.hsn = h->hsn;
+ req->h1.maio = h->maio;
- /* Forward hopping parameters to TRX */
- rc = trx_if_cmd_setfh(trxcon->trx, h->hsn, h->maio, ma, h->n);
- if (rc)
- return rc;
-
- /**
- * TODO: update the state of trx_instance somehow
- * in order to indicate that it is in hopping mode...
- */
return 0;
}
static int l1ctl_rx_dm_est_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1c->priv;
- enum gsm_phys_chan_config config;
struct l1ctl_dm_est_req *est_req;
struct l1ctl_info_ul *ul;
- struct l1sched_ts *ts;
- uint8_t chan_nr, tn;
int rc;
ul = (struct l1ctl_info_ul *) msg->l1h;
est_req = (struct l1ctl_dm_est_req *) ul->payload;
- chan_nr = ul->chan_nr;
- tn = chan_nr & 0x07;
+ struct trxcon_param_dedicated_establish_req req = {
+ .chan_nr = ul->chan_nr,
+ .tch_mode = est_req->tch_mode,
+ .tsc = est_req->tsc,
+ .hopping = est_req->h,
+ };
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"Received L1CTL_DM_EST_REQ "
"(tn=%u, chan_nr=0x%02x, tsc=%u, tch_mode=0x%02x)\n",
- tn, chan_nr, est_req->tsc, est_req->tch_mode);
-
- /* Determine channel config */
- config = l1sched_chan_nr2pchan_config(chan_nr);
- if (config == GSM_PCHAN_NONE) {
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR, "Couldn't determine channel
config\n");
- rc = -EINVAL;
- goto exit;
- }
+ req.chan_nr & 0x07, req.chan_nr, req.tsc, req.tch_mode);
/* Frequency hopping? */
if (est_req->h)
- rc = l1ctl_proc_est_req_h1(trxcon, &est_req->h1);
+ rc = l1ctl_proc_est_req_h1(trxcon, &req, &est_req->h1);
else /* Single ARFCN */
- rc = l1ctl_proc_est_req_h0(trxcon, &est_req->h0);
+ rc = l1ctl_proc_est_req_h0(trxcon, &req, &est_req->h0);
if (rc)
goto exit;
- /* Configure requested TS */
- rc = l1sched_configure_ts(trxcon->sched, tn, config);
- ts = trxcon->sched->ts[tn];
- if (rc) {
- rc = -EINVAL;
- goto exit;
- }
-
- /* Deactivate all lchans */
- l1sched_deactivate_all_lchans(ts);
-
- /* Activate only requested lchans */
- rc = l1sched_set_lchans(ts, chan_nr, 1, est_req->tch_mode, est_req->tsc);
- if (rc) {
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR, "Couldn't activate requested
lchans\n");
- rc = -EINVAL;
- goto exit;
- }
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_DEDICATED_ESTABLISH_REQ, &req);
exit:
msgb_free(msg);
@@ -717,11 +613,9 @@
{
struct trxcon_inst *trxcon = l1c->priv;
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
- "Received L1CTL_DM_REL_REQ, resetting scheduler\n");
+ LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE, "Received L1CTL_DM_REL_REQ\n");
- /* Reset scheduler */
- l1sched_reset(trxcon->sched, false);
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_DEDICATED_RELEASE_REQ, NULL);
msgb_free(msg);
return 0;
@@ -735,34 +629,29 @@
{
struct trxcon_inst *trxcon = l1c->priv;
struct l1ctl_info_ul *ul;
- struct l1sched_ts_prim *prim;
- uint8_t chan_nr, link_id;
- size_t payload_len;
- int rc;
/* Extract UL frame header */
ul = (struct l1ctl_info_ul *) msg->l1h;
-
- /* Calculate the payload len */
msg->l2h = ul->payload;
- payload_len = msgb_l2len(msg);
- /* Obtain channel description */
- chan_nr = ul->chan_nr;
- link_id = ul->link_id & 0x40;
+ struct trxcon_param_tx_traffic_data_req req = {
+ .chan_nr = ul->chan_nr,
+ .link_id = ul->link_id & 0x40,
+ .data_len = msgb_l2len(msg),
+ .data = ul->payload,
+ };
LOGPFSMSL(trxcon->fi, DL1D, LOGL_DEBUG,
"Recv %s Req (chan_nr=0x%02x, link_id=0x%02x, len=%zu)\n",
- traffic ? "TRAFFIC" : "DATA", chan_nr, link_id, payload_len);
+ traffic ? "TRAFFIC" : "DATA", req.chan_nr, req.link_id,
req.data_len);
- /* Push this primitive to transmit queue */
- prim = l1sched_prim_push(trxcon->sched, L1SCHED_PRIM_DATA,
- chan_nr, link_id, ul->payload, payload_len);
- if (prim == NULL)
- rc = -ENOMEM;
+ if (traffic)
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_TRAFFIC_REQ, &req);
+ else
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_DATA_REQ, &req);
msgb_free(msg);
- return rc;
+ return 0;
}
static int l1ctl_rx_param_req(struct l1ctl_client *l1c, struct msgb *msg)
@@ -778,13 +667,12 @@
"Received L1CTL_PARAM_REQ (ta=%d, tx_power=%u)\n",
par_req->ta, par_req->tx_power);
- /* Instruct TRX to use new TA value */
- if (trxcon->trx->ta != par_req->ta) {
- trx_if_cmd_setta(trxcon->trx, par_req->ta);
- trxcon->trx->ta = par_req->ta;
- }
+ struct trxcon_param_set_config_req req = {
+ .timing_advance = par_req->ta,
+ .tx_power = par_req->tx_power,
+ };
- trxcon->trx->tx_power = par_req->tx_power;
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_SET_CONFIG_REQ, &req);
msgb_free(msg);
return 0;
@@ -793,41 +681,27 @@
static int l1ctl_rx_tch_mode_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1c->priv;
- struct l1ctl_tch_mode_req *req;
- struct l1sched_lchan_state *lchan;
- struct l1sched_ts *ts;
- unsigned int tn;
+ struct l1ctl_tch_mode_req *mode_req;
+ int rc;
- req = (struct l1ctl_tch_mode_req *) msg->l1h;
+ mode_req = (struct l1ctl_tch_mode_req *)msg->l1h;
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"Received L1CTL_TCH_MODE_REQ (tch_mode=%u, audio_mode=%u)\n",
- req->tch_mode, req->audio_mode);
-
- /* Iterate over timeslot list */
- for (tn = 0; tn < ARRAY_SIZE(trxcon->sched->ts); tn++) {
- /* Timeslot is not allocated */
- ts = trxcon->sched->ts[tn];
- if (ts == NULL)
- continue;
-
- /* Timeslot is not configured */
- if (ts->mf_layout == NULL)
- continue;
-
- /* Iterate over all allocated lchans */
- llist_for_each_entry(lchan, &ts->lchans, list) {
- /* Omit inactive channels */
- if (!lchan->active)
- continue;
-
- /* Set TCH mode */
- lchan->tch_mode = req->tch_mode;
- }
- }
+ mode_req->tch_mode, mode_req->audio_mode);
/* TODO: do we need to care about audio_mode? */
+ struct trxcon_param_set_ccch_tch_mode_req req = {
+ .mode = mode_req->tch_mode,
+ };
+
+ rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_SET_TCH_MODE_REQ, &req);
+ if (rc != 0 || !req.applied) {
+ talloc_free(msg);
+ return rc;
+ }
+
/* Re-use the original message as confirmation */
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
l1h->msg_type = L1CTL_TCH_MODE_CONF;
@@ -838,41 +712,27 @@
static int l1ctl_rx_crypto_req(struct l1ctl_client *l1c, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1c->priv;
- struct l1ctl_crypto_req *req;
+ struct l1ctl_crypto_req *cr;
struct l1ctl_info_ul *ul;
- struct l1sched_ts *ts;
- uint8_t tn;
- int rc = 0;
ul = (struct l1ctl_info_ul *) msg->l1h;
- req = (struct l1ctl_crypto_req *) ul->payload;
+ cr = (struct l1ctl_crypto_req *) ul->payload;
+
+ struct trxcon_param_crypto_req req = {
+ .chan_nr = ul->chan_nr,
+ .a5_algo = cr->algo,
+ .key_len = cr->key_len,
+ .key = cr->key,
+ };
LOGPFSMSL(trxcon->fi, DL1C, LOGL_NOTICE,
"L1CTL_CRYPTO_REQ (algo=A5/%u, key_len=%u)\n",
- req->algo, req->key_len);
+ req.a5_algo, req.key_len);
- /* Determine TS index */
- tn = ul->chan_nr & 0x7;
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_CRYPTO_REQ, &req);
- /* Make sure that required TS is allocated and configured */
- ts = trxcon->sched->ts[tn];
- if (ts == NULL || ts->mf_layout == NULL) {
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR, "TS %u is not configured\n", tn);
- rc = -EINVAL;
- goto exit;
- }
-
- /* Poke scheduler */
- rc = l1sched_start_ciphering(ts, req->algo, req->key, req->key_len);
- if (rc) {
- LOGPFSMSL(trxcon->fi, DL1C, LOGL_ERROR, "Couldn't configure
ciphering\n");
- rc = -EINVAL;
- goto exit;
- }
-
-exit:
msgb_free(msg);
- return rc;
+ return 0;
}
int l1ctl_rx_cb(struct l1ctl_client *l1c, struct msgb *msg)
diff --git a/src/host/trxcon/src/trx_if.c b/src/host/trxcon/src/trx_if.c
index 92b9d12..d51c9d1 100644
--- a/src/host/trxcon/src/trx_if.c
+++ b/src/host/trxcon/src/trx_if.c
@@ -40,7 +40,6 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/bb/l1sched/l1sched.h>
-#include <osmocom/bb/trxcon/l1ctl.h>
#include <osmocom/bb/trxcon/trxcon.h>
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/logging.h>
@@ -163,7 +162,6 @@
static void trx_ctrl_timer_cb(void *data)
{
struct trx_instance *trx = (struct trx_instance *) data;
- struct trxcon_inst *trxcon = trx->trxcon;
struct trx_ctrl_msg *tcm;
/* Queue may be cleaned at this moment */
@@ -176,7 +174,7 @@
if (++tcm->retry_cnt > 3) {
LOGPFSML(trx->fi, LOGL_NOTICE, "Transceiver offline\n");
osmo_fsm_inst_state_chg(trx->fi, TRX_STATE_OFFLINE, 0, 0);
- osmo_fsm_inst_dispatch(trxcon->fi, TRX_EVENT_OFFLINE, trx);
+ osmo_fsm_inst_term(trx->fi, OSMO_FSM_TERM_TIMEOUT, NULL);
return;
}
@@ -388,9 +386,13 @@
return;
}
- /* Send L1CTL_PM_CONF */
- l1ctl_tx_pm_conf(trxcon->l1c, band_arfcn, dbm,
- band_arfcn == trx->pm_band_arfcn_stop);
+ struct trxcon_param_full_power_scan_res res = {
+ .last_result = band_arfcn == trx->pm_band_arfcn_stop,
+ .band_arfcn = band_arfcn,
+ .dbm = dbm,
+ };
+
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_FULL_POWER_SCAN_RES, &res);
/* Schedule a next measurement */
if (band_arfcn != trx->pm_band_arfcn_stop)
@@ -479,7 +481,6 @@
static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct trx_instance *trx = ofd->data;
- struct trxcon_inst *trxcon = trx->trxcon;
struct trx_ctrl_msg *tcm;
int resp, rsp_len;
char buf[TRXC_BUF_SIZE], *p;
@@ -560,8 +561,7 @@
return 0;
rsp_error:
- /* Notify higher layers about the problem */
- osmo_fsm_inst_dispatch(trxcon->fi, TRX_EVENT_RSP_ERROR, trx);
+ osmo_fsm_inst_term(trx->fi, OSMO_FSM_TERM_ERROR, NULL);
return -EIO;
}
@@ -712,7 +712,7 @@
}
/* Allocate a new dedicated state machine */
- trx->fi = osmo_fsm_inst_alloc_child(&trx_fsm, trxcon->fi, TRX_EVENT_OFFLINE);
+ trx->fi = osmo_fsm_inst_alloc_child(&trx_fsm, trxcon->fi,
TRXCON_EV_L1IF_FAILURE);
if (trx->fi == NULL) {
LOGPFSML(trxcon->fi, LOGL_ERROR, "Failed to allocate an instance "
"of FSM '%s'\n", trx_fsm.name);
diff --git a/src/host/trxcon/src/trxcon.c b/src/host/trxcon/src/trxcon.c
index 14354d1..d4f4214 100644
--- a/src/host/trxcon/src/trxcon.c
+++ b/src/host/trxcon/src/trxcon.c
@@ -49,8 +49,6 @@
#include <osmocom/bb/trxcon/l1ctl_proto.h>
#include <osmocom/bb/l1sched/l1sched.h>
-#define S(x) (1 << (x))
-
#define COPYRIGHT \
"Copyright (C) 2016-2022 by Vadim Yanitskiy <axilirator(a)gmail.com>\n" \
"Contributions by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>\n" \
@@ -142,35 +140,35 @@
const struct l1sched_lchan_desc *lchan_desc;
struct l1sched_state *sched = lchan->ts->sched;
struct trxcon_inst *trxcon = sched->priv;
- struct l1ctl_info_dl dl_hdr;
int rc;
lchan_desc = &l1sched_lchan_desc[lchan->type];
- dl_hdr = (struct l1ctl_info_dl) {
+ struct trxcon_param_rx_traffic_data_ind ind = {
.chan_nr = lchan_desc->chan_nr | lchan->ts->index,
.link_id = lchan_desc->link_id,
- .frame_nr = htonl(meas->fn),
- .band_arfcn = htons(trxcon->trx->band_arfcn),
- .fire_crc = data_len > 0 ? 0 : 2,
- .rx_level = dbm2rxlev(meas->rssi),
- .num_biterr = n_errors,
- /* TODO: set proper .snr */
+ .frame_nr = meas->fn,
+ .toa256 = meas->toa256,
+ .rssi = meas->rssi,
+ .n_errors = n_errors,
+ .n_bits_total = n_bits_total,
+ .data_len = data_len,
+ .data = data,
};
switch (dt) {
case L1SCHED_DT_TRAFFIC:
case L1SCHED_DT_PACKET_DATA:
- rc = l1ctl_tx_dt_ind(trxcon->l1c, &dl_hdr, data, data_len, true);
+ rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_RX_TRAFFIC_IND, &ind);
break;
case L1SCHED_DT_SIGNALING:
- rc = l1ctl_tx_dt_ind(trxcon->l1c, &dl_hdr, data, data_len, false);
+ rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_RX_DATA_IND, &ind);
break;
case L1SCHED_DT_OTHER:
if (lchan->type == L1SCHED_SCH) {
- if (trxcon->fbsb_conf_sent)
+ if (trxcon->fi->state != TRXCON_ST_FBSB_SEARCH)
return 0;
- rc = l1ctl_tx_fbsb_conf(trxcon->l1c, 0, &dl_hdr, sched->bsic);
+ rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_FBSB_SEARCH_RES, NULL);
break;
}
/* fall through */
@@ -255,75 +253,6 @@
return rc;
}
-/* The trxcon state machine */
-static void trxcon_fsm_idle_action(struct osmo_fsm_inst *fi,
- uint32_t event, void *data)
-{
- if (event == L1CTL_EVENT_CONNECT)
- osmo_fsm_inst_state_chg(fi, TRXCON_STATE_MANAGED, 0, 0);
-}
-
-static void trxcon_fsm_managed_action(struct osmo_fsm_inst *fi,
- uint32_t event, void *data)
-{
- struct trxcon_inst *trxcon = fi->priv;
-
- switch (event) {
- case L1CTL_EVENT_DISCONNECT:
- osmo_fsm_inst_state_chg(fi, TRXCON_STATE_IDLE, 0, 0);
-
- if (trxcon->trx->fi->state != TRX_STATE_OFFLINE) {
- /* Reset scheduler and clock counter */
- l1sched_reset(trxcon->sched, true);
-
- /* TODO: implement trx_if_reset() */
- trx_if_cmd_poweroff(trxcon->trx);
- trx_if_cmd_echo(trxcon->trx);
- }
- break;
- case TRX_EVENT_RSP_ERROR:
- case TRX_EVENT_OFFLINE:
- /* TODO: notify L2 & L3 about that */
- break;
- default:
- LOGPFSML(fi, LOGL_ERROR, "Unhandled event %u\n", event);
- }
-}
-
-static struct osmo_fsm_state trxcon_fsm_states[] = {
- [TRXCON_STATE_IDLE] = {
- .in_event_mask = S(L1CTL_EVENT_CONNECT),
- .out_state_mask = S(TRXCON_STATE_MANAGED),
- .name = "IDLE",
- .action = trxcon_fsm_idle_action,
- },
- [TRXCON_STATE_MANAGED] = {
- .in_event_mask = (
- S(L1CTL_EVENT_DISCONNECT) |
- S(TRX_EVENT_RSP_ERROR) |
- S(TRX_EVENT_OFFLINE)),
- .out_state_mask = S(TRXCON_STATE_IDLE),
- .name = "MANAGED",
- .action = trxcon_fsm_managed_action,
- },
-};
-
-static const struct value_string trxcon_fsm_event_names[] = {
- OSMO_VALUE_STRING(L1CTL_EVENT_CONNECT),
- OSMO_VALUE_STRING(L1CTL_EVENT_DISCONNECT),
- OSMO_VALUE_STRING(TRX_EVENT_OFFLINE),
- OSMO_VALUE_STRING(TRX_EVENT_RSP_ERROR),
- { 0, NULL }
-};
-
-static struct osmo_fsm trxcon_fsm_def = {
- .name = "trxcon",
- .states = trxcon_fsm_states,
- .num_states = ARRAY_SIZE(trxcon_fsm_states),
- .log_subsys = DAPP,
- .event_names = trxcon_fsm_event_names,
-};
-
struct trxcon_inst *trxcon_inst_alloc(void *ctx, unsigned int id)
{
struct trxcon_inst *trxcon;
@@ -377,8 +306,6 @@
if (trxcon->trx != NULL)
trx_if_close(trxcon->trx);
- osmo_timer_del(&trxcon->fbsb_timer);
-
if (trxcon->fi != NULL)
osmo_fsm_inst_free(trxcon->fi);
talloc_free(trxcon);
@@ -406,6 +333,8 @@
if (trxcon == NULL)
return;
+ osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_L2IF_FAILURE, NULL);
+
/* l1c is free()ed by the caller */
trxcon->l1c = NULL;
trxcon_inst_free(trxcon);
@@ -560,6 +489,8 @@
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END);
+ osmo_fsm_log_timeouts(true);
+
/* Optional GSMTAP */
if (app_data.gsmtap_ip != NULL) {
app_data.gsmtap = gsmtap_source_init(app_data.gsmtap_ip, GSMTAP_UDP_PORT, 1);
@@ -571,9 +502,6 @@
gsmtap_source_add_sink(app_data.gsmtap);
}
- /* Register the trxcon state machine */
- OSMO_ASSERT(osmo_fsm_register(&trxcon_fsm_def) == 0);
-
/* Start the L1CTL server */
server_cfg = (struct l1ctl_server_cfg) {
.sock_path = app_data.bind_socket,
diff --git a/src/host/trxcon/src/trxcon_fsm.c b/src/host/trxcon/src/trxcon_fsm.c
new file mode 100644
index 0000000..1d3b515
--- /dev/null
+++ b/src/host/trxcon/src/trxcon_fsm.c
@@ -0,0 +1,481 @@
+/*
+ * OsmocomBB <-> SDR connection bridge
+ *
+ * (C) 2022 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy(a)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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+
+#include <osmocom/bb/trxcon/trxcon.h>
+#include <osmocom/bb/trxcon/trx_if.h>
+#include <osmocom/bb/trxcon/logging.h>
+#include <osmocom/bb/trxcon/l1ctl.h>
+#include <osmocom/bb/trxcon/l1ctl_server.h>
+#include <osmocom/bb/trxcon/l1ctl_proto.h>
+#include <osmocom/bb/l1sched/l1sched.h>
+
+#define S(x) (1 << (x))
+
+static void trxcon_allstate_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+
+ switch (event) {
+ case TRXCON_EV_L1IF_FAILURE:
+ case TRXCON_EV_L2IF_FAILURE:
+ LOGPFSML(fi, LOGL_NOTICE, "Event %s is not handled\n",
+ osmo_fsm_event_name(&trxcon_fsm_def, event));
+ /* TODO: osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL); */
+ break;
+ case TRXCON_EV_RESET_FULL_REQ:
+ if (fi->state != TRXCON_ST_RESET)
+ osmo_fsm_inst_state_chg(fi, TRXCON_ST_RESET, 0, 0);
+ l1sched_reset(trxcon->sched, true);
+ trx_if_cmd_poweroff(trxcon->trx);
+ trx_if_cmd_echo(trxcon->trx);
+ break;
+ case TRXCON_EV_RESET_SCHED_REQ:
+ l1sched_reset(trxcon->sched, false);
+ break;
+ case TRXCON_EV_SET_CONFIG_REQ:
+ {
+ const struct trxcon_param_set_config_req *req = data;
+
+ if (trxcon->trx->ta != req->timing_advance)
+ trx_if_cmd_setta(trxcon->trx, req->timing_advance);
+ trxcon->trx->tx_power = req->tx_power;
+ trxcon->trx->ta = req->timing_advance;
+ break;
+ }
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static int trxcon_timer_cb(struct osmo_fsm_inst *fi)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+
+ switch (fi->state) {
+ case TRXCON_ST_FBSB_SEARCH:
+ l1ctl_tx_fbsb_fail(trxcon->l1c, trxcon->trx->band_arfcn);
+ osmo_fsm_inst_state_chg(fi, TRXCON_ST_RESET, 0, 0);
+ return 0;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void trxcon_st_reset_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+
+ switch (event) {
+ case TRXCON_EV_FBSB_SEARCH_REQ:
+ {
+ const struct trxcon_param_fbsb_search_req *req = data;
+
+ osmo_fsm_inst_state_chg_ms(fi, TRXCON_ST_FBSB_SEARCH, req->timeout_ms, 0);
+
+ l1sched_configure_ts(trxcon->sched, 0, req->pchan_config);
+
+ /* Only if current ARFCN differs */
+ if (trxcon->trx->band_arfcn != req->band_arfcn) {
+ /* Update current ARFCN */
+ trxcon->trx->band_arfcn = req->band_arfcn;
+
+ /* Tune transceiver to required ARFCN */
+ trx_if_cmd_rxtune(trxcon->trx, req->band_arfcn);
+ trx_if_cmd_txtune(trxcon->trx, req->band_arfcn);
+ }
+
+ /* Transceiver might have been powered on before, e.g.
+ * in case of sending L1CTL_FBSB_REQ due to signal loss. */
+ if (!trxcon->trx->powered_up)
+ trx_if_cmd_poweron(trxcon->trx);
+ break;
+ }
+ case TRXCON_EV_FULL_POWER_SCAN_REQ:
+ {
+ const struct trxcon_param_full_power_scan_req *req = data;
+
+ osmo_fsm_inst_state_chg(fi, TRXCON_ST_FULL_POWER_SCAN, 0, 0); /* TODO: timeout */
+ trx_if_cmd_measure(trxcon->trx, req->band_arfcn_start, req->band_arfcn_stop);
+ break;
+ }
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void trxcon_st_full_power_scan_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+
+ switch (event) {
+ case TRXCON_EV_FULL_POWER_SCAN_RES:
+ {
+ const struct trxcon_param_full_power_scan_res *res = data;
+
+ l1ctl_tx_pm_conf(trxcon->l1c, res->band_arfcn, res->dbm,
res->last_result);
+ break;
+ }
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void trxcon_st_fbsb_search_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+
+ switch (event) {
+ case TRXCON_EV_FBSB_SEARCH_RES:
+ osmo_fsm_inst_state_chg(fi, TRXCON_ST_BCCH_CCCH, 0, 0);
+ l1ctl_tx_fbsb_conf(trxcon->l1c,
+ trxcon->trx->band_arfcn,
+ trxcon->sched->bsic);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void handle_tx_access_burst_req(struct osmo_fsm_inst *fi,
+ const struct trxcon_param_tx_access_burst_req *req)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+ enum l1sched_ts_prim_type prim_type;
+ const struct l1sched_ts_prim *prim;
+
+ const struct l1sched_ts_prim_rach rach = {
+ .synch_seq = req->synch_seq,
+ .offset = req->offset,
+ .ra = req->ra,
+ };
+
+ prim_type = req->is_11bit ? L1SCHED_PRIM_RACH11 : L1SCHED_PRIM_RACH8;
+ prim = l1sched_prim_push(trxcon->sched, prim_type,
+ req->chan_nr, req->link_id,
+ (const uint8_t *)&rach, sizeof(rach));
+ if (prim == NULL)
+ LOGPFSML(fi, LOGL_ERROR, "Failed to enqueue a prim\n");
+}
+
+static void trxcon_st_bcch_ccch_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+ struct l1sched_ts *ts;
+ int rc;
+
+ switch (event) {
+ case TRXCON_EV_TX_ACCESS_BURST_REQ:
+ handle_tx_access_burst_req(fi, data);
+ break;
+ case TRXCON_EV_SET_CCCH_MODE_REQ:
+ {
+ struct trxcon_param_set_ccch_tch_mode_req *req = data;
+ enum gsm_phys_chan_config chan_config = req->mode;
+
+ /* Make sure that TS0 is allocated and configured */
+ ts = trxcon->sched->ts[0];
+ if (ts == NULL || ts->mf_layout == NULL) {
+ LOGPFSML(fi, LOGL_ERROR, "TS0 is not configured\n");
+ return;
+ }
+
+ /* Do nothing if the current mode matches required */
+ if (ts->mf_layout->chan_config != chan_config)
+ l1sched_configure_ts(trxcon->sched, 0, chan_config);
+ req->applied = true;
+ break;
+ }
+ case TRXCON_EV_DEDICATED_ESTABLISH_REQ:
+ {
+ const struct trxcon_param_dedicated_establish_req *req = data;
+ enum gsm_phys_chan_config config;
+
+ config = l1sched_chan_nr2pchan_config(req->chan_nr);
+ if (config == GSM_PCHAN_NONE) {
+ LOGPFSML(fi, LOGL_ERROR, "Failed to determine channel config\n");
+ return;
+ }
+
+ if (req->hopping) {
+ /* Apply the freq. hopping parameters */
+ rc = trx_if_cmd_setfh(trxcon->trx,
+ req->h1.hsn, req->h1.maio,
+ &req->h1.ma[0], req->h1.n);
+ if (rc)
+ return;
+
+ /* Set current ARFCN to an invalid value */
+ trxcon->trx->band_arfcn = 0xffff;
+ } else {
+ /* Tune transceiver to required ARFCN */
+ if (trx_if_cmd_rxtune(trxcon->trx, req->h0.band_arfcn))
+ return;
+ if (trx_if_cmd_txtune(trxcon->trx, req->h0.band_arfcn))
+ return;
+
+ /* Update current ARFCN */
+ trxcon->trx->band_arfcn = req->h0.band_arfcn;
+ }
+
+ rc = l1sched_configure_ts(trxcon->sched, req->chan_nr & 0x07, config);
+ if (rc)
+ return;
+ ts = trxcon->sched->ts[req->chan_nr & 0x07];
+ OSMO_ASSERT(ts != NULL);
+
+ l1sched_deactivate_all_lchans(ts);
+
+ /* Activate only requested lchans */
+ rc = l1sched_set_lchans(ts, req->chan_nr, 1, req->tch_mode, req->tsc);
+ if (rc) {
+ LOGPFSML(fi, LOGL_ERROR, "Failed to activate requested lchans\n");
+ return;
+ }
+
+ osmo_fsm_inst_state_chg(fi, TRXCON_ST_DEDICATED, 0, 0);
+ break;
+ }
+ case TRXCON_EV_RX_DATA_IND:
+ {
+ const struct trxcon_param_rx_traffic_data_ind *ind = data;
+ const struct l1ctl_info_dl dl_hdr = {
+ .chan_nr = ind->chan_nr,
+ .link_id = ind->link_id,
+ .frame_nr = htonl(ind->frame_nr),
+ .band_arfcn = htons(trxcon->trx->band_arfcn),
+ .fire_crc = ind->data_len > 0 ? 0 : 2,
+ .rx_level = dbm2rxlev(ind->rssi),
+ .num_biterr = ind->n_errors,
+ /* TODO: set proper .snr */
+ };
+
+ l1ctl_tx_dt_ind(trxcon->l1c, &dl_hdr, ind->data, ind->data_len, false);
+ break;
+ }
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void trxcon_st_dedicated_action(struct osmo_fsm_inst *fi,
+ uint32_t event, void *data)
+{
+ struct trxcon_inst *trxcon = fi->priv;
+
+ switch (event) {
+ case TRXCON_EV_TX_ACCESS_BURST_REQ:
+ handle_tx_access_burst_req(fi, data);
+ break;
+ case TRXCON_EV_DEDICATED_RELEASE_REQ:
+ l1sched_reset(trxcon->sched, false);
+ osmo_fsm_inst_state_chg(fi, TRXCON_ST_RESET, 0, 0);
+ break;
+ case TRXCON_EV_SET_TCH_MODE_REQ:
+ {
+ struct trxcon_param_set_ccch_tch_mode_req *req = data;
+ unsigned int tn;
+
+ /* Iterate over timeslot list */
+ for (tn = 0; tn < ARRAY_SIZE(trxcon->sched->ts); tn++) {
+ struct l1sched_ts *ts = trxcon->sched->ts[tn];
+ struct l1sched_lchan_state *lchan;
+
+ /* Timeslot is not allocated */
+ if (ts == NULL || ts->mf_layout == NULL)
+ continue;
+
+ /* Iterate over all allocated lchans */
+ llist_for_each_entry(lchan, &ts->lchans, list) {
+ /* Omit inactive channels */
+ if (!lchan->active)
+ continue;
+ lchan->tch_mode = req->mode;
+ req->applied = true;
+ }
+ }
+ break;
+ }
+ case TRXCON_EV_CRYPTO_REQ:
+ {
+ const struct trxcon_param_crypto_req *req = data;
+ unsigned int tn = req->chan_nr & 0x07;
+ struct l1sched_ts *ts;
+
+ /* Make sure that required TS is allocated and configured */
+ ts = trxcon->sched->ts[tn];
+ if (ts == NULL || ts->mf_layout == NULL) {
+ LOGPFSML(fi, LOGL_ERROR, "TS%u is not configured\n", tn);
+ return;
+ }
+
+ if (l1sched_start_ciphering(ts, req->a5_algo, req->key, req->key_len) != 0) {
+ LOGPFSML(fi, LOGL_ERROR, "Failed to configure ciphering\n");
+ return;
+ }
+ break;
+ }
+ case TRXCON_EV_TX_TRAFFIC_REQ:
+ case TRXCON_EV_TX_DATA_REQ:
+ {
+ const struct trxcon_param_tx_traffic_data_req *req = data;
+ struct l1sched_ts_prim *prim;
+
+ prim = l1sched_prim_push(trxcon->sched, L1SCHED_PRIM_DATA,
+ req->chan_nr, req->link_id,
+ req->data, req->data_len);
+ if (prim == NULL) {
+ LOGPFSML(fi, LOGL_ERROR, "Failed to enqueue a prim\n");
+ return;
+ }
+ break;
+ }
+ case TRXCON_EV_RX_TRAFFIC_IND:
+ case TRXCON_EV_RX_DATA_IND:
+ {
+ const struct trxcon_param_rx_traffic_data_ind *ind = data;
+ const struct l1ctl_info_dl dl_hdr = {
+ .chan_nr = ind->chan_nr,
+ .link_id = ind->link_id,
+ .frame_nr = htonl(ind->frame_nr),
+ .band_arfcn = htons(trxcon->trx->band_arfcn),
+ .fire_crc = ind->data_len > 0 ? 0 : 2,
+ .rx_level = dbm2rxlev(ind->rssi),
+ .num_biterr = ind->n_errors,
+ /* TODO: set proper .snr */
+ };
+
+ l1ctl_tx_dt_ind(trxcon->l1c, &dl_hdr,
+ ind->data, ind->data_len,
+ event == TRXCON_EV_RX_TRAFFIC_IND);
+ break;
+ }
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static const struct osmo_fsm_state trxcon_fsm_states[] = {
+ [TRXCON_ST_RESET] = {
+ .name = "RESET",
+ .out_state_mask = S(TRXCON_ST_FBSB_SEARCH)
+ | S(TRXCON_ST_FULL_POWER_SCAN),
+ .in_event_mask = S(TRXCON_EV_FBSB_SEARCH_REQ)
+ | S(TRXCON_EV_FULL_POWER_SCAN_REQ),
+ .action = &trxcon_st_reset_action,
+ },
+ [TRXCON_ST_FULL_POWER_SCAN] = {
+ .name = "FULL_POWER_SCAN",
+ .out_state_mask = S(TRXCON_ST_RESET),
+ .in_event_mask = S(TRXCON_EV_FULL_POWER_SCAN_RES),
+ .action = &trxcon_st_full_power_scan_action,
+ },
+ [TRXCON_ST_FBSB_SEARCH] = {
+ .name = "FBSB_SEARCH",
+ .out_state_mask = S(TRXCON_ST_RESET)
+ | S(TRXCON_ST_BCCH_CCCH),
+ .in_event_mask = S(TRXCON_EV_FBSB_SEARCH_RES),
+ .action = &trxcon_st_fbsb_search_action,
+ },
+ [TRXCON_ST_BCCH_CCCH] = {
+ .name = "BCCH_CCCH",
+ .out_state_mask = S(TRXCON_ST_RESET)
+ | S(TRXCON_ST_FBSB_SEARCH)
+ | S(TRXCON_ST_DEDICATED),
+ .in_event_mask = S(TRXCON_EV_RX_DATA_IND)
+ | S(TRXCON_EV_SET_CCCH_MODE_REQ)
+ | S(TRXCON_EV_TX_ACCESS_BURST_REQ)
+ | S(TRXCON_EV_DEDICATED_ESTABLISH_REQ),
+ .action = &trxcon_st_bcch_ccch_action,
+ },
+ [TRXCON_ST_DEDICATED] = {
+ .name = "DEDICATED",
+ .out_state_mask = S(TRXCON_ST_RESET)
+ | S(TRXCON_ST_FBSB_SEARCH)
+ | S(TRXCON_ST_BCCH_CCCH),
+ .in_event_mask = S(TRXCON_EV_DEDICATED_RELEASE_REQ)
+ | S(TRXCON_EV_TX_ACCESS_BURST_REQ)
+ | S(TRXCON_EV_SET_TCH_MODE_REQ)
+ | S(TRXCON_EV_TX_TRAFFIC_REQ)
+ | S(TRXCON_EV_RX_TRAFFIC_IND)
+ | S(TRXCON_EV_TX_DATA_REQ)
+ | S(TRXCON_EV_RX_DATA_IND)
+ | S(TRXCON_EV_CRYPTO_REQ),
+ .action = &trxcon_st_dedicated_action,
+ },
+};
+
+static const struct value_string trxcon_fsm_event_names[] = {
+ OSMO_VALUE_STRING(TRXCON_EV_L1IF_FAILURE),
+ OSMO_VALUE_STRING(TRXCON_EV_L2IF_FAILURE),
+ OSMO_VALUE_STRING(TRXCON_EV_RESET_FULL_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_RESET_SCHED_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_FULL_POWER_SCAN_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_FULL_POWER_SCAN_RES),
+ OSMO_VALUE_STRING(TRXCON_EV_FBSB_SEARCH_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_FBSB_SEARCH_RES),
+ OSMO_VALUE_STRING(TRXCON_EV_SET_CCCH_MODE_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_SET_TCH_MODE_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_SET_CONFIG_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_TX_ACCESS_BURST_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_DEDICATED_ESTABLISH_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_DEDICATED_RELEASE_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_TX_TRAFFIC_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_RX_TRAFFIC_IND),
+ OSMO_VALUE_STRING(TRXCON_EV_TX_DATA_REQ),
+ OSMO_VALUE_STRING(TRXCON_EV_RX_DATA_IND),
+ OSMO_VALUE_STRING(TRXCON_EV_CRYPTO_REQ),
+ { 0, NULL }
+};
+
+struct osmo_fsm trxcon_fsm_def = {
+ .name = "trxcon",
+ .states = trxcon_fsm_states,
+ .num_states = ARRAY_SIZE(trxcon_fsm_states),
+ .log_subsys = DAPP,
+ .event_names = trxcon_fsm_event_names,
+ .allstate_event_mask = S(TRXCON_EV_L1IF_FAILURE)
+ | S(TRXCON_EV_L2IF_FAILURE)
+ | S(TRXCON_EV_RESET_FULL_REQ)
+ | S(TRXCON_EV_RESET_SCHED_REQ)
+ | S(TRXCON_EV_SET_CONFIG_REQ),
+ .allstate_action = &trxcon_allstate_action,
+ .timer_cb = &trxcon_timer_cb,
+};
+
+static __attribute__((constructor)) void on_dso_load(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&trxcon_fsm_def) == 0);
+}
--
To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/28809
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: Ifaf63ead9dd180181358e771367b2a686ba159ca
Gerrit-Change-Number: 28809
Gerrit-PatchSet: 4
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged