<p>Hoernchen has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-trx/+/19664">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">osmo-trx-ipc<br><br>This adds a IPC backend that uses shared memory interface<br>to communicate with (proprietary) devices.<br><br>Requires config file option<br>dev-args ipc_msock=/path/to/socket<br>to specify the master socket the ipc backend should connect to.<br><br>If UHD is avaialble the ipc-driver-test tool can be used to test the<br>backend with a uhd device, this was so far only tested with a b2xx.<br><br>Change-Id: Ice63d3499026293ade8aad675ff7a883bcdd5756<br><br>xxyy<br><br>Change-Id: Iefae70cc079a0174f48309f9ef25157c530e5c32<br>---<br>M .gitignore<br>M Transceiver52M/Makefile.am<br>M Transceiver52M/device/Makefile.am<br>A Transceiver52M/device/ipc/IPCDevice.cpp<br>A Transceiver52M/device/ipc/IPCDevice.h<br>A Transceiver52M/device/ipc/Makefile.am<br>A Transceiver52M/device/ipc/ipc-driver-test.c<br>A Transceiver52M/device/ipc/ipc-driver-test.h<br>A Transceiver52M/device/ipc/ipc_chan.c<br>A Transceiver52M/device/ipc/ipc_chan.h<br>A Transceiver52M/device/ipc/ipc_shm.c<br>A Transceiver52M/device/ipc/ipc_shm.h<br>A Transceiver52M/device/ipc/ipc_sock.c<br>A Transceiver52M/device/ipc/ipc_sock.h<br>A Transceiver52M/device/ipc/shm.c<br>A Transceiver52M/device/ipc/shm.h<br>A Transceiver52M/device/ipc/uhdwrap.cpp<br>A Transceiver52M/device/ipc/uhdwrap.h<br>M Transceiver52M/device/uhd/UHDDevice.cpp<br>M Transceiver52M/device/uhd/UHDDevice.h<br>M configure.ac<br>M contrib/jenkins.sh<br>M contrib/osmo-trx.spec.in<br>M contrib/systemd/Makefile.am<br>A contrib/systemd/osmo-trx-ipc.service<br>M debian/control<br>A debian/osmo-trx-ipc.install<br>M debian/rules<br>M doc/examples/Makefile.am<br>A doc/examples/osmo-trx-ipc/osmo-trx-ipc.cfg<br>30 files changed, 3,823 insertions(+), 10 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/64/19664/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/.gitignore b/.gitignore</span><br><span>index 128f803..5b864e7 100644</span><br><span>--- a/.gitignore</span><br><span>+++ b/.gitignore</span><br><span>@@ -5,6 +5,7 @@</span><br><span> Transceiver52M/osmo-trx-uhd</span><br><span> Transceiver52M/osmo-trx-usrp1</span><br><span> Transceiver52M/osmo-trx-lms</span><br><span style="color: hsl(120, 100%, 40%);">+Transceiver52M/osmo-trx-ipc</span><br><span> </span><br><span> # tests</span><br><span> tests/CommonLibs/BitVectorTest</span><br><span>@@ -19,6 +20,7 @@</span><br><span> tests/CommonLibs/PRBSTest</span><br><span> tests/Transceiver52M/convolve_test</span><br><span> tests/Transceiver52M/LMSDeviceTest</span><br><span style="color: hsl(120, 100%, 40%);">+Transceiver52M/device/ipc/ipc-driver-test</span><br><span> </span><br><span> # automake/autoconf</span><br><span> *.in</span><br><span>@@ -66,3 +68,5 @@</span><br><span> </span><br><span> contrib/osmo-trx.spec</span><br><span> !contrib/osmo-trx.spec.in</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+utils/osmo-prbs-tool</span><br><span>diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am</span><br><span>index ade4e30..7dad159 100644</span><br><span>--- a/Transceiver52M/Makefile.am</span><br><span>+++ b/Transceiver52M/Makefile.am</span><br><span>@@ -104,3 +104,13 @@</span><br><span>    $(LMS_LIBS)</span><br><span> osmo_trx_lms_CPPFLAGS  = $(AM_CPPFLAGS) $(LMS_CFLAGS)</span><br><span> endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_IPC</span><br><span style="color: hsl(120, 100%, 40%);">+bin_PROGRAMS += osmo-trx-ipc</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_trx_ipc_SOURCES = osmo-trx.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_trx_ipc_LDADD = \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(builddir)/device/ipc/libdevice.la \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(COMMON_LDADD)</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_trx_ipc_CPPFLAGS  = $(AM_CPPFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/Transceiver52M/device/Makefile.am b/Transceiver52M/device/Makefile.am</span><br><span>index 369e877..93ba7e3 100644</span><br><span>--- a/Transceiver52M/device/Makefile.am</span><br><span>+++ b/Transceiver52M/device/Makefile.am</span><br><span>@@ -2,6 +2,10 @@</span><br><span> </span><br><span> SUBDIRS = common</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_IPC</span><br><span style="color: hsl(120, 100%, 40%);">+SUBDIRS += ipc</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if DEVICE_USRP1</span><br><span> SUBDIRS += usrp1</span><br><span> endif</span><br><span>diff --git a/Transceiver52M/device/ipc/IPCDevice.cpp b/Transceiver52M/device/ipc/IPCDevice.cpp</span><br><span>new file mode 100644</span><br><span>index 0000000..1781751</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/IPCDevice.cpp</span><br><span>@@ -0,0 +1,1272 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: AGPL-3.0+</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+* it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+* the Free Software Foundation, either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+* (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+* but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+* GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+* along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+* See the COPYING file in the main directory for details.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <cstdint></span><br><span style="color: hsl(120, 100%, 40%);">+#include <cstring></span><br><span style="color: hsl(120, 100%, 40%);">+#include <cstdlib></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CONFIG_H</span><br><span style="color: hsl(120, 100%, 40%);">+#include "config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Logger.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Threads.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "IPCDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "smpl_buf.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/mman.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h> /* For mode constants */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <fcntl.h> /* For O_* constants */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmo_signal.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SAMPLE_BUF_SZ (1 << 20)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+using namespace std;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+IPCDevice::IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,</span><br><span style="color: hsl(120, 100%, 40%);">+               const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)</span><br><span style="color: hsl(120, 100%, 40%);">+  : RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths), tx_attenuation(),</span><br><span style="color: hsl(120, 100%, 40%);">+        tmp_state(IPC_IF_MSG_GREETING_REQ), shm(NULL), shm_dec(0), started(false)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGC(DDEV, INFO) << "creating IPC device...";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       //m_IPC_stream_rx.resize(chans);</span><br><span style="color: hsl(120, 100%, 40%);">+      //m_IPC_stream_tx.resize(chans);</span><br><span style="color: hsl(120, 100%, 40%);">+      rx_gains.resize(chans);</span><br><span style="color: hsl(120, 100%, 40%);">+       tx_gains.resize(chans);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rx_buffers.resize(chans);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sk_chan_state.resize(chans, ipc_per_trx_sock_state());</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Set up per-channel Rx timestamp based Ring buffers */</span><br><span style="color: hsl(120, 100%, 40%);">+      for (size_t i = 0; i < rx_buffers.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+IPCDevice::~IPCDevice()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      //unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGC(DDEV, INFO) << "Closing IPC device";</span><br><span style="color: hsl(120, 100%, 40%);">+     /* disable all channels */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (size_t i = 0; i < rx_buffers.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             delete rx_buffers[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_sock_close(&master_sk_state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (unsigned int i = 0; i < sk_chan_state.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            ipc_sock_close(&sk_chan_state[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (auto i : shm_io_rx_streams)</span><br><span style="color: hsl(120, 100%, 40%);">+              ipc_shm_close(i);</span><br><span style="color: hsl(120, 100%, 40%);">+     for (auto i : shm_io_tx_streams)</span><br><span style="color: hsl(120, 100%, 40%);">+              ipc_shm_close(i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (shm_dec)</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(shm_dec);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_shm_connect(const char *shm_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int fd;</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t shm_len;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DDEV, LOGL_NOTICE, "Opening shm path %s\n", shm_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((fd = shm_open(shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDEV, LOGL_ERROR, "shm_open %d: %s\n", errno, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+          goto err_shm_open;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   // Get size of the allocated memory</span><br><span style="color: hsl(120, 100%, 40%);">+   struct stat shm_stat;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fstat(fd, &shm_stat) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DDEV, LOGL_ERROR, "fstat %d: %s\n", errno, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+          goto err_mmap;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   shm_len = shm_stat.st_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DDEV, LOGL_NOTICE, "mmaping shared memory fd %d (size=%zu)\n", fd, shm_len);</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((shm = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DDEV, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+          goto err_mmap;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DDEV, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);</span><br><span style="color: hsl(120, 100%, 40%);">+     //      LOGP(DDEV, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));</span><br><span style="color: hsl(120, 100%, 40%);">+      /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */</span><br><span style="color: hsl(120, 100%, 40%);">+ close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+err_mmap:</span><br><span style="color: hsl(120, 100%, 40%);">+  shm_unlink(shm_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+err_shm_open:</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_sock_send(struct ipc_per_trx_sock_state *state, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb *ipc_msgb_alloc(uint8_t msg_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_alloc(sizeof(struct ipc_sk_if) + 1000, "ipc_sock_tx");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put(msg, sizeof(struct ipc_sk_if) + 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->msg_type = msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_tx_greeting_req(struct ipc_per_trx_sock_state *state, uint8_t req_version)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGC(DDEV, NOTICE) << "Tx Greeting Req (" << IPC_IF_MSG_GREETING_REQ << ")\n";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msg = ipc_msgb_alloc(IPC_IF_MSG_GREETING_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, INFO) << "ipc_msgb_alloc() returns NULL!";</span><br><span style="color: hsl(120, 100%, 40%);">+         return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.greeting_req.req_version = req_version;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return ipc_sock_send(state, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_tx_info_req(struct ipc_per_trx_sock_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     //struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGC(DDEV, NOTICE) << "Tx INFO Req\n";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msg = ipc_msgb_alloc(IPC_IF_MSG_INFO_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     //ipc_prim = (struct ipc_sk_if *) msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return ipc_sock_send(state, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_tx_open_req(struct ipc_per_trx_sock_state *state, uint32_t num_chans, uint32_t ref)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sk_if_open_req_chan *chan_info;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGC(DDEV, NOTICE) << "Tx Open Req\n";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msg = ipc_msgb_alloc(IPC_IF_MSG_OPEN_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.open_req.num_chans = num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* FIXME: this is actually the sps value, not the sample rate!</span><br><span style="color: hsl(120, 100%, 40%);">+         * sample rate is looked up according to the sps rate by uhd backend */</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim->u.open_req.rx_sample_freq_num = rx_sps;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.open_req.rx_sample_freq_den = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim->u.open_req.tx_sample_freq_num = tx_sps;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.open_req.tx_sample_freq_den = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (ref) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case ReferenceType::REF_EXTERNAL:</span><br><span style="color: hsl(120, 100%, 40%);">+             ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_EXTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case ReferenceType::REF_INTERNAL:</span><br><span style="color: hsl(120, 100%, 40%);">+     case ReferenceType::REF_GPS:</span><br><span style="color: hsl(120, 100%, 40%);">+          ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_INTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* FIXME: clock ref part of config, not open */</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_EXTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (unsigned int i = 0; i < num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             chan_info = &ipc_prim->u.open_req.chan_info[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_STRLCPY_ARRAY(chan_info->rx_path, rx_paths[i].c_str());</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_STRLCPY_ARRAY(chan_info->tx_path, tx_paths[i].c_str());</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ipc_sock_send(state, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void ipc_sock_timeout(void *_priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGC(DDEV, INFO) << "UNIX SOCKET TIMEOUT!";</span><br><span style="color: hsl(120, 100%, 40%);">+   exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (greeting_cnf->req_version == IPC_SOCK_API_VERSION) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, NOTICE) << "Rx Greeting CNF: correct sock API version" << greeting_cnf->req_version;</span><br><span style="color: hsl(120, 100%, 40%);">+              tmp_state = IPC_IF_MSG_GREETING_CNF;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, ERROR) << "Wrong IPC SOCK API VERSION RECEIVED!" << greeting_cnf->req_version;</span><br><span style="color: hsl(120, 100%, 40%);">+            exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  current_info_cnf = *info_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (info_cnf->max_num_chans < chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGC(DDEV, ERROR) << "chan num mismatch:" << info_cnf->max_num_chans << " vs " << chans;</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Here:</span><br><span style="color: hsl(120, 100%, 40%);">+       * verify info_cnf->max_num_chans >= requested chans</span><br><span style="color: hsl(120, 100%, 40%);">+     * verify supports setting reflock as asked by user looking in info_cnf->feature_mask</span><br><span style="color: hsl(120, 100%, 40%);">+       * cache locally min/max tx/rxGain values from info_cnf</span><br><span style="color: hsl(120, 100%, 40%);">+        * do whatever validations or print info_cnf->dev_desc</span><br><span style="color: hsl(120, 100%, 40%);">+      * cache rx/tx paths per channel, and make sure it matches the one the user wants to set</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+            << "Rx Info CNF:"</span><br><span style="color: hsl(120, 100%, 40%);">+             << " name=" << info_cnf->dev_desc << std::endl</span><br><span style="color: hsl(120, 100%, 40%);">+         << " max_num_chans=" << info_cnf->max_num_chans << " feature_mask=" << info_cnf->feature_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < info_cnf->max_num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int j = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+            bool rx_found = false, tx_found = false;</span><br><span style="color: hsl(120, 100%, 40%);">+              while (strcmp(info_cnf->chan_info[i].rx_path[j], "") != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+                            << "chan " << i << ": RxPath[" << j << "]: " << info_cnf->chan_info[i].rx_path[j]</span><br><span style="color: hsl(120, 100%, 40%);">+                                << " min_rx_gain=" << info_cnf->chan_info[i].min_rx_gain</span><br><span style="color: hsl(120, 100%, 40%);">+                             << " max_rx_gain=" << info_cnf->chan_info[i].max_rx_gain</span><br><span style="color: hsl(120, 100%, 40%);">+                             << " min_tx_gain=" << info_cnf->chan_info[i].min_tx_gain</span><br><span style="color: hsl(120, 100%, 40%);">+                             << " max_tx_gain=" << info_cnf->chan_info[i].max_tx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (rx_paths.size() < (i + 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                       strcmp(rx_paths[i].c_str(), info_cnf->chan_info[i].rx_path[j]) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         rx_found = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                              break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     j++;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             j = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                while (strcmp(info_cnf->chan_info[i].tx_path[j], "") != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+                            << "chan " << i << ": TxPath[" << j << "]: " << info_cnf->chan_info[i].tx_path[j];</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (tx_paths.size() < (i + 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                       strcmp(tx_paths[i].c_str(), info_cnf->chan_info[i].tx_path[j]) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         tx_found = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                              break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     j++;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!rx_found) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGC(DDEV, ERROR) << "rx antenna not found: " << rx_paths[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                   exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!tx_found) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGC(DDEV, ERROR) << "tx antenna not found: " << rx_paths[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                   exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     tmp_state = IPC_IF_MSG_INFO_CNF;</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       current_open_cnf = *open_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+            << "Rx Open CNF:"</span><br><span style="color: hsl(120, 100%, 40%);">+             << " return_code=" << (unsigned int)open_cnf->return_code << " shm_name=" << open_cnf->shm_name;</span><br><span style="color: hsl(120, 100%, 40%);">+    LOGC(DDEV, NOTICE) << "Rx Open CNF:"</span><br><span style="color: hsl(120, 100%, 40%);">+                     << " ipc device path delay: " << (unsigned int)open_cnf->path_delay;</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, NOTICE) << "chan " << i << ": sk_path=" << open_cnf->chan_info[i].chan_ipc_sk_path;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* FIXME: current limit IPC_MAX_NUM_TRX chans, make dynamic */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (i < IPC_MAX_NUM_TRX) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct ipc_per_trx_sock_state *state = &sk_chan_state[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       INIT_LLIST_HEAD(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+                      rc = osmo_sock_unix_init_ofd(&state->conn_bfd, SOCK_SEQPACKET, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   open_cnf->chan_info[i].chan_ipc_sk_path, OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGC(DDEV, ERROR) << "Failed to connect to the BTS ("</span><br><span style="color: hsl(120, 100%, 40%);">+                                           << open_cnf->chan_info[i].chan_ipc_sk_path << "). "</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  << "Retrying...\n";</span><br><span style="color: hsl(120, 100%, 40%);">+                         osmo_timer_setup(&state->timer, ipc_sock_timeout, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_timer_schedule(&state->timer, 5, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     state->conn_bfd.cb = ipc_chan_sock_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+                     state->conn_bfd.data = this;</span><br><span style="color: hsl(120, 100%, 40%);">+                       state->conn_bfd.priv_nr = i;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_STRLCPY_ARRAY(shm_name, open_cnf->shm_name);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ipc_shm_connect(shm_name) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    shm_dec = ipc_shm_decode_region(NULL, (ipc_shm_raw_region *)shm);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGC(DDEV, NOTICE) << "shm: num_chans=" << shm_dec->num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* server inits both producers */</span><br><span style="color: hsl(120, 100%, 40%);">+     for (unsigned int i = 0; i < shm_dec->num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    << "shm: chan" << i << "/dl: num_buffers=" << shm_dec->channels[i]->dl_stream->num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    << "shm: chan" << i << "/dl: buffer_size=" << shm_dec->channels[i]->dl_stream->buffer_size;</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    << "shm: chan" << i << "/ul: num_buffers=" << shm_dec->channels[i]->ul_stream->num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, NOTICE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    << "shm: chan" << i << "/ul: buffer_size=" << shm_dec->channels[i]->ul_stream->buffer_size;</span><br><span style="color: hsl(120, 100%, 40%);">+              shm_io_rx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->ul_stream));</span><br><span style="color: hsl(120, 100%, 40%);">+            shm_io_tx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->dl_stream));</span><br><span style="color: hsl(120, 100%, 40%);">+            //              shm_io_tx_streams.push_back(ipc_shm_init_producer(shm_dec->channels[i]->dl_stream));</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   tmp_state = IPC_IF_MSG_OPEN_CNF;</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case IPC_IF_MSG_GREETING_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = ipc_rx_greeting_cnf(&ipc_prim->u.greeting_cnf);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_INFO_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = ipc_rx_info_cnf(&ipc_prim->u.info_cnf);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_OPEN_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = ipc_rx_open_cnf(&ipc_prim->u.open_cnf);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDEV, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal start response for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+            return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal stop response for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal setgain response for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ret->is_tx ? tx_gains[chan_nr] = ret->gain : rx_gains[chan_nr] = ret->gain;</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal tx attn response for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   tx_attenuation[chan_nr] = ret->attenuation;</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal setfreq response for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal underfloww notification for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   m_ctr[chan_nr].tx_underruns += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_signal_dispatch(SS_DEVICE, S_DEVICE_COUNTER_CHANGE, &m_ctr[chan_nr]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (chan_nr >= chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, NOTICE) << "shm: illegal overflow notification for chan #" << chan_nr << " ?!?";</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   m_ctr[chan_nr].rx_overruns += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_signal_dispatch(SS_DEVICE, S_DEVICE_COUNTER_CHANGE, &m_ctr[chan_nr]);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case IPC_IF_MSG_START_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ipc_rx_chan_start_cnf(&ipc_prim->u.start_cnf, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_STOP_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = ipc_rx_chan_stop_cnf(&ipc_prim->u.stop_cnf, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_SETGAIN_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_rx_chan_setgain_cnf(&ipc_prim->u.set_gain_cnf, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_SETFREQ_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_rx_chan_setfreq_cnf(&ipc_prim->u.set_freq_cnf, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_NOTIFY_UNDERFLOW:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = ipc_rx_chan_notify_underflow(&ipc_prim->u.notify, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_NOTIFY_OVERFLOW:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_rx_chan_notify_overflow(&ipc_prim->u.notify, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_SETTXATTN_CNF:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = ipc_rx_chan_settxattn_cnf(&ipc_prim->u.txatten_cnf, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_sock_send(struct ipc_per_trx_sock_state *state, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fd *conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+     //struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!state) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMAIN, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "IPC socket not created, "</span><br><span style="color: hsl(120, 100%, 40%);">+                  "dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "IPC socket not connected, "</span><br><span style="color: hsl(120, 100%, 40%);">+                "dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_enqueue(&state->upqueue, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    conn_bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void IPCDevice::ipc_sock_close(struct ipc_per_trx_sock_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (state == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fd *bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (bfd->fd <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DDEV, LOGL_NOTICE, "IPC socket has LOST connection\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      close(bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+    bfd->fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fd_unregister(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* flush the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (!llist_empty(&state->upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg = msgb_dequeue(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_sock_read(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim = (struct ipc_sk_if *)msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((size_t)rc < sizeof(*ipc_prim)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDEV, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "Received %d bytes on Unix Socket, but primitive size "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "is %zu, discarding\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc, sizeof(*ipc_prim));</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ipc_rx(ipc_prim->msg_type, ipc_prim);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* as we always synchronously process the message in IPC_rx() and</span><br><span style="color: hsl(120, 100%, 40%);">+      * its callbacks, we can free the message here. */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_sock_close(&master_sk_state);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_chan_sock_read(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_chan_sock_rx");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim = (struct ipc_sk_chan_if *)msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((size_t)rc < sizeof(*ipc_prim)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDEV, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "Received %d bytes on Unix Socket, but primitive size "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "is %zu, discarding\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc, sizeof(*ipc_prim));</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* store mask of last received messages so we can check later */</span><br><span style="color: hsl(120, 100%, 40%);">+      sk_chan_state[bfd->priv_nr].messages_processed_mask |= (1 << (ipc_prim->msg_type - IPC_IF_CHAN_MSG_OFFSET));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* as we always synchronously process the message in IPC_rx() and</span><br><span style="color: hsl(120, 100%, 40%);">+      * its callbacks, we can free the message here. */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_sock_close(&sk_chan_state[bfd->priv_nr]);</span><br><span style="color: hsl(120, 100%, 40%);">+  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_sock_write(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while (!llist_empty(&master_sk_state.upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct msgb *msg, *msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* peek at the beginning of the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+              msg = llist_entry(master_sk_state.upqueue.next, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+           ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                bfd->when &= ~BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!msgb_length(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DDEV, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "message type (%d) with ZERO "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "bytes!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ipc_prim->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto dontsend;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* try to send it over the socket */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   dontsend:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* _after_ we send it, we can deueue */</span><br><span style="color: hsl(120, 100%, 40%);">+               msg2 = msgb_dequeue(&master_sk_state.upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+            assert(msg == msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_sock_close(&master_sk_state);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::ipc_chan_sock_write(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while (!llist_empty(&sk_chan_state[bfd->priv_nr].upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct msgb *msg, *msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* peek at the beginning of the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+              msg = llist_entry(sk_chan_state[bfd->priv_nr].upqueue.next, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+            ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+             bfd->when &= ~BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+            /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!msgb_length(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DDEV, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "message type (%d) with ZERO "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "bytes!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ipc_prim->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto dontsend;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* try to send it over the socket */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   dontsend:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* _after_ we send it, we can deueue */</span><br><span style="color: hsl(120, 100%, 40%);">+               msg2 = msgb_dequeue(&sk_chan_state[bfd->priv_nr].upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+             assert(msg == msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_sock_close(&sk_chan_state[bfd->priv_nr]);</span><br><span style="color: hsl(120, 100%, 40%);">+  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   IPCDevice *device = static_cast<IPCDevice *>(bfd->data);</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (flags & BSC_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = device->ipc_sock_read(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (flags & BSC_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = device->ipc_sock_write(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      IPCDevice *device = static_cast<IPCDevice *>(bfd->data);</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (flags & BSC_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = device->ipc_chan_sock_read(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (flags & BSC_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = device->ipc_chan_sock_write(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::open(const std::string &args, int ref, bool swap_channels)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     std::string k, v;</span><br><span style="color: hsl(120, 100%, 40%);">+     std::string::size_type keyend;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((keyend = args.find('=')) != std::string::npos) {</span><br><span style="color: hsl(120, 100%, 40%);">+         k = args.substr(0, keyend++);</span><br><span style="color: hsl(120, 100%, 40%);">+         v = args.substr(keyend);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (k != "ipc_msock" || !v.length()) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, ERROR) << "Invalid device args provided, expected  \"dev-args ipc_msock=/path/to/socket\"\n";</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGC(DDEV, INFO) << "Opening IPC device" << v << "..";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        INIT_LLIST_HEAD(&master_sk_state.upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_sock_unix_init_ofd(&master_sk_state.conn_bfd, SOCK_SEQPACKET, 0, v.c_str(), OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, ERROR) << "Failed to connect to the BTS (" << v << "). "</span><br><span style="color: hsl(120, 100%, 40%);">+                               << "Retrying...\n";</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_timer_setup(&master_sk_state.timer, ipc_sock_timeout, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_timer_schedule(&master_sk_state.timer, 5, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     master_sk_state.conn_bfd.cb = ipc_sock_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+    master_sk_state.conn_bfd.data = this;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_tx_greeting_req(&master_sk_state, IPC_SOCK_API_VERSION);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Wait until confirmation is recieved */</span><br><span style="color: hsl(120, 100%, 40%);">+     while (tmp_state != IPC_IF_MSG_GREETING_CNF)</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ipc_tx_info_req(&master_sk_state);</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Wait until confirmation is recieved */</span><br><span style="color: hsl(120, 100%, 40%);">+     while (tmp_state != IPC_IF_MSG_INFO_CNF)</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ipc_tx_open_req(&master_sk_state, chans, ref);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Wait until confirmation is recieved */</span><br><span style="color: hsl(120, 100%, 40%);">+     while (tmp_state != IPC_IF_MSG_OPEN_CNF)</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGC(DDEV, NOTICE) << "Device driver opened successfuly!";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* configure antennas */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!set_antennas()) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGC(DDEV, FATAL) << "IPC antenna setting failed";</span><br><span style="color: hsl(120, 100%, 40%);">+            goto out_close;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return iface == MULTI_ARFCN ? MULTI_ARFCN : NORMAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+out_close:</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGC(DDEV, FATAL) << "Error in IPC open, closing";</span><br><span style="color: hsl(120, 100%, 40%);">+    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void IPCDevice::manually_poll_sock_fds()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct timeval wait = { 0, 100000 };</span><br><span style="color: hsl(120, 100%, 40%);">+  fd_set crfds, cwfds;</span><br><span style="color: hsl(120, 100%, 40%);">+  int max_fd = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     FD_ZERO(&crfds);</span><br><span style="color: hsl(120, 100%, 40%);">+  FD_ZERO(&cwfds);</span><br><span style="color: hsl(120, 100%, 40%);">+  for (unsigned int i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct osmo_fd *curr_fd = &sk_chan_state[i].conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+             max_fd = curr_fd->fd > max_fd ? curr_fd->fd : max_fd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (curr_fd->when & OSMO_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+                      FD_SET(curr_fd->fd, &crfds);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (curr_fd->when & OSMO_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+                     FD_SET(curr_fd->fd, &cwfds);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   select(max_fd + 1, &crfds, &cwfds, 0, &wait);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (unsigned int i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int flags = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct osmo_fd *ofd = &sk_chan_state[i].conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (FD_ISSET(ofd->fd, &crfds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       flags |= OSMO_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+                        FD_CLR(ofd->fd, &crfds);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (FD_ISSET(ofd->fd, &cwfds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       flags |= OSMO_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+                       FD_CLR(ofd->fd, &cwfds);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (flags)</span><br><span style="color: hsl(120, 100%, 40%);">+                    ipc_chan_sock_cb(ofd, flags);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::send_chan_wait_rsp(uint32_t chan, struct msgb *msg_to_send, uint32_t expected_rsp_msg_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct timeval timer_now, timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  sk_chan_state[chan].messages_processed_mask = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      ipc_sock_send(&sk_chan_state[chan], msg_to_send);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gettimeofday(&timeout, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        timeout.tv_sec += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        while (!(sk_chan_state[chan].messages_processed_mask & (1 << (expected_rsp_msg_id - IPC_IF_CHAN_MSG_OFFSET)))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* just poll here, we're already in select, so there is no other way to drive</span><br><span style="color: hsl(120, 100%, 40%);">+      * the fds and "wait" for a response or retry */</span><br><span style="color: hsl(120, 100%, 40%);">+            manually_poll_sock_fds();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           gettimeofday(&timer_now, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (timercmp(&timer_now, &timeout, >))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::send_all_chan_wait_rsp(uint32_t msgid_to_send, uint32_t msgid_to_expect)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct timeval timer_now, timeout;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (unsigned int i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         msg = ipc_msgb_alloc(msgid_to_send);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+               ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+             ipc_prim->u.start_req.dummy = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         sk_chan_state[i].messages_processed_mask = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         ipc_sock_send(&sk_chan_state[i], msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   gettimeofday(&timeout, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        timeout.tv_sec += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int msg_received_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  while (msg_received_count != chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+         msg_received_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* just poll here, we're already in select, so there is no other way to drive</span><br><span style="color: hsl(120, 100%, 40%);">+              * the fds and "wait" for a response or retry */</span><br><span style="color: hsl(120, 100%, 40%);">+            manually_poll_sock_fds();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           for (unsigned int i = 0; i < sk_chan_state.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (sk_chan_state[i].messages_processed_mask &</span><br><span style="color: hsl(120, 100%, 40%);">+                        (1 << (msgid_to_expect - IPC_IF_CHAN_MSG_OFFSET)))</span><br><span style="color: hsl(120, 100%, 40%);">+                          msg_received_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               gettimeofday(&timer_now, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (timercmp(&timer_now, &timeout, >))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* the call stack is rather difficult here, we're already in select:</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#0  IPCDevice::start (this=<optimized out>) at IPCDevice.cpp:789\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#1  in RadioInterface::start (this=0x614000001640) at radioInterface.cpp:187\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#2  in Transceiver::start (this=<optimized out>) at Transceiver.cpp:293\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#3  in Transceiver::ctrl_sock_handle_rx (this=0x61600000b180, chan=0) at Transceiver.cpp:838\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#4  in Transceiver::ctrl_sock_cb (bfd=<optimized out>, flags=1) at Transceiver.cpp:168\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#5  in osmo_fd_disp_fds (_rset=<optimized out>, _wset=<optimized out>, _eset=<optimized out>) at select.c:227\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#6  _osmo_select_main (polling=<optimized out>) at select.c:265\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#7  in osmo_select_main (polling=128) at select.c:274\n"</span><br><span style="color: hsl(120, 100%, 40%);">+>~"#8  in main (argc=<optimized out>, argv=<optimized out>) at osmo-trx.cpp:649\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ * */</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::start()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGC(DDEV, INFO) << "starting IPC...";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (started) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGC(DDEV, ERR) << "Device already started";</span><br><span style="color: hsl(120, 100%, 40%);">+          return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!(send_all_chan_wait_rsp(IPC_IF_MSG_START_REQ, IPC_IF_MSG_START_CNF))) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGC(DDEV, ERR) << "start timeout!";</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   int max_bufs_to_flush = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    for (unsigned int i = 0; i < shm_dec->num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int buf_per_chan = shm_dec->channels[i]->ul_stream->num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+             max_bufs_to_flush = max_bufs_to_flush < buf_per_chan ? buf_per_chan : max_bufs_to_flush;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     flush_recv(max_bufs_to_flush);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      started = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::stop()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!started)</span><br><span style="color: hsl(120, 100%, 40%);">+         return true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!(send_all_chan_wait_rsp(IPC_IF_MSG_STOP_REQ, IPC_IF_MSG_STOP_CNF))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, ERR) << "stop timeout!";</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGC(DDEV, NOTICE) << "All channels stopped, terminating...";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       started = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double IPCDevice::maxRxGain()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return current_info_cnf.chan_info[0].max_rx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double IPCDevice::minRxGain()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return current_info_cnf.chan_info[0].min_rx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::getNominalTxPower(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return current_info_cnf.chan_info[chan].nominal_tx_power;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double IPCDevice::setPowerAttenuation(int atten, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (chan >= chans)</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGCHAN(chan, DDEV, NOTICE) << "Setting TX attenuation to " << atten << " dB"</span><br><span style="color: hsl(120, 100%, 40%);">+                               << " chan " << chan;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msg = ipc_msgb_alloc(IPC_IF_MSG_SETTXATTN_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.txatten_req.attenuation = atten;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETTXATTN_CNF))</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGCHAN(chan, DDEV, ERROR) << "Setting TX attenuation timeout! ";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return atten;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double IPCDevice::getPowerAttenuation(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (chan >= chans)</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return tx_attenuation[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double IPCDevice::setRxGain(double dB, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (dB > maxRxGain())</span><br><span style="color: hsl(120, 100%, 40%);">+              dB = maxRxGain();</span><br><span style="color: hsl(120, 100%, 40%);">+     if (dB < minRxGain())</span><br><span style="color: hsl(120, 100%, 40%);">+              dB = minRxGain();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGCHAN(chan, DDEV, NOTICE) << "Setting RX gain to " << dB << " dB";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msg = ipc_msgb_alloc(IPC_IF_MSG_SETGAIN_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.set_gain_req.is_tx = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        ipc_prim->u.set_gain_req.gain = dB;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETGAIN_CNF))</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGCHAN(chan, DDEV, ERROR) << "Setting RX gain timeout! ";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return rx_gains[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::flush_recv(size_t num_pkts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   std::vector<uint16_t> tmp(4096);</span><br><span style="color: hsl(120, 100%, 40%);">+        uint64_t tmps;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t read = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (uint32_t j = 0; j < num_pkts; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          for (unsigned int i = 0; i < chans; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                   read = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)&tmp.front(), 4096 / 2, &tmps, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ts_initial = tmps + read;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGC(DDEV, INFO) << "Initial timestamp " << ts_initial << std::endl;</span><br><span style="color: hsl(120, 100%, 40%);">+      return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::setRxAntenna(const std::string &ant, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+std::string IPCDevice::getRxAntenna(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return "";</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::setTxAntenna(const std::string &ant, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+std::string IPCDevice::getTxAntenna(size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return "";</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::requiresRadioAlign()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GSM::Time IPCDevice::minLatency()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* UNUSED */</span><br><span style="color: hsl(120, 100%, 40%);">+  return GSM::Time(0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/** Returns the starting write Timestamp*/</span><br><span style="color: hsl(120, 100%, 40%);">+TIMESTAMP IPCDevice::initialWriteTimestamp(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ts_initial;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/** Returns the starting read Timestamp*/</span><br><span style="color: hsl(120, 100%, 40%);">+TIMESTAMP IPCDevice::initialReadTimestamp(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return ts_initial;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+// NOTE: Assumes sequential reads</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc, num_smpls; //, expect_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+  ssize_t avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+  TIMESTAMP expect_timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (bufs.size() != chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *overrun = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     *underrun = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  timestamp += current_open_cnf.path_delay;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Check that timestamp is valid */</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = rx_buffers[0]->avail_smpls(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGC(DDEV, ERROR) << rx_buffers[0]->str_code(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGC(DDEV, ERROR) << rx_buffers[0]->str_status(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Receive samples from HW until we have enough */</span><br><span style="color: hsl(120, 100%, 40%);">+            while ((avail_smpls = rx_buffers[i]->avail_smpls(timestamp)) < len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   uint64_t recv_timestamp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        thread_enable_cancel(false);</span><br><span style="color: hsl(120, 100%, 40%);">+                  num_smpls = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)bufs[i], len - avail_smpls,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 &recv_timestamp, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     expect_timestamp = timestamp + avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+                   thread_enable_cancel(true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (num_smpls == -ETIMEDOUT)</span><br><span style="color: hsl(120, 100%, 40%);">+                          continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGCHAN(i, DDEV, DEBUG)</span><br><span style="color: hsl(120, 100%, 40%);">+                       "Received timestamp = " << (TIMESTAMP)recv_timestamp << " (" << num_smpls << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     //expect_smpls = len - avail_smpls;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (expect_timestamp != (TIMESTAMP)recv_timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+                            LOGCHAN(i, DDEV, ERROR) << "Unexpected recv buffer timestamp: expect "</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        << expect_timestamp << " got " << recv_timestamp << ", diff="</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     << ((uint64_t)recv_timestamp > expect_timestamp ?</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                (uint64_t)recv_timestamp - expect_timestamp :</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                 expect_timestamp - recv_timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = rx_buffers[i]->write(bufs[i], num_smpls, (TIMESTAMP)recv_timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              LOGCHAN(i, DDEV, ERROR)</span><br><span style="color: hsl(120, 100%, 40%);">+                                       << rx_buffers[i]->str_code(rc) << " num smpls: " << num_smpls << " chan: " << i;</span><br><span style="color: hsl(120, 100%, 40%);">+                         LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (rc != smpl_buf::ERROR_OVERFLOW)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We have enough samples */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (size_t i = 0; i < rx_buffers.size(); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = rx_buffers[i]->read(bufs[i], len, timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+         if ((rc < 0) || (rc != len)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "</span><br><span style="color: hsl(120, 100%, 40%);">+                                               << rx_buffers[i]->str_status(timestamp) << ", (len=" << len << ")";</span><br><span style="color: hsl(120, 100%, 40%);">+                    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return len;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int IPCDevice::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, unsigned long long timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (bufs.size() != chans) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *underrun = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGCHAN(i, DDEV, DEBUG) << "send buffer of len " << len << " timestamp " << std::hex << timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+          thread_enable_cancel(false);</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_shm_enqueue(shm_io_tx_streams[i], timestamp, len, (uint16_t *)bufs[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+              thread_enable_cancel(true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc != len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGCHAN(i, DDEV, ERROR) << "LMS: Device Tx timed out (" << rc << " vs exp " << len << ").";</span><br><span style="color: hsl(120, 100%, 40%);">+                       return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::updateAlignment(TIMESTAMP timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::setTxFreq(double wFreq, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.set_freq_req.is_tx = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        ipc_prim->u.set_freq_req.freq = wFreq;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETFREQ_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool IPCDevice::setRxFreq(double wFreq, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGCHAN(chan, DDEV, NOTICE) << "Setting Rx Freq to " << wFreq << " Hz";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.set_freq_req.is_tx = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        ipc_prim->u.set_freq_req.freq = wFreq;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return send_chan_wait_rsp(chan, msg, IPC_IF_MSG_SETFREQ_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,</span><br><span style="color: hsl(120, 100%, 40%);">+                        const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tx_sps != rx_sps) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, ERROR) << "IPC Requires tx_sps == rx_sps";</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (lo_offset != 0.0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGC(DDEV, ERROR) << "IPC doesn't support lo_offset";</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     return new IPCDevice(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/IPCDevice.h b/Transceiver52M/device/ipc/IPCDevice.h</span><br><span>new file mode 100644</span><br><span>index 0000000..a7618f9</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/IPCDevice.h</span><br><span>@@ -0,0 +1,239 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: AGPL-3.0+</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+* it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+* the Free Software Foundation, either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+* (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+* but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+* GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+* along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+* See the COPYING file in the main directory for details.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _IPC_DEVICE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+#define _IPC_DEVICE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <cstdint></span><br><span style="color: hsl(120, 100%, 40%);">+#include <cstddef></span><br><span style="color: hsl(120, 100%, 40%);">+#include <climits></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_CONFIG_H</span><br><span style="color: hsl(120, 100%, 40%);">+#include "config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "radioDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class smpl_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_MAX_NUM_TRX 8</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_per_trx_sock_state {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fd conn_bfd; /* fd for connection to the BTS */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_timer_list timer; /* socket connect retry timer */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head upqueue; /* queue for sending messages */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t messages_processed_mask; // (=| IPC_IF_MSG_xxx-IPC_IF_CHAN_MSG_OFFSET) bitmask</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_per_trx_sock_state() : conn_bfd(), timer(), upqueue(), messages_processed_mask()</span><br><span style="color: hsl(120, 100%, 40%);">+  {</span><br><span style="color: hsl(120, 100%, 40%);">+             conn_bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class IPCDevice : public RadioDevice {</span><br><span style="color: hsl(120, 100%, 40%);">+    protected:</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ipc_per_trx_sock_state master_sk_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      std::vector<struct ipc_per_trx_sock_state> sk_chan_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t tx_attenuation[IPC_MAX_NUM_TRX];</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t tmp_state;</span><br><span style="color: hsl(120, 100%, 40%);">+    char shm_name[SHM_NAME_MAX];</span><br><span style="color: hsl(120, 100%, 40%);">+  int ipc_shm_connect(const char *shm_name);</span><br><span style="color: hsl(120, 100%, 40%);">+    void *shm;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ipc_shm_region *shm_dec;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     std::vector<smpl_buf *> rx_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+     double actualSampleRate;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    bool started;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       TIMESTAMP ts_initial, ts_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    std::vector<double> tx_gains, rx_gains;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ipc_sk_if_info_req current_info_req;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sk_if_info_cnf current_info_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sk_if_open_cnf current_open_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ std::vector<struct ipc_shm_io *> shm_io_rx_streams;</span><br><span style="color: hsl(120, 100%, 40%);">+     std::vector<struct ipc_shm_io *> shm_io_tx_streams;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bool flush_recv(size_t num_pkts);</span><br><span style="color: hsl(120, 100%, 40%);">+     void update_stream_stats_rx(size_t chan, bool *overrun);</span><br><span style="color: hsl(120, 100%, 40%);">+      void update_stream_stats_tx(size_t chan, bool *underrun);</span><br><span style="color: hsl(120, 100%, 40%);">+     void manually_poll_sock_fds();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      void ipc_sock_close(ipc_per_trx_sock_state *state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim);</span><br><span style="color: hsl(120, 100%, 40%);">+     int ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf);</span><br><span style="color: hsl(120, 100%, 40%);">+       int ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf);</span><br><span style="color: hsl(120, 100%, 40%);">+       int ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf);</span><br><span style="color: hsl(120, 100%, 40%);">+       int ipc_tx_open_req(struct ipc_per_trx_sock_state *state, uint32_t num_chans, uint32_t ref);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        int ipc_chan_rx(uint8_t msg_type, ipc_sk_chan_if *ipc_prim, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ int ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+        int ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ int ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+       int ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+   int ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+        int ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ int ipc_rx_chan_settxattn_cnf(ipc_sk_chan_if_tx_attenuation *ret, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bool send_chan_wait_rsp(uint32_t chan, struct msgb *msg_to_send, uint32_t expected_rsp_msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+       bool send_all_chan_wait_rsp(uint32_t msgid_to_send, uint32_t msgid_to_expect);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    public:</span><br><span style="color: hsl(120, 100%, 40%);">+ int ipc_sock_read(struct osmo_fd *bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+       int ipc_sock_write(struct osmo_fd *bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+      int ipc_chan_sock_read(osmo_fd *bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ int ipc_chan_sock_write(osmo_fd *bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** Object constructor */</span><br><span style="color: hsl(120, 100%, 40%);">+     IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,</span><br><span style="color: hsl(120, 100%, 40%);">+                 const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths);</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual ~IPCDevice() override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** Instantiate the IPC */</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual int open(const std::string &args, int ref, bool swap_channels) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /** Start the IPC */</span><br><span style="color: hsl(120, 100%, 40%);">+  virtual bool start() override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** Stop the IPC */</span><br><span style="color: hsl(120, 100%, 40%);">+   virtual bool stop() override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* FIXME: any != USRP1 will do for now... */</span><br><span style="color: hsl(120, 100%, 40%);">+  enum TxWindowType getWindowType() override</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             return TX_WINDOW_LMS1;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /**</span><br><span style="color: hsl(120, 100%, 40%);">+   Read samples from the IPC.</span><br><span style="color: hsl(120, 100%, 40%);">+    @param buf preallocated buf to contain read result</span><br><span style="color: hsl(120, 100%, 40%);">+    @param len number of samples desired</span><br><span style="color: hsl(120, 100%, 40%);">+  @param overrun Set if read buffer has been overrun, e.g. data not being read fast enough</span><br><span style="color: hsl(120, 100%, 40%);">+      @param timestamp The timestamp of the first samples to be read</span><br><span style="color: hsl(120, 100%, 40%);">+        @param underrun Set if IPC does not have data to transmit, e.g. data not being sent fast enough</span><br><span style="color: hsl(120, 100%, 40%);">+       @return The number of samples actually read</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual int readSamples(std::vector<short *> &buf, int len, bool *overrun, TIMESTAMP timestamp = 0xffffffff,</span><br><span style="color: hsl(120, 100%, 40%);">+                                bool *underrun = NULL) override;</span><br><span style="color: hsl(120, 100%, 40%);">+      /**</span><br><span style="color: hsl(120, 100%, 40%);">+   Write samples to the IPC.</span><br><span style="color: hsl(120, 100%, 40%);">+     @param buf Contains the data to be written.</span><br><span style="color: hsl(120, 100%, 40%);">+   @param len number of samples to write.</span><br><span style="color: hsl(120, 100%, 40%);">+        @param underrun Set if IPC does not have data to transmit, e.g. data not being sent fast enough</span><br><span style="color: hsl(120, 100%, 40%);">+       @param timestamp The timestamp of the first sample of the data buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+        @return The number of samples actually written</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,</span><br><span style="color: hsl(120, 100%, 40%);">+                                TIMESTAMP timestamp = 0xffffffff) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /** Update the alignment between the read and write timestamps */</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual bool updateAlignment(TIMESTAMP timestamp) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /** Set the transmitter frequency */</span><br><span style="color: hsl(120, 100%, 40%);">+  virtual bool setTxFreq(double wFreq, size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /** Set the receiver frequency */</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual bool setRxFreq(double wFreq, size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /** Returns the starting write Timestamp*/</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual TIMESTAMP initialWriteTimestamp(void) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /** Returns the starting read Timestamp*/</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual TIMESTAMP initialReadTimestamp(void) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** returns the full-scale transmit amplitude **/</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual double fullScaleInputValue() override</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+             return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /** returns the full-scale receive amplitude **/</span><br><span style="color: hsl(120, 100%, 40%);">+      virtual double fullScaleOutputValue() override</span><br><span style="color: hsl(120, 100%, 40%);">+        {</span><br><span style="color: hsl(120, 100%, 40%);">+             return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /** sets the receive chan gain, returns the gain setting **/</span><br><span style="color: hsl(120, 100%, 40%);">+  virtual double setRxGain(double dB, size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /** get the current receive gain */</span><br><span style="color: hsl(120, 100%, 40%);">+   virtual double getRxGain(size_t chan = 0) override</span><br><span style="color: hsl(120, 100%, 40%);">+    {</span><br><span style="color: hsl(120, 100%, 40%);">+             return rx_gains[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /** return maximum Rx Gain **/</span><br><span style="color: hsl(120, 100%, 40%);">+        virtual double maxRxGain(void) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /** return minimum Rx Gain **/</span><br><span style="color: hsl(120, 100%, 40%);">+        virtual double minRxGain(void) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    double setPowerAttenuation(int atten, size_t chan) override;</span><br><span style="color: hsl(120, 100%, 40%);">+  double getPowerAttenuation(size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       virtual int getNominalTxPower(size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /** sets the RX path to use, returns true if successful and false otherwise */</span><br><span style="color: hsl(120, 100%, 40%);">+        virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* return the used RX path */</span><br><span style="color: hsl(120, 100%, 40%);">+ virtual std::string getRxAntenna(size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /** sets the RX path to use, returns true if successful and false otherwise */</span><br><span style="color: hsl(120, 100%, 40%);">+        virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* return the used RX path */</span><br><span style="color: hsl(120, 100%, 40%);">+ virtual std::string getTxAntenna(size_t chan = 0) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /** return whether user drives synchronization of Tx/Rx of USRP */</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual bool requiresRadioAlign() override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /** return whether user drives synchronization of Tx/Rx of USRP */</span><br><span style="color: hsl(120, 100%, 40%);">+    virtual GSM::Time minLatency() override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /** Return internal status values */</span><br><span style="color: hsl(120, 100%, 40%);">+  virtual inline double getTxFreq(size_t chan = 0) override</span><br><span style="color: hsl(120, 100%, 40%);">+     {</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual inline double getRxFreq(size_t chan = 0) override</span><br><span style="color: hsl(120, 100%, 40%);">+     {</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual inline double getSampleRate() override</span><br><span style="color: hsl(120, 100%, 40%);">+        {</span><br><span style="color: hsl(120, 100%, 40%);">+             return actualSampleRate;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif // _IPC_DEVICE_H_</span><br><span>diff --git a/Transceiver52M/device/ipc/Makefile.am b/Transceiver52M/device/ipc/Makefile.am</span><br><span>new file mode 100644</span><br><span>index 0000000..b753f28</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/Makefile.am</span><br><span>@@ -0,0 +1,42 @@</span><br><span style="color: hsl(120, 100%, 40%);">+include $(top_srcdir)/Makefile.common</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+AM_LDFLAGS = -lpthread -lrt</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_HEADERS = IPCDevice.h shm.h ipc_shm.h ipc_chan.h ipc_sock.h</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_UHD</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_HEADERS += ../uhd/UHDDevice.h uhdwrap.h ipc-driver-test.h</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+noinst_LTLIBRARIES = libdevice.la</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+libdevice_la_SOURCES = IPCDevice.cpp shm.c ipc_shm.c ipc_chan.c ipc_sock.c</span><br><span style="color: hsl(120, 100%, 40%);">+libdevice_la_LIBADD = $(top_builddir)/Transceiver52M/device/common/libdevice_common.la</span><br><span style="color: hsl(120, 100%, 40%);">+libdevice_la_CXXFLAGS = $(AM_CXXFLAGS) -DIPCMAGIC</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_UHD</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#work around distclean issue on older autotools vers:</span><br><span style="color: hsl(120, 100%, 40%);">+#a direct build of ../uhd/UHDDevice.cpp tries to clean</span><br><span style="color: hsl(120, 100%, 40%);">+#../uhd/.dep/UHDDevice.Plo zwice and fails</span><br><span style="color: hsl(120, 100%, 40%);">+uhddev_ipc.cpp:</span><br><span style="color: hsl(120, 100%, 40%);">+   echo "#include \"../uhd/UHDDevice.cpp\"" >$@</span><br><span style="color: hsl(120, 100%, 40%);">+CLEANFILES= uhddev_ipc.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bin_PROGRAMS = ipc-driver-test</span><br><span style="color: hsl(120, 100%, 40%);">+#ipc_driver_test_SHORTNAME = drvt</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_SOURCES = ipc-driver-test.c uhdwrap.cpp ipc_shm.c ipc_chan.c ipc_sock.c uhddev_ipc.cpp</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_LDADD = \</span><br><span style="color: hsl(120, 100%, 40%);">+        shm.lo \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(LIBOSMOCORE_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOVTY_LIBS)</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_CXXFLAGS = $(AM_CXXFLAGS) $(UHD_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_CPPFLAGS  = $(AM_CPPFLAGS) $(UHD_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_CFLAGS  = $(AM_CFLAGS) $(UHD_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_LDFLAGS  = $(AM_LDFLAGS) $(UHD_LIBS)</span><br><span style="color: hsl(120, 100%, 40%);">+ipc_driver_test_LDADD += $(top_builddir)/Transceiver52M/device/common/libdevice_common.la $(top_builddir)/CommonLibs/libcommon.la</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc-driver-test.c b/Transceiver52M/device/ipc/ipc-driver-test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..0640aaf</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc-driver-test.c</span><br><span>@@ -0,0 +1,498 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define _GNU_SOURCE</span><br><span style="color: hsl(120, 100%, 40%);">+#include <pthread.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/un.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/mman.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h> /* For mode constants */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <fcntl.h> /* For O_* constants */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <getopt.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_chan.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_sock.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_SHM_NAME "/osmo-trx-ipc-driver-shm2"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *tall_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sock_state *global_ipc_sock_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 8 channels are plenty */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sock_state *global_ctrl_socks[8];</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io *ios_tx_to_device[8];</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io *ios_rx_from_device[8];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *shm;</span><br><span style="color: hsl(120, 100%, 40%);">+void *global_dev;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ipc_shm_region *decoded_region;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Debug Areas of the code */</span><br><span style="color: hsl(120, 100%, 40%);">+//enum { DMAIN,</span><br><span style="color: hsl(120, 100%, 40%);">+//};</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct log_info_cat default_categories[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [DMAIN] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "DMAIN",</span><br><span style="color: hsl(120, 100%, 40%);">+            .color = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                .description = "Main generic category",</span><br><span style="color: hsl(120, 100%, 40%);">+             .loglevel = LOGL_DEBUG,.enabled = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DDEV] = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .name = "DDEV",</span><br><span style="color: hsl(120, 100%, 40%);">+             .description = "Device/Driver specific code",</span><br><span style="color: hsl(120, 100%, 40%);">+               .color = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                .enabled = 1, .loglevel = LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct log_info log_infox = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .cat = default_categories,</span><br><span style="color: hsl(120, 100%, 40%);">+    .num_cat = ARRAY_SIZE(default_categories),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "uhdwrap.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+volatile int ipc_exit_requested = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_shm_setup(const char *shm_name, size_t shm_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int fd;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DMAIN, LOGL_NOTICE, "Opening shm path %s\n", shm_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((fd = shm_open(shm_name, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_ERROR, "shm_open %d: %s\n", errno, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+          goto err_shm_open;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DMAIN, LOGL_NOTICE, "Truncating %d to size %zu\n", fd, shm_len);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ftruncate(fd, shm_len) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DMAIN, LOGL_ERROR, "ftruncate %d: %s\n", errno, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+          goto err_mmap;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DMAIN, LOGL_NOTICE, "mmaping shared memory fd %d\n", fd);</span><br><span style="color: hsl(120, 100%, 40%);">+      if ((shm = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DMAIN, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+          goto err_mmap;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DMAIN, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */</span><br><span style="color: hsl(120, 100%, 40%);">+ close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+err_mmap:</span><br><span style="color: hsl(120, 100%, 40%);">+  shm_unlink(shm_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+err_shm_open:</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *ipc_msgb_alloc(uint8_t msg_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_alloc(sizeof(struct ipc_sk_if) + 1000, "ipc_sock_tx");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put(msg, sizeof(struct ipc_sk_if) + 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->msg_type = msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_tx_greeting_cnf(uint8_t req_version)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = ipc_msgb_alloc(IPC_IF_MSG_GREETING_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.greeting_cnf.req_version = req_version;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return ipc_sock_send(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_tx_info_cnf()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = ipc_msgb_alloc(IPC_IF_MSG_INFO_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        uhdwrap_fill_info_cnf(ipc_prim);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return ipc_sock_send(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_tx_open_cnf(int rc, uint32_t num_chans, int32_t timingoffset)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sk_if_open_cnf_chan *chan_info;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = ipc_msgb_alloc(IPC_IF_MSG_OPEN_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.open_cnf.return_code = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.open_cnf.path_delay = timingoffset; // 6.18462e-5 * 1625e3 / 6;</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_STRLCPY_ARRAY(ipc_prim->u.open_cnf.shm_name, DEFAULT_SHM_NAME);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     chan_info = ipc_prim->u.open_cnf.chan_info;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          snprintf(chan_info->chan_ipc_sk_path, sizeof(chan_info->chan_ipc_sk_path), "%s_%d",</span><br><span style="color: hsl(120, 100%, 40%);">+                    IPC_SOCK_PATH_PREFIX, i);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* FIXME: dynamc chan limit, currently 8 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (i < 8)</span><br><span style="color: hsl(120, 100%, 40%);">+                 ipc_sock_init(chan_info->chan_ipc_sk_path, &global_ctrl_socks[i], ipc_chan_sock_accept, i);</span><br><span style="color: hsl(120, 100%, 40%);">+            chan_info++;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ipc_sock_send(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_greeting_req(struct ipc_sk_if_greeting *greeting_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (greeting_req->req_version == IPC_SOCK_API_VERSION)</span><br><span style="color: hsl(120, 100%, 40%);">+             ipc_tx_greeting_cnf(IPC_SOCK_API_VERSION);</span><br><span style="color: hsl(120, 100%, 40%);">+    else</span><br><span style="color: hsl(120, 100%, 40%);">+          ipc_tx_greeting_cnf(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_info_req(struct ipc_sk_if_info_req *info_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_tx_info_cnf();</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   /* calculate size needed */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   global_dev = uhdwrap_open(open_req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* b210 packet size is 2040, but our tx size is 2500, so just do *2 */</span><br><span style="color: hsl(120, 100%, 40%);">+        int shmbuflen = uhdwrap_get_bufsizerx(global_dev) * 2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      len = ipc_shm_encode_region(NULL, open_req->num_chans, 4, shmbuflen);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Here we verify num_chans, rx_path, tx_path, clockref, etc. */</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = ipc_shm_setup(DEFAULT_SHM_NAME, len);</span><br><span style="color: hsl(120, 100%, 40%);">+        len = ipc_shm_encode_region((struct ipc_shm_raw_region *)shm, open_req->num_chans, 4, shmbuflen);</span><br><span style="color: hsl(120, 100%, 40%);">+  //      LOGP(DMAIN, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* set up our own copy of the decoded area, we have to do it here,</span><br><span style="color: hsl(120, 100%, 40%);">+    * since the uhd wrapper does not allow starting single channels</span><br><span style="color: hsl(120, 100%, 40%);">+       * additionally go for the producer init for both, so only we are responsible for the init, instead</span><br><span style="color: hsl(120, 100%, 40%);">+    * of splitting it with the client and causing potential races if one side uses it too early */</span><br><span style="color: hsl(120, 100%, 40%);">+        decoded_region = ipc_shm_decode_region(0, (struct ipc_shm_raw_region *)shm);</span><br><span style="color: hsl(120, 100%, 40%);">+  for (unsigned int i = 0; i < open_req->num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                //              ios_tx_to_device[i] = ipc_shm_init_consumer(decoded_region->channels[i]->dl_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+            ios_tx_to_device[i] = ipc_shm_init_producer(decoded_region->channels[i]->dl_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+            ios_rx_from_device[i] = ipc_shm_init_producer(decoded_region->channels[i]->ul_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_tx_open_cnf(-rc, open_req->num_chans, uhdwrap_get_timingoffset(global_dev));</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+volatile int ul_running = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+volatile int dl_running = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *uplink_thread(void *x_void_ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t chann = decoded_region->num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+        ul_running = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       pthread_setname_np(pthread_self(), "uplink rx");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  while (!ipc_exit_requested) {</span><br><span style="color: hsl(120, 100%, 40%);">+         int32_t read = uhdwrap_read(global_dev, chann);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (read < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void *downlink_thread(void *x_void_ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int chann = decoded_region->num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+     dl_running = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       pthread_setname_np(pthread_self(), "downlink tx");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        while (!ipc_exit_requested) {</span><br><span style="color: hsl(120, 100%, 40%);">+         bool underrun;</span><br><span style="color: hsl(120, 100%, 40%);">+                uhdwrap_write(global_dev, chann, &underrun);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = uhdwrap_start(global_dev, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* no per-chan start/stop */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!dl_running || !ul_running) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* chan != first chan start will "fail", which is fine, usrp can't start/stop chans independently */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGP(DMAIN, LOGL_INFO, "starting rx/tx threads.. req for chan:%d\n", chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+                      pthread_t rx, tx;</span><br><span style="color: hsl(120, 100%, 40%);">+                     pthread_create(&rx, NULL, uplink_thread, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                      pthread_create(&tx, NULL, downlink_thread, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_INFO, "starting rx/tx threads request ignored.. req for chan:%d\n", chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    msg = ipc_msgb_alloc(IPC_IF_MSG_START_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.start_cnf.return_code = rc ? 0 : -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ipc_chan_sock_send(msg, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_stop_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* no per-chan start/stop */</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = uhdwrap_stop(global_dev, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = ipc_msgb_alloc(IPC_IF_MSG_STOP_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.stop_cnf.return_code = rc ? 0 : -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return ipc_chan_sock_send(msg, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_setgain_req(struct ipc_sk_chan_if_gain *req, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      double rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rv = uhdwrap_set_gain(global_dev, req->gain, chan_nr, req->is_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    msg = ipc_msgb_alloc(IPC_IF_MSG_SETGAIN_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.set_gain_cnf.is_tx = req->is_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+    ipc_prim->u.set_gain_cnf.gain = rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return ipc_chan_sock_send(msg, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_setfreq_req(struct ipc_sk_chan_if_freq_req *req, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rv = uhdwrap_set_freq(global_dev, req->freq, chan_nr, req->is_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.set_freq_cnf.return_code = rv ? 0 : 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return ipc_chan_sock_send(msg, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_settxatten_req(struct ipc_sk_chan_if_tx_attenuation *req, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      double rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rv = uhdwrap_set_txatt(global_dev, req->attenuation, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msg = ipc_msgb_alloc(IPC_IF_MSG_SETTXATTN_CNF);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim->u.txatten_cnf.attenuation = rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return ipc_chan_sock_send(msg, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,</span><br><span style="color: hsl(120, 100%, 40%);">+            int (*sock_callback_fn)(struct osmo_fd *fd, unsigned int what), int n)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sock_state *state;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd *bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     state = talloc_zero(NULL, struct ipc_sock_state);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!state)</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       *global_state_var = state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+      state->conn_bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bfd = &state->listen_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (bfd->fd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMAIN, LOGL_ERROR, "Could not create %s unix socket: %s\n", path, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(state);</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bfd->when = BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+   bfd->cb = sock_callback_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+        bfd->data = state;</span><br><span style="color: hsl(120, 100%, 40%);">+ bfd->priv_nr = n;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_fd_register(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMAIN, LOGL_ERROR, "Could not register listen fd: %d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+          close(bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+            talloc_free(state);</span><br><span style="color: hsl(120, 100%, 40%);">+           return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   //osmo_signal_register_handler(SS_GLOBAL, IPC_if_signal_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DMAIN, LOGL_INFO, "Started listening on IPC socket: %s\n", path);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void print_help(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("ipc-driver-test Usage:\n"</span><br><span style="color: hsl(120, 100%, 40%);">+          " -h  --help                This message\n"</span><br><span style="color: hsl(120, 100%, 40%);">+         " -n  --sock-num NR Master socket suffix number NR\n");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int msocknum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_options(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           int option_index = 0, c;</span><br><span style="color: hsl(120, 100%, 40%);">+              const struct option long_options[] = { { "help", 0, 0, 'h' },</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      { "sock-num", 1, 0, 'n' },</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  { 0, 0, 0, 0 } };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            c = getopt_long(argc, argv, "hn:", long_options, &option_index);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (c == -1)</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (c) {</span><br><span style="color: hsl(120, 100%, 40%);">+          case 'h':</span><br><span style="color: hsl(120, 100%, 40%);">+                     print_help();</span><br><span style="color: hsl(120, 100%, 40%);">+                 exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'n':</span><br><span style="color: hsl(120, 100%, 40%);">+                     msocknum = atoi(optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      exit(2);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (argc > optind) {</span><br><span style="color: hsl(120, 100%, 40%);">+               fprintf(stderr, "Unsupported positional arguments on command line\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              exit(2);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(IPCMAGIC) && defined(__cplusplus)</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int osmo_ctx_init(const char *id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int magicmain(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_ctx_init("main");</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_select_init();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+      char ipc_msock_path[sizeof(IPC_SOCK_PATH_PREFIX) + 3];</span><br><span style="color: hsl(120, 100%, 40%);">+        tall_ctx = talloc_named_const(NULL, 0, "OsmoTRX");</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_talloc_ctx_init(tall_ctx, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_init_logging2(tall_ctx, &log_infox);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_enable_multithread();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   handle_options(argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+   snprintf(ipc_msock_path, sizeof(ipc_msock_path), "%s%d", IPC_SOCK_PATH_PREFIX, msocknum);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DMAIN, LOGL_INFO, "Starting %s\n", argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_sock_init(ipc_msock_path, &global_ipc_sock_state, ipc_sock_accept, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        while (!ipc_exit_requested)</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (global_dev)</span><br><span style="color: hsl(120, 100%, 40%);">+               for (unsigned int i = 0; i < decoded_region->num_chans; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                    uhdwrap_stop(global_dev, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        //ipc_sock_close()</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc-driver-test.h b/Transceiver52M/device/ipc/ipc-driver-test.h</span><br><span>new file mode 100644</span><br><span>index 0000000..55c17b1</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc-driver-test.h</span><br><span>@@ -0,0 +1,45 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct ipc_sock_state *global_ipc_sock_state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 8 channels are plenty */</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct ipc_sock_state *global_ctrl_socks[8];</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct ipc_shm_io *ios_tx_to_device[8];</span><br><span style="color: hsl(120, 100%, 40%);">+extern struct ipc_shm_io *ios_rx_from_device[8];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sock_state {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fd listen_bfd; /* fd for listen socket */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd conn_bfd; /* fd for connection to lcr */</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head upqueue; /* queue for sending messages */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,</span><br><span style="color: hsl(120, 100%, 40%);">+                int (*sock_callback_fn)(struct osmo_fd *fd, unsigned int what), int n);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_greeting_req(struct ipc_sk_if_greeting *greeting_req);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_info_req(struct ipc_sk_if_info_req *info_req);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_stop_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_setgain_req(struct ipc_sk_chan_if_gain *req, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_setfreq_req(struct ipc_sk_chan_if_freq_req *req, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_rx_chan_settxatten_req(struct ipc_sk_chan_if_tx_attenuation *req, uint8_t chan_nr);</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc_chan.c b/Transceiver52M/device/ipc/ipc_chan.c</span><br><span>new file mode 100644</span><br><span>index 0000000..c13bb3a</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc_chan.c</span><br><span>@@ -0,0 +1,268 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/un.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/mman.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h> /* For mode constants */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <fcntl.h> /* For O_* constants */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc-driver-test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_chan.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_sock.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case IPC_IF_MSG_START_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ipc_rx_chan_start_req(&ipc_prim->u.start_req, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+           fprintf(stderr, "%s:%d: IPC_IF_MSG_START_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_STOP_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = ipc_rx_chan_stop_req(&ipc_prim->u.stop_req, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+             fprintf(stderr, "%s:%d: IPC_IF_MSG_STOP_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_SETGAIN_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_rx_chan_setgain_req(&ipc_prim->u.set_gain_req, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "%s:%d: IPC_IF_MSG_SETGAIN_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_SETFREQ_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_rx_chan_setfreq_req(&ipc_prim->u.set_freq_req, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "%s:%d: IPC_IF_MSG_SETFREQ_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_SETTXATTN_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = ipc_rx_chan_settxatten_req(&ipc_prim->u.txatten_req, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+            fprintf(stderr, "%s:%d: IPC_IF_MSG_SETTXATTN_REQ chan priv no %d\n", __FILE__, __LINE__, chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "Received unknown IPC msg type %d\n", msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     fflush(stderr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_chan_sock_read(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_chan_sock_rx");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim = (struct ipc_sk_chan_if *)msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < (int)sizeof(*ipc_prim)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Received %d bytes on Unix Socket, but primitive size "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "is %zu, discarding\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc, sizeof(*ipc_prim));</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* as we always synchronously process the message in IPC_rx() and</span><br><span style="color: hsl(120, 100%, 40%);">+      * its callbacks, we can free the message here. */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_sock_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ipc_sock_state *state = global_ctrl_socks[chan_nr];</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fd *conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!state)</span><br><span style="color: hsl(120, 100%, 40%);">+           return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!state) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMAIN, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "IPC socket not created, "</span><br><span style="color: hsl(120, 100%, 40%);">+                  "dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "IPC socket not connected, "</span><br><span style="color: hsl(120, 100%, 40%);">+                "dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_enqueue(&state->upqueue, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    conn_bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_chan_sock_write(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while (!llist_empty(&state->upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg, *msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_chan_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* peek at the beginning of the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+              msg = llist_entry(state->upqueue.next, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+         ipc_prim = (struct ipc_sk_chan_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           bfd->when &= ~BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!msgb_length(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "message type (%d) with ZERO "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "bytes!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ipc_prim->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto dontsend;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* try to send it over the socket */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   dontsend:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* _after_ we send it, we can deueue */</span><br><span style="color: hsl(120, 100%, 40%);">+               msg2 = msgb_dequeue(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+          assert(msg == msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_sock_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (flags & BSC_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_chan_sock_read(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (flags & BSC_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = ipc_chan_sock_write(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd *conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_un un_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   socklen_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     len = sizeof(un_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "osmo-trx connects but we already have "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "another active connection ?!?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            /* We already have one IPC connected, this is all we support */</span><br><span style="color: hsl(120, 100%, 40%);">+               state->listen_bfd.when &= ~BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+                close(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+            return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   conn_bfd->fd = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ conn_bfd->when = BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+      conn_bfd->cb = ipc_chan_sock_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+   conn_bfd->data = state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* copy chan nr, required for proper bfd<->chan # mapping */</span><br><span style="color: hsl(120, 100%, 40%);">+    conn_bfd->priv_nr = bfd->priv_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_fd_register(conn_bfd) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Failed to register new connection "</span><br><span style="color: hsl(120, 100%, 40%);">+                "fd\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               close(conn_bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+               conn_bfd->fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* send current info */</span><br><span style="color: hsl(120, 100%, 40%);">+       //IPC_tx_info_ind();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc_chan.h b/Transceiver52M/device/ipc/ipc_chan.h</span><br><span>new file mode 100644</span><br><span>index 0000000..d606cce</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc_chan.h</span><br><span>@@ -0,0 +1,25 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef IPC_CHAN_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_CHAN_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc-driver-test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif // IPC_CHAN_H</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc_shm.c b/Transceiver52M/device/ipc/ipc_shm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..ce863ba</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc_shm.c</span><br><span>@@ -0,0 +1,206 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Eric Wild <ewild@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <shm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include <pthread.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <semaphore.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SAMPLE_SIZE_BYTE sizeof(uint16_t) * 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_shm_io *r = (struct ipc_shm_io *)malloc(sizeof(struct ipc_shm_io));</span><br><span style="color: hsl(120, 100%, 40%);">+        r->this_stream = s->raw;</span><br><span style="color: hsl(120, 100%, 40%);">+        r->buf_ptrs =</span><br><span style="color: hsl(120, 100%, 40%);">+              (volatile struct ipc_shm_raw_smpl_buf **)malloc(sizeof(struct ipc_shm_raw_smpl_buf *) * s->num_buffers);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* save actual ptrs */</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < s->num_buffers; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            r->buf_ptrs[i] = s->buffers[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       r->partial_read_begin_ptr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     return r;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rv;</span><br><span style="color: hsl(120, 100%, 40%);">+       pthread_mutexattr_t att;</span><br><span style="color: hsl(120, 100%, 40%);">+      pthread_condattr_t t1, t2;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ipc_shm_io *r = ipc_shm_init_consumer(s);</span><br><span style="color: hsl(120, 100%, 40%);">+      rv = pthread_mutexattr_init(&att);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = pthread_mutexattr_setrobust(&att, PTHREAD_MUTEX_ROBUST);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = pthread_mutexattr_setpshared(&att, PTHREAD_PROCESS_SHARED);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = pthread_mutex_init((pthread_mutex_t *)&r->this_stream->lock, &att);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pthread_mutexattr_destroy(&att);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rv = pthread_condattr_setpshared(&t1, PTHREAD_PROCESS_SHARED);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = pthread_condattr_setpshared(&t2, PTHREAD_PROCESS_SHARED);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = pthread_cond_init((pthread_cond_t *)&r->this_stream->cf, &t1);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = pthread_cond_init((pthread_cond_t *)&r->this_stream->ce, &t2);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(EXIT_FAILURE);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pthread_condattr_destroy(&t1);</span><br><span style="color: hsl(120, 100%, 40%);">+    pthread_condattr_destroy(&t2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  r->this_stream->read_next = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  r->this_stream->write_next = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ return r;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ipc_shm_close(struct ipc_shm_io *r)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (r) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (r->buf_ptrs)</span><br><span style="color: hsl(120, 100%, 40%);">+                   free(r->buf_ptrs);</span><br><span style="color: hsl(120, 100%, 40%);">+         free(r);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ipc_shm_enqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     volatile struct ipc_shm_raw_smpl_buf *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+    int32_t rv;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct timespec tv;</span><br><span style="color: hsl(120, 100%, 40%);">+   clock_gettime(CLOCK_REALTIME, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+       tv.tv_sec += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rv = pthread_mutex_timedlock((pthread_mutex_t *)&r->this_stream->lock, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rv != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (((r->this_stream->write_next + 1) & (r->this_stream->num_buffers - 1)) == r->this_stream->read_next &&</span><br><span style="color: hsl(120, 100%, 40%);">+          rv == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               rv = pthread_cond_timedwait((pthread_cond_t *)&r->this_stream->ce,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      (pthread_mutex_t *)&r->this_stream->lock, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rv != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ buf = r->buf_ptrs[r->this_stream->write_next];</span><br><span style="color: hsl(120, 100%, 40%);">+       buf->timestamp = timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      rv = len_in_sps <= r->this_stream->buffer_size ? len_in_sps : r->this_stream->buffer_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy((void *)buf->samples, data, SAMPLE_SIZE_BYTE * rv);</span><br><span style="color: hsl(120, 100%, 40%);">+ buf->data_len = rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      r->this_stream->write_next = (r->this_stream->write_next + 1) & (r->this_stream->num_buffers - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pthread_cond_signal((pthread_cond_t *)&r->this_stream->cf);</span><br><span style="color: hsl(120, 100%, 40%);">+ pthread_mutex_unlock((pthread_mutex_t *)&r->this_stream->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rv;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ipc_shm_read(struct ipc_shm_io *r, uint16_t *out_buf, uint32_t num_samples, uint64_t *timestamp,</span><br><span style="color: hsl(120, 100%, 40%);">+                  uint32_t timeout_seconds)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     volatile struct ipc_shm_raw_smpl_buf *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+    int32_t rv;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t freeflag = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timespec tv;</span><br><span style="color: hsl(120, 100%, 40%);">+   clock_gettime(CLOCK_REALTIME, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+       tv.tv_sec += timeout_seconds;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rv = pthread_mutex_timedlock((pthread_mutex_t *)&r->this_stream->lock, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rv != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (r->this_stream->write_next == r->this_stream->read_next && rv == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                rv = pthread_cond_timedwait((pthread_cond_t *)&r->this_stream->cf,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      (pthread_mutex_t *)&r->this_stream->lock, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rv != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ buf = r->buf_ptrs[r->this_stream->read_next];</span><br><span style="color: hsl(120, 100%, 40%);">+        if (buf->data_len <= num_samples) {</span><br><span style="color: hsl(120, 100%, 40%);">+             memcpy(out_buf, (void *)&buf->samples[r->partial_read_begin_ptr * 2], SAMPLE_SIZE_BYTE * buf->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+         r->partial_read_begin_ptr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             rv = buf->data_len;</span><br><span style="color: hsl(120, 100%, 40%);">+                buf->data_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         r->this_stream->read_next = (r->this_stream->read_next + 1) & (r->this_stream->num_buffers - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                freeflag = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       } else /*if (buf->data_len > num_samples)*/ {</span><br><span style="color: hsl(120, 100%, 40%);">+           memcpy(out_buf, (void *)&buf->samples[r->partial_read_begin_ptr * 2], SAMPLE_SIZE_BYTE * num_samples);</span><br><span style="color: hsl(120, 100%, 40%);">+              r->partial_read_begin_ptr += num_samples;</span><br><span style="color: hsl(120, 100%, 40%);">+          buf->data_len -= num_samples;</span><br><span style="color: hsl(120, 100%, 40%);">+              rv = num_samples;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   *timestamp = buf->timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+       buf->timestamp += rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (freeflag)</span><br><span style="color: hsl(120, 100%, 40%);">+         pthread_cond_signal((pthread_cond_t *)&r->this_stream->ce);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       pthread_mutex_unlock((pthread_mutex_t *)&r->this_stream->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rv;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc_shm.h b/Transceiver52M/device/ipc/ipc_shm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..228169b</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc_shm.h</span><br><span>@@ -0,0 +1,45 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Eric Wild <ewild@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef IPC_SHM_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_SHM_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <shm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io {</span><br><span style="color: hsl(120, 100%, 40%);">+       volatile struct ipc_shm_raw_stream *this_stream; // plus num_buffers at end</span><br><span style="color: hsl(120, 100%, 40%);">+   volatile struct ipc_shm_raw_smpl_buf **volatile buf_ptrs;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t partial_read_begin_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s);</span><br><span style="color: hsl(120, 100%, 40%);">+void ipc_shm_close(struct ipc_shm_io *r);</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ipc_shm_enqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data);</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ipc_shm_tryenqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data);</span><br><span style="color: hsl(120, 100%, 40%);">+volatile struct ipc_shm_raw_smpl_buf *ipc_shm_dequeue(struct ipc_shm_io *r);</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ipc_shm_read(struct ipc_shm_io *r, uint16_t *out_buf, uint32_t num_samples, uint64_t *timestamp,</span><br><span style="color: hsl(120, 100%, 40%);">+                   uint32_t timeout_seconds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif // IPC_SHM_H</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc_sock.c b/Transceiver52M/device/ipc/ipc_sock.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6847448</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc_sock.c</span><br><span>@@ -0,0 +1,273 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/un.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/mman.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h> /* For mode constants */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <fcntl.h> /* For O_* constants */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc-driver-test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern volatile int ipc_exit_requested;</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case IPC_IF_MSG_GREETING_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = ipc_rx_greeting_req(&ipc_prim->u.greeting_req);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_INFO_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = ipc_rx_info_req(&ipc_prim->u.info_req);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case IPC_IF_MSG_OPEN_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = ipc_rx_open_req(&ipc_prim->u.open_req);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_send(struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ipc_sock_state *state = global_ipc_sock_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd *conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+     //struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!state) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMAIN, LOGL_INFO,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "IPC socket not created, "</span><br><span style="color: hsl(120, 100%, 40%);">+                  "dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "IPC socket not connected, "</span><br><span style="color: hsl(120, 100%, 40%);">+                "dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_enqueue(&state->upqueue, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    conn_bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ipc_sock_close(struct ipc_sock_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fd *bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGP(DMAIN, LOGL_NOTICE, "IPC socket has LOST connection\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_exit_requested = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     close(bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+    bfd->fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fd_unregister(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* re-enable the generation of ACCEPT for new connections */</span><br><span style="color: hsl(120, 100%, 40%);">+  state->listen_bfd.when |= BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* flush the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (!llist_empty(&state->upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg = msgb_dequeue(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_read(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ipc_prim = (struct ipc_sk_if *)msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < (int)sizeof(*ipc_prim)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Received %d bytes on Unix Socket, but primitive size "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "is %zu, discarding\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc, sizeof(*ipc_prim));</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ipc_rx(ipc_prim->msg_type, ipc_prim);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* as we always synchronously process the message in IPC_rx() and</span><br><span style="color: hsl(120, 100%, 40%);">+      * its callbacks, we can free the message here. */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       ipc_sock_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_sock_write(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while (!llist_empty(&state->upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg, *msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_if *ipc_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* peek at the beginning of the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+              msg = llist_entry(state->upqueue.next, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+         ipc_prim = (struct ipc_sk_if *)msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                bfd->when &= ~BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!msgb_length(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "message type (%d) with ZERO "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "bytes!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ipc_prim->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto dontsend;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* try to send it over the socket */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                bfd->when |= BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   dontsend:</span><br><span style="color: hsl(120, 100%, 40%);">+             /* _after_ we send it, we can deueue */</span><br><span style="color: hsl(120, 100%, 40%);">+               msg2 = msgb_dequeue(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+          assert(msg == msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+   ipc_sock_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (flags & BSC_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = ipc_sock_read(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (flags & BSC_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = ipc_sock_write(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* accept connection coming from IPC */</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd *conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_un un_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   socklen_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     len = sizeof(un_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+                   "ip clent connects but we already have "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "another active connection ?!?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            /* We already have one IPC connected, this is all we support */</span><br><span style="color: hsl(120, 100%, 40%);">+               state->listen_bfd.when &= ~BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+                close(rc);</span><br><span style="color: hsl(120, 100%, 40%);">+            return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   conn_bfd->fd = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ conn_bfd->when = BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+      conn_bfd->cb = ipc_sock_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+        conn_bfd->data = state;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (osmo_fd_register(conn_bfd) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DMAIN, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Failed to register new connection "</span><br><span style="color: hsl(120, 100%, 40%);">+                "fd\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               close(conn_bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+               conn_bfd->fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* send current info */</span><br><span style="color: hsl(120, 100%, 40%);">+       //IPC_tx_info_ind();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/ipc_sock.h b/Transceiver52M/device/ipc/ipc_sock.h</span><br><span>new file mode 100644</span><br><span>index 0000000..918e70a</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/ipc_sock.h</span><br><span>@@ -0,0 +1,26 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef IPC_SOCK_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_SOCK_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc-driver-test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_send(struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+void ipc_sock_close(struct ipc_sock_state *state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif // IPC_SOCK_H</span><br><span>diff --git a/Transceiver52M/device/ipc/shm.c b/Transceiver52M/device/ipc/shm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..743b990</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/shm.c</span><br><span>@@ -0,0 +1,163 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stddef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//#define ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Convert offsets to pointers */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_stream *ipc_shm_decode_stream(void *tall_ctx, struct ipc_shm_raw_region *root_raw,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct ipc_shm_raw_stream *stream_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ipc_shm_stream *stream;</span><br><span style="color: hsl(120, 100%, 40%);">+        stream = talloc_zero(tall_ctx, struct ipc_shm_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+        stream = talloc_zero_size(tall_ctx, sizeof(struct ipc_shm_stream) +</span><br><span style="color: hsl(120, 100%, 40%);">+                                               sizeof(struct ipc_shm_raw_smpl_buf *) * stream_raw->num_buffers);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!stream)</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  stream->num_buffers = stream_raw->num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+  stream->buffer_size = stream_raw->buffer_size;</span><br><span style="color: hsl(120, 100%, 40%);">+  stream->raw = stream_raw;</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < stream->num_buffers; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+         fprintf(stderr, "decode: smpl_buf %d at offset %u\n", i, stream_raw->buffer_offset[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+          stream->buffers[i] =</span><br><span style="color: hsl(120, 100%, 40%);">+                       (struct ipc_shm_raw_smpl_buf *)(((uint8_t *)root_raw) + stream_raw->buffer_offset[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return stream;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_channel *ipc_shm_decode_channel(void *tall_ctx, struct ipc_shm_raw_region *root_raw,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct ipc_shm_raw_channel *chan_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ipc_shm_channel *chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ chan = talloc_zero(tall_ctx, struct ipc_shm_channel);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!chan)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+      fprintf(stderr, "decode: streams at offset %u and %u\n", chan_raw->dl_buf_offset, chan_raw->ul_buf_offset);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+   chan->dl_stream = ipc_shm_decode_stream(</span><br><span style="color: hsl(120, 100%, 40%);">+           chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->dl_buf_offset));</span><br><span style="color: hsl(120, 100%, 40%);">+   chan->ul_stream = ipc_shm_decode_stream(</span><br><span style="color: hsl(120, 100%, 40%);">+           chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->ul_buf_offset));</span><br><span style="color: hsl(120, 100%, 40%);">+   return chan;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_region *root_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ipc_shm_region *root;</span><br><span style="color: hsl(120, 100%, 40%);">+  root = talloc_zero_size(tall_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                             sizeof(struct ipc_shm_region) + sizeof(struct ipc_shm_channel *) * root_raw->num_chans);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!root)</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        root->num_chans = root_raw->num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < root->num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+             fprintf(stderr, "decode: channel %d at offset %u\n", i, root_raw->chan_offset[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+               root->channels[i] = ipc_shm_decode_channel(</span><br><span style="color: hsl(120, 100%, 40%);">+                        root, root_raw,</span><br><span style="color: hsl(120, 100%, 40%);">+                       (struct ipc_shm_raw_channel *)(((uint8_t *)root_raw) + root_raw->chan_offset[i]));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return root;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ipc_shm_encode_smpl_buf(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_smpl_buf *smpl_buf_raw,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    uint32_t buffer_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int offset = sizeof(struct ipc_shm_raw_smpl_buf);</span><br><span style="color: hsl(120, 100%, 40%);">+    offset = (((uintptr_t)offset + 7) & ~0x07ULL);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+        fprintf(stderr, "encode: smpl_buf at offset %lu\n", (start - (uint8_t *)root_raw));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+ offset += buffer_size * sizeof(uint16_t) * 2; /* samples */</span><br><span style="color: hsl(120, 100%, 40%);">+   return offset;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ipc_shm_encode_stream(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_stream *stream_raw,</span><br><span style="color: hsl(120, 100%, 40%);">+                              uint32_t num_buffers, uint32_t buffer_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       ptrdiff_t start = (ptrdiff_t)stream_raw;</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int offset = sizeof(struct ipc_shm_raw_stream) + sizeof(uint32_t) * num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+     offset = (((uintptr_t)offset + 7) & ~0x07ULL);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+        fprintf(stderr, "encode: stream at offset %lu\n", (start - (ptrdiff_t)root_raw));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+   if (root_raw) {</span><br><span style="color: hsl(120, 100%, 40%);">+               stream_raw->num_buffers = num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+             stream_raw->buffer_size = buffer_size;</span><br><span style="color: hsl(120, 100%, 40%);">+             stream_raw->read_next = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         stream_raw->write_next = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < num_buffers; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (root_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+                 stream_raw->buffer_offset[i] = (start + offset - (ptrdiff_t)root_raw);</span><br><span style="color: hsl(120, 100%, 40%);">+             offset +=</span><br><span style="color: hsl(120, 100%, 40%);">+                     ipc_shm_encode_smpl_buf(root_raw, (struct ipc_shm_raw_smpl_buf *)(start + offset), buffer_size);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return offset;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ipc_shm_encode_channel(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_channel *chan_raw,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 uint32_t num_buffers, uint32_t buffer_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t *start = (uint8_t *)chan_raw;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int offset = sizeof(struct ipc_shm_raw_channel);</span><br><span style="color: hsl(120, 100%, 40%);">+     offset = (((uintptr_t)offset + 7) & ~0x07ULL);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+        fprintf(stderr, "encode: channel at offset %lu\n", (start - (uint8_t *)root_raw));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+  if (root_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_raw->dl_buf_offset = (start + offset - (uint8_t *)root_raw);</span><br><span style="color: hsl(120, 100%, 40%);">+  offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 buffer_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (root_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_raw->ul_buf_offset = (start + offset - (uint8_t *)root_raw);</span><br><span style="color: hsl(120, 100%, 40%);">+  offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 buffer_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ return offset;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+/* if root_raw is NULL, then do a dry run, aka only calculate final offset */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers,</span><br><span style="color: hsl(120, 100%, 40%);">+                              uint32_t buffer_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned i;</span><br><span style="color: hsl(120, 100%, 40%);">+   uintptr_t start = (uintptr_t)root_raw;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int offset = sizeof(struct ipc_shm_raw_region) + sizeof(uint32_t) * num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+       offset = (((uintptr_t)offset + 7) & ~0x07ULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (root_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+         root_raw->num_chans = num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (root_raw)</span><br><span style="color: hsl(120, 100%, 40%);">+                 root_raw->chan_offset[i] = (start + offset - (uintptr_t)root_raw);</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef ENCDECDEBUG</span><br><span style="color: hsl(120, 100%, 40%);">+             fprintf(stderr, "encode: channel %d chan_offset[i]=%u\n", i, ofs);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+          offset += ipc_shm_encode_channel(root_raw, (struct ipc_shm_raw_channel *)(start + offset), num_buffers,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                buffer_size);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     //TODO: pass maximum size and verify we didn't go through</span><br><span style="color: hsl(120, 100%, 40%);">+ return offset;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/shm.h b/Transceiver52M/device/ipc/shm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..e85df3a</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/shm.h</span><br><span>@@ -0,0 +1,236 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <limits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pthread.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <semaphore.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* RAW structures */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_raw_smpl_buf {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint64_t timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t data_len; /* In samples */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t samples[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_raw_stream {</span><br><span style="color: hsl(120, 100%, 40%);">+       pthread_mutex_t lock;</span><br><span style="color: hsl(120, 100%, 40%);">+ pthread_cond_t cf;</span><br><span style="color: hsl(120, 100%, 40%);">+    pthread_cond_t ce;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t buffer_size; /* In samples */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t read_next;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t write_next;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t buffer_offset[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    //struct ipc_shm_smpl_buf buffers[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_raw_channel {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t dl_buf_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t ul_buf_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_raw_region {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t chan_offset[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* non-raw, Pointer converted structures */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_stream {</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t num_buffers;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t buffer_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ volatile struct ipc_shm_raw_stream *raw;</span><br><span style="color: hsl(120, 100%, 40%);">+      volatile struct ipc_shm_raw_smpl_buf *buffers[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_channel {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_shm_stream *dl_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_shm_stream *ul_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Pointer converted structures */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_region {</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_shm_channel *channels[0];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers,</span><br><span style="color: hsl(120, 100%, 40%);">+                            uint32_t buffer_size);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_region *root_raw);</span><br><span style="color: hsl(120, 100%, 40%);">+/****************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+/* UNIX SOCKET API                      */</span><br><span style="color: hsl(120, 100%, 40%);">+/****************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+// Master socket</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_SOCK_PATH_PREFIX "/tmp/ipc_sock"</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_SOCK_API_VERSION 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* msg_type */</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_GREETING_REQ 0x00</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_GREETING_CNF 0x01</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_INFO_REQ 0x02</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_INFO_CNF 0x03</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_OPEN_REQ 0x04</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_OPEN_CNF 0x05</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAX_NUM_CHANS 30</span><br><span style="color: hsl(120, 100%, 40%);">+#define RF_PATH_NAME_SIZE 25</span><br><span style="color: hsl(120, 100%, 40%);">+#define MAX_NUM_RF_PATHS 10</span><br><span style="color: hsl(120, 100%, 40%);">+#define SHM_NAME_MAX NAME_MAX /* 255 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define FEATURE_MASK_CLOCKREF_INTERNAL (0x1 << 0)</span><br><span style="color: hsl(120, 100%, 40%);">+#define FEATURE_MASK_CLOCKREF_EXTERNAL (0x1 << 1)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_info_chan {</span><br><span style="color: hsl(120, 100%, 40%);">+       char tx_path[MAX_NUM_RF_PATHS][RF_PATH_NAME_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+    char rx_path[MAX_NUM_RF_PATHS][RF_PATH_NAME_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+    double min_rx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+   double max_rx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+   double min_tx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+   double max_tx_gain;</span><br><span style="color: hsl(120, 100%, 40%);">+   double nominal_tx_power; /* dBm */</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_open_req_chan {</span><br><span style="color: hsl(120, 100%, 40%);">+    char tx_path[RF_PATH_NAME_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+      char rx_path[RF_PATH_NAME_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_open_cnf_chan {</span><br><span style="color: hsl(120, 100%, 40%);">+      char chan_ipc_sk_path[108];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_greeting {</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t req_version;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_info_req {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t spare;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_info_cnf {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t feature_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+        double iq_scaling_val_rx; /* for scaling, sample format is 16 bit, but adc/dac might be less */</span><br><span style="color: hsl(120, 100%, 40%);">+       double iq_scaling_val_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t max_num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+       char dev_desc[200];</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sk_if_info_chan chan_info[MAX_NUM_CHANS];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_open_req {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t clockref; /* One of FEATUER_MASK_CLOCKREF_* */</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t rx_sample_freq_num;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t rx_sample_freq_den;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t tx_sample_freq_num;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t tx_sample_freq_den;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t bandwidth;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ipc_sk_if_open_req_chan chan_info[MAX_NUM_CHANS];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if_open_cnf {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t return_code;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t path_delay;</span><br><span style="color: hsl(120, 100%, 40%);">+  char shm_name[SHM_NAME_MAX];</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ipc_sk_if_open_cnf_chan chan_info[MAX_NUM_CHANS];</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_if {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t msg_type; /* message type */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t spare[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ipc_sk_if_greeting greeting_req;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ipc_sk_if_greeting greeting_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ipc_sk_if_info_req info_req;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ipc_sk_if_info_cnf info_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ipc_sk_if_open_req open_req;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ipc_sk_if_open_cnf open_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+   } u;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+// Channel socket</span><br><span style="color: hsl(120, 100%, 40%);">+//////////////////</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_CHAN_MSG_OFFSET 50</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_START_REQ IPC_IF_CHAN_MSG_OFFSET + 0</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_START_CNF IPC_IF_CHAN_MSG_OFFSET + 1</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_STOP_REQ IPC_IF_CHAN_MSG_OFFSET + 2</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_STOP_CNF IPC_IF_CHAN_MSG_OFFSET + 3</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_SETGAIN_REQ IPC_IF_CHAN_MSG_OFFSET + 4</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_SETGAIN_CNF IPC_IF_CHAN_MSG_OFFSET + 5</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_SETFREQ_REQ IPC_IF_CHAN_MSG_OFFSET + 6</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_SETFREQ_CNF IPC_IF_CHAN_MSG_OFFSET + 7</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_NOTIFY_UNDERFLOW IPC_IF_CHAN_MSG_OFFSET + 8</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_NOTIFY_OVERFLOW IPC_IF_CHAN_MSG_OFFSET + 9</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_SETTXATTN_REQ IPC_IF_CHAN_MSG_OFFSET + 10</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_IF_MSG_SETTXATTN_CNF IPC_IF_CHAN_MSG_OFFSET + 11</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_op_void {</span><br><span style="color: hsl(120, 100%, 40%);">+      // at least one dummy byte, to allow c/c++ compatibility</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t dummy;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_op_rc {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t return_code;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_gain {</span><br><span style="color: hsl(120, 100%, 40%);">+      double gain;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t is_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_freq_req {</span><br><span style="color: hsl(120, 100%, 40%);">+        double freq;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t is_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_freq_cnf {</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t return_code;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_notfiy {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t dummy;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if_tx_attenuation {</span><br><span style="color: hsl(120, 100%, 40%);">+  double attenuation;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ipc_sk_chan_if {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t msg_type; /* message type */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t spare[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ipc_sk_chan_if_op_void start_req;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_chan_if_op_rc start_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ipc_sk_chan_if_op_void stop_req;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ipc_sk_chan_if_op_rc stop_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ipc_sk_chan_if_gain set_gain_req;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_chan_if_gain set_gain_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ipc_sk_chan_if_freq_req set_freq_req;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ipc_sk_chan_if_freq_cnf set_freq_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ipc_sk_chan_if_notfiy notify;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ipc_sk_chan_if_tx_attenuation txatten_req;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct ipc_sk_chan_if_tx_attenuation txatten_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+     } u;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span>diff --git a/Transceiver52M/device/ipc/uhdwrap.cpp b/Transceiver52M/device/ipc/uhdwrap.cpp</span><br><span>new file mode 100644</span><br><span>index 0000000..130f80a</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/uhdwrap.cpp</span><br><span>@@ -0,0 +1,256 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Eric Wild <ewild@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc_shm.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ipc-driver-test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#include "../uhd/UHDDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "uhdwrap.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_vty.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Logger.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Threads.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "Utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int uhd_wrap::open(const std::string &args, int ref, bool swap_channels)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rv = uhd_device::open(args, ref, swap_channels);</span><br><span style="color: hsl(120, 100%, 40%);">+  samps_per_buff_rx = rx_stream->get_max_num_samps();</span><br><span style="color: hsl(120, 100%, 40%);">+        samps_per_buff_tx = tx_stream->get_max_num_samps();</span><br><span style="color: hsl(120, 100%, 40%);">+        channel_count = usrp_dev->get_rx_num_channels();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ wrap_rx_buffs = std::vector<std::vector<short> >(channel_count, std::vector<short>(2 * samps_per_buff_rx));</span><br><span style="color: hsl(120, 100%, 40%);">+ for (size_t i = 0; i < wrap_rx_buffs.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+          wrap_rx_buf_ptrs.push_back(&wrap_rx_buffs[i].front());</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  wrap_tx_buffs = std::vector<std::vector<short> >(channel_count, std::vector<short>(2 * 5000));</span><br><span style="color: hsl(120, 100%, 40%);">+      for (size_t i = 0; i < wrap_tx_buffs.size(); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+          wrap_tx_buf_ptrs.push_back(&wrap_tx_buffs[i].front());</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return rv;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uhd_wrap::~uhd_wrap()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     //      drvtest::gshutdown = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       //t->join();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+size_t uhd_wrap::bufsizerx()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return samps_per_buff_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+size_t uhd_wrap::bufsizetx()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return samps_per_buff_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int uhd_wrap::chancount()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return channel_count;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int uhd_wrap::wrap_read(TIMESTAMP *timestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  uhd::rx_metadata_t md;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t num_rx_samps = rx_stream->recv(wrap_rx_buf_ptrs, samps_per_buff_rx, md, 0.1, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ *timestamp = md.time_spec.to_ticks(rx_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+  return num_rx_samps; //uhd_device::readSamples(bufs, len, overrun, timestamp, underrun);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" void *uhdwrap_open(struct ipc_sk_if_open_req *open_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int rx_sps, tx_sps;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* FIXME: dev arg string* */</span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: rx frontend bw? */</span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: tx frontend bw? */</span><br><span style="color: hsl(120, 100%, 40%);">+  ReferenceType cref;</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (open_req->clockref) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case FEATURE_MASK_CLOCKREF_EXTERNAL:</span><br><span style="color: hsl(120, 100%, 40%);">+          cref = ReferenceType::REF_EXTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case FEATURE_MASK_CLOCKREF_INTERNAL:</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              cref = ReferenceType::REF_INTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   std::vector<std::string> tx_paths;</span><br><span style="color: hsl(120, 100%, 40%);">+      std::vector<std::string> rx_paths;</span><br><span style="color: hsl(120, 100%, 40%);">+      for (unsigned int i = 0; i < open_req->num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                tx_paths.push_back(open_req->chan_info[i].tx_path);</span><br><span style="color: hsl(120, 100%, 40%);">+                rx_paths.push_back(open_req->chan_info[i].rx_path);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* FIXME: this is actually the sps value, not the sample rate!</span><br><span style="color: hsl(120, 100%, 40%);">+         * sample rate is looked up according to the sps rate by uhd backend */</span><br><span style="color: hsl(120, 100%, 40%);">+       rx_sps = open_req->rx_sample_freq_num / open_req->rx_sample_freq_den;</span><br><span style="color: hsl(120, 100%, 40%);">+   tx_sps = open_req->tx_sample_freq_num / open_req->tx_sample_freq_den;</span><br><span style="color: hsl(120, 100%, 40%);">+   uhd_wrap *uhd_wrap_dev =</span><br><span style="color: hsl(120, 100%, 40%);">+              new uhd_wrap(tx_sps, rx_sps, RadioDevice::NORMAL, open_req->num_chans, 0.0, tx_paths, rx_paths);</span><br><span style="color: hsl(120, 100%, 40%);">+   uhd_wrap_dev->open("", cref, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return uhd_wrap_dev;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int32_t uhdwrap_get_bufsizerx(void *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        return d->bufsizerx();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int32_t uhdwrap_get_timingoffset(void *dev)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        return d->getTimingOffset();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int32_t uhdwrap_read(void *dev, uint32_t num_chans)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     TIMESTAMP t;</span><br><span style="color: hsl(120, 100%, 40%);">+  uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (num_chans != d->wrap_rx_buf_ptrs.size()) {</span><br><span style="color: hsl(120, 100%, 40%);">+             perror("omg chans?!");</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   int32_t read = d->wrap_read(&t);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* multi channel rx on b210 will return 0 due to alignment adventures, do not put 0 samples into a ipc buffer... */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (read <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+             return read;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (uint32_t i = 0; i < num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ipc_shm_enqueue(ios_rx_from_device[i], t, read, (uint16_t *)&d->wrap_rx_buffs[i].front());</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return read;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int32_t uhdwrap_write(void *dev, uint32_t num_chans, bool *underrun)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      uint64_t timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+   int32_t len = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+     for (uint32_t i = 0; i < num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         len = ipc_shm_read(ios_tx_to_device[i], (uint16_t *)&d->wrap_tx_buffs[i].front(), 5000, &timestamp, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (len < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return d->writeSamples(d->wrap_tx_buf_ptrs, len, underrun, timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" double uhdwrap_set_freq(void *dev, double f, size_t chan, bool for_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (for_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+           return d->setTxFreq(f, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+          return d->setRxFreq(f, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" double uhdwrap_set_gain(void *dev, double f, size_t chan, bool for_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        //      if (for_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+   //              return d->setTxGain(f, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+      //      else</span><br><span style="color: hsl(120, 100%, 40%);">+  return d->setRxGain(f, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" double uhdwrap_set_txatt(void *dev, double a, size_t chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        return d->setPowerAttenuation(a, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int32_t uhdwrap_start(void *dev, int chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        return d->start();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" int32_t uhdwrap_stop(void *dev, int chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uhd_wrap *d = (uhd_wrap *)dev;</span><br><span style="color: hsl(120, 100%, 40%);">+        return d->stop();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" void uhdwrap_fill_info_cnf(struct ipc_sk_if *ipc_prim)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ipc_sk_if_info_chan *chan_info;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      uhd::device_addr_t args("");</span><br><span style="color: hsl(120, 100%, 40%);">+        uhd::device_addrs_t devs_found = uhd::device::find(args);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (devs_found.size() < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+               std::cout << "\n No device found!";</span><br><span style="color: hsl(120, 100%, 40%);">+           exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(devs_found[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        auto rxchans = usrp->get_rx_num_channels();</span><br><span style="color: hsl(120, 100%, 40%);">+        auto txchans = usrp->get_tx_num_channels();</span><br><span style="color: hsl(120, 100%, 40%);">+        auto rx_range = usrp->get_rx_gain_range();</span><br><span style="color: hsl(120, 100%, 40%);">+ auto tx_range = usrp->get_tx_gain_range();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       //auto nboards = usrp->get_num_mboards();</span><br><span style="color: hsl(120, 100%, 40%);">+  auto refs = usrp->get_clock_sources(0);</span><br><span style="color: hsl(120, 100%, 40%);">+    auto devname = usrp->get_mboard_name(0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ipc_prim->u.info_cnf.feature_mask = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (std::find(refs.begin(), refs.end(), "internal") != refs.end())</span><br><span style="color: hsl(120, 100%, 40%);">+          ipc_prim->u.info_cnf.feature_mask |= FEATURE_MASK_CLOCKREF_INTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (std::find(refs.begin(), refs.end(), "external") != refs.end())</span><br><span style="color: hsl(120, 100%, 40%);">+          ipc_prim->u.info_cnf.feature_mask |= FEATURE_MASK_CLOCKREF_EXTERNAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     // at least one duplex channel</span><br><span style="color: hsl(120, 100%, 40%);">+        auto num_chans = rxchans == txchans ? txchans : 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ipc_prim->u.info_cnf.iq_scaling_val_rx = 0.3;</span><br><span style="color: hsl(120, 100%, 40%);">+      ipc_prim->u.info_cnf.iq_scaling_val_tx = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        ipc_prim->u.info_cnf.max_num_chans = num_chans;</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_STRLCPY_ARRAY(ipc_prim->u.info_cnf.dev_desc, devname.c_str());</span><br><span style="color: hsl(120, 100%, 40%);">+        chan_info = ipc_prim->u.info_cnf.chan_info;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (unsigned int i = 0; i < ipc_prim->u.info_cnf.max_num_chans; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         auto rxant = usrp->get_rx_antennas(i);</span><br><span style="color: hsl(120, 100%, 40%);">+             auto txant = usrp->get_tx_antennas(i);</span><br><span style="color: hsl(120, 100%, 40%);">+             for (unsigned int j = 0; j < txant.size(); j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  OSMO_STRLCPY_ARRAY(chan_info->tx_path[j], txant[j].c_str());</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             for (unsigned int j = 0; j < rxant.size(); j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  OSMO_STRLCPY_ARRAY(chan_info->rx_path[j], rxant[j].c_str());</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             chan_info->min_rx_gain = rx_range.start();</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_info->max_rx_gain = rx_range.stop();</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_info->min_tx_gain = tx_range.start();</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_info->max_tx_gain = tx_range.stop();</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_info->nominal_tx_power = 7.5; // FIXME: would require uhd dev + freq info</span><br><span style="color: hsl(120, 100%, 40%);">+             chan_info++;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/Transceiver52M/device/ipc/uhdwrap.h b/Transceiver52M/device/ipc/uhdwrap.h</span><br><span>new file mode 100644</span><br><span>index 0000000..e235fe7</span><br><span>--- /dev/null</span><br><span>+++ b/Transceiver52M/device/ipc/uhdwrap.h</span><br><span>@@ -0,0 +1,83 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+* Author: Eric Wild <ewild@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* SPDX-License-Identifier: 0BSD</span><br><span style="color: hsl(120, 100%, 40%);">+*</span><br><span style="color: hsl(120, 100%, 40%);">+* Permission to use, copy, modify, and/or distribute this software for any purpose</span><br><span style="color: hsl(120, 100%, 40%);">+* with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE</span><br><span style="color: hsl(120, 100%, 40%);">+* AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL</span><br><span style="color: hsl(120, 100%, 40%);">+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR</span><br><span style="color: hsl(120, 100%, 40%);">+* BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES</span><br><span style="color: hsl(120, 100%, 40%);">+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF</span><br><span style="color: hsl(120, 100%, 40%);">+* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE</span><br><span style="color: hsl(120, 100%, 40%);">+* USE OR PERFORMANCE OF THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef IPC_UHDWRAP_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define IPC_UHDWRAP_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+#include "../uhd/UHDDevice.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class uhd_wrap : public uhd_device {</span><br><span style="color: hsl(120, 100%, 40%);">+    public:</span><br><span style="color: hsl(120, 100%, 40%);">+       //      std::thread *t;</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t samps_per_buff_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t samps_per_buff_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+     int channel_count;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  std::vector<std::vector<short> > wrap_rx_buffs;</span><br><span style="color: hsl(120, 100%, 40%);">+   std::vector<std::vector<short> > wrap_tx_buffs;</span><br><span style="color: hsl(120, 100%, 40%);">+   std::vector<short *> wrap_rx_buf_ptrs;</span><br><span style="color: hsl(120, 100%, 40%);">+  std::vector<short *> wrap_tx_buf_ptrs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        template <typename... Args> uhd_wrap(Args... args) : uhd_device(args...)</span><br><span style="color: hsl(120, 100%, 40%);">+        {</span><br><span style="color: hsl(120, 100%, 40%);">+             //      t = new std::thread(magicthread);</span><br><span style="color: hsl(120, 100%, 40%);">+             // give the thread some time to start and set up</span><br><span style="color: hsl(120, 100%, 40%);">+              //      std::this_thread::sleep_for(std::chrono::seconds(1));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     virtual ~uhd_wrap();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        //    void ipc_sock_close() override {};</span><br><span style="color: hsl(120, 100%, 40%);">+      int wrap_read(TIMESTAMP *timestamp);</span><br><span style="color: hsl(120, 100%, 40%);">+  virtual int open(const std::string &args, int ref, bool swap_channels) override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        //      bool start() override;</span><br><span style="color: hsl(120, 100%, 40%);">+        //      bool stop() override;</span><br><span style="color: hsl(120, 100%, 40%);">+ //      virtual TIMESTAMP initialWriteTimestamp() override;</span><br><span style="color: hsl(120, 100%, 40%);">+   //      virtual TIMESTAMP initialReadTimestamp() override;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  int getTimingOffset()</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+             return ts_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t bufsizerx();</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t bufsizetx();</span><br><span style="color: hsl(120, 100%, 40%);">+   int chancount();</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+void *uhdwrap_open(struct ipc_sk_if_open_req *open_req);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t uhdwrap_get_bufsizerx(void *dev);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t uhdwrap_get_timingoffset(void *dev);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t uhdwrap_read(void *dev, uint32_t num_chans);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t uhdwrap_write(void *dev, uint32_t num_chans, bool *underrun);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double uhdwrap_set_freq(void *dev, double f, size_t chan, bool for_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double uhdwrap_set_gain(void *dev, double f, size_t chan, bool for_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t uhdwrap_start(void *dev, int chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t uhdwrap_stop(void *dev, int chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void uhdwrap_fill_info_cnf(struct ipc_sk_if *ipc_prim);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+double uhdwrap_set_txatt(void *dev, double a, size_t chan);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif // IPC_B210_H</span><br><span>diff --git a/Transceiver52M/device/uhd/UHDDevice.cpp b/Transceiver52M/device/uhd/UHDDevice.cpp</span><br><span>index b5dda28..43b9f9c 100644</span><br><span>--- a/Transceiver52M/device/uhd/UHDDevice.cpp</span><br><span>+++ b/Transceiver52M/device/uhd/UHDDevice.cpp</span><br><span>@@ -152,7 +152,7 @@</span><br><span> void *async_event_loop(uhd_device *dev)</span><br><span> {</span><br><span>      set_selfthread_name("UHDAsyncEvent");</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(osmo_cpu_sched_vty_apply_localthread() == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_cpu_sched_vty_apply_localthread();</span><br><span> </span><br><span>  while (1) {</span><br><span>          dev->recv_async_msg();</span><br><span>@@ -1316,6 +1316,7 @@</span><br><span>    return ost.str();</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef IPCMAGIC</span><br><span> RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,</span><br><span>                                InterfaceType iface, size_t chans, double lo_offset,</span><br><span>                         const std::vector<std::string>& tx_paths,</span><br><span>@@ -1323,3 +1324,4 @@</span><br><span> {</span><br><span>      return new uhd_device(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>diff --git a/Transceiver52M/device/uhd/UHDDevice.h b/Transceiver52M/device/uhd/UHDDevice.h</span><br><span>index 22a0948..c159e63 100644</span><br><span>--- a/Transceiver52M/device/uhd/UHDDevice.h</span><br><span>+++ b/Transceiver52M/device/uhd/UHDDevice.h</span><br><span>@@ -133,7 +133,7 @@</span><br><span>              ERROR_UNHANDLED = -4,</span><br><span>        };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-private:</span><br><span style="color: hsl(120, 100%, 40%);">+protected:</span><br><span>   uhd::usrp::multi_usrp::sptr usrp_dev;</span><br><span>        uhd::tx_streamer::sptr tx_stream;</span><br><span>    uhd::rx_streamer::sptr rx_stream;</span><br><span>diff --git a/configure.ac b/configure.ac</span><br><span>index 07d4bf4..e651176 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -140,6 +140,11 @@</span><br><span>         [enable LimeSuite based transceiver])</span><br><span> ])</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AC_ARG_WITH(ipc, [</span><br><span style="color: hsl(120, 100%, 40%);">+    AS_HELP_STRING([--with-ipc],</span><br><span style="color: hsl(120, 100%, 40%);">+        [enable IPC])</span><br><span style="color: hsl(120, 100%, 40%);">+])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AC_ARG_WITH(singledb, [</span><br><span>     AS_HELP_STRING([--with-singledb],</span><br><span>         [enable single daughterboard use on USRP1])</span><br><span>@@ -179,7 +184,7 @@</span><br><span>     PKG_CHECK_MODULES(LMS, LimeSuite)</span><br><span> ])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-AS_IF([test "x$with_uhd" != "xno"],[</span><br><span style="color: hsl(120, 100%, 40%);">+AS_IF([test "x$with_uhd" == "xyes"],[</span><br><span>     PKG_CHECK_MODULES(UHD, uhd >= 003.011,</span><br><span>         [AC_DEFINE(USE_UHD_3_11, 1, UHD version 3.11.0 or higher)],</span><br><span>         [PKG_CHECK_MODULES(UHD, uhd >= 003.009,</span><br><span>@@ -238,9 +243,10 @@</span><br><span>     AC_DEFINE(HAVE_ATOMIC_OPS, 1, [Support all required atomic operations], [AC_MSG_WARN("At least one aotmic operation missing, will use mutex")])</span><br><span> ])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" != "xno"])</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CONDITIONAL(DEVICE_UHD, [test "x$with_uhd" == "xyes"])</span><br><span> AM_CONDITIONAL(DEVICE_USRP1, [test "x$with_usrp1" = "xyes"])</span><br><span> AM_CONDITIONAL(DEVICE_LMS, [test "x$with_lms" = "xyes"])</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CONDITIONAL(DEVICE_IPC, [test "x$with_ipc" = "xyes"])</span><br><span> AM_CONDITIONAL(ARCH_ARM, [test "x$with_neon" = "xyes" || test "x$with_neon_vfpv4" = "xyes"])</span><br><span> AM_CONDITIONAL(ARCH_ARM_A15, [test "x$with_neon_vfpv4" = "xyes"])</span><br><span> </span><br><span>@@ -325,6 +331,7 @@</span><br><span>     Transceiver52M/device/uhd/Makefile \</span><br><span>     Transceiver52M/device/usrp1/Makefile \</span><br><span>     Transceiver52M/device/lms/Makefile \</span><br><span style="color: hsl(120, 100%, 40%);">+    Transceiver52M/device/ipc/Makefile \</span><br><span>     tests/Makefile \</span><br><span>     tests/CommonLibs/Makefile \</span><br><span>     tests/Transceiver52M/Makefile \</span><br><span>diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh</span><br><span>index df444ca..95ea128 100755</span><br><span>--- a/contrib/jenkins.sh</span><br><span>+++ b/contrib/jenkins.sh</span><br><span>@@ -85,7 +85,7 @@</span><br><span> export LD_LIBRARY_PATH="$inst/lib"</span><br><span> export PATH="$inst/bin:$PATH"</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-CONFIG="--enable-sanitize --enable-werror --with-uhd --with-usrp1 --with-lms $INSTR"</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG="--enable-sanitize --enable-werror --with-uhd --with-usrp1 --with-lms --with-ipc $INSTR"</span><br><span> </span><br><span> # Additional configure options and depends</span><br><span> if [ "$WITH_MANUALS" = "1" ]; then</span><br><span>diff --git a/contrib/osmo-trx.spec.in b/contrib/osmo-trx.spec.in</span><br><span>index aebd355..86b96d3 100644</span><br><span>--- a/contrib/osmo-trx.spec.in</span><br><span>+++ b/contrib/osmo-trx.spec.in</span><br><span>@@ -129,6 +129,26 @@</span><br><span> generations of mobile phone networks. (post-2G/GSM)</span><br><span> %endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+%package ipc</span><br><span style="color: hsl(120, 100%, 40%);">+Summary:        SDR transceiver that implements Layer 1 of a GSM BTS (IPC)</span><br><span style="color: hsl(120, 100%, 40%);">+Group:          Productivity/Telephony/Servers</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+%description ipc</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoTRX is a software-defined radio transceiver that implements the Layer 1</span><br><span style="color: hsl(120, 100%, 40%);">+physical layer of a BTS comprising the following 3GPP specifications:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+TS 05.01 "Physical layer on the radio path"</span><br><span style="color: hsl(120, 100%, 40%);">+TS 05.02 "Multiplexing and Multiple Access on the Radio Path"</span><br><span style="color: hsl(120, 100%, 40%);">+TS 05.04 "Modulation"</span><br><span style="color: hsl(120, 100%, 40%);">+TS 05.10 "Radio subsystem synchronization"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+In this context, BTS is "Base transceiver station". It's the stations that</span><br><span style="color: hsl(120, 100%, 40%);">+connect mobile phones to the mobile network.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+3GPP is the "3rd Generation Partnership Project" which is the collaboration</span><br><span style="color: hsl(120, 100%, 40%);">+between different telecommunication associations for developing new</span><br><span style="color: hsl(120, 100%, 40%);">+generations of mobile phone networks. (post-2G/GSM)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> %prep</span><br><span> %setup -q</span><br><span> </span><br><span>@@ -142,14 +162,16 @@</span><br><span>   --with-systemdsystemunitdir=%{_unitdir} \</span><br><span>   --without-lms \</span><br><span>   --with-uhd \</span><br><span style="color: hsl(0, 100%, 40%);">-  --without-usrp1</span><br><span style="color: hsl(120, 100%, 40%);">+  --without-usrp1 \</span><br><span style="color: hsl(120, 100%, 40%);">+  --with-ipc</span><br><span> %else</span><br><span> %configure \</span><br><span>   --docdir=%{_docdir}/%{name} \</span><br><span>   --with-systemdsystemunitdir=%{_unitdir} \</span><br><span>   --with-lms \</span><br><span>   --with-uhd \</span><br><span style="color: hsl(0, 100%, 40%);">-  --with-usrp1</span><br><span style="color: hsl(120, 100%, 40%);">+  --with-usrp1 \</span><br><span style="color: hsl(120, 100%, 40%);">+  --with-ipc</span><br><span> %endif</span><br><span> </span><br><span> make %{?_smp_mflags} V=1</span><br><span>@@ -174,6 +196,10 @@</span><br><span> %post   usrp1 %service_add_post   osmo-trx-usrp1.service</span><br><span> %preun  usrp1 %service_del_preun  osmo-trx-usrp1.service</span><br><span> %postun usrp1 %service_del_postun osmo-trx-usrp1.service</span><br><span style="color: hsl(120, 100%, 40%);">+%pre    ipc %service_add_pre    osmo-trx-ipc.service</span><br><span style="color: hsl(120, 100%, 40%);">+%post   ipc %service_add_post   osmo-trx-ipc.service</span><br><span style="color: hsl(120, 100%, 40%);">+%preun  ipc %service_del_preun  osmo-trx-ipc.service</span><br><span style="color: hsl(120, 100%, 40%);">+%postun ipc %service_del_postun osmo-trx-ipc.service</span><br><span> %endif</span><br><span> </span><br><span> %files</span><br><span>@@ -206,4 +232,11 @@</span><br><span> %{_unitdir}/osmo-trx-usrp1.service</span><br><span> %endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+%files ipc</span><br><span style="color: hsl(120, 100%, 40%);">+%{_bindir}/osmo-trx-ipc</span><br><span style="color: hsl(120, 100%, 40%);">+%{_bindir}/ipc-driver-test</span><br><span style="color: hsl(120, 100%, 40%);">+%dir %{_sysconfdir}/osmocom</span><br><span style="color: hsl(120, 100%, 40%);">+# FIXME: missing: osmo-trx-ipc.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+%{_unitdir}/osmo-trx-ipc.service</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> %changelog</span><br><span>diff --git a/contrib/systemd/Makefile.am b/contrib/systemd/Makefile.am</span><br><span>index 800b1e1..6566b97 100644</span><br><span>--- a/contrib/systemd/Makefile.am</span><br><span>+++ b/contrib/systemd/Makefile.am</span><br><span>@@ -1,7 +1,8 @@</span><br><span> EXTRA_DIST = \</span><br><span>   osmo-trx-lms.service \</span><br><span>   osmo-trx-uhd.service \</span><br><span style="color: hsl(0, 100%, 40%);">-  osmo-trx-usrp1.service</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo-trx-usrp1.service \</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo-trx-ipc.service</span><br><span> </span><br><span> if HAVE_SYSTEMD</span><br><span> SYSTEMD_SERVICES =</span><br><span>@@ -18,5 +19,9 @@</span><br><span> SYSTEMD_SERVICES += osmo-trx-lms.service</span><br><span> endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_IPC</span><br><span style="color: hsl(120, 100%, 40%);">+SYSTEMD_SERVICES += osmo-trx-ipc.service</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> systemdsystemunit_DATA = $(SYSTEMD_SERVICES)</span><br><span> endif # HAVE_SYSTEMD</span><br><span>diff --git a/contrib/systemd/osmo-trx-ipc.service b/contrib/systemd/osmo-trx-ipc.service</span><br><span>new file mode 100644</span><br><span>index 0000000..c886ed7</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/systemd/osmo-trx-ipc.service</span><br><span>@@ -0,0 +1,11 @@</span><br><span style="color: hsl(120, 100%, 40%);">+[Unit]</span><br><span style="color: hsl(120, 100%, 40%);">+Description=Osmocom SDR BTS L1 Transceiver (IPC Backend)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[Service]</span><br><span style="color: hsl(120, 100%, 40%);">+Type=simple</span><br><span style="color: hsl(120, 100%, 40%);">+Restart=always</span><br><span style="color: hsl(120, 100%, 40%);">+ExecStart=/usr/bin/osmo-trx-ipc -C /etc/osmocom/osmo-trx-ipc.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+RestartSec=2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[Install]</span><br><span style="color: hsl(120, 100%, 40%);">+WantedBy=multi-user.target</span><br><span>diff --git a/debian/control b/debian/control</span><br><span>index 31c738e..12d9af5 100644</span><br><span>--- a/debian/control</span><br><span>+++ b/debian/control</span><br><span>@@ -30,7 +30,7 @@</span><br><span> Architecture: any</span><br><span> Section: debug</span><br><span> Priority: extra</span><br><span style="color: hsl(0, 100%, 40%);">-Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-lms (= ${binary:Version}), ${misc:Depends}</span><br><span style="color: hsl(120, 100%, 40%);">+Depends: osmo-trx-uhd (= ${binary:Version}), osmo-trx-usrp1 (= ${binary:Version}), osmo-trx-lms (= ${binary:Version}), osmo-trx-ipc (= ${binary:Version}), ${misc:Depends}</span><br><span> Description: Debug symbols for the osmo-trx-*</span><br><span>  Make debugging possible</span><br><span> </span><br><span>@@ -91,6 +91,25 @@</span><br><span>  between different telecommunication associations for developing new</span><br><span>  generations of mobile phone networks. (post-2G/GSM)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+Package: osmo-trx-ipc</span><br><span style="color: hsl(120, 100%, 40%);">+Architecture: any</span><br><span style="color: hsl(120, 100%, 40%);">+Depends: ${shlibs:Depends}, ${misc:Depends}</span><br><span style="color: hsl(120, 100%, 40%);">+Description: SDR transceiver that implements Layer 1 of a GSM BTS (generic IPC)</span><br><span style="color: hsl(120, 100%, 40%);">+ OsmoTRX is a software-defined radio transceiver that implements the Layer 1</span><br><span style="color: hsl(120, 100%, 40%);">+ physical layer of a BTS comprising the following 3GPP specifications:</span><br><span style="color: hsl(120, 100%, 40%);">+ .</span><br><span style="color: hsl(120, 100%, 40%);">+ TS 05.01 "Physical layer on the radio path"</span><br><span style="color: hsl(120, 100%, 40%);">+ TS 05.02 "Multiplexing and Multiple Access on the Radio Path"</span><br><span style="color: hsl(120, 100%, 40%);">+ TS 05.04 "Modulation"</span><br><span style="color: hsl(120, 100%, 40%);">+ TS 05.10 "Radio subsystem synchronization"</span><br><span style="color: hsl(120, 100%, 40%);">+ .</span><br><span style="color: hsl(120, 100%, 40%);">+ In this context, BTS is "Base transceiver station". It's the stations that</span><br><span style="color: hsl(120, 100%, 40%);">+ connect mobile phones to the mobile network.</span><br><span style="color: hsl(120, 100%, 40%);">+ .</span><br><span style="color: hsl(120, 100%, 40%);">+ 3GPP is the "3rd Generation Partnership Project" which is the collaboration</span><br><span style="color: hsl(120, 100%, 40%);">+ between different telecommunication associations for developing new</span><br><span style="color: hsl(120, 100%, 40%);">+ generations of mobile phone networks. (post-2G/GSM)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> Package: osmo-trx-doc</span><br><span> Architecture: all</span><br><span> Section: doc</span><br><span>diff --git a/debian/osmo-trx-ipc.install b/debian/osmo-trx-ipc.install</span><br><span>new file mode 100644</span><br><span>index 0000000..db64623</span><br><span>--- /dev/null</span><br><span>+++ b/debian/osmo-trx-ipc.install</span><br><span>@@ -0,0 +1,4 @@</span><br><span style="color: hsl(120, 100%, 40%);">+etc/osmocom/osmo-trx-ipc.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+lib/systemd/system/osmo-trx-ipc.service</span><br><span style="color: hsl(120, 100%, 40%);">+/usr/bin/osmo-trx-ipc</span><br><span style="color: hsl(120, 100%, 40%);">+/usr/share/doc/osmo-trx/examples/osmo-trx-ipc/osmo-trx-ipc.cfg /usr/share/doc/osmo-trx/examples/osmo-trx-ipc/</span><br><span>diff --git a/debian/rules b/debian/rules</span><br><span>index 627c0c8..5795643 100755</span><br><span>--- a/debian/rules</span><br><span>+++ b/debian/rules</span><br><span>@@ -9,7 +9,7 @@</span><br><span>  dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info</span><br><span> </span><br><span> override_dh_auto_configure:</span><br><span style="color: hsl(0, 100%, 40%);">-   dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals</span><br><span style="color: hsl(120, 100%, 40%);">+      dh_auto_configure -- --with-uhd --with-usrp1 --with-lms --with-ipc --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals</span><br><span> </span><br><span> override_dh_strip:</span><br><span>        dh_strip --dbg-package=osmo-trx-dbg</span><br><span>diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am</span><br><span>index 88d9142..0b06130 100644</span><br><span>--- a/doc/examples/Makefile.am</span><br><span>+++ b/doc/examples/Makefile.am</span><br><span>@@ -14,6 +14,10 @@</span><br><span> OSMOCONF_FILES += osmo-trx-lms/osmo-trx-lms.cfg</span><br><span> endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+if DEVICE_IPC</span><br><span style="color: hsl(120, 100%, 40%);">+OSMOCONF_FILES += osmo-trx-ipc/osmo-trx-ipc.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> osmoconf_DATA = $(OSMOCONF_FILES)</span><br><span> EXTRA_DIST = $(OSMOCONF_FILES)</span><br><span> </span><br><span>diff --git a/doc/examples/osmo-trx-ipc/osmo-trx-ipc.cfg b/doc/examples/osmo-trx-ipc/osmo-trx-ipc.cfg</span><br><span>new file mode 100644</span><br><span>index 0000000..2e0b67e</span><br><span>--- /dev/null</span><br><span>+++ b/doc/examples/osmo-trx-ipc/osmo-trx-ipc.cfg</span><br><span>@@ -0,0 +1,33 @@</span><br><span style="color: hsl(120, 100%, 40%);">+log stderr</span><br><span style="color: hsl(120, 100%, 40%);">+ logging filter all 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging color 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print category 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging timestamp 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print file basename</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level set-all notice</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+line vty</span><br><span style="color: hsl(120, 100%, 40%);">+ no login</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+cpu-sched</span><br><span style="color: hsl(120, 100%, 40%);">+ policy rr 18</span><br><span style="color: hsl(120, 100%, 40%);">+trx</span><br><span style="color: hsl(120, 100%, 40%);">+ bind-ip 127.0.0.1</span><br><span style="color: hsl(120, 100%, 40%);">+ remote-ip 127.0.0.1</span><br><span style="color: hsl(120, 100%, 40%);">+ egprs disable</span><br><span style="color: hsl(120, 100%, 40%);">+ ! 28 dB offset below is valid only for the B2xx in 1800 MHz band, see</span><br><span style="color: hsl(120, 100%, 40%);">+ ! https://osmocom.org/issues/4468 for more details</span><br><span style="color: hsl(120, 100%, 40%);">+ rssi-offset 28.000000</span><br><span style="color: hsl(120, 100%, 40%);">+ tx-sps 4</span><br><span style="color: hsl(120, 100%, 40%);">+ rx-sps 4</span><br><span style="color: hsl(120, 100%, 40%);">+ clock-ref external</span><br><span style="color: hsl(120, 100%, 40%);">+ egprs disable</span><br><span style="color: hsl(120, 100%, 40%);">+ ext-rach disable</span><br><span style="color: hsl(120, 100%, 40%);">+ dev-args ipc_msock=/tmp/ipc_sock0</span><br><span style="color: hsl(120, 100%, 40%);">+ multi-arfcn disable</span><br><span style="color: hsl(120, 100%, 40%);">+ chan 0</span><br><span style="color: hsl(120, 100%, 40%);">+  tx-path TX/RX</span><br><span style="color: hsl(120, 100%, 40%);">+  rx-path RX2</span><br><span style="color: hsl(120, 100%, 40%);">+ chan 1</span><br><span style="color: hsl(120, 100%, 40%);">+  tx-path TX/RX</span><br><span style="color: hsl(120, 100%, 40%);">+  rx-path RX2</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-trx/+/19664">change 19664</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-trx/+/19664"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-trx </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iefae70cc079a0174f48309f9ef25157c530e5c32 </div>
<div style="display:none"> Gerrit-Change-Number: 19664 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>