From e3f96a21bd260161f3128a6f6dda182cb3d306e3 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Fri, 31 Jul 2020 19:04:00 +0200 Subject: i460_mux: add callback to notify empty tx queue There is no way for the API user to know if the TX queue of the multiplexer runs empty. However, this is criticil since an empty TX queue will cause dropout of a TRAU frame, which can have quite severe effects to the receiving end. Lets add a callback that allows the APU user to insert appropiate idle frames or silent frames into the queue before it runs empty. Change-Id: I88a87724235fe50d55ce6215bb385c044072226e Related: OS#2547 --- include/osmocom/gsm/i460_mux.h | 11 +++++++++++ src/gsm/i460_mux.c | 14 +++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/osmocom/gsm/i460_mux.h b/include/osmocom/gsm/i460_mux.h index 2e33b37e..1c18a3fd 100644 --- a/include/osmocom/gsm/i460_mux.h +++ b/include/osmocom/gsm/i460_mux.h @@ -52,9 +52,13 @@ struct osmo_i460_subchan_demux { void *user_data; }; +typedef void (*in_cb_queue_empty_t)(void *user_data); + struct osmo_i460_subchan_mux { /*! list of to-be-transmitted message buffers */ struct llist_head tx_queue; + in_cb_queue_empty_t in_cb_queue_empty; + void *user_data; }; struct osmo_i460_subchan { @@ -87,6 +91,13 @@ struct osmo_i460_schan_desc { /* opaque user data pointer to pass to out_cb */ void *user_data; } demux; + + struct { + /* FIXME: docstring */ + in_cb_queue_empty_t in_cb_queue_empty; + /* opaque user data pointer to pass to in_cb */ + void *user_data; + } mux; }; void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len); diff --git a/src/gsm/i460_mux.c b/src/gsm/i460_mux.c index 50cb56e9..dfd50e52 100644 --- a/src/gsm/i460_mux.c +++ b/src/gsm/i460_mux.c @@ -175,9 +175,15 @@ static ubit_t mux_schan_provide_bit(struct osmo_i460_subchan *schan) ubit_t bit; /* if we don't have anything to transmit, return '1' bits */ - if (llist_empty(&mux->tx_queue)) - return 0x01; - + if (llist_empty(&mux->tx_queue)) { + /* User code now has a last chance to put something into the queue. */ + if (mux->in_cb_queue_empty) + mux->in_cb_queue_empty(mux->user_data); + + /* If the queue is still empty, return idle bits */ + if (llist_empty(&mux->tx_queue)) + return 0x01; + } msg = llist_entry(mux->tx_queue.next, struct msgb, list); bit = msgb_pull_u8(msg); @@ -360,6 +366,8 @@ osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osm schan->demux.out_cb_bits = chd->demux.out_cb_bits; schan->demux.out_cb_bytes = chd->demux.out_cb_bytes; schan->demux.user_data = chd->demux.user_data; + schan->mux.in_cb_queue_empty = chd->mux.in_cb_queue_empty; + schan->mux.user_data = chd->mux.user_data; rc = alloc_bitbuf(ctx, schan, chd->demux.num_bits); if (rc < 0) { subchan_reset(schan, false); -- cgit v1.2.3