fixeria has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmocom-bb/+/35582?usp=email )
Change subject: [WIP] mobile: integrate V.110 TA & soft-UART from libosmocore
......................................................................
[WIP] mobile: integrate V.110 TA & soft-UART from libosmocore
Change-Id: I7ac9c0e5010730fa4d8bc7a7a3c7ff85e11731c0
Depends: libosmocore.git I5716bd6fd0201ee7a7a29e72f775972cd374082f
Related: OS#4396
---
M src/host/layer23/configure.ac
M src/host/layer23/include/osmocom/bb/mobile/tch.h
M src/host/layer23/src/mobile/Makefile.am
M src/host/layer23/src/mobile/tch.c
A src/host/layer23/src/mobile/tch_data.c
5 files changed, 375 insertions(+), 11 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/82/35582/1
diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac
index b4eb860..7fb8bf1 100644
--- a/src/host/layer23/configure.ac
+++ b/src/host/layer23/configure.ac
@@ -45,6 +45,7 @@
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm)
+PKG_CHECK_MODULES(LIBOSMOISDN, libosmoisdn)
PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec)
PKG_CHECK_MODULES(LIBOSMOGPRSRLCMAC, libosmo-gprs-rlcmac)
PKG_CHECK_MODULES(LIBOSMOGPRSLLC, libosmo-gprs-llc)
diff --git a/src/host/layer23/include/osmocom/bb/mobile/tch.h
b/src/host/layer23/include/osmocom/bb/mobile/tch.h
index d2cb4bc..a31655a 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/tch.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/tch.h
@@ -13,6 +13,8 @@
} voice;
struct tch_data_state {
enum tch_data_io_handler handler;
+ struct osmo_v110_ta *v110_ta;
+ struct osmo_soft_uart *suart;
} data;
};
};
diff --git a/src/host/layer23/src/mobile/Makefile.am
b/src/host/layer23/src/mobile/Makefile.am
index 0639916..b4e45e2 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -8,6 +8,7 @@
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOISDN_CFLAGS) \
$(LIBOSMOGPRSRLCMAC_CFLAGS) \
$(LIBOSMOGPRSLLC_CFLAGS) \
$(LIBOSMOGPRSSNDCP_CFLAGS) \
@@ -31,6 +32,7 @@
mncc_sock.c \
primitives.c \
tch.c \
+ tch_data.c \
tch_voice.c \
transaction.c \
vty_interface.c \
@@ -45,6 +47,7 @@
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOISDN_LIBS) \
$(LIBOSMOGPRSRLCMAC_LIBS) \
$(LIBOSMOGPRSLLC_LIBS) \
$(LIBOSMOGPRSSNDCP_LIBS) \
diff --git a/src/host/layer23/src/mobile/tch.c b/src/host/layer23/src/mobile/tch.c
index e5599dd..fa457ac 100644
--- a/src/host/layer23/src/mobile/tch.c
+++ b/src/host/layer23/src/mobile/tch.c
@@ -37,9 +37,14 @@
int tch_voice_state_init(struct gsm_trans *trans,
struct tch_voice_state *state);
+int tch_data_state_init(struct gsm_trans *trans,
+ struct tch_data_state *state);
+
void tch_voice_state_free(struct tch_voice_state *state);
+void tch_data_state_free(struct tch_data_state *state);
int tch_voice_recv(struct osmocom_ms *ms, struct msgb *msg);
+int tch_data_recv(struct osmocom_ms *ms, struct msgb *msg);
int tch_voice_serve_ms(struct osmocom_ms *ms);
/* Receive a Downlink traffic (voice/data) frame from the lower layers */
@@ -54,10 +59,8 @@
if (state->voice_or_data)
return tch_voice_recv(ms, msg);
- else /* TODO: tch_recv_data() */
- msgb_free(msg);
-
- return 0;
+ else
+ return tch_data_recv(ms, msg);
}
/* Send an Uplink voice frame to the lower layers */
@@ -139,14 +142,11 @@
case GSM48_CMODE_DATA_12k0:
case GSM48_CMODE_DATA_6k0:
case GSM48_CMODE_DATA_3k6:
-#if 0
state->voice_or_data = false;
state->data.handler = ms->settings.tch_data.io_handler;
- /* TODO: tch_data_state_init() */
if (tch_data_state_init(trans, &state->data) != 0)
goto exit_free;
break;
-#endif
case GSM48_CMODE_SIGN:
default:
LOGP(DL1C, LOGL_ERROR, "Unhandled channel mode %s\n",
@@ -168,10 +168,8 @@
return;
if (state->voice_or_data)
tch_voice_state_free(&state->voice);
-#if 0
- else /* TODO: tch_state_free_data() */
- tch_state_free_data(&state->data);
-#endif
+ else
+ tch_data_state_free(&state->data);
talloc_free(state);
ms->tch_state = NULL;
diff --git a/src/host/layer23/src/mobile/tch_data.c
b/src/host/layer23/src/mobile/tch_data.c
new file mode 100644
index 0000000..082c397
--- /dev/null
+++ b/src/host/layer23/src/mobile/tch_data.c
@@ -0,0 +1,349 @@
+/*
+ * (C) 2023 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 <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/soft_uart.h>
+
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/gsm/gsm44021.h>
+
+#include <osmocom/isdn/v110.h>
+#include <osmocom/isdn/v110_ta.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/ms.h>
+#include <osmocom/bb/mobile/mncc.h>
+#include <osmocom/bb/mobile/transaction.h>
+#include <osmocom/bb/mobile/tch.h>
+
+struct csd_v110_frame_desc {
+ uint16_t num_blocks;
+ uint16_t num_bits;
+};
+
+struct csd_v110_lchan_desc {
+ struct csd_v110_frame_desc fr;
+ struct csd_v110_frame_desc hr;
+};
+
+/* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */
+const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = {
+#if 0
+ [GSM48_CMODE_DATA_14k5] = {
+ /* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */
+ .fr = { .num_blocks = 1, .num_bits = 290 },
+ },
+#endif
+ [GSM48_CMODE_DATA_12k0] = {
+ /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */
+ .fr = { .num_blocks = 4, .num_bits = 60 },
+ },
+ [GSM48_CMODE_DATA_6k0] = {
+ /* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */
+ .fr = { .num_blocks = 2, .num_bits = 60 },
+ /* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */
+ .hr = { .num_blocks = 4, .num_bits = 60 },
+ },
+ [GSM48_CMODE_DATA_3k6] = {
+ /* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */
+ .fr = { .num_blocks = 2, .num_bits = 36 },
+ /* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */
+ .hr = { .num_blocks = 4, .num_bits = 36 },
+ },
+};
+
+static void tch_soft_uart_rx_cb(void *priv, struct msgb *msg, unsigned int flags)
+{
+ LOGP(DL1C, LOGL_FATAL, "%s(): [flags=0x%08x] %s\n",
+ __func__, flags, msgb_hexdump(msg));
+ msgb_free(msg);
+}
+
+static void tch_soft_uart_tx_cb(void *priv, struct msgb *msg)
+{
+ const char *data = "TEST\r\n";
+ size_t n_bytes;
+
+ n_bytes = OSMO_MIN(msg->data_len, strlen(data));
+ if (n_bytes > 0)
+ memcpy(msgb_put(msg, n_bytes), (void *)data, n_bytes);
+}
+
+struct osmo_soft_uart *tch_soft_uart_alloc(struct osmocom_ms *ms)
+{
+ struct osmo_soft_uart *suart;
+
+ /* FIXME: take the exact config from BCap */
+ const struct osmo_soft_uart_cfg cfg = {
+ .num_data_bits = 8,
+ .num_stop_bits = 1,
+ .parity_mode = OSMO_SUART_PARITY_NONE,
+ .rx_buf_size = 1024, /* TODO: align with the current TCH mode */
+ .rx_timeout_ms = 100, /* TODO: align with TCH framing interval */
+ .priv = &ms->tch_state->data,
+ .rx_cb = &tch_soft_uart_rx_cb,
+ .tx_cb = &tch_soft_uart_tx_cb,
+ };
+
+ suart = osmo_soft_uart_alloc(ms, "csd_soft_uart", &cfg);
+ if (suart == NULL)
+ return NULL;
+
+ osmo_soft_uart_set_rx(suart, true);
+ osmo_soft_uart_set_tx(suart, true);
+
+ return suart;
+}
+
+/*************************************************************************************/
+
+static void tch_v110_ta_rx_cb(void *priv, const ubit_t *buf, size_t buf_size)
+{
+ struct tch_data_state *state = (struct tch_data_state *)priv;
+
+ /* XXX: we're assuming async call here */
+ osmo_soft_uart_rx_ubits(state->suart, buf, buf_size);
+}
+
+static void tch_v110_ta_tx_cb(void *priv, ubit_t *buf, size_t buf_size)
+{
+ struct tch_data_state *state = (struct tch_data_state *)priv;
+
+ /* XXX: we're assuming async call here */
+ osmo_soft_uart_tx_ubits(state->suart, buf, buf_size);
+}
+
+static void tch_v110_ta_status_update_cb(void *priv, unsigned int status)
+{
+ LOGP(DL1C, LOGL_DEBUG, "%s(): [status=0x%08x]\n", __func__, status);
+ /* TODO: update status lines of the soft-UART */
+}
+
+struct osmo_v110_ta *tch_v110_ta_alloc(struct osmocom_ms *ms,
+ enum osmo_v100_sync_ra1_rate rate)
+{
+ const struct osmo_v110_ta_cfg cfg = {
+ .rate = rate,
+ .priv = &ms->tch_state->data,
+ .rx_cb = &tch_v110_ta_rx_cb,
+ .tx_cb = &tch_v110_ta_tx_cb,
+ .status_update_cb = &tch_v110_ta_status_update_cb,
+ };
+
+ return osmo_v110_ta_alloc(ms, "csd_v110_ta", &cfg);
+}
+
+/*************************************************************************************/
+
+static void swap_words(uint8_t *data, size_t data_len)
+{
+ /* swap bytes in words */
+ while (data_len >= 2) {
+ uint8_t tmp = data[0];
+ data[0] = data[1];
+ data[1] = tmp;
+ data_len -= 2;
+ data += 2;
+ }
+}
+
+int tch_csd_rx_from_l1(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct tch_data_state *state = &ms->tch_state->data;
+ const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
+ const struct csd_v110_frame_desc *desc;
+ ubit_t data[4 * 60];
+
+ if (msgb_l3len(msg) < 30)
+ return -EINVAL;
+
+ if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs)
+ desc = &csd_v110_lchan_desc[cd->mode].fr;
+ else /* RSL_CHAN_Lm_ACCHs */
+ desc = &csd_v110_lchan_desc[cd->mode].hr;
+ if (OSMO_UNLIKELY(desc->num_blocks == 0))
+ return -ENOTSUP;
+
+ switch (ms->settings.tch_data.io_format) {
+ case TCH_DATA_IOF_OSMO:
+ break;
+ case TCH_DATA_IOF_TI:
+ /* the layer1 firmware emits frames with swapped words (LE ordering) */
+ swap_words(msgb_l3(msg), msgb_l3len(msg));
+ break;
+ }
+
+ /* unpack packed bits (MSB goes first) */
+ osmo_pbit2ubit_ext(data, 0, msgb_l3(msg), 0, sizeof(data), 1);
+
+ for (unsigned int i = 0; i < desc->num_blocks; i++) {
+ struct osmo_v110_decoded_frame df;
+
+ if (desc->num_bits == 60)
+ osmo_csd_12k_6k_decode_frame(&df, &data[i * 60], 60);
+ else /* desc->num_bits == 36 */
+ osmo_csd_3k6_decode_frame(&df, &data[i * 36], 36);
+
+ /* FIXME: properly set E1/E2/E3 depending on data rate */
+ df.e_bits[0] = 0;
+ df.e_bits[1] = 1;
+ df.e_bits[2] = 1;
+
+ osmo_v110_ta_frame_in(state->v110_ta, &df);
+ }
+
+ return 0;
+}
+
+int tch_csd_tx_to_l1(struct osmocom_ms *ms)
+{
+ struct tch_data_state *state = &ms->tch_state->data;
+ const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
+ const struct csd_v110_frame_desc *desc;
+ ubit_t data[60 * 4];
+ struct msgb *nmsg;
+
+ if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs)
+ desc = &csd_v110_lchan_desc[cd->mode].fr;
+ else /* RSL_CHAN_Lm_ACCHs */
+ desc = &csd_v110_lchan_desc[cd->mode].hr;
+ if (OSMO_UNLIKELY(desc->num_blocks == 0))
+ return -ENOTSUP;
+
+ for (unsigned int i = 0; i < desc->num_blocks; i++) {
+ struct osmo_v110_decoded_frame df;
+
+ if (osmo_v110_ta_frame_out(state->v110_ta, &df) != 0)
+ memset(&df, 0x01, sizeof(df));
+
+ /* set E7 to binary 0 in every 4-th frame
+ * (as per 3GPP TS 44.021, subclause 10.2.1)
+ * FIXME: properly handle desc->num_blocks == 2 */
+ df.e_bits[6] = (i > 0);
+
+ if (desc->num_bits == 60)
+ osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df);
+ else /* desc->num_bits == 36 */
+ osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df);
+ }
+
+ nmsg = msgb_alloc_headroom(33 + 64, 64, __func__);
+ OSMO_ASSERT(nmsg != NULL);
+
+ nmsg->l2h = msgb_put(nmsg, 33); /* XXX: proper size */
+
+ /* pack unpacked bits (MSB goes first) */
+ osmo_ubit2pbit_ext(msgb_l2(nmsg), 0, &data[0], 0, sizeof(data), 1);
+
+ switch (ms->settings.tch_data.io_format) {
+ case TCH_DATA_IOF_OSMO:
+ break;
+ case TCH_DATA_IOF_TI:
+ /* the layer1 firmware expects frames with swapped words (LE ordering) */
+ swap_words(msgb_l2(nmsg), msgb_l2len(nmsg));
+ break;
+ }
+
+ return gsm48_rr_tx_traffic(ms, nmsg);
+}
+
+/* TODO: set/unset OSMO_V110_TA_C_108 */
+/* TODO: call osmo_v110_ta_sync_ind() */
+
+/*************************************************************************************/
+
+int tch_data_recv(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct tch_data_state *state = &ms->tch_state->data;
+
+ switch (state->handler) {
+ case TCH_DATA_IOH_LOOPBACK:
+ /* Remove the DL info header */
+ msgb_pull_to_l2(msg);
+ /* Send data frame back */
+ return tch_send_msg(ms, msg);
+ case TCH_DATA_IOH_UNIX_SOCK:
+ tch_csd_rx_from_l1(ms, msg);
+ tch_csd_tx_to_l1(ms);
+ msgb_free(msg);
+ break;
+ case TCH_DATA_IOH_NONE:
+ /* Drop voice frame */
+ msgb_free(msg);
+ }
+
+ return 0;
+}
+
+int tch_data_state_init(struct gsm_trans *trans,
+ struct tch_data_state *state)
+{
+ struct osmocom_ms *ms = trans->ms;
+
+ switch (state->handler) {
+ case TCH_DATA_IOH_UNIX_SOCK:
+ /* TODO: open listening socket */
+ break;
+ case TCH_DATA_IOH_LOOPBACK:
+ case TCH_DATA_IOH_NONE:
+ /* we don't need V.110 TA / soft-UART */
+ return 0;
+ default:
+ break;
+ }
+
+#if 1
+ state->suart = tch_soft_uart_alloc(ms);
+ if (state->suart == NULL)
+ goto exit_free;
+#endif
+
+ state->v110_ta = tch_v110_ta_alloc(ms, OSMO_V110_SYNC_RA1_9600); /* XXX */
+ if (state->v110_ta == NULL)
+ goto exit_free;
+
+ return 0;
+
+exit_free:
+ if (state->suart != NULL)
+ osmo_soft_uart_free(state->suart);
+ if (state->v110_ta != NULL)
+ osmo_v110_ta_free(state->v110_ta);
+ return -1;
+}
+
+void tch_data_state_free(struct tch_data_state *state)
+{
+ if (state->suart != NULL)
+ osmo_soft_uart_free(state->suart);
+ if (state->v110_ta != NULL)
+ osmo_v110_ta_free(state->v110_ta);
+
+ switch (state->handler) {
+ case TCH_DATA_IOH_UNIX_SOCK:
+ /* TODO: close listening socket */
+ break;
+ default:
+ break;
+ }
+}
--
To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/35582?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I7ac9c0e5010730fa4d8bc7a7a3c7ff85e11731c0
Gerrit-Change-Number: 35582
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange