trxcon: introduce and use struct 'trxcon_inst'

trxcon consists of the following three main components:

* the L1 TDMA scheduler (libl1sched),
* L1 interface (TRXC/TRXD over UDP),
* L2 interface (L1CTL).

In [1] and [2] the L1 scheduler was abstracted out from both L1
and L2 interfaces and separated into a library, so it does not
use the TRXC/TRXD nor L1CTL related API directly.

This change is the next step towards the goal of having all three
components abstracted from each other.  Moreover, this patch brings
us closer to another goal of being able to support multiple L1CTL
connections (each having its own scheduler).

The idea is to give both L1 and L2 interfaces access to the
'trxcon_inst' structure, which basically groups all three components
mentioned above into a single piece.  The end goal is to eliminate
direct interaction between the interfaces, and the scheduler, so that
one could easily replace TRXC/TRXD and/or L1CTL with something else.

Change-Id: I23319951c56577085e1092669b5534f9d6bda48d
Related: [1] I31f77976a7a225ef292fe6dcd583513aec97ed44
Related: [2] I001fb7bc2663eea308b5a8882746ed9863f2c2f8
This commit is contained in:
Vadim Yanitskiy 2022-07-13 03:30:55 +07:00
parent e1740e2fc8
commit 27900b3a2d
9 changed files with 188 additions and 123 deletions

View File

@ -17,9 +17,6 @@
*/
#define L1CTL_MSG_LEN_FIELD 2
/* Forward declaration to avoid mutual include */
struct trx_instance;
enum l1ctl_fsm_states {
L1CTL_STATE_IDLE = 0,
L1CTL_STATE_CONNECTED,
@ -30,11 +27,8 @@ struct l1ctl_link {
struct osmo_fd listen_bfd;
struct osmo_wqueue wq;
/* Scheduler for this interface */
struct l1sched_state *sched;
/* Bind TRX instance */
struct trx_instance *trx;
/* Some private data */
void *priv;
/* L1CTL handlers specific */
struct osmo_timer_list fbsb_timer;

View File

@ -366,6 +366,8 @@ struct l1sched_state {
struct l1sched_ts *ts[TRX_TS_COUNT];
/*! BSIC value learned from SCH bursts */
uint8_t bsic;
/*! Some private data */
void *priv;
};
extern const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX];
@ -373,7 +375,7 @@ const struct l1sched_tdma_multiframe *l1sched_mframe_layout(
enum gsm_phys_chan_config config, int tn);
/* Scheduler management functions */
struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance);
struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance, void *priv);
void l1sched_reset(struct l1sched_state *sched, bool reset_clock);
void l1sched_free(struct l1sched_state *sched);

View File

@ -12,8 +12,7 @@
/* Forward declaration to avoid mutual include */
struct l1sched_burst_req;
struct l1sched_state;
struct l1ctl_link;
struct trxcon_inst;
enum trx_fsm_states {
TRX_STATE_OFFLINE = 0,
@ -23,6 +22,9 @@ enum trx_fsm_states {
};
struct trx_instance {
/* trxcon instance we belong to */
struct trxcon_inst *trxcon;
struct osmo_fd trx_ofd_ctrl;
struct osmo_fd trx_ofd_data;
@ -40,12 +42,6 @@ struct trx_instance {
uint16_t band_arfcn;
uint8_t tx_power;
int8_t ta;
/* Scheduler for this interface */
struct l1sched_state *sched;
/* Bind L1CTL link */
struct l1ctl_link *l1l;
};
struct trx_ctrl_msg {
@ -56,7 +52,7 @@ struct trx_ctrl_msg {
int cmd_len;
};
struct trx_instance *trx_if_open(void *tall_ctx,
struct trx_instance *trx_if_open(struct trxcon_inst *trxcon,
const char *local_host, const char *remote_host, uint16_t port);
void trx_if_flush_ctrl(struct trx_instance *trx);
void trx_if_close(struct trx_instance *trx);

View File

@ -2,7 +2,9 @@
#define GEN_MASK(state) (0x01 << state)
extern struct osmo_fsm_inst *trxcon_fsm;
struct l1sched_state;
struct trx_instance;
struct l1ctl_link;
enum trxcon_fsm_states {
TRXCON_STATE_IDLE = 0,
@ -18,3 +20,16 @@ enum trxcon_fsm_events {
TRX_EVENT_RSP_ERROR,
TRX_EVENT_OFFLINE,
};
struct trxcon_inst {
struct osmo_fsm_inst *fi;
/* The L1 scheduler */
struct l1sched_state *sched;
/* L1/L2 interfaces */
struct trx_instance *trx;
struct l1ctl_link *l1l;
};
struct trxcon_inst *trxcon_inst_alloc(void *ctx);
void trxcon_inst_free(struct trxcon_inst *trxcon);

View File

@ -42,6 +42,7 @@
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/l1sched.h>
#include <osmocom/bb/trxcon/trxcon.h>
static const char *arfcn2band_name(uint16_t arfcn)
{
@ -296,6 +297,7 @@ static enum gsm_phys_chan_config l1ctl_ccch_mode2pchan_config(enum ccch_mode mod
static void fbsb_timer_cb(void *data)
{
struct l1ctl_link *l1l = (struct l1ctl_link *) data;
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_info_dl *dl;
struct msgb *msg;
@ -303,12 +305,13 @@ static void fbsb_timer_cb(void *data)
if (msg == NULL)
return;
LOGP(DL1C, LOGL_NOTICE, "FBSB timer fired for ARFCN %u\n", l1l->trx->band_arfcn & ~ARFCN_FLAG_MASK);
LOGP(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(l1l->trx->band_arfcn);
dl->band_arfcn = htons(trxcon->trx->band_arfcn);
fbsb_conf_make(msg, 255, 0);
@ -320,6 +323,7 @@ static void fbsb_timer_cb(void *data)
static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
enum gsm_phys_chan_config ch_config;
struct l1ctl_fbsb_req *fbsb;
uint16_t band_arfcn;
@ -343,28 +347,28 @@ static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
band_arfcn & ~ARFCN_FLAG_MASK);
/* Reset scheduler and clock counter */
l1sched_reset(l1l->sched, true);
l1sched_reset(trxcon->sched, true);
/* Configure a single timeslot */
l1sched_configure_ts(l1l->sched, 0, ch_config);
l1sched_configure_ts(trxcon->sched, 0, ch_config);
/* Ask SCH handler to send L1CTL_FBSB_CONF */
l1l->fbsb_conf_sent = false;
/* Only if current ARFCN differs */
if (l1l->trx->band_arfcn != band_arfcn) {
if (trxcon->trx->band_arfcn != band_arfcn) {
/* Update current ARFCN */
l1l->trx->band_arfcn = band_arfcn;
trxcon->trx->band_arfcn = band_arfcn;
/* Tune transceiver to required ARFCN */
trx_if_cmd_rxtune(l1l->trx, band_arfcn);
trx_if_cmd_txtune(l1l->trx, band_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 (!l1l->trx->powered_up)
trx_if_cmd_poweron(l1l->trx);
if (!trxcon->trx->powered_up)
trx_if_cmd_poweron(trxcon->trx);
/* Start FBSB expire timer */
l1l->fbsb_timer.data = l1l;
@ -381,6 +385,7 @@ exit:
static int l1ctl_rx_pm_req(struct l1ctl_link *l1l, struct msgb *msg)
{
uint16_t band_arfcn_start, band_arfcn_stop;
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_pm_req *pmr;
int rc = 0;
@ -402,7 +407,7 @@ static int l1ctl_rx_pm_req(struct l1ctl_link *l1l, struct msgb *msg)
band_arfcn_stop & ~ARFCN_FLAG_MASK);
/* Send measurement request to transceiver */
rc = trx_if_cmd_measure(l1l->trx, band_arfcn_start, band_arfcn_stop);
rc = trx_if_cmd_measure(trxcon->trx, band_arfcn_start, band_arfcn_stop);
exit:
msgb_free(msg);
@ -411,6 +416,7 @@ exit:
static int l1ctl_rx_reset_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_reset *res;
int rc = 0;
@ -428,12 +434,12 @@ static int l1ctl_rx_reset_req(struct l1ctl_link *l1l, struct msgb *msg)
switch (res->type) {
case L1CTL_RES_T_FULL:
/* TODO: implement trx_if_reset() */
trx_if_cmd_poweroff(l1l->trx);
trx_if_cmd_echo(l1l->trx);
trx_if_cmd_poweroff(trxcon->trx);
trx_if_cmd_echo(trxcon->trx);
/* Fall through */
case L1CTL_RES_T_SCHED:
l1sched_reset(l1l->sched, true);
l1sched_reset(trxcon->sched, true);
break;
default:
LOGP(DL1C, LOGL_ERROR, "Unknown L1CTL_RESET_REQ type\n");
@ -465,6 +471,7 @@ static int l1ctl_rx_echo_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
enum gsm_phys_chan_config ch_config;
struct l1ctl_ccch_mode_req *req;
struct l1sched_ts *ts;
@ -482,7 +489,7 @@ static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
req->ccch_mode); /* TODO: add value-string for ccch_mode */
/* Make sure that TS0 is allocated and configured */
ts = l1l->sched->ts[0];
ts = trxcon->sched->ts[0];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP(DL1C, LOGL_ERROR, "TS0 is not configured");
rc = -EINVAL;
@ -494,7 +501,7 @@ static int l1ctl_rx_ccch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
/* Do nothing if the current mode matches required */
if (ts->mf_layout->chan_config != ch_config)
rc = l1sched_configure_ts(l1l->sched, 0, ch_config);
rc = l1sched_configure_ts(trxcon->sched, 0, ch_config);
/* Confirm reconfiguration */
if (!rc)
@ -507,6 +514,7 @@ exit:
static int l1ctl_rx_rach_req(struct l1ctl_link *l1l, struct msgb *msg, bool ext)
{
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_info_ul *ul;
struct l1sched_ts_prim *prim;
struct l1sched_ts_prim_rach rach;
@ -553,7 +561,7 @@ static int l1ctl_rx_rach_req(struct l1ctl_link *l1l, struct msgb *msg, bool ext)
* Indicated timeslot needs to be configured.
*/
prim_type = ext ? L1SCHED_PRIM_RACH11 : L1SCHED_PRIM_RACH8;
prim = l1sched_prim_push(l1l->sched, prim_type, ul->chan_nr, ul->link_id,
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;
@ -624,6 +632,7 @@ static int l1ctl_proc_est_req_h1(struct trx_instance *trx, struct l1ctl_h1 *h)
static int l1ctl_rx_dm_est_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
enum gsm_phys_chan_config config;
struct l1ctl_dm_est_req *est_req;
struct l1ctl_info_ul *ul;
@ -651,15 +660,15 @@ static int l1ctl_rx_dm_est_req(struct l1ctl_link *l1l, struct msgb *msg)
/* Frequency hopping? */
if (est_req->h)
rc = l1ctl_proc_est_req_h1(l1l->trx, &est_req->h1);
rc = l1ctl_proc_est_req_h1(trxcon->trx, &est_req->h1);
else /* Single ARFCN */
rc = l1ctl_proc_est_req_h0(l1l->trx, &est_req->h0);
rc = l1ctl_proc_est_req_h0(trxcon->trx, &est_req->h0);
if (rc)
goto exit;
/* Configure requested TS */
rc = l1sched_configure_ts(l1l->sched, tn, config);
ts = l1l->sched->ts[tn];
rc = l1sched_configure_ts(trxcon->sched, tn, config);
ts = trxcon->sched->ts[tn];
if (rc) {
rc = -EINVAL;
goto exit;
@ -683,10 +692,12 @@ exit:
static int l1ctl_rx_dm_rel_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
LOGP(DL1C, LOGL_NOTICE, "Received L1CTL_DM_REL_REQ, resetting scheduler\n");
/* Reset scheduler */
l1sched_reset(l1l->sched, false);
l1sched_reset(trxcon->sched, false);
msgb_free(msg);
return 0;
@ -698,6 +709,7 @@ static int l1ctl_rx_dm_rel_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
struct msgb *msg, bool traffic)
{
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_info_ul *ul;
struct l1sched_ts_prim *prim;
uint8_t chan_nr, link_id;
@ -720,7 +732,7 @@ static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
chan_nr, link_id, payload_len);
/* Push this primitive to transmit queue */
prim = l1sched_prim_push(l1l->sched, L1SCHED_PRIM_DATA,
prim = l1sched_prim_push(trxcon->sched, L1SCHED_PRIM_DATA,
chan_nr, link_id, ul->payload, payload_len);
if (prim == NULL)
rc = -ENOMEM;
@ -731,6 +743,7 @@ static int l1ctl_rx_dt_req(struct l1ctl_link *l1l,
static int l1ctl_rx_param_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_par_req *par_req;
struct l1ctl_info_ul *ul;
@ -741,12 +754,12 @@ static int l1ctl_rx_param_req(struct l1ctl_link *l1l, struct msgb *msg)
"(ta=%d, tx_power=%u)\n", par_req->ta, par_req->tx_power);
/* Instruct TRX to use new TA value */
if (l1l->trx->ta != par_req->ta) {
trx_if_cmd_setta(l1l->trx, par_req->ta);
l1l->trx->ta = par_req->ta;
if (trxcon->trx->ta != par_req->ta) {
trx_if_cmd_setta(trxcon->trx, par_req->ta);
trxcon->trx->ta = par_req->ta;
}
l1l->trx->tx_power = par_req->tx_power;
trxcon->trx->tx_power = par_req->tx_power;
msgb_free(msg);
return 0;
@ -754,6 +767,7 @@ static int l1ctl_rx_param_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_tch_mode_req *req;
struct l1sched_lchan_state *lchan;
struct l1sched_ts *ts;
@ -765,9 +779,9 @@ static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
"(tch_mode=%u, audio_mode=%u)\n", req->tch_mode, req->audio_mode);
/* Iterate over timeslot list */
for (tn = 0; tn < ARRAY_SIZE(l1l->sched->ts); tn++) {
for (tn = 0; tn < ARRAY_SIZE(trxcon->sched->ts); tn++) {
/* Timeslot is not allocated */
ts = l1l->sched->ts[tn];
ts = trxcon->sched->ts[tn];
if (ts == NULL)
continue;
@ -797,6 +811,7 @@ static int l1ctl_rx_tch_mode_req(struct l1ctl_link *l1l, struct msgb *msg)
static int l1ctl_rx_crypto_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct trxcon_inst *trxcon = l1l->priv;
struct l1ctl_crypto_req *req;
struct l1ctl_info_ul *ul;
struct l1sched_ts *ts;
@ -813,7 +828,7 @@ static int l1ctl_rx_crypto_req(struct l1ctl_link *l1l, struct msgb *msg)
tn = ul->chan_nr & 0x7;
/* Make sure that required TS is allocated and configured */
ts = l1l->sched->ts[tn];
ts = trxcon->sched->ts[tn];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP(DL1C, LOGL_ERROR, "TS %u is not configured\n", tn);
rc = -EINVAL;

View File

@ -136,6 +136,7 @@ static int l1ctl_link_write_cb(struct osmo_fd *bfd, struct msgb *msg)
static int l1ctl_link_accept(struct osmo_fd *bfd, unsigned int flags)
{
struct l1ctl_link *l1l = (struct l1ctl_link *) bfd->data;
struct trxcon_inst *trxcon = l1l->priv;
struct osmo_fd *conn_bfd = &l1l->wq.bfd;
struct sockaddr_un un_addr;
socklen_t len;
@ -170,7 +171,7 @@ static int l1ctl_link_accept(struct osmo_fd *bfd, unsigned int flags)
return -1;
}
osmo_fsm_inst_dispatch(trxcon_fsm, L1CTL_EVENT_CONNECT, l1l);
osmo_fsm_inst_dispatch(trxcon->fi, L1CTL_EVENT_CONNECT, l1l);
osmo_fsm_inst_state_chg(l1l->fsm, L1CTL_STATE_CONNECTED, 0, 0);
LOGP(DL1C, LOGL_NOTICE, "L1CTL has a new connection\n");
@ -205,6 +206,7 @@ int l1ctl_link_send(struct l1ctl_link *l1l, struct msgb *msg)
int l1ctl_link_close_conn(struct l1ctl_link *l1l)
{
struct osmo_fd *conn_bfd = &l1l->wq.bfd;
struct trxcon_inst *trxcon = l1l->priv;
if (conn_bfd->fd <= 0)
return -EINVAL;
@ -217,7 +219,7 @@ int l1ctl_link_close_conn(struct l1ctl_link *l1l)
/* Clear pending messages */
osmo_wqueue_clear(&l1l->wq);
osmo_fsm_inst_dispatch(trxcon_fsm, L1CTL_EVENT_DISCONNECT, l1l);
osmo_fsm_inst_dispatch(trxcon->fi, L1CTL_EVENT_DISCONNECT, l1l);
osmo_fsm_inst_state_chg(l1l->fsm, L1CTL_STATE_IDLE, 0, 0);
return 0;

View File

@ -150,7 +150,7 @@ static void sched_frame_clck_cb(struct l1sched_state *sched)
l1sched_handle_burst_req(sched, &br[tn]);
}
struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance)
struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance, void *priv)
{
struct l1sched_state *sched;
@ -164,6 +164,7 @@ struct l1sched_state *l1sched_alloc(void *ctx, uint32_t fn_advance)
/* .clock_timer is set up in l1sched_clck_correct() */
.clock_cb = &sched_frame_clck_cb,
.fn_counter_advance = fn_advance,
.priv = priv,
};
return sched;

View File

@ -161,6 +161,7 @@ static void trx_ctrl_send(struct trx_instance *trx)
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 */
@ -173,7 +174,7 @@ static void trx_ctrl_timer_cb(void *data)
if (++tcm->retry_cnt > 3) {
LOGP(DTRX, LOGL_NOTICE, "Transceiver offline\n");
osmo_fsm_inst_state_chg(trx->fsm, TRX_STATE_OFFLINE, 0, 0);
osmo_fsm_inst_dispatch(trxcon_fsm, TRX_EVENT_OFFLINE, trx);
osmo_fsm_inst_dispatch(trxcon->fi, TRX_EVENT_OFFLINE, trx);
return;
}
@ -366,6 +367,7 @@ int trx_if_cmd_measure(struct trx_instance *trx,
static void trx_if_measure_rsp_cb(struct trx_instance *trx, char *resp)
{
struct trxcon_inst *trxcon = trx->trxcon;
unsigned int freq10;
uint16_t band_arfcn;
int dbm;
@ -385,7 +387,7 @@ static void trx_if_measure_rsp_cb(struct trx_instance *trx, char *resp)
}
/* Send L1CTL_PM_CONF */
l1ctl_tx_pm_conf(trx->l1l, band_arfcn, dbm,
l1ctl_tx_pm_conf(trxcon->l1l, band_arfcn, dbm,
band_arfcn == trx->pm_band_arfcn_stop);
/* Schedule a next measurement */
@ -475,6 +477,7 @@ int trx_if_cmd_setfh(struct trx_instance *trx, uint8_t hsn,
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;
@ -557,7 +560,7 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
rsp_error:
/* Notify higher layers about the problem */
osmo_fsm_inst_dispatch(trxcon_fsm, TRX_EVENT_RSP_ERROR, trx);
osmo_fsm_inst_dispatch(trxcon->fi, TRX_EVENT_RSP_ERROR, trx);
return -EIO;
}
@ -586,6 +589,7 @@ rsp_error:
static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
{
struct trx_instance *trx = ofd->data;
struct trxcon_inst *trxcon = trx->trxcon;
struct l1sched_meas_set meas;
uint8_t buf[TRXD_BUF_SIZE];
sbit_t bits[148];
@ -635,11 +639,11 @@ static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
};
/* Poke scheduler */
l1sched_handle_rx_burst(trx->sched, tn, fn, bits, 148, &meas);
l1sched_handle_rx_burst(trxcon->sched, tn, fn, bits, 148, &meas);
/* Correct local clock counter */
if (fn % 51 == 0)
l1sched_clck_handle(trx->sched, fn);
l1sched_clck_handle(trxcon->sched, fn);
return 0;
}
@ -686,7 +690,7 @@ int trx_if_tx_burst(struct trx_instance *trx,
}
/* Init TRX interface (TRXC, TRXD sockets and FSM) */
struct trx_instance *trx_if_open(void *tall_ctx,
struct trx_instance *trx_if_open(struct trxcon_inst *trxcon,
const char *local_host, const char *remote_host,
uint16_t base_port)
{
@ -697,13 +701,14 @@ struct trx_instance *trx_if_open(void *tall_ctx,
"(%s:%u)\n", remote_host, base_port);
/* Try to allocate memory */
trx = talloc_zero(tall_ctx, struct trx_instance);
trx = talloc_zero(trxcon, struct trx_instance);
if (!trx) {
LOGP(DTRX, LOGL_ERROR, "Failed to allocate memory\n");
return NULL;
}
/* Allocate a new dedicated state machine */
/* TODO: allocate it as a child of trxcon->fi */
trx->fsm = osmo_fsm_inst_alloc(&trx_fsm, trx,
NULL, LOGL_DEBUG, "trx_interface");
if (trx->fsm == NULL) {
@ -727,6 +732,8 @@ struct trx_instance *trx_if_open(void *tall_ctx,
if (rc < 0)
goto udp_error;
trx->trxcon = trxcon;
return trx;
udp_error:

View File

@ -62,15 +62,10 @@ static struct {
int daemonize;
int quit;
/* The scheduler */
struct l1sched_state *sched;
/* L1CTL specific */
struct l1ctl_link *l1l;
const char *bind_socket;
/* TRX specific */
struct trx_instance *trx;
const char *trx_bind_ip;
const char *trx_remote_ip;
uint16_t trx_base_port;
@ -88,7 +83,6 @@ static struct {
};
static void *tall_trxcon_ctx = NULL;
struct osmo_fsm_inst *trxcon_fsm;
static void trxcon_gsmtap_send(const struct l1sched_lchan_desc *lchan_desc,
uint32_t fn, uint8_t tn, uint16_t band_arfcn,
@ -112,13 +106,15 @@ static void trxcon_gsmtap_send(const struct l1sched_lchan_desc *lchan_desc,
int l1sched_handle_config_req(struct l1sched_state *sched,
const struct l1sched_config_req *cr)
{
struct trxcon_inst *trxcon = sched->priv;
switch (cr->type) {
case L1SCHED_CFG_PCHAN_COMB:
return trx_if_cmd_setslot(app_data.trx,
return trx_if_cmd_setslot(trxcon->trx,
cr->pchan_comb.tn,
cr->pchan_comb.pchan);
default:
LOGPFSML(trxcon_fsm, LOGL_ERROR,
LOGPFSML(trxcon->fi, LOGL_ERROR,
"Unhandled config request (type 0x%02x)\n", cr->type);
return -ENODEV;
}
@ -127,7 +123,9 @@ int l1sched_handle_config_req(struct l1sched_state *sched,
int l1sched_handle_burst_req(struct l1sched_state *sched,
const struct l1sched_burst_req *br)
{
return trx_if_tx_burst(app_data.trx, br);
struct trxcon_inst *trxcon = sched->priv;
return trx_if_tx_burst(trxcon->trx, br);
}
/* External L2 API for the scheduler */
@ -138,6 +136,8 @@ int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan,
{
const struct l1sched_meas_set *meas = &lchan->meas_avg;
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;
@ -147,7 +147,7 @@ int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan,
.chan_nr = lchan_desc->chan_nr | lchan->ts->index,
.link_id = lchan_desc->link_id,
.frame_nr = htonl(meas->fn),
.band_arfcn = htons(app_data.trx->band_arfcn),
.band_arfcn = htons(trxcon->trx->band_arfcn),
.fire_crc = data_len > 0 ? 0 : 2,
.rx_level = dbm2rxlev(meas->rssi),
.num_biterr = n_errors,
@ -157,29 +157,28 @@ int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan,
switch (dt) {
case L1SCHED_DT_TRAFFIC:
case L1SCHED_DT_PACKET_DATA:
rc = l1ctl_tx_dt_ind(app_data.l1l, &dl_hdr, data, data_len, true);
rc = l1ctl_tx_dt_ind(trxcon->l1l, &dl_hdr, data, data_len, true);
break;
case L1SCHED_DT_SIGNALING:
rc = l1ctl_tx_dt_ind(app_data.l1l, &dl_hdr, data, data_len, false);
rc = l1ctl_tx_dt_ind(trxcon->l1l, &dl_hdr, data, data_len, false);
break;
case L1SCHED_DT_OTHER:
if (lchan->type == L1SCHED_SCH) {
if (app_data.l1l->fbsb_conf_sent)
if (trxcon->l1l->fbsb_conf_sent)
return 0;
rc = l1ctl_tx_fbsb_conf(app_data.l1l, 0, &dl_hdr,
lchan->ts->sched->bsic);
rc = l1ctl_tx_fbsb_conf(trxcon->l1l, 0, &dl_hdr, sched->bsic);
break;
}
/* fall through */
default:
LOGPFSML(trxcon_fsm, LOGL_ERROR,
LOGPFSML(trxcon->fi, LOGL_ERROR,
"Unhandled L2 DATA.ind (type 0x%02x)\n", dt);
return -ENODEV;
}
if (data != NULL && data_len > 0) {
trxcon_gsmtap_send(lchan_desc, meas->fn, lchan->ts->index,
app_data.trx->band_arfcn, meas->rssi, 0,
trxcon->trx->band_arfcn, meas->rssi, 0,
data, data_len);
}
@ -190,6 +189,8 @@ int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
uint32_t fn, enum l1sched_data_type dt)
{
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;
const uint8_t *data;
uint8_t ra_buf[2];
@ -202,18 +203,18 @@ int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
.chan_nr = lchan_desc->chan_nr | lchan->ts->index,
.link_id = lchan_desc->link_id,
.frame_nr = htonl(fn),
.band_arfcn = htons(app_data.trx->band_arfcn),
.band_arfcn = htons(trxcon->trx->band_arfcn),
};
switch (dt) {
case L1SCHED_DT_TRAFFIC:
case L1SCHED_DT_PACKET_DATA:
rc = l1ctl_tx_dt_conf(app_data.l1l, &dl_hdr, true);
rc = l1ctl_tx_dt_conf(trxcon->l1l, &dl_hdr, true);
data_len = lchan->prim->payload_len;
data = lchan->prim->payload;
break;
case L1SCHED_DT_SIGNALING:
rc = l1ctl_tx_dt_conf(app_data.l1l, &dl_hdr, false);
rc = l1ctl_tx_dt_conf(trxcon->l1l, &dl_hdr, false);
data_len = lchan->prim->payload_len;
data = lchan->prim->payload;
break;
@ -223,7 +224,7 @@ int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
rach = (struct l1sched_ts_prim_rach *)lchan->prim->payload;
rc = l1ctl_tx_rach_conf(app_data.l1l, app_data.trx->band_arfcn, fn);
rc = l1ctl_tx_rach_conf(trxcon->l1l, trxcon->trx->band_arfcn, fn);
if (lchan->prim->type == L1SCHED_PRIM_RACH11) {
ra_buf[0] = (uint8_t)(rach->ra >> 3);
ra_buf[1] = (uint8_t)(rach->ra & 0x07);
@ -238,13 +239,13 @@ int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan,
}
/* fall through */
default:
LOGPFSML(trxcon_fsm, LOGL_ERROR,
LOGPFSML(trxcon->fi, LOGL_ERROR,
"Unhandled L2 DATA.cnf (type 0x%02x)\n", dt);
return -ENODEV;
}
trxcon_gsmtap_send(lchan_desc, fn, lchan->ts->index,
app_data.trx->band_arfcn | ARFCN_UPLINK,
trxcon->trx->band_arfcn | ARFCN_UPLINK,
0, 0, data, data_len);
return rc;
@ -255,23 +256,25 @@ 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(trxcon_fsm, TRXCON_STATE_MANAGED, 0, 0);
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(trxcon_fsm, TRXCON_STATE_IDLE, 0, 0);
osmo_fsm_inst_state_chg(fi, TRXCON_STATE_IDLE, 0, 0);
if (app_data.trx->fsm->state != TRX_STATE_OFFLINE) {
if (trxcon->trx->fsm->state != TRX_STATE_OFFLINE) {
/* Reset scheduler and clock counter */
l1sched_reset(app_data.sched, true);
l1sched_reset(trxcon->sched, true);
/* TODO: implement trx_if_reset() */
trx_if_cmd_poweroff(app_data.trx);
trx_if_cmd_echo(app_data.trx);
trx_if_cmd_poweroff(trxcon->trx);
trx_if_cmd_echo(trxcon->trx);
}
break;
case TRX_EVENT_RSP_ERROR:
@ -310,13 +313,69 @@ static const struct value_string trxcon_fsm_event_names[] = {
};
static struct osmo_fsm trxcon_fsm_def = {
.name = "trxcon_app_fsm",
.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)
{
struct trxcon_inst *trxcon;
trxcon = talloc_zero(ctx, struct trxcon_inst);
OSMO_ASSERT(trxcon != NULL);
trxcon->fi = osmo_fsm_inst_alloc(&trxcon_fsm_def, tall_trxcon_ctx,
trxcon, LOGL_DEBUG, NULL);
OSMO_ASSERT(trxcon->fi != NULL);
/* Init L1CTL server */
trxcon->l1l = l1ctl_link_init(trxcon, app_data.bind_socket);
if (trxcon->l1l == NULL) {
trxcon_inst_free(trxcon);
return NULL;
}
/* Init transceiver interface */
trxcon->trx = trx_if_open(trxcon,
app_data.trx_bind_ip,
app_data.trx_remote_ip,
app_data.trx_base_port);
if (trxcon->trx == NULL) {
trxcon_inst_free(trxcon);
return NULL;
}
trxcon->l1l->priv = trxcon;
/* Init scheduler */
trxcon->sched = l1sched_alloc(trxcon, app_data.trx_fn_advance, trxcon);
if (trxcon->sched == NULL) {
trxcon_inst_free(trxcon);
return NULL;
}
return trxcon;
}
void trxcon_inst_free(struct trxcon_inst *trxcon)
{
/* Shutdown the scheduler */
if (trxcon->sched != NULL)
l1sched_free(trxcon->sched);
/* Close active connections */
if (trxcon->l1l != NULL)
l1ctl_link_shutdown(trxcon->l1l);
if (trxcon->trx != NULL)
trx_if_close(trxcon->trx);
if (trxcon->fi != NULL)
osmo_fsm_inst_free(trxcon->fi);
talloc_free(trxcon);
}
static void print_usage(const char *app)
{
printf("Usage: %s\n", app);
@ -427,6 +486,7 @@ static void signal_handler(int signum)
int main(int argc, char **argv)
{
struct trxcon_inst *trxcon = NULL;
int rc = 0;
printf("%s", COPYRIGHT);
@ -469,37 +529,14 @@ int main(int argc, char **argv)
gsmtap_source_add_sink(app_data.gsmtap);
}
/* Allocate the application state machine */
/* Register the trxcon state machine */
OSMO_ASSERT(osmo_fsm_register(&trxcon_fsm_def) == 0);
trxcon_fsm = osmo_fsm_inst_alloc(&trxcon_fsm_def, tall_trxcon_ctx,
NULL, LOGL_DEBUG, "main");
/* Init L1CTL server */
app_data.l1l = l1ctl_link_init(tall_trxcon_ctx,
app_data.bind_socket);
if (app_data.l1l == NULL)
/* Allocate the trxcon instance (only one for now) */
trxcon = trxcon_inst_alloc(tall_trxcon_ctx);
if (trxcon == NULL)
goto exit;
/* Init transceiver interface */
app_data.trx = trx_if_open(tall_trxcon_ctx,
app_data.trx_bind_ip, app_data.trx_remote_ip,
app_data.trx_base_port);
if (!app_data.trx)
goto exit;
/* Bind L1CTL with TRX and vice versa */
app_data.l1l->trx = app_data.trx;
app_data.trx->l1l = app_data.l1l;
/* Init scheduler */
app_data.sched = l1sched_alloc(tall_trxcon_ctx, app_data.trx_fn_advance);
if (app_data.sched == NULL)
goto exit;
/* Let both L1CTL and TRX interfaces access to the scheduler */
app_data.l1l->sched = app_data.sched;
app_data.trx->sched = app_data.sched;
LOGP(DAPP, LOGL_NOTICE, "Init complete\n");
if (app_data.daemonize) {
@ -517,13 +554,9 @@ int main(int argc, char **argv)
osmo_select_main(0);
exit:
/* Close active connections */
l1ctl_link_shutdown(app_data.l1l);
l1sched_free(app_data.sched);
trx_if_close(app_data.trx);
/* Shutdown main state machine */
osmo_fsm_inst_free(trxcon_fsm);
/* Release the trxcon instance */
if (trxcon != NULL)
trxcon_inst_free(trxcon);
/* Deinitialize logging */
log_fini();