Timur Davydov has uploaded this change for review.
trx: add JSON serialization for 'show trx'
Introduce trx_to_json() helper to serialize the output of
'show trx' into JSON format.
Also initialize talloc/VTY context in websdr entrypoint to
allow accessing TRX configuration programmatically.
Intended for external consumers (e.g. WebSDR frontend).
Change-Id: Icbfb754580daa6db9b5646cc6698a6a6ee1c1610
---
M CommonLibs/Makefile.am
A CommonLibs/trx_stats_json.c
A CommonLibs/trx_stats_json.h
M Transceiver52M/osmo-trx-websdr.cpp
4 files changed, 290 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/78/42678/1
diff --git a/CommonLibs/Makefile.am b/CommonLibs/Makefile.am
index 4a0652d..23feb98 100644
--- a/CommonLibs/Makefile.am
+++ b/CommonLibs/Makefile.am
@@ -59,3 +59,8 @@
debug.h \
osmo_signal.h \
config_defs.h
+
+if ENABLE_WEBSDR
+libcommon_la_SOURCES += trx_stats_json.c
+include_HEADERS = trx_stats_json.h
+endif
diff --git a/CommonLibs/trx_stats_json.c b/CommonLibs/trx_stats_json.c
new file mode 100644
index 0000000..8eff19d
--- /dev/null
+++ b/CommonLibs/trx_stats_json.c
@@ -0,0 +1,243 @@
+/* JSON helpers for OsmoTRX: trx serialization API implementation
+ *
+ * Copyright (C) 2026 Timur Davydov <dtv.comp@gmail.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <osmocom/core/utils.h>
+
+#include "trx_vty.h"
+#include "config_defs.h"
+
+#include "trx_stats_json.h"
+
+/* function trx_from_vty is implemented in trx_vty.c */
+struct trx_ctx *trx_from_vty(struct vty *v);
+
+/* JSON serialization context for transceiver config */
+struct trx_stats_json_ctx {
+ char *buf;
+ size_t buflen;
+ size_t off;
+};
+
+/* append a single character into ctx->buf */
+static int tsj_append_char(struct trx_stats_json_ctx *ctx, char c)
+{
+ if (ctx->off + 1 >= ctx->buflen)
+ return -ENOSPC;
+
+ ctx->buf[ctx->off++] = c;
+ ctx->buf[ctx->off] = '\0';
+
+ return 0;
+}
+
+/* append a formatted string into ctx->buf */
+static int tsj_append_fmt(struct trx_stats_json_ctx *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ int rc;
+ size_t rem;
+
+ if (ctx->off >= ctx->buflen)
+ return -ENOSPC;
+
+ rem = ctx->buflen - ctx->off;
+ va_start(ap, fmt);
+ rc = vsnprintf(ctx->buf + ctx->off, rem, fmt, ap);
+ va_end(ap);
+
+ if (rc < 0)
+ return -EIO;
+ if ((size_t)rc >= rem)
+ return -ENOSPC;
+
+ ctx->off += rc;
+ return 0;
+}
+
+/* simple JSON string escaper that appends into ctx->buf */
+static int tsj_append_json_str(struct trx_stats_json_ctx *ctx, const char *s)
+{
+ int rc;
+
+ if (!s) s = "";
+
+ rc = tsj_append_char(ctx, '"');
+ if (rc)
+ return rc;
+
+ for (size_t j = 0; s[j] != '\0'; j++) {
+ char c = s[j];
+ if (c == '"' || c == '\\') {
+ rc = tsj_append_char(ctx, '\\');
+ if (rc)
+ return rc;
+ rc = tsj_append_char(ctx, c);
+ if (rc)
+ return rc;
+ } else if ((unsigned char)c < 0x20) {
+ rc = tsj_append_char(ctx, ' ');
+ if (rc)
+ return rc;
+ } else {
+ rc = tsj_append_char(ctx, c);
+ if (rc)
+ return rc;
+ }
+ }
+
+ return tsj_append_char(ctx, '"');
+}
+
+/* Build JSON for 'show trx' by enumerating transceivers */
+int trx_to_json(char *buf, size_t buflen)
+{
+ struct trx_ctx *trx = trx_from_vty(NULL);
+ struct trx_stats_json_ctx ctx = {
+ .buf = buf,
+ .buflen = buflen,
+ };
+ int rc;
+
+ if (!buf || buflen == 0)
+ return -EINVAL;
+
+ rc = tsj_append_char(&ctx, '{');
+ if (rc)
+ return rc;
+
+ if (!trx) {
+ rc = tsj_append_fmt(&ctx, "\"trx_config\":null");
+ if (rc)
+ return rc;
+ } else {
+ rc = tsj_append_fmt(&ctx, "\"trx_config\":{");
+ if (rc)
+ return rc;
+
+ rc = tsj_append_fmt(&ctx, "\"local_ip\":");
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, trx->cfg.bind_addr);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_fmt(&ctx, ",\"remote_ip\":");
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, trx->cfg.remote_addr);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_fmt(&ctx, ",\"base_port\":%u,\"dev_args\":", trx->cfg.base_port);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, trx->cfg.dev_args);
+ if (rc)
+ return rc;
+
+ const char *filler_str = get_value_string(filler_names, trx->cfg.filler);
+ const char *clock_ref_str = get_value_string(clock_ref_names, trx->cfg.clock_ref);
+
+ rc = tsj_append_fmt(&ctx, ",\"tx_sps\":%u,\"rx_sps\":%u,\"filler\":",
+ trx->cfg.tx_sps, trx->cfg.rx_sps);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, filler_str);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_fmt(&ctx, ",\"rtsc\":%u,\"rach_delay\":%u,\"clock_ref\":",
+ trx->cfg.rtsc, trx->cfg.rach_delay);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, clock_ref_str);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_fmt(&ctx,
+ ",\"multi_arfcn\":%s,\"offset\":%f,\"rssi_offset\":%f"
+ ",\"swap_channels\":%s,\"egprs\":%s,\"ext_rach\":%s,\"sched_rr\":%u,\"stack_size\":%u"
+ ",\"channels\":[",
+ trx->cfg.multi_arfcn ? "true" : "false",
+ trx->cfg.offset, trx->cfg.rssi_offset,
+ trx->cfg.swap_channels ? "true" : "false",
+ trx->cfg.egprs ? "true" : "false",
+ trx->cfg.ext_rach ? "true" : "false",
+ trx->cfg.sched_rr, trx->cfg.stack_size);
+ if (rc)
+ return rc;
+
+ for (unsigned int i = 0; i < trx->cfg.num_chans; i++) {
+ struct trx_chan *chan = &trx->cfg.chans[i];
+ if (i != 0) {
+ rc = tsj_append_char(&ctx, ',');
+ if (rc)
+ return rc;
+ }
+ rc = tsj_append_fmt(&ctx, "{\"idx\":%u,\"rx_path\":", chan->idx);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, chan->rx_path);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_fmt(&ctx, ",\"tx_path\":");
+ if (rc)
+ return rc;
+
+ rc = tsj_append_json_str(&ctx, chan->tx_path);
+ if (rc)
+ return rc;
+
+ rc = tsj_append_char(&ctx, '}');
+ if (rc)
+ return rc;
+ }
+
+ rc = tsj_append_char(&ctx, ']');
+ if (rc)
+ return rc;
+
+ rc = tsj_append_char(&ctx, '}');
+ if (rc)
+ return rc;
+ }
+
+ rc = tsj_append_char(&ctx, '}');
+ if (rc)
+ return rc;
+
+ return (int)ctx.off;
+}
diff --git a/CommonLibs/trx_stats_json.h b/CommonLibs/trx_stats_json.h
new file mode 100644
index 0000000..37f331f
--- /dev/null
+++ b/CommonLibs/trx_stats_json.h
@@ -0,0 +1,36 @@
+/* JSON helpers for OsmoTXR: trx serialization API
+ *
+ * Copyright (C) 2026 Timur Davydov <dtv.comp@gmail.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TRX_STATS_JSON_H
+#define TRX_STATS_JSON_H
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int trx_to_json(char *buf, size_t buflen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TRX_STATS_JSON_H */
diff --git a/Transceiver52M/osmo-trx-websdr.cpp b/Transceiver52M/osmo-trx-websdr.cpp
index 8913893..69265af 100644
--- a/Transceiver52M/osmo-trx-websdr.cpp
+++ b/Transceiver52M/osmo-trx-websdr.cpp
@@ -40,6 +40,7 @@
uint32_t g_tx_ts;
uint32_t g_tx_len;
+static void *tall_trx_ctx;
static struct trx_ctx *g_trx_ctx;
static RadioDevice *usrp;
@@ -201,6 +202,9 @@
convolve_init();
convert_init();
+ tall_trx_ctx = talloc_named_const(NULL, 0, "OsmoTRX");
+ g_trx_ctx = vty_trx_ctx_alloc(tall_trx_ctx);
+
g_trx_ctx->cfg.tx_sps = 4;
g_trx_ctx->cfg.rx_sps = 4;
g_trx_ctx->cfg.base_port = 5700;
@@ -218,6 +222,8 @@
srandom(time(NULL));
+ trx_vty_init(g_trx_ctx);
+
if(trx_start(g_trx_ctx) < 0)
return EXIT_FAILURE;
To view, visit change 42678. To unsubscribe, or for help writing mail filters, visit settings.