TRX: Lost TCH frame detection of omitted bursts from tranceiver
This commit is contained in:
parent
b9880bc812
commit
9de67ca962
|
@ -54,7 +54,7 @@ struct trx_chan_state {
|
|||
sbit_t *ul_bursts; /* burst buffer for RX */
|
||||
uint32_t ul_first_fn; /* fn of first burst */
|
||||
uint8_t ul_mask; /* mask of received bursts */
|
||||
uint8_t sacch_lost; /* SACCH loss detection */
|
||||
uint8_t lost; /* (SACCH) loss detection */
|
||||
uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */
|
||||
};
|
||||
|
||||
|
|
|
@ -523,7 +523,57 @@ found_msg:
|
|||
}
|
||||
|
||||
static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len);
|
||||
enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(l2_len);
|
||||
l1sap = msgb_l1sap_prim(msg);
|
||||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.data.chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
l1sap->u.data.link_id = trx_chan_desc[chan].link_id;
|
||||
l1sap->u.data.fn = fn;
|
||||
msg->l2h = msgb_put(msg, l2_len);
|
||||
if (l2_len)
|
||||
memcpy(msg->l2h, l2, l2_len);
|
||||
|
||||
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id))
|
||||
l1h->chan_states[tn][chan].lost = 0;
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1h->trx, l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compose_tch_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(tch_len);
|
||||
l1sap = msgb_l1sap_prim(msg);
|
||||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.tch.chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
l1sap->u.tch.fn = fn;
|
||||
msg->l2h = msgb_put(msg, tch_len);
|
||||
if (tch_len)
|
||||
memcpy(msg->l2h, tch, tch_len);
|
||||
|
||||
if (l1h->chan_states[tn][chan].lost)
|
||||
l1h->chan_states[tn][chan].lost--;
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1h->trx, l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t bid)
|
||||
|
@ -569,7 +619,7 @@ got_msg:
|
|||
/* handle loss detection of sacch */
|
||||
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
|
||||
/* count and send BFI */
|
||||
if (++(l1h->chan_states[tn][chan].sacch_lost) > 1)
|
||||
if (++(l1h->chan_states[tn][chan].lost) > 1)
|
||||
compose_ph_data_ind(l1h, tn, 0, chan, NULL, 0);
|
||||
}
|
||||
|
||||
|
@ -686,6 +736,19 @@ static const ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
goto send_burst;
|
||||
}
|
||||
|
||||
/* handle loss detection of received TCH frames */
|
||||
if (++(l1h->chan_states[tn][chan].lost) > 5) {
|
||||
uint8_t tch_data[33];
|
||||
|
||||
LOGP(DL1C, LOGL_NOTICE, "Missing TCH bursts detected, sending "
|
||||
"BFI for %s\n", trx_chan_desc[chan].name);
|
||||
|
||||
/* indicate bad frame */
|
||||
memset(tch_data, 0, sizeof(tch_data));
|
||||
// FIXME length depends on codec
|
||||
compose_tch_ind(l1h, tn, 0, chan, tch_data, 33);
|
||||
}
|
||||
|
||||
/* get frame and unlink from queue */
|
||||
msg1 = dequeue_prim(l1h, tn, fn, chan);
|
||||
msg2 = dequeue_prim(l1h, tn, fn, chan);
|
||||
|
@ -757,6 +820,14 @@ static const ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
goto send_burst;
|
||||
}
|
||||
|
||||
/* bad frame */
|
||||
if (msg_tch && !msg_facch && (msg_tch->l2h[0] >> 4) != 0xd) {
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad frame' trx=%u "
|
||||
"ts=%u at fn=%u to transmit.\n",
|
||||
trx_chan_desc[chan].name, l1h->trx->nr, tn, fn);
|
||||
goto send_burst;
|
||||
}
|
||||
|
||||
/* encode bursts (priorize FACCH) */
|
||||
if (msg_facch)
|
||||
tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch),
|
||||
|
@ -835,33 +906,6 @@ static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(l2_len);
|
||||
l1sap = msgb_l1sap_prim(msg);
|
||||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.data.chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
l1sap->u.data.link_id = trx_chan_desc[chan].link_id;
|
||||
l1sap->u.data.fn = fn;
|
||||
msg->l2h = msgb_put(msg, l2_len);
|
||||
if (l2_len)
|
||||
memcpy(msg->l2h, l2, l2_len);
|
||||
|
||||
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id))
|
||||
l1h->chan_states[tn][chan].sacch_lost = 0;
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1h->trx, l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
|
||||
{
|
||||
|
@ -999,29 +1043,6 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
return compose_ph_data_ind(l1h, tn, *first_fn, chan, l2, rc + 1);
|
||||
}
|
||||
|
||||
static int compose_tch_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(tch_len);
|
||||
l1sap = msgb_l1sap_prim(msg);
|
||||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.tch.chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
l1sap->u.tch.fn = fn;
|
||||
msg->l2h = msgb_put(msg, tch_len);
|
||||
if (tch_len)
|
||||
memcpy(msg->l2h, tch, tch_len);
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1h->trx, l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, float toa)
|
||||
{
|
||||
|
@ -1085,17 +1106,19 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
|
|||
if (rc < 0) {
|
||||
LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame at fn=%u "
|
||||
"for %s\n", *first_fn, trx_chan_desc[chan].name);
|
||||
memset(tch_data, 0, sizeof(tch_data));
|
||||
// FIXME length depends on codec
|
||||
rc = 33;
|
||||
goto bfi;
|
||||
}
|
||||
|
||||
/* FACCH */
|
||||
if (rc == 23)
|
||||
return compose_ph_data_ind(l1h, tn, *first_fn, chan, tch_data,
|
||||
23);
|
||||
|
||||
if (rc == 23) {
|
||||
compose_ph_data_ind(l1h, tn, *first_fn, chan, tch_data, 23);
|
||||
bfi:
|
||||
// FIXME length depends on codec
|
||||
rc = 33;
|
||||
/* indicate bad tch frame */
|
||||
memset(tch_data, 0, sizeof(tch_data));
|
||||
}
|
||||
|
||||
/* TCH or BFI */
|
||||
return compose_tch_ind(l1h, tn, *first_fn, chan, tch_data, rc);
|
||||
}
|
||||
|
@ -1917,7 +1940,7 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
|
|||
l1h->chan_states[tn][i].ul_active = active;
|
||||
l1h->chan_states[tn][i].ul_active = active;
|
||||
}
|
||||
l1h->chan_states[tn][i].sacch_lost = 0;
|
||||
l1h->chan_states[tn][i].lost = 0;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue