summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/host/trxcon/sched_prim.c89
-rw-r--r--src/host/trxcon/sched_trx.c13
-rw-r--r--src/host/trxcon/sched_trx.h12
-rw-r--r--src/host/trxcon/trxcon.c4
4 files changed, 118 insertions, 0 deletions
diff --git a/src/host/trxcon/sched_prim.c b/src/host/trxcon/sched_prim.c
index fb5f0a0d..c17fb2a4 100644
--- a/src/host/trxcon/sched_prim.c
+++ b/src/host/trxcon/sched_prim.c
@@ -23,6 +23,7 @@
*/
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <talloc.h>
@@ -31,6 +32,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
#include "scheduler.h"
#include "sched_trx.h"
@@ -227,6 +229,93 @@ void sched_prim_drop(struct trx_lchan_state *lchan)
}
/**
+ * Assigns a dummy primitive to a lchan depending on its type.
+ * Could be used when there is nothing to transmit, but
+ * CBTX (Continuous Burst Transmission) is assumed.
+ *
+ * @param lchan lchan to assign a primitive
+ * @return zero in case of success, otherwise a error code
+ */
+int sched_prim_dummy(struct trx_lchan_state *lchan)
+{
+ enum trx_lchan_type chan = lchan->type;
+ uint8_t tch_mode = lchan->tch_mode;
+ struct trx_ts_prim *prim;
+ uint8_t prim_buffer[40];
+ size_t prim_len = 0;
+ int i;
+
+ /**
+ * TS 144.006, section 8.4.2.3 "Fill frames"
+ * A fill frame is a UI command frame for SAPI 0, P=0
+ * and with an information field of 0 octet length.
+ */
+ static const uint8_t lapdm_fill_frame[] = {
+ 0x01, 0x03, 0x01,
+ /* Pending part is to be randomized */
+ };
+
+ /* Make sure that there is no existing primitive */
+ OSMO_ASSERT(lchan->prim == NULL);
+
+ /**
+ * Determine what actually should be generated:
+ * TCH in GSM48_CMODE_SIGN: LAPDm fill frame;
+ * TCH in other modes: silence frame;
+ * other channels: LAPDm fill frame.
+ */
+ if (CHAN_IS_TCH(chan) && TCH_MODE_IS_SPEECH(tch_mode)) {
+ /**
+ * Silence frame indication
+ * HACK: use actual rsl_cmode!
+ */
+ prim_len = sched_bad_frame_ind(prim_buffer,
+ RSL_CMOD_SPD_SPEECH, tch_mode);
+ } else if (CHAN_IS_TCH(chan) && TCH_MODE_IS_DATA(tch_mode)) {
+ /* FIXME: should we do anything for CSD? */
+ return 0;
+ } else {
+ /**
+ * TS 144.006, section 8.1.2.3 "Fill frames"
+ * A fill frame is a UI command frame for SAPI 0, P=0
+ * and with an information field of 0 octet length.
+ */
+ memcpy(prim_buffer, lapdm_fill_frame, 3);
+
+ /* Randomize pending unused bytes */
+ for (i = 3; i < GSM_MACBLOCK_LEN; i++)
+ prim_buffer[i] = (uint8_t) rand();
+
+ /* Define a prim length */
+ prim_len = GSM_MACBLOCK_LEN;
+ }
+
+ /* Nothing to allocate / assign */
+ if (!prim_len)
+ return 0;
+
+ /* Allocate a new primitive */
+ prim = talloc_zero_size(lchan, sizeof(struct trx_ts_prim) + prim_len);
+ if (prim == NULL)
+ return -ENOMEM;
+
+ /* Init primitive header */
+ prim->payload_len = prim_len;
+ prim->chan = lchan->type;
+
+ /* Fill in the payload */
+ memcpy(prim->payload, prim_buffer, prim_len);
+
+ /* Assign the current prim */
+ lchan->prim = prim;
+
+ LOGP(DSCHD, LOGL_DEBUG, "Transmitting a dummy / silence frame "
+ "on lchan=%s\n", trx_lchan_desc[chan].name);
+
+ return 0;
+}
+
+/**
* Flushes a queue of primitives
*
* @param list list of prims going to be flushed
diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c
index 8c859dee..168c4efa 100644
--- a/src/host/trxcon/sched_trx.c
+++ b/src/host/trxcon/sched_trx.c
@@ -97,6 +97,19 @@ static void sched_frame_clck_cb(struct trx_sched *sched)
if (lchan->prim == NULL)
lchan->prim = sched_prim_dequeue(&ts->tx_prims, chan);
+ /* TODO: report TX buffers health to the higher layers */
+
+ /* If CBTX (Continuous Burst Transmission) is assumed */
+ if (trx_lchan_desc[chan].flags & TRX_CH_FLAG_CBTX) {
+ /**
+ * Probably, a TX buffer is empty. Nevertheless,
+ * we shall continuously transmit anything on
+ * CBTX channels.
+ */
+ if (lchan->prim == NULL)
+ sched_prim_dummy(lchan);
+ }
+
/* If there is no primitive, do nothing */
if (lchan->prim == NULL)
continue;
diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h
index 6a025436..d9e0c8ed 100644
--- a/src/host/trxcon/sched_trx.h
+++ b/src/host/trxcon/sched_trx.h
@@ -275,6 +275,17 @@ int sched_prim_init(struct trx_instance *trx, struct trx_ts_prim **prim,
int sched_prim_push(struct trx_instance *trx,
struct trx_ts_prim *prim, uint8_t chan_nr);
+#define TCH_MODE_IS_SPEECH(mode) \
+ (mode == GSM48_CMODE_SPEECH_V1 \
+ || mode == GSM48_CMODE_SPEECH_EFR \
+ || mode == GSM48_CMODE_SPEECH_AMR)
+
+#define TCH_MODE_IS_DATA(mode) \
+ (mode == GSM48_CMODE_DATA_14k5 \
+ || mode == GSM48_CMODE_DATA_12k0 \
+ || mode == GSM48_CMODE_DATA_6k0 \
+ || mode == GSM48_CMODE_DATA_3k6)
+
#define CHAN_IS_TCH(chan) \
(chan == TRXC_TCHF || chan == TRXC_TCHH_0 || chan == TRXC_TCHH_1)
@@ -286,6 +297,7 @@ int sched_prim_push(struct trx_instance *trx,
struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,
enum trx_lchan_type lchan_type);
+int sched_prim_dummy(struct trx_lchan_state *lchan);
void sched_prim_drop(struct trx_lchan_state *lchan);
void sched_prim_flush_queue(struct llist_head *list);
diff --git a/src/host/trxcon/trxcon.c b/src/host/trxcon/trxcon.c
index 55422403..43c98a5c 100644
--- a/src/host/trxcon/trxcon.c
+++ b/src/host/trxcon/trxcon.c
@@ -28,6 +28,7 @@
#include <getopt.h>
#include <unistd.h>
#include <signal.h>
+#include <time.h>
#include <arpa/inet.h>
@@ -293,6 +294,9 @@ int main(int argc, char **argv)
}
}
+ /* Initialize pseudo-random generator */
+ srand(time(NULL));
+
while (!app_data.quit)
osmo_select_main(0);