aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric <ewild@sysmocom.de>2020-04-24 21:39:17 +0200
committerEric <ewild@sysmocom.de>2020-04-27 05:02:26 +0200
commit90b0b8696d1eed260780792f9c29c2bf84b2d79e (patch)
tree8633322f88bdc756178d742585146ca2dafe2814
parent2120eb1e0a5d7cd3a0aceb3aa7ed54ed197a1b3d (diff)
v1
-rw-r--r--Transceiver52M/Makefile.am5
-rw-r--r--Transceiver52M/device/ipc/IPCDevice.cpp706
-rw-r--r--Transceiver52M/device/ipc/IPCDevice.h136
-rw-r--r--Transceiver52M/device/ipc/Makefile.am18
-rw-r--r--Transceiver52M/device/ipc/ipc-driver-test.c531
-rw-r--r--Transceiver52M/device/ipc/ipc-driver-test.h29
-rw-r--r--Transceiver52M/device/ipc/ipc_chan.c242
-rw-r--r--Transceiver52M/device/ipc/ipc_chan.h10
-rw-r--r--Transceiver52M/device/ipc/ipc_shm.c204
-rw-r--r--Transceiver52M/device/ipc/ipc_shm.h43
-rw-r--r--Transceiver52M/device/ipc/ipc_sock.c259
-rw-r--r--Transceiver52M/device/ipc/ipc_sock.h11
-rw-r--r--Transceiver52M/device/ipc/ipcb210.cpp190
-rw-r--r--Transceiver52M/device/ipc/ipcb210.h36
-rw-r--r--Transceiver52M/device/ipc/magicwrap.cpp20
-rw-r--r--Transceiver52M/device/ipc/magicwrap.h14
-rw-r--r--Transceiver52M/device/ipc/shm.c209
-rw-r--r--Transceiver52M/device/ipc/shm.h265
-rw-r--r--Transceiver52M/device/ipc/uhdwrap.cpp231
-rw-r--r--Transceiver52M/device/ipc/uhdwrap.h66
-rw-r--r--Transceiver52M/device/uhd/UHDDevice.cpp2
-rw-r--r--Transceiver52M/device/uhd/UHDDevice.h2
22 files changed, 2382 insertions, 847 deletions
diff --git a/Transceiver52M/Makefile.am b/Transceiver52M/Makefile.am
index 4e01e9c..ec65bfd 100644
--- a/Transceiver52M/Makefile.am
+++ b/Transceiver52M/Makefile.am
@@ -109,5 +109,6 @@ bin_PROGRAMS += osmo-trx-ipc
osmo_trx_ipc_SOURCES = osmo-trx.cpp
osmo_trx_ipc_LDADD = \
$(builddir)/device/ipc/libdevice.la \
- $(COMMON_LDADD)
-oosmo_trx_ipc_CPPFLAGS = $(AM_CPPFLAGS)
+ $(COMMON_LDADD) \
+ $(UHD_LIBS)
+osmo_trx_ipc_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
diff --git a/Transceiver52M/device/ipc/IPCDevice.cpp b/Transceiver52M/device/ipc/IPCDevice.cpp
index 1c04558..7cf69a5 100644
--- a/Transceiver52M/device/ipc/IPCDevice.cpp
+++ b/Transceiver52M/device/ipc/IPCDevice.cpp
@@ -22,8 +22,8 @@
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
-#include <sys/stat.h> /* For mode constants */
-#include <fcntl.h> /* For O_* constants */
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
#include <map>
@@ -50,15 +50,16 @@ extern "C" {
#include "config.h"
#endif
-#define SAMPLE_BUF_SZ (1 << 20)
+#define SAMPLE_BUF_SZ (1 << 20)
using namespace std;
+static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags);
+
IPCDevice::IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
- const std::vector<std::string>& tx_paths,
- const std::vector<std::string>& rx_paths):
- RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths),
- tmp_state(IPC_IF_MSG_GREETING_REQ), shm(NULL), started(false)
+ const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)
+ : RadioDevice(tx_sps, rx_sps, iface, chan_num, lo_offset, tx_paths, rx_paths),
+ tmp_state(IPC_IF_MSG_GREETING_REQ), shm(NULL), started(false)
{
LOGC(DDEV, INFO) << "creating IPC device...";
@@ -73,6 +74,7 @@ IPCDevice::IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t c
for (size_t i = 0; i < rx_buffers.size(); i++)
rx_buffers[i] = new smpl_buf(SAMPLE_BUF_SZ / sizeof(uint32_t));
+ memset(&sk_chan_state, 0, sizeof(sk_chan_state));
}
IPCDevice::~IPCDevice()
@@ -83,6 +85,14 @@ IPCDevice::~IPCDevice()
for (size_t i = 0; i < rx_buffers.size(); i++)
delete rx_buffers[i];
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(sk_chan_state); i++)
+ ipc_sock_close(&sk_chan_state[i]);
+
+ for (auto i : shm_io_rx_streams)
+ ipc_shm_close(i);
+ for (auto i : shm_io_tx_streams)
+ ipc_shm_close(i);
}
int IPCDevice::ipc_shm_connect(const char *shm_name)
@@ -92,43 +102,43 @@ int IPCDevice::ipc_shm_connect(const char *shm_name)
int rc;
LOGP(DDEV, LOGL_NOTICE, "Opening shm path %s\n", shm_name);
- if ((fd = shm_open(shm_name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
+ if ((fd = shm_open(shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
LOGP(DDEV, LOGL_ERROR, "shm_open %d: %s\n", errno, strerror(errno));
- rc = -errno;
- goto err_shm_open;
- }
+ rc = -errno;
+ goto err_shm_open;
+ }
// Get size of the allocated memory
struct stat shm_stat;
if (fstat(fd, &shm_stat) < 0) {
LOGP(DDEV, LOGL_ERROR, "fstat %d: %s\n", errno, strerror(errno));
- rc = -errno;
- goto err_mmap;
+ rc = -errno;
+ goto err_mmap;
}
shm_len = shm_stat.st_size;
- LOGP(DDEV, LOGL_NOTICE, "mmaping shared memory fd %d (size=%zu)\n", fd,shm_len);
- if ((shm = mmap(NULL, shm_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
- LOGP(DDEV, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));
- rc = -errno;
- goto err_mmap;
- }
- LOGP(DDEV, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
- LOGP(DDEV, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *) shm, 80));
- /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
- close(fd);
- return 0;
+ LOGP(DDEV, LOGL_NOTICE, "mmaping shared memory fd %d (size=%zu)\n", fd, shm_len);
+ if ((shm = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ LOGP(DDEV, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));
+ rc = -errno;
+ goto err_mmap;
+ }
+ LOGP(DDEV, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
+ LOGP(DDEV, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
+ /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
+ close(fd);
+ return 0;
err_mmap:
- shm_unlink(shm_name);
- close(fd);
+ shm_unlink(shm_name);
+ close(fd);
err_shm_open:
- return rc;
+ return rc;
}
-static int ipc_sock_send(struct ipc_sock_state* state, struct msgb *msg);
+static int ipc_sock_send(struct ipc_sock_state *state, struct msgb *msg);
-struct msgb *ipc_msgb_alloc(uint8_t msg_type)
+static struct msgb *ipc_msgb_alloc(uint8_t msg_type)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
@@ -137,13 +147,13 @@ struct msgb *ipc_msgb_alloc(uint8_t msg_type)
if (!msg)
return NULL;
msgb_put(msg, sizeof(struct ipc_sk_if) + 1000);
- ipc_prim = (struct ipc_sk_if *) msg->data;
+ ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->msg_type = msg_type;
return msg;
}
-int ipc_tx_greeting_req(struct ipc_sock_state* state, uint8_t req_version)
+static int ipc_tx_greeting_req(struct ipc_sock_state *state, uint8_t req_version)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
@@ -155,13 +165,13 @@ int ipc_tx_greeting_req(struct ipc_sock_state* state, uint8_t req_version)
LOGC(DDEV, INFO) << "ipc_msgb_alloc() returns NULL!";
return -ENOMEM;
}
- ipc_prim = (struct ipc_sk_if *) msg->data;
+ ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->u.greeting_req.req_version = req_version;
return ipc_sock_send(state, msg);
}
-int ipc_tx_info_req(struct ipc_sock_state* state)
+static int ipc_tx_info_req(struct ipc_sock_state *state)
{
struct msgb *msg;
//struct ipc_sk_if *ipc_prim;
@@ -177,7 +187,7 @@ int ipc_tx_info_req(struct ipc_sock_state* state)
return ipc_sock_send(state, msg);
}
-int ipc_tx_open_req(struct ipc_sock_state* state, uint32_t num_chans)
+int IPCDevice::ipc_tx_open_req(struct ipc_sock_state *state, uint32_t num_chans, uint32_t ref)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
@@ -189,11 +199,33 @@ int ipc_tx_open_req(struct ipc_sock_state* state, uint32_t num_chans)
if (!msg) {
return -ENOMEM;
}
- ipc_prim = (struct ipc_sk_if *) msg->data;
+ ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->u.open_req.num_chans = num_chans;
- chan_info = ipc_prim->u.open_req.chan_info;
- OSMO_STRLCPY_ARRAY(chan_info->rx_path, "RxAntenna1");
- OSMO_STRLCPY_ARRAY(chan_info->tx_path, "TxAntenna2");
+
+ /* FIXME: pass fractional freq */
+ ipc_prim->u.open_req.rx_sample_freq_num = rx_sps;
+ ipc_prim->u.open_req.rx_sample_freq_den = 1;
+ ipc_prim->u.open_req.tx_sample_freq_num = tx_sps;
+ ipc_prim->u.open_req.tx_sample_freq_den = 1;
+
+ switch (ref) {
+ case ReferenceType::REF_EXTERNAL:
+ ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_EXTERNAL;
+ break;
+ case ReferenceType::REF_INTERNAL:
+ case ReferenceType::REF_GPS:
+ ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_INTERNAL;
+ break;
+ }
+
+ /* FIXME: clock ref part of config, not open */
+ ipc_prim->u.open_req.clockref = FEATURE_MASK_CLOCKREF_EXTERNAL;
+
+ for (unsigned int i = 0; i < num_chans; i++) {
+ chan_info = &ipc_prim->u.open_req.chan_info[i];
+ OSMO_STRLCPY_ARRAY(chan_info->rx_path, rx_paths[i].c_str());
+ OSMO_STRLCPY_ARRAY(chan_info->tx_path, tx_paths[i].c_str());
+ }
return ipc_sock_send(state, msg);
}
@@ -206,18 +238,24 @@ static void ipc_sock_timeout(void *_priv)
int IPCDevice::ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf)
{
- if (greeting_cnf->req_version == IPC_SOCK_API_VERSION) {
- LOGC(DDEV, NOTICE) << "Rx Greeting CNF: correct sock API version" << greeting_cnf->req_version;
+ if (greeting_cnf->req_version == IPC_SOCK_API_VERSION) {
+ LOGC(DDEV, NOTICE) << "Rx Greeting CNF: correct sock API version" << greeting_cnf->req_version;
tmp_state = IPC_IF_MSG_GREETING_CNF;
- } else {
- LOGC(DDEV, ERROR) << "Wrong IPC SOCK API VERSION RECEIVED!" << greeting_cnf->req_version;
+ } else {
+ LOGC(DDEV, ERROR) << "Wrong IPC SOCK API VERSION RECEIVED!" << greeting_cnf->req_version;
exit(1);
}
- return 0;
+ return 0;
}
int IPCDevice::ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf)
{
+ current_info_cnf = *info_cnf;
+ unsigned int i;
+
+ if (info_cnf->max_num_chans < chans)
+ return -1;
+
/* Here:
* verify info_cnf->max_num_chans >= requested chans
* verify supports setting reflock as asked by user looking in info_cnf->feature_mask
@@ -225,48 +263,102 @@ int IPCDevice::ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf)
* do whatever validations or print info_cnf->dev_desc
* cache rx/tx paths per channel, and make sure it matches the one the user wants to set
*/
- unsigned int i;
+
LOGC(DDEV, NOTICE) << "Rx Info CNF:"
- << " max_num_chans=" << info_cnf->max_num_chans
- << " feature_mask=" << info_cnf->feature_mask
- << " min_rx_gain=" << info_cnf->min_rx_gain
- << " max_rx_gain=" << info_cnf->max_rx_gain;
+ << " name=" << info_cnf->dev_desc << std::endl
+ << " max_num_chans=" << info_cnf->max_num_chans << " feature_mask=" << info_cnf->feature_mask
+ << " min_rx_gain=" << info_cnf->min_rx_gain << " max_rx_gain=" << info_cnf->max_rx_gain
+ << " min_tx_gain=" << info_cnf->min_tx_gain << " max_tx_gain=" << info_cnf->max_tx_gain;
for (i = 0; i < info_cnf->max_num_chans; i++) {
int j = 0;
- while (strcmp(info_cnf->chan_info[i].rx_path[j],"")!=0) {
- LOGC(DDEV, NOTICE) << "chan " << i << ": RxPath[" << j <<"]: " << info_cnf->chan_info[i].rx_path[j];
+ bool rx_found = false, tx_found = false;
+ while (strcmp(info_cnf->chan_info[i].rx_path[j], "") != 0) {
+ LOGC(DDEV, NOTICE)
+ << "chan " << i << ": RxPath[" << j << "]: " << info_cnf->chan_info[i].rx_path[j];
+
+ if (rx_paths.size() < (i + 1) ||
+ strcmp(rx_paths[i].c_str(), info_cnf->chan_info[i].rx_path[j]) == 0) {
+ rx_found = true;
+ break;
+ }
j++;
}
j = 0;
- while (strcmp(info_cnf->chan_info[i].tx_path[j],"")!=0) {
- LOGC(DDEV, NOTICE) << "chan " << i << ": TxPath[" << j <<"]: " << info_cnf->chan_info[i].tx_path[j];
+ while (strcmp(info_cnf->chan_info[i].tx_path[j], "") != 0) {
+ LOGC(DDEV, NOTICE)
+ << "chan " << i << ": TxPath[" << j << "]: " << info_cnf->chan_info[i].tx_path[j];
+ if (tx_paths.size() < (i + 1) ||
+ strcmp(tx_paths[i].c_str(), info_cnf->chan_info[i].tx_path[j]) == 0) {
+ tx_found = true;
+ break;
+ }
j++;
}
+
+ if (!rx_found) {
+ LOGC(DDEV, ERROR) << "rx antenna not found: " << rx_paths[i];
+ exit(0);
+ }
+ if (!tx_found) {
+ LOGC(DDEV, ERROR) << "tx antenna not found: " << rx_paths[i];
+ exit(0);
+ }
}
- tmp_state = IPC_IF_MSG_INFO_CNF;
- return 0;
+ tmp_state = IPC_IF_MSG_INFO_CNF;
+ return 0;
}
int IPCDevice::ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf)
{
unsigned int i;
- LOGC(DDEV, NOTICE) << "Rx Open CNF:"
- << " return_code=" << (unsigned int)open_cnf->return_code
- << " shm_name=" << open_cnf->shm_name;
+ current_open_cnf = *open_cnf;
+
+ LOGC(DDEV, NOTICE)
+ << "Rx Open CNF:"
+ << " return_code=" << (unsigned int)open_cnf->return_code << " shm_name=" << open_cnf->shm_name;
for (i = 0; i < chans; i++) {
+ int rc;
LOGC(DDEV, NOTICE) << "chan " << i << ": sk_path=" << open_cnf->chan_info[i].chan_ipc_sk_path;
+
+ /* FIXME: current limit 8 chans, make dynamic */
+ if (i < 8) {
+ struct ipc_sock_state *state = &sk_chan_state[i];
+ memset(state, 0x00, sizeof(*state));
+
+ INIT_LLIST_HEAD(&state->upqueue);
+ rc = osmo_sock_unix_init_ofd(&state->conn_bfd, SOCK_SEQPACKET, 0,
+ open_cnf->chan_info[i].chan_ipc_sk_path, OSMO_SOCK_F_CONNECT);
+ if (rc < 0) {
+ LOGC(DDEV, ERROR) << "Failed to connect to the BTS ("
+ << open_cnf->chan_info[i].chan_ipc_sk_path << "). "
+ << "Retrying...\n";
+ osmo_timer_setup(&state->timer, ipc_sock_timeout, NULL);
+ osmo_timer_schedule(&state->timer, 5, 0);
+ return -1;
+ }
+ state->conn_bfd.cb = ipc_chan_sock_cb;
+ state->conn_bfd.data = this;
+ state->conn_bfd.priv_nr = i;
+ }
}
OSMO_STRLCPY_ARRAY(shm_name, open_cnf->shm_name);
if (ipc_shm_connect(shm_name) < 0)
return -1;
- shm_dec = ipc_shm_decode_region(NULL, (ipc_shm_raw_region*)shm);
+ shm_dec = ipc_shm_decode_region(NULL, (ipc_shm_raw_region *)shm);
LOGC(DDEV, NOTICE) << "shm: num_chans=" << shm_dec->num_chans;
LOGC(DDEV, NOTICE) << "shm: chan0/dl: num_buffers=" << shm_dec->channels[0]->dl_stream->num_buffers;
LOGC(DDEV, NOTICE) << "shm: chan0/dl: buffer_size=" << shm_dec->channels[0]->dl_stream->buffer_size;
- tmp_state = IPC_IF_MSG_OPEN_CNF;
- return 0;
+ /* server inits both producers */
+ for (unsigned int i = 0; i < shm_dec->num_chans; i++) {
+ shm_io_rx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->ul_stream));
+ shm_io_tx_streams.push_back(ipc_shm_init_consumer(shm_dec->channels[i]->dl_stream));
+ // shm_io_tx_streams.push_back(ipc_shm_init_producer(shm_dec->channels[i]->dl_stream));
+ }
+
+ tmp_state = IPC_IF_MSG_OPEN_CNF;
+ return 0;
}
int IPCDevice::ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
@@ -275,8 +367,8 @@ int IPCDevice::ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
switch (msg_type) {
case IPC_IF_MSG_GREETING_CNF:
- rc = ipc_rx_greeting_cnf(&ipc_prim->u.greeting_cnf);
- break;
+ rc = ipc_rx_greeting_cnf(&ipc_prim->u.greeting_cnf);
+ break;
case IPC_IF_MSG_INFO_CNF:
rc = ipc_rx_info_cnf(&ipc_prim->u.info_cnf);
break;
@@ -284,29 +376,87 @@ int IPCDevice::ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
rc = ipc_rx_open_cnf(&ipc_prim->u.open_cnf);
break;
default:
- LOGP(DDEV, LOGL_ERROR, "Received unknown PCU msg type %d\n",
- msg_type);
+ LOGP(DDEV, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
rc = -EINVAL;
}
return rc;
}
-static int ipc_sock_send(struct ipc_sock_state* state, struct msgb *msg)
+int IPCDevice::ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)
+{
+ tmp_state = IPC_IF_MSG_START_CNF;
+ return 0;
+}
+int IPCDevice::ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr)
+{
+ return 0;
+}
+int IPCDevice::ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr)
+{
+ return 0;
+}
+int IPCDevice::ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr)
+{
+ return 0;
+}
+int IPCDevice::ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)
+{
+ return 0;
+}
+int IPCDevice::ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr)
+{
+ return 0;
+}
+
+int IPCDevice::ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_t chan_nr)
+{
+ int rc = 0;
+
+ switch (msg_type) {
+ case IPC_IF_MSG_START_CNF:
+ rc = ipc_rx_chan_start_cnf(&ipc_prim->u.start_cnf, chan_nr);
+ break;
+ case IPC_IF_MSG_STOP_CNF:
+ rc = ipc_rx_chan_stop_cnf(&ipc_prim->u.stop_cnf, chan_nr);
+ break;
+ case IPC_IF_MSG_SETGAIN_CNF:
+ rc = ipc_rx_chan_setgain_cnf(&ipc_prim->u.set_gain_cnf, chan_nr);
+ break;
+ case IPC_IF_MSG_SETFREQ_CNF:
+ rc = ipc_rx_chan_setfreq_cnf(&ipc_prim->u.set_freq_cnf, chan_nr);
+ break;
+ case IPC_IF_NOTIFY_UNDERFLOW:
+ rc = ipc_rx_chan_notify_underflow(&ipc_prim->u.notify, chan_nr);
+ break;
+ case IPC_IF_NOTIFY_OVERFLOW:
+ rc = ipc_rx_chan_notify_overflow(&ipc_prim->u.notify, chan_nr);
+ break;
+ default:
+ LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int ipc_sock_send(struct ipc_sock_state *state, struct msgb *msg)
{
struct osmo_fd *conn_bfd;
//struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;
if (!state) {
- LOGP(DMAIN, LOGL_INFO, "PCU socket not created, "
- "dropping message\n");
+ LOGP(DMAIN, LOGL_INFO,
+ "IPC socket not created, "
+ "dropping message\n");
msgb_free(msg);
return -EINVAL;
}
conn_bfd = &state->conn_bfd;
if (conn_bfd->fd <= 0) {
- LOGP(DMAIN, LOGL_NOTICE, "PCU socket not connected, "
- "dropping message\n");
+ LOGP(DMAIN, LOGL_NOTICE,
+ "IPC socket not connected, "
+ "dropping message\n");
msgb_free(msg);
return -EIO;
}
@@ -316,19 +466,25 @@ static int ipc_sock_send(struct ipc_sock_state* state, struct msgb *msg)
return 0;
}
-void IPCDevice::ipc_sock_close()
+void IPCDevice::ipc_sock_close(struct ipc_sock_state *state)
{
- struct osmo_fd *bfd = &sk_state.conn_bfd;
+ if (state == 0)
+ return;
+
+ struct osmo_fd *bfd = &state->conn_bfd;
+
+ if (bfd->fd <= 0)
+ return;
- LOGP(DDEV, LOGL_NOTICE, "PCU socket has LOST connection\n");
+ LOGP(DDEV, LOGL_NOTICE, "IPC socket has LOST connection\n");
close(bfd->fd);
bfd->fd = -1;
osmo_fd_unregister(bfd);
/* flush the queue */
- while (!llist_empty(&sk_state.upqueue)) {
- struct msgb *msg = msgb_dequeue(&sk_state.upqueue);
+ while (!llist_empty(&state->upqueue)) {
+ struct msgb *msg = msgb_dequeue(&state->upqueue);
msgb_free(msg);
}
}
@@ -343,7 +499,7 @@ int IPCDevice::ipc_sock_read(struct osmo_fd *bfd)
if (!msg)
return -ENOMEM;
- ipc_prim = (struct ipc_sk_if *) msg->tail;
+ ipc_prim = (struct ipc_sk_if *)msg->tail;
rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
if (rc == 0)
@@ -358,15 +514,64 @@ int IPCDevice::ipc_sock_read(struct osmo_fd *bfd)
}
if ((size_t)rc < sizeof(*ipc_prim)) {
- LOGP(DDEV, LOGL_ERROR, "Received %d bytes on Unix Socket, but primitive size "
- "is %zu, discarding\n", rc, sizeof(*ipc_prim));
+ LOGP(DDEV, LOGL_ERROR,
+ "Received %d bytes on Unix Socket, but primitive size "
+ "is %zu, discarding\n",
+ rc, sizeof(*ipc_prim));
msgb_free(msg);
return 0;
}
rc = ipc_rx(ipc_prim->msg_type, ipc_prim);
- /* as we always synchronously process the message in pcu_rx() and
+ /* as we always synchronously process the message in IPC_rx() and
+ * its callbacks, we can free the message here. */
+ msgb_free(msg);
+
+ return rc;
+
+close:
+ msgb_free(msg);
+ ipc_sock_close(&sk_state);
+ return -1;
+}
+
+int IPCDevice::ipc_chan_sock_read(struct osmo_fd *bfd)
+{
+ struct ipc_sk_chan_if *ipc_prim;
+ struct msgb *msg;
+ int rc;
+
+ msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_chan_sock_rx");
+ if (!msg)
+ return -ENOMEM;
+
+ ipc_prim = (struct ipc_sk_chan_if *)msg->tail;
+
+ rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
+ if (rc == 0)
+ goto close;
+
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ msgb_free(msg);
+ return 0;
+ }
+ goto close;
+ }
+
+ if ((size_t)rc < sizeof(*ipc_prim)) {
+ LOGP(DDEV, LOGL_ERROR,
+ "Received %d bytes on Unix Socket, but primitive size "
+ "is %zu, discarding\n",
+ rc, sizeof(*ipc_prim));
+ msgb_free(msg);
+ return 0;
+ }
+
+ rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);
+
+ /* as we always synchronously process the message in IPC_rx() and
* its callbacks, we can free the message here. */
msgb_free(msg);
@@ -374,7 +579,7 @@ int IPCDevice::ipc_sock_read(struct osmo_fd *bfd)
close:
msgb_free(msg);
- ipc_sock_close();
+ ipc_sock_close(&sk_chan_state[bfd->priv_nr]);
return -1;
}
@@ -394,8 +599,10 @@ int IPCDevice::ipc_sock_write(struct osmo_fd *bfd)
/* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
if (!msgb_length(msg)) {
- LOGP(DDEV, LOGL_ERROR, "message type (%d) with ZERO "
- "bytes!\n", ipc_prim->msg_type);
+ LOGP(DDEV, LOGL_ERROR,
+ "message type (%d) with ZERO "
+ "bytes!\n",
+ ipc_prim->msg_type);
goto dontsend;
}
@@ -411,7 +618,7 @@ int IPCDevice::ipc_sock_write(struct osmo_fd *bfd)
goto close;
}
-dontsend:
+ dontsend:
/* _after_ we send it, we can deueue */
msg2 = msgb_dequeue(&sk_state.upqueue);
assert(msg == msg2);
@@ -420,13 +627,59 @@ dontsend:
return 0;
close:
- ipc_sock_close();
+ ipc_sock_close(&sk_state);
+ return -1;
+}
+
+int IPCDevice::ipc_chan_sock_write(struct osmo_fd *bfd)
+{
+ int rc;
+
+ while (!llist_empty(&sk_chan_state[bfd->priv_nr].upqueue)) {
+ struct msgb *msg, *msg2;
+ struct ipc_sk_chan_if *ipc_prim;
+
+ /* peek at the beginning of the queue */
+ msg = llist_entry(sk_chan_state[bfd->priv_nr].upqueue.next, struct msgb, list);
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ bfd->when &= ~BSC_FD_WRITE;
+ /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
+ if (!msgb_length(msg)) {
+ LOGP(DDEV, LOGL_ERROR,
+ "message type (%d) with ZERO "
+ "bytes!\n",
+ ipc_prim->msg_type);
+ goto dontsend;
+ }
+
+ /* try to send it over the socket */
+ rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
+ if (rc == 0)
+ goto close;
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ bfd->when |= BSC_FD_WRITE;
+ break;
+ }
+ goto close;
+ }
+
+ dontsend:
+ /* _after_ we send it, we can deueue */
+ msg2 = msgb_dequeue(&sk_chan_state[bfd->priv_nr].upqueue);
+ assert(msg == msg2);
+ msgb_free(msg);
+ }
+ return 0;
+
+close:
+ ipc_sock_close(&sk_chan_state[bfd->priv_nr]);
return -1;
}
static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
{
- IPCDevice *device = (IPCDevice *)bfd->data;
+ IPCDevice *device = static_cast<IPCDevice *>(bfd->data);
int rc = 0;
if (flags & BSC_FD_READ)
@@ -440,6 +693,22 @@ static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
return rc;
}
+static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
+{
+ IPCDevice *device = static_cast<IPCDevice *>(bfd->data);
+ int rc = 0;
+
+ if (flags & BSC_FD_READ)
+ rc = device->ipc_chan_sock_read(bfd);
+ if (rc < 0)
+ return rc;
+
+ if (flags & BSC_FD_WRITE)
+ rc = device->ipc_chan_sock_write(bfd);
+
+ return rc;
+}
+
int IPCDevice::open(const std::string &args, int ref, bool swap_channels)
{
//float_type sr_host, sr_rf;
@@ -451,11 +720,10 @@ int IPCDevice::open(const std::string &args, int ref, bool swap_channels)
memset(&sk_state, 0x00, sizeof(sk_state));
INIT_LLIST_HEAD(&sk_state.upqueue);
- rc = osmo_sock_unix_init_ofd(&sk_state.conn_bfd, SOCK_SEQPACKET, 0,
- IPC_SOCK_PATH, OSMO_SOCK_F_CONNECT);
+ rc = osmo_sock_unix_init_ofd(&sk_state.conn_bfd, SOCK_SEQPACKET, 0, IPC_SOCK_PATH, OSMO_SOCK_F_CONNECT);
if (rc < 0) {
- LOGC(DDEV, ERROR) << "Failed to connect to the BTS (" << IPC_SOCK_PATH << "). " <<
- "Retrying...\n";
+ LOGC(DDEV, ERROR) << "Failed to connect to the BTS (" << IPC_SOCK_PATH << "). "
+ << "Retrying...\n";
osmo_timer_setup(&sk_state.timer, ipc_sock_timeout, NULL);
osmo_timer_schedule(&sk_state.timer, 5, 0);
return -1;
@@ -465,17 +733,17 @@ int IPCDevice::open(const std::string &args, int ref, bool swap_channels)
ipc_tx_greeting_req(&sk_state, IPC_SOCK_API_VERSION);
/* Wait until confirmation is recieved */
- while(tmp_state != IPC_IF_MSG_GREETING_CNF)
+ while (tmp_state != IPC_IF_MSG_GREETING_CNF)
osmo_select_main(0);
ipc_tx_info_req(&sk_state);
/* Wait until confirmation is recieved */
- while(tmp_state != IPC_IF_MSG_INFO_CNF)
+ while (tmp_state != IPC_IF_MSG_INFO_CNF)
osmo_select_main(0);
- ipc_tx_open_req(&sk_state, chans);
+ ipc_tx_open_req(&sk_state, chans, ref);
/* Wait until confirmation is recieved */
- while(tmp_state != IPC_IF_MSG_OPEN_CNF)
+ while (tmp_state != IPC_IF_MSG_OPEN_CNF)
osmo_select_main(0);
LOGC(DDEV, NOTICE) << "Device driver opened successfuly!";
@@ -496,35 +764,23 @@ bool IPCDevice::start()
{
LOGC(DDEV, INFO) << "starting IPC...";
- unsigned int i;
-
if (started) {
LOGC(DDEV, ERR) << "Device already started";
- return false;
+ return true;
}
- /* configure the channels/streams */
- for (i=0; i<chans; i++) {
- /* Set gains for calibration/filter setup */
- /* TX gain to maximum */
- setTxGain(maxTxGain(), i);
- /* RX gain to midpoint */
- setRxGain((minRxGain() + maxRxGain()) / 2, i);
-
- /* set up Rx and Tx filters */
- if (!do_filters(i))
- return false;
- /* Perform Rx and Tx calibration */
- if (!do_calib(i))
- return false;
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
- /* configure Streams */
- }
+ msg = ipc_msgb_alloc(IPC_IF_MSG_START_REQ);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.start_req.dummy = 0;
- /* now start the streams in a second loop, as we can no longer call
- * IPC_SetupStream() after IPC_StartStream() of the first stream */
- //for (i = 0; i < chans; i++) {
- //}
+ ipc_sock_send(&sk_chan_state[0], msg);
+ while (tmp_state != IPC_IF_MSG_START_CNF)
+ osmo_select_main(0);
flush_recv(10);
@@ -539,16 +795,16 @@ bool IPCDevice::stop()
if (!started)
return true;
- /*
- for (i=0; i<chans; i++) {
- IPC_StopStream(&m_IPC_stream_tx[i]);
- IPC_StopStream(&m_IPC_stream_rx[i]);
- }
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
- for (i=0; i<chans; i++) {
- IPC_DestroyStream(m_IPC_dev, &m_IPC_stream_tx[i]);
- IPC_DestroyStream(m_IPC_dev, &m_IPC_stream_rx[i]);
- }*/
+ msg = ipc_msgb_alloc(IPC_IF_MSG_STOP_REQ);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.start_req.dummy = 0;
+
+ ipc_sock_send(&sk_chan_state[0], msg);
started = false;
return true;
@@ -568,26 +824,25 @@ bool IPCDevice::do_filters(size_t chan)
return true;
}
-
double IPCDevice::maxTxGain()
{
//return dev_param_map.at(m_dev_type).max_tx_gain;
- return 70.0;
+ return current_info_cnf.max_tx_gain;
}
double IPCDevice::minTxGain()
{
- return 0.0;
+ return current_info_cnf.min_tx_gain;
}
double IPCDevice::maxRxGain()
{
- return 73.0;
+ return current_info_cnf.max_rx_gain;
}
double IPCDevice::minRxGain()
{
- return 0.0;
+ return current_info_cnf.min_rx_gain;
}
double IPCDevice::setTxGain(double dB, size_t chan)
@@ -602,7 +857,7 @@ double IPCDevice::setTxGain(double dB, size_t chan)
//if (IPC_SetGaindB(m_IPC_dev, IPC_CH_TX, chan, dB) < 0)
// LOGCHAN(chan, DDEV, ERR) << "Error setting TX gain to " << dB << " dB";
//else
- tx_gains[chan] = dB;
+ tx_gains[chan] = dB;
return tx_gains[chan];
}
@@ -618,50 +873,27 @@ double IPCDevice::setRxGain(double dB, size_t chan)
//if (IPC_SetGaindB(m_IPC_dev, IPC_CH_RX, chan, dB) < 0)
// LOGCHAN(chan, DDEV, ERR) << "Error setting RX gain to " << dB << " dB";
//else
- rx_gains[chan] = dB;
+ rx_gains[chan] = dB;
return rx_gains[chan];
}
-
-void IPCDevice::log_ant_list(bool dir_tx, size_t chan, std::ostringstream& os)
-{
- int num_names = 0;
- int i;
- for (i = 0; i < num_names; i++) {
- if (i)
- os << ", ";
- os << "''";
- }
-}
-
bool IPCDevice::flush_recv(size_t num_pkts)
-{/*
- #define CHUNK 625
- int len = CHUNK * tx_sps;
- short *buffer = (short*) alloca(sizeof(short) * len * 2);
- int rc;
- IPC_stream_meta_t rx_metadata = {};
- rx_metadata.flushPartialPacket = false;
- rx_metadata.waitForTimestamp = false;
-
- ts_initial = 0;
-
- while (!ts_initial || (num_pkts-- > 0)) {
- rc = IPC_RecvStream(&m_IPC_stream_rx[0], &buffer[0], len, &rx_metadata, 100);
- LOGC(DDEV, DEBUG) << "Flush: Recv buffer of len " << rc << " at " << std::hex << rx_metadata.timestamp;
- if (rc != len) {
- LOGC(DDEV, ERROR) << "Flush: Device receive timed out";
- return false;
- }
+{
+ std::vector<uint16_t> tmp(4096);
+ uint64_t tmps;
+ uint32_t read;
- ts_initial = rx_metadata.timestamp + len;
+ for (uint32_t j = 0; j < num_pkts; j++) {
+ for (unsigned int i = 0; i < chans; i++)
+ read = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)&tmp.front(), 4096 / 2, &tmps, 1);
}
-*/
+ ts_initial = tmps + read;
+ return ts_initial;
LOGC(DDEV, INFO) << "Initial timestamp " << ts_initial << std::endl;
return true;
}
-bool IPCDevice::setRxAntenna(const std::string & ant, size_t chan)
+bool IPCDevice::setRxAntenna(const std::string &ant, size_t chan)
{
return true;
}
@@ -669,10 +901,9 @@ bool IPCDevice::setRxAntenna(const std::string & ant, size_t chan)
std::string IPCDevice::getRxAntenna(size_t chan)
{
return "";
-
}
-bool IPCDevice::setTxAntenna(const std::string & ant, size_t chan)
+bool IPCDevice::setTxAntenna(const std::string &ant, size_t chan)
{
return true;
}
@@ -687,22 +918,127 @@ bool IPCDevice::requiresRadioAlign()
return false;
}
-GSM::Time IPCDevice::minLatency() {
+GSM::Time IPCDevice::minLatency()
+{
/* UNUSED */
- return GSM::Time(0,0);
+ return GSM::Time(0, 0);
+}
+
+/** Returns the starting write Timestamp*/
+TIMESTAMP IPCDevice::initialWriteTimestamp(void)
+{
+ return ts_initial;
+}
+
+/** Returns the starting read Timestamp*/
+TIMESTAMP IPCDevice::initialReadTimestamp(void)
+{
+ return ts_initial;
}
// NOTE: Assumes sequential reads
-int IPCDevice::readSamples(std::vector < short *>&bufs, int len, bool * overrun,
- TIMESTAMP timestamp, bool * underrun)
+int IPCDevice::readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun)
{
+ int rc, num_smpls, expect_smpls;
+ ssize_t avail_smpls;
+ TIMESTAMP expect_timestamp;
+ unsigned int i;
+
+ if (bufs.size() != chans) {
+ LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
+ return -1;
+ }
+
+ *overrun = false;
+ *underrun = false;
+
+ timestamp += current_open_cnf.path_delay;
+
+ /* Check that timestamp is valid */
+ rc = rx_buffers[0]->avail_smpls(timestamp);
+ if (rc < 0) {
+ LOGC(DDEV, ERROR) << rx_buffers[0]->str_code(rc);
+ LOGC(DDEV, ERROR) << rx_buffers[0]->str_status(timestamp);
+ return 0;
+ }
+
+ for (i = 0; i < chans; i++) {
+ /* Receive samples from HW until we have enough */
+ while ((avail_smpls = rx_buffers[i]->avail_smpls(timestamp)) < len) {
+ uint64_t recv_timestamp = 0;
+
+ thread_enable_cancel(false);
+
+ num_smpls = ipc_shm_read(shm_io_rx_streams[i], (uint16_t *)bufs[i], len - avail_smpls,
+ &recv_timestamp, 1);
+ expect_timestamp = timestamp + avail_smpls;
+ thread_enable_cancel(true);
+
+ LOGCHAN(i, DDEV, DEBUG)
+ "Received timestamp = " << (TIMESTAMP)recv_timestamp << " (" << num_smpls << ")";
+
+ expect_smpls = len - avail_smpls;
+ // if (expect_smpls != num_smpls)
+ // LOGCHAN(i, DDEV, NOTICE)
+ // << "Unexpected recv buffer len: expect " << expect_smpls << " got " << num_smpls
+ // << ", diff=" << expect_smpls - num_smpls;
+
+ //expect_timestamp = timestamp + avail_smpls;
+ if (expect_timestamp != (TIMESTAMP)recv_timestamp)
+ LOGCHAN(i, DDEV, ERROR)
+ << "Unexpected recv buffer timestamp: expect " << expect_timestamp << " got "
+ << recv_timestamp << ", diff=" << recv_timestamp - expect_timestamp;
+
+ rc = rx_buffers[i]->write(bufs[i], num_smpls, (TIMESTAMP)recv_timestamp);
+ if (rc < 0) {
+ LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc);
+ LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
+ if (rc != smpl_buf::ERROR_OVERFLOW)
+ return 0;
+ }
+ }
+ }
+
+ /* We have enough samples */
+ for (size_t i = 0; i < rx_buffers.size(); i++) {
+ rc = rx_buffers[i]->read(bufs[i], len, timestamp);
+ if ((rc < 0) || (rc != len)) {
+ LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "
+ << rx_buffers[i]->str_status(timestamp) << ", (len=" << len << ")";
+ return 0;
+ }
+ }
+
return len;
}
-int IPCDevice::writeSamples(std::vector < short *>&bufs, int len,
- bool * underrun, unsigned long long timestamp)
+int IPCDevice::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, unsigned long long timestamp)
{
- return len;
+ int rc = 0;
+ unsigned int i;
+
+ if (bufs.size() != chans) {
+ LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
+ return -1;
+ }
+
+ *underrun = false;
+
+ for (i = 0; i < chans; i++) {
+ LOGCHAN(i, DDEV, DEBUG) << "send buffer of len " << len << " timestamp " << std::hex << timestamp;
+ // thread_enable_cancel(false);
+ rc = ipc_shm_enqueue(shm_io_tx_streams[i], timestamp, len, (uint16_t *)bufs[i]);
+
+ // rc = LMS_SendStream(&m_lms_stream_tx[i], bufs[i], len, &tx_metadata, 100);
+ // update_stream_stats_tx(i, underrun);
+ // thread_enable_cancel(true);
+ if (rc != len) {
+ LOGCHAN(i, DDEV, ERROR) << "LMS: Device Tx timed out (" << rc << " vs exp " << len << ").";
+ return -1;
+ }
+ }
+
+ return rc;
}
bool IPCDevice::updateAlignment(TIMESTAMP timestamp)
@@ -712,16 +1048,32 @@ bool IPCDevice::updateAlignment(TIMESTAMP timestamp)
bool IPCDevice::setTxFreq(double wFreq, size_t chan)
{
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
LOGCHAN(chan, DDEV, NOTICE) << "Setting Tx Freq to " << wFreq << " Hz";
- return true;
+ msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_REQ);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.set_freq_req.is_tx = 1;
+ ipc_prim->u.set_freq_req.freq = wFreq;
+
+ return ipc_sock_send(&sk_chan_state[chan], msg) < 0 ? false : true;
}
bool IPCDevice::setRxFreq(double wFreq, size_t chan)
{
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
LOGCHAN(chan, DDEV, NOTICE) << "Setting Rx Freq to " << wFreq << " Hz";
- return true;
-}
-
+ msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_REQ);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.set_freq_req.is_tx = 0;
+ ipc_prim->u.set_freq_req.freq = wFreq;
+ return ipc_sock_send(&sk_chan_state[chan], msg) < 0 ? false : true;
+}
diff --git a/Transceiver52M/device/ipc/IPCDevice.h b/Transceiver52M/device/ipc/IPCDevice.h
index c7a2a1b..335ed10 100644
--- a/Transceiver52M/device/ipc/IPCDevice.h
+++ b/Transceiver52M/device/ipc/IPCDevice.h
@@ -27,6 +27,7 @@ extern "C" {
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include "shm.h"
+#include "ipc_shm.h"
}
#include "radioDevice.h"
@@ -40,17 +41,17 @@ extern "C" {
#include <lime/LimeSuite.h>
struct ipc_sock_state {
- struct osmo_fd conn_bfd; /* fd for connection to the BTS */
- struct osmo_timer_list timer; /* socket connect retry timer */
- struct llist_head upqueue; /* queue for sending messages */
+ struct osmo_fd conn_bfd; /* fd for connection to the BTS */
+ struct osmo_timer_list timer; /* socket connect retry timer */
+ struct llist_head upqueue; /* queue for sending messages */
};
-
/** A class to handle a LimeSuite supported device */
-class IPCDevice:public RadioDevice {
-
-private:
+class IPCDevice : public RadioDevice {
+ protected:
struct ipc_sock_state sk_state;
+ /* FIXME: current limit 8 chans, make dynamic */
+ struct ipc_sock_state sk_chan_state[8];
uint8_t tmp_state;
char shm_name[SHM_NAME_MAX];
int ipc_shm_connect(const char *shm_name);
@@ -58,49 +59,56 @@ private:
struct ipc_shm_region *shm_dec;
std::vector<smpl_buf *> rx_buffers;
- double actualSampleRate; ///< the actual USRP sampling rate
+ double actualSampleRate; ///< the actual USRP sampling rate
- bool started; ///< flag indicates LMS has started
- bool skipRx; ///< set if LMS is transmit-only.
+ bool started; ///< flag indicates LMS has started
+ bool skipRx; ///< set if LMS is transmit-only.
TIMESTAMP ts_initial, ts_offset;
std::vector<double> tx_gains, rx_gains;
+ struct ipc_sk_if_info_req current_info_req;
+ struct ipc_sk_if_info_cnf current_info_cnf;
+ struct ipc_sk_if_open_cnf current_open_cnf;
+
+ std::vector<struct ipc_shm_io *> shm_io_rx_streams;
+ std::vector<struct ipc_shm_io *> shm_io_tx_streams;
+
bool do_calib(size_t chan);
bool do_filters(size_t chan);
- void log_ant_list(bool dir_tx, size_t chan, std::ostringstream& os);
- int get_ant_idx(const std::string & name, bool dir_tx, size_t chan);
- bool flush_recv(size_t num_pkts);
+ int get_ant_idx(const std::string &name, bool dir_tx, size_t chan);
+ virtual bool flush_recv(size_t num_pkts);
void update_stream_stats_rx(size_t chan, bool *overrun);
void update_stream_stats_tx(size_t chan, bool *underrun);
bool do_clock_src_freq(enum ReferenceType ref, double freq);
-public:
- virtual void ipc_sock_close();
+ public:
+ virtual void ipc_sock_close(ipc_sock_state *state);
virtual int ipc_sock_read(struct osmo_fd *bfd);
virtual int ipc_sock_write(struct osmo_fd *bfd);
virtual int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim);
virtual int ipc_rx_greeting_cnf(const struct ipc_sk_if_greeting *greeting_cnf);
virtual int ipc_rx_info_cnf(const struct ipc_sk_if_info_cnf *info_cnf);
virtual int ipc_rx_open_cnf(const struct ipc_sk_if_open_cnf *open_cnf);
+ virtual int ipc_tx_open_req(struct ipc_sock_state *state, uint32_t num_chans, uint32_t ref);
/** Object constructor */
IPCDevice(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chan_num, double lo_offset,
- const std::vector<std::string>& tx_paths,
- const std::vector<std::string>& rx_paths);
- virtual ~IPCDevice();
+ const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths);
+ virtual ~IPCDevice() override;
/** Instantiate the LMS */
- virtual int open(const std::string &args, int ref, bool swap_channels);
+ virtual int open(const std::string &args, int ref, bool swap_channels) override;
/** Start the LMS */
- virtual bool start();
+ virtual bool start() override;
/** Stop the LMS */
- virtual bool stop();
+ virtual bool stop() override;
- enum TxWindowType getWindowType() {
+ enum TxWindowType getWindowType() override
+ {
return TX_WINDOW_LMS1;
}
@@ -113,9 +121,8 @@ public:
@param underrun Set if LMS does not have data to transmit, e.g. data not being sent fast enough
@return The number of samples actually read
*/
- virtual int readSamples(std::vector < short *>&buf, int len, bool * overrun,
- TIMESTAMP timestamp = 0xffffffff, bool * underrun =
- NULL);
+ virtual int readSamples(std::vector<short *> &buf, int len, bool *overrun, TIMESTAMP timestamp = 0xffffffff,
+ bool *underrun = NULL) override;
/**
Write samples to the LMS.
@param buf Contains the data to be written.
@@ -124,95 +131,106 @@ public:
@param timestamp The timestamp of the first sample of the data buffer.
@return The number of samples actually written
*/
- virtual int writeSamples(std::vector < short *>&bufs, int len, bool * underrun,
- TIMESTAMP timestamp = 0xffffffff);
+ virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
+ TIMESTAMP timestamp = 0xffffffff) override;
/** Update the alignment between the read and write timestamps */
- virtual bool updateAlignment(TIMESTAMP timestamp);
+ virtual bool updateAlignment(TIMESTAMP timestamp) override;
/** Set the transmitter frequency */
- virtual bool setTxFreq(double wFreq, size_t chan = 0);
+ virtual bool setTxFreq(double wFreq, size_t chan = 0) override;
/** Set the receiver frequency */
- virtual bool setRxFreq(double wFreq, size_t chan = 0);
+ virtual bool setRxFreq(double wFreq, size_t chan = 0) override;
/** Returns the starting write Timestamp*/
- virtual TIMESTAMP initialWriteTimestamp(void) {
- return ts_initial;
- }
+ virtual TIMESTAMP initialWriteTimestamp(void) override;
/** Returns the starting read Timestamp*/
- virtual TIMESTAMP initialReadTimestamp(void) {
- return ts_initial;
- }
+ virtual TIMESTAMP initialReadTimestamp(void) override;
/** returns the full-scale transmit amplitude **/
- virtual double fullScaleInputValue() {
- #define LIMESDR_TX_AMPL 0.3
- return(double) SHRT_MAX * LIMESDR_TX_AMPL;
+ virtual double fullScaleInputValue() override
+ {
+ return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_rx;
}
/** returns the full-scale receive amplitude **/
- virtual double fullScaleOutputValue() {
- return (double) SHRT_MAX;
+ virtual double fullScaleOutputValue() override
+ {
+ return (double)SHRT_MAX * current_info_cnf.iq_scaling_val_tx;
}
/** sets the receive chan gain, returns the gain setting **/
- virtual double setRxGain(double dB, size_t chan = 0);
+ virtual double setRxGain(double dB, size_t chan = 0) override;
/** get the current receive gain */
- virtual double getRxGain(size_t chan = 0) {
+ virtual double getRxGain(size_t chan = 0) override
+ {
return rx_gains[chan];
}
/** return maximum Rx Gain **/
- virtual double maxRxGain(void);
+ virtual double maxRxGain(void) override;
/** return minimum Rx Gain **/
- virtual double minRxGain(void);
+ virtual double minRxGain(void) override;
/** sets the transmit chan gain, returns the gain setting **/
- virtual double setTxGain(double dB, size_t chan = 0);
+ virtual double setTxGain(double dB, size_t chan = 0) override;
/** get transmit gain */
- virtual double getTxGain(size_t chan = 0) {
+ virtual double getTxGain(size_t chan = 0) override
+ {
return tx_gains[chan];
}
/** return maximum Tx Gain **/
- virtual double maxTxGain(void);
+ virtual double maxTxGain(void) override;
/** return minimum Rx Gain **/
- virtual double minTxGain(void);
+ virtual double minTxGain(void) override;
/** sets the RX path to use, returns true if successful and false otherwise */
- virtual bool setRxAntenna(const std::string & ant, size_t chan = 0);
+ virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) override;
/* return the used RX path */
- virtual std::string getRxAntenna(size_t chan = 0);
+ virtual std::string getRxAntenna(size_t chan = 0) override;
/** sets the RX path to use, returns true if successful and false otherwise */
- virtual bool setTxAntenna(const std::string & ant, size_t chan = 0);
+ virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) override;
/* return the used RX path */
- virtual std::string getTxAntenna(size_t chan = 0);
+ virtual std::string getTxAntenna(size_t chan = 0) override;
/** return whether user drives synchronization of Tx/Rx of USRP */
- virtual bool requiresRadioAlign();
+ virtual bool requiresRadioAlign() override;
- /** return whether user drives synchronization of Tx/Rx of USRP */
- virtual GSM::Time minLatency();
+ /** return whether user drives synchronization of Tx/Rx of USRP */
+ virtual GSM::Time minLatency() override;
/** Return internal status values */
- virtual inline double getTxFreq(size_t chan = 0) {
+ virtual inline double getTxFreq(size_t chan = 0) override
+ {
return 0;
}
- virtual inline double getRxFreq(size_t chan = 0) {
+ virtual inline double getRxFreq(size_t chan = 0) override
+ {
return 0;
}
- virtual inline double getSampleRate() {
+ virtual inline double getSampleRate() override
+ {
return actualSampleRate;
}
+ int ipc_chan_sock_read(osmo_fd *bfd);
+ int ipc_chan_sock_write(osmo_fd *bfd);
+ int ipc_chan_rx(uint8_t msg_type, ipc_sk_chan_if *ipc_prim, uint8_t chan_nr);
+ int ipc_rx_chan_start_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);
+ int ipc_rx_chan_stop_cnf(ipc_sk_chan_if_op_rc *ret, uint8_t chan_nr);
+ int ipc_rx_chan_setgain_cnf(ipc_sk_chan_if_gain *ret, uint8_t chan_nr);
+ int ipc_rx_chan_setfreq_cnf(ipc_sk_chan_if_freq_cnf *ret, uint8_t chan_nr);
+ int ipc_rx_chan_notify_underflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);
+ int ipc_rx_chan_notify_overflow(ipc_sk_chan_if_notfiy *ret, uint8_t chan_nr);
};
#endif // _IPC_DEVICE_H_
diff --git a/Transceiver52M/device/ipc/Makefile.am b/Transceiver52M/device/ipc/Makefile.am
index 40146f7..20c8ec3 100644
--- a/Transceiver52M/device/ipc/Makefile.am
+++ b/Transceiver52M/device/ipc/Makefile.am
@@ -5,21 +5,25 @@ AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_C
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
AM_LDFLAGS = -lpthread -lrt
-noinst_HEADERS = IPCDevice.h shm.h ipcb210.h magicwrap.h
+noinst_HEADERS = IPCDevice.h shm.h ipcb210.h ../uhd/UHDDevice.h uhdwrap.h
noinst_LTLIBRARIES = libdevice.la
-libdevice_la_SOURCES = ipcb210.cpp IPCDevice.cpp shm.c magicwrap.cpp
+libdevice_la_SOURCES = ipc-driver-test.c ipcb210.cpp IPCDevice.cpp shm.c ../uhd/UHDDevice.cpp uhdwrap.cpp ipc_shm.c ipc_chan.c ipc_sock.c
libdevice_la_LIBADD = $(top_builddir)/Transceiver52M/device/common/libdevice_common.la
-
+libdevice_la_CXXFLAGS = $(AM_CXXFLAGS) $(UHD_CFLAGS) -DIPCMAGIC
bin_PROGRAMS = ipc-driver-test
-ipc_driver_test_SOURCES = ipc-driver-test.c
+#ipc_driver_test_SHORTNAME = drvt
+ipc_driver_test_SOURCES = ipc-driver-test.c uhdwrap.cpp ipc_shm.c ipc_chan.c ipc_sock.c ../uhd/UHDDevice.cpp
ipc_driver_test_LDADD = \
shm.lo \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOVTY_LIBS)
-ipc_driver_test_CPPFLAGS = $(AM_CPPFLAGS)
-ipc_driver_test_CFLAGS = $(AM_CFLAGS)
-ipc_driver_test_LDFLAGS = $(AM_LDFLAGS)
+ipc_driver_test_CXXFLAGS = $(AM_CXXFLAGS) $(UHD_CFLAGS)
+ipc_driver_test_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
+ipc_driver_test_CFLAGS = $(AM_CFLAGS) $(UHD_CFLAGS)
+ipc_driver_test_LDFLAGS = $(AM_LDFLAGS) $(UHD_LIBS)
+ipc_driver_test_LDADD += $(top_builddir)/Transceiver52M/device/common/libdevice_common.la $(top_builddir)/CommonLibs/libcommon.la
+
diff --git a/Transceiver52M/device/ipc/ipc-driver-test.c b/Transceiver52M/device/ipc/ipc-driver-test.c
index 58f5c58..32215cd 100644
--- a/Transceiver52M/device/ipc/ipc-driver-test.c
+++ b/Transceiver52M/device/ipc/ipc-driver-test.c
@@ -18,6 +18,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _GNU_SOURCE
+#include <pthread.h>
+
+
+#include <debug.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -28,8 +38,9 @@
#include <sys/un.h>
#include <inttypes.h>
#include <sys/mman.h>
-#include <sys/stat.h> /* For mode constants */
-#include <fcntl.h> /* For O_* constants */
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
@@ -42,25 +53,28 @@
#include <osmocom/core/timer.h>
#include "shm.h"
+#include "ipc_shm.h"
+#include "ipc_chan.h"
+#include "ipc_sock.h"
#define DEFAULT_SHM_NAME "/osmo-trx-ipc-driver-shm2"
-struct ipc_sock_state {
- struct osmo_fd listen_bfd; /* fd for listen socket */
- struct osmo_fd conn_bfd; /* fd for connection to lcr */
- struct llist_head upqueue; /* queue for sending messages */
-};
-
static void *tall_ctx;
-static struct ipc_sock_state *global_ipc_sock_state;
+struct ipc_sock_state *global_ipc_sock_state;
+
+/* 8 channels are plenty */
+struct ipc_sock_state *global_ctrl_socks[8];
+struct ipc_shm_io *ios_tx_to_device[8];
+struct ipc_shm_io *ios_rx_from_device[8];
void *shm;
+void *global_dev;
+static struct ipc_shm_region *decoded_region;
/* Debug Areas of the code */
-enum {
- DMAIN,
-};
+//enum { DMAIN,
+//};
static const struct log_info_cat default_categories[] = {
[DMAIN] = {
.name = "DMAIN",
@@ -70,49 +84,55 @@ static const struct log_info_cat default_categories[] = {
},
};
-const struct log_info log_info = {
+const struct log_info log_infox = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
+#ifdef __cplusplus
+}
+#endif
+
+#include "uhdwrap.h"
+
+volatile int ipc_exit_requested = 0;
+
+static int ipc_shm_setup(const char *shm_name, size_t shm_len)
+{
+ int fd;
+ int rc;
+
+ LOGP(DMAIN, LOGL_NOTICE, "Opening shm path %s\n", shm_name);
+ if ((fd = shm_open(shm_name, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
+ LOGP(DMAIN, LOGL_ERROR, "shm_open %d: %s\n", errno, strerror(errno));
+ rc = -errno;
+ goto err_shm_open;
+ }
+
+ LOGP(DMAIN, LOGL_NOTICE, "Truncating %d to size %zu\n", fd, shm_len);
+ if (ftruncate(fd, shm_len) < 0) {
+ LOGP(DMAIN, LOGL_ERROR, "ftruncate %d: %s\n", errno, strerror(errno));
+ rc = -errno;
+ goto err_mmap;
+ }
+
+ LOGP(DMAIN, LOGL_NOTICE, "mmaping shared memory fd %d\n", fd);
+ if ((shm = mmap(NULL, shm_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ LOGP(DMAIN, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));
+ rc = -errno;
+ goto err_mmap;
+ }
-static int ipc_shm_setup(const char *shm_name, size_t shm_len) {
- int fd;
- int rc;
-
- LOGP(DMAIN, LOGL_NOTICE, "Opening shm path %s\n", shm_name);
- if ((fd = shm_open(shm_name, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) {
- LOGP(DMAIN, LOGL_ERROR, "shm_open %d: %s\n", errno, strerror(errno));
- rc = -errno;
- goto err_shm_open;
- }
-
- LOGP(DMAIN, LOGL_NOTICE, "Truncating %d to size %zu\n", fd, shm_len);
- if (ftruncate(fd, shm_len) < 0) {
- LOGP(DMAIN, LOGL_ERROR, "ftruncate %d: %s\n", errno, strerror(errno));
- rc = -errno;
- goto err_mmap;
- }
-
- LOGP(DMAIN, LOGL_NOTICE, "mmaping shared memory fd %d\n", fd);
- if ((shm = mmap(NULL, shm_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
- LOGP(DMAIN, LOGL_ERROR, "mmap %d: %s\n", errno, strerror(errno));
- rc = -errno;
- goto err_mmap;
- }
-
- LOGP(DMAIN, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
- /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
- close(fd);
- return 0;
+ LOGP(DMAIN, LOGL_NOTICE, "mmap'ed shared memory at addr %p\n", shm);
+ /* After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping. */
+ close(fd);
+ return 0;
err_mmap:
- shm_unlink(shm_name);
- close(fd);
+ shm_unlink(shm_name);
+ close(fd);
err_shm_open:
- return rc;
+ return rc;
}
-static int ipc_sock_send(struct msgb *msg);
-
struct msgb *ipc_msgb_alloc(uint8_t msg_type)
{
struct msgb *msg;
@@ -122,7 +142,7 @@ struct msgb *ipc_msgb_alloc(uint8_t msg_type)
if (!msg)
return NULL;
msgb_put(msg, sizeof(struct ipc_sk_if) + 1000);
- ipc_prim = (struct ipc_sk_if *) msg->data;
+ ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->msg_type = msg_type;
return msg;
@@ -136,7 +156,7 @@ static int ipc_tx_greeting_cnf(uint8_t req_version)
msg = ipc_msgb_alloc(IPC_IF_MSG_GREETING_CNF);
if (!msg)
return -ENOMEM;
- ipc_prim = (struct ipc_sk_if *) msg->data;
+ ipc_prim = (struct ipc_sk_if *)msg->data;
ipc_prim->u.greeting_cnf.req_version = req_version;
return ipc_sock_send(msg);
@@ -146,309 +166,191 @@ static int ipc_tx_info_cnf()
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
- struct ipc_sk_if_info_chan *chan_info;
- unsigned int i;
msg = ipc_msgb_alloc(IPC_IF_MSG_INFO_CNF);
if (!msg)
return -ENOMEM;
- ipc_prim = (struct ipc_sk_if *) msg->data;
- ipc_prim->u.info_cnf.feature_mask = FEATURE_MASK_CLOCKREF_INTERNAL |
- FEATURE_MASK_CLOCKREF_EXTERNAL;
- ipc_prim->u.info_cnf.min_rx_gain = 0.0;
- ipc_prim->u.info_cnf.max_rx_gain = 70.0;
- ipc_prim->u.info_cnf.min_tx_gain = 0.0;
- ipc_prim->u.info_cnf.max_tx_gain = 63.0;
- ipc_prim->u.info_cnf.iq_scaling_val = 0.3;
- ipc_prim->u.info_cnf.max_num_chans = 2;
- OSMO_STRLCPY_ARRAY(ipc_prim->u.info_cnf.dev_desc, "Hello To my Virtual device!");
- chan_info = ipc_prim->u.info_cnf.chan_info;
- for (i = 0; i < ipc_prim->u.info_cnf.max_num_chans; i++) {
- OSMO_STRLCPY_ARRAY(chan_info->tx_path[0], "TxAntenna1");
- OSMO_STRLCPY_ARRAY(chan_info->tx_path[1], "TxAntenna2");
- OSMO_STRLCPY_ARRAY(chan_info->tx_path[2], "TxAntenna3");
- OSMO_STRLCPY_ARRAY(chan_info->rx_path[0], "RxAntenna1");
- OSMO_STRLCPY_ARRAY(chan_info->rx_path[1], "RxAntenna2");
- chan_info++;
- }
+ ipc_prim = (struct ipc_sk_if *)msg->data;
+
+ uhdwrap_fill_info_cnf(ipc_prim);
return ipc_sock_send(msg);
}
-static int ipc_tx_open_cnf(int rc, uint32_t num_chans)
+static int ipc_tx_open_cnf(int rc, uint32_t num_chans, int32_t timingoffset)
{
struct msgb *msg;
struct ipc_sk_if *ipc_prim;
- struct ipc_sk_if_open_cnf_chan *chan_info;
- unsigned int i;
+ struct ipc_sk_if_open_cnf_chan *chan_info;
+ unsigned int i;
msg = ipc_msgb_alloc(IPC_IF_MSG_OPEN_CNF);
if (!msg)
return -ENOMEM;
- ipc_prim = (struct ipc_sk_if *) msg->data;
- ipc_prim->u.open_cnf.return_code = rc;
- OSMO_STRLCPY_ARRAY(ipc_prim->u.open_cnf.shm_name, DEFAULT_SHM_NAME);
-
- chan_info = ipc_prim->u.open_cnf.chan_info;
- for (i = 0; i < num_chans; i++) {
- snprintf(chan_info->chan_ipc_sk_path, sizeof(chan_info->chan_ipc_sk_path), "%s_%d", IPC_SOCK_PATH, i+1);
- chan_info++;
- }
+ ipc_prim = (struct ipc_sk_if *)msg->data;
+ ipc_prim->u.open_cnf.return_code = rc;
+ ipc_prim->u.open_cnf.path_delay = timingoffset; // 6.18462e-5 * 1625e3 / 6;
+ OSMO_STRLCPY_ARRAY(ipc_prim->u.open_cnf.shm_name, DEFAULT_SHM_NAME);
+
+ chan_info = ipc_prim->u.open_cnf.chan_info;
+ for (i = 0; i < num_chans; i++) {
+ snprintf(chan_info->chan_ipc_sk_path, sizeof(chan_info->chan_ipc_sk_path), "%s_%d", IPC_SOCK_PATH, i);
+ /* FIXME: dynamc chan limit, currently 8 */
+ if (i < 8)
+ ipc_sock_init(chan_info->chan_ipc_sk_path, &global_ctrl_socks[i], ipc_chan_sock_accept, i);
+ chan_info++;
+ }
return ipc_sock_send(msg);
}
-static int ipc_rx_greeting_req(const struct ipc_sk_if_greeting *greeting_req)
+int ipc_rx_greeting_req(struct ipc_sk_if_greeting *greeting_req)
{
- if (greeting_req->req_version == IPC_SOCK_API_VERSION)
- ipc_tx_greeting_cnf(IPC_SOCK_API_VERSION);
- else
- ipc_tx_greeting_cnf(0);
- return 0;
-}
-
-static int ipc_rx_info_req(const struct ipc_sk_if_info_req *info_req)
-{
- ipc_tx_info_cnf();
- return 0;
+ if (greeting_req->req_version == IPC_SOCK_API_VERSION)
+ ipc_tx_greeting_cnf(IPC_SOCK_API_VERSION);
+ else
+ ipc_tx_greeting_cnf(0);
+ return 0;
}
-static int ipc_rx_open_req(const struct ipc_sk_if_open_req *open_req)
+int ipc_rx_info_req(struct ipc_sk_if_info_req *info_req)
{
- /* calculate size needed */
- unsigned int len;
- len = ipc_shm_encode_region(NULL, open_req->num_chans, 4, 4096);
- /* Here we verify num_chans, rx_path, tx_path, clockref, etc. */
- int rc = ipc_shm_setup(DEFAULT_SHM_NAME, len);
- len = ipc_shm_encode_region((struct ipc_shm_raw_region *)shm, open_req->num_chans, 4, 4096);
- LOGP(DMAIN, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *) shm, 80));
- ipc_tx_open_cnf(-rc, open_req->num_chans);
- return 0;
+ ipc_tx_info_cnf();
+ return 0;
}
-static int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
+int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req)
{
- int rc = 0;
-
- switch (msg_type) {
- case IPC_IF_MSG_GREETING_REQ:
- rc = ipc_rx_greeting_req(&ipc_prim->u.greeting_req);
- break;
- case IPC_IF_MSG_INFO_REQ:
- rc = ipc_rx_info_req(&ipc_prim->u.info_req);
- break;
- case IPC_IF_MSG_OPEN_REQ:
- rc = ipc_rx_open_req(&ipc_prim->u.open_req);
- break;
- default:
- LOGP(DMAIN, LOGL_ERROR, "Received unknown PCU msg type %d\n",
- msg_type);
- rc = -EINVAL;
+ /* calculate size needed */
+ unsigned int len;
+
+ global_dev = uhdwrap_open(open_req);
+
+ /* b210 packet size is 2040, but our tx size is 2500, so just do *2 */
+ int shmbuflen = uhdwrap_get_bufsizerx(global_dev) * 2;
+
+ len = ipc_shm_encode_region(NULL, open_req->num_chans, 4, shmbuflen);
+ /* Here we verify num_chans, rx_path, tx_path, clockref, etc. */
+ int rc = ipc_shm_setup(DEFAULT_SHM_NAME, len);
+ len = ipc_shm_encode_region((struct ipc_shm_raw_region *)shm, open_req->num_chans, 4, shmbuflen);
+ LOGP(DMAIN, LOGL_NOTICE, "%s\n", osmo_hexdump((const unsigned char *)shm, 80));
+
+ /* set up our own copy of the decoded area, we have to do it here,
+ * since the uhd wrapper does not allow starting single channels
+ * additionally go for the producer init for both, so only we are responsible for the init, instead
+ * of splitting it with the client and causing potential races if one side uses it too early */
+ decoded_region = ipc_shm_decode_region(0, (struct ipc_shm_raw_region *)shm);
+ for (unsigned int i = 0; i < open_req->num_chans; i++) {
+ // ios_tx_to_device[i] = ipc_shm_init_consumer(decoded_region->channels[i]->dl_stream);
+ ios_tx_to_device[i] = ipc_shm_init_producer(decoded_region->channels[i]->dl_stream);
+ ios_rx_from_device[i] = ipc_shm_init_producer(decoded_region->channels[i]->ul_stream);
}
- return rc;
+ ipc_tx_open_cnf(-rc, open_req->num_chans, uhdwrap_get_timingoffset(global_dev));
+ return 0;
}
-static int ipc_sock_send(struct msgb *msg)
+void *uplink_thread(void *x_void_ptr)
{
- struct ipc_sock_state *state = global_ipc_sock_state;
- struct osmo_fd *conn_bfd;
- //struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;
-
- if (!state) {
- LOGP(DMAIN, LOGL_INFO, "PCU socket not created, "
- "dropping message\n");
- msgb_free(msg);
- return -EINVAL;
- }
- conn_bfd = &state->conn_bfd;
- if (conn_bfd->fd <= 0) {
- LOGP(DMAIN, LOGL_NOTICE, "PCU socket not connected, "
- "dropping message\n");
- msgb_free(msg);
- return -EIO;
- }
- msgb_enqueue(&state->upqueue, msg);
- conn_bfd->when |= BSC_FD_WRITE;
+ uint32_t chann = decoded_region->num_chans;
+ pthread_setname_np(pthread_self(), "uplink rx");
+
+ while (!ipc_exit_requested) {
+ int32_t read = uhdwrap_read(global_dev, chann);
+ if (read < 0)
+ return 0;
+ }
return 0;
}
-static void ipc_sock_close(struct ipc_sock_state *state)
+void *downlink_thread(void *x_void_ptr)
{
- struct osmo_fd *bfd = &state->conn_bfd;
+ int chann = decoded_region->num_chans;
+ pthread_setname_np(pthread_self(), "downlink tx");
- LOGP(DMAIN, LOGL_NOTICE, "PCU socket has LOST connection\n");
-
- close(bfd->fd);
- bfd->fd = -1;
- osmo_fd_unregister(bfd);
-
- /* re-enable the generation of ACCEPT for new connections */
- state->listen_bfd.when |= BSC_FD_READ;
-
- /* flush the queue */
- while (!llist_empty(&state->upqueue)) {
- struct msgb *msg = msgb_dequeue(&state->upqueue);
- msgb_free(msg);
+ while (!ipc_exit_requested) {
+ bool underrun;
+ uhdwrap_write(global_dev, chann, &underrun);
}
+ return 0;
}
-static int ipc_sock_read(struct osmo_fd *bfd)
+int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)
{
- struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
- struct ipc_sk_if *ipc_prim;
struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
int rc;
- msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");
- if (!msg)
- return -ENOMEM;
-
- ipc_prim = (struct ipc_sk_if *) msg->tail;
-
- rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
- if (rc == 0)
- goto close;
-
- if (rc < 0) {
- if (errno == EAGAIN) {
- msgb_free(msg);
- return 0;
- }
- goto close;
- }
-
- if (rc < (int)sizeof(*ipc_prim)) {
- LOGP(DMAIN, LOGL_ERROR, "Received %d bytes on Unix Socket, but primitive size "
- "is %zu, discarding\n", rc, sizeof(*ipc_prim));
- msgb_free(msg);
- return 0;
- }
-
- rc = ipc_rx(ipc_prim->msg_type, ipc_prim);
+ /* no per-chan start/stop */
+ rc = uhdwrap_start(global_dev, chan_nr);
- /* as we always synchronously process the message in pcu_rx() and
- * its callbacks, we can free the message here. */
- msgb_free(msg);
+ pthread_t rx, tx;
+ pthread_create(&rx, NULL, uplink_thread, 0);
+ pthread_create(&tx, NULL, downlink_thread, 0);
- return rc;
+ msg = ipc_msgb_alloc(IPC_IF_MSG_START_CNF);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.start_cnf.return_code = rc ? 0 : -1;
-close:
- msgb_free(msg);
- ipc_sock_close(state);
- return -1;
+ return ipc_chan_sock_send(msg, chan_nr);
}
-
-static int ipc_sock_write(struct osmo_fd *bfd)
+int ipc_rx_chan_stop_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr)
{
- struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
int rc;
- while (!llist_empty(&state->upqueue)) {
- struct msgb *msg, *msg2;
- struct ipc_sk_if *ipc_prim;
-
- /* peek at the beginning of the queue */
- msg = llist_entry(state->upqueue.next, struct msgb, list);
- ipc_prim = (struct ipc_sk_if *)msg->data;
-
- bfd->when &= ~BSC_FD_WRITE;
-
- /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
- if (!msgb_length(msg)) {
- LOGP(DMAIN, LOGL_ERROR, "message type (%d) with ZERO "
- "bytes!\n", ipc_prim->msg_type);
- goto dontsend;
- }
-
- /* try to send it over the socket */
- rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
- if (rc == 0)
- goto close;
- if (rc < 0) {
- if (errno == EAGAIN) {
- bfd->when |= BSC_FD_WRITE;
- break;
- }
- goto close;
- }
-
-dontsend:
- /* _after_ we send it, we can deueue */
- msg2 = msgb_dequeue(&state->upqueue);
- assert(msg == msg2);
- msgb_free(msg);
- }
- return 0;
+ /* no per-chan start/stop */
+ rc = uhdwrap_stop(global_dev, chan_nr);
-close:
- ipc_sock_close(state);
- return -1;
-}
+ msg = ipc_msgb_alloc(IPC_IF_MSG_STOP_CNF);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.stop_cnf.return_code = rc ? 0 : -1;
-static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
+ return ipc_chan_sock_send(msg, chan_nr);
+}
+int ipc_rx_chan_setgain_req(struct ipc_sk_chan_if_gain *req, uint8_t chan_nr)
{
- int rc = 0;
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
+ double rv;
- if (flags & BSC_FD_READ)
- rc = ipc_sock_read(bfd);
- if (rc < 0)
- return rc;
+ rv = uhdwrap_set_gain(global_dev, req->gain, chan_nr, req->is_tx);
- if (flags & BSC_FD_WRITE)
- rc = ipc_sock_write(bfd);
+ msg = ipc_msgb_alloc(IPC_IF_MSG_SETGAIN_CNF);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.set_gain_cnf.is_tx = req->is_tx;
+ ipc_prim->u.set_gain_cnf.gain = rv;
- return rc;
+ return ipc_chan_sock_send(msg, chan_nr);
}
-/* accept connection coming from PCU */
-static int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)
+int ipc_rx_chan_setfreq_req(struct ipc_sk_chan_if_freq_req *req, uint8_t chan_nr)
{
- struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
- struct osmo_fd *conn_bfd = &state->conn_bfd;
- struct sockaddr_un un_addr;
- socklen_t len;
- int rc;
-
- len = sizeof(un_addr);
- rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len);
- if (rc < 0) {
- LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");
- return -1;
- }
-
- if (conn_bfd->fd >= 0) {
- LOGP(DMAIN, LOGL_NOTICE, "osmo-trx connects but we already have "
- "another active connection ?!?\n");
- /* We already have one PCU connected, this is all we support */
- state->listen_bfd.when &= ~BSC_FD_READ;
- close(rc);
- return 0;
- }
-
- conn_bfd->fd = rc;
- conn_bfd->when = BSC_FD_READ;
- conn_bfd->cb = ipc_sock_cb;
- conn_bfd->data = state;
-
- if (osmo_fd_register(conn_bfd) != 0) {
- LOGP(DMAIN, LOGL_ERROR, "Failed to register new connection "
- "fd\n");
- close(conn_bfd->fd);
- conn_bfd->fd = -1;
- return -1;
- }
+ struct msgb *msg;
+ struct ipc_sk_chan_if *ipc_prim;
+ bool rv;
- LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
+ rv = uhdwrap_set_freq(global_dev, req->freq, chan_nr, req->is_tx);
- /* send current info */
- //pcu_tx_info_ind();
+ msg = ipc_msgb_alloc(IPC_IF_MSG_SETFREQ_CNF);
+ if (!msg)
+ return -ENOMEM;
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+ ipc_prim->u.set_freq_cnf.return_code = rv ? 0 : 1;
- return 0;
+ return ipc_chan_sock_send(msg, chan_nr);
}
-int ipc_sock_init(const char *path)
+int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
+ int (*sock_callback_fn)(struct osmo_fd *fd, unsigned int what), int n)
{
struct ipc_sock_state *state;
struct osmo_fd *bfd;
@@ -457,58 +359,61 @@ int ipc_sock_init(const char *path)
state = talloc_zero(NULL, struct ipc_sock_state);
if (!state)
return -ENOMEM;
- global_ipc_sock_state = state;
+ *global_state_var = state;
INIT_LLIST_HEAD(&state->upqueue);
- state->conn_bfd.fd = -1;
+ state->conn_bfd.fd = -1;
bfd = &state->listen_bfd;
- bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path,
- OSMO_SOCK_F_BIND);
+ bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, OSMO_SOCK_F_BIND);
if (bfd->fd < 0) {
- LOGP(DMAIN, LOGL_ERROR, "Could not create %s unix socket: %s\n",
- path, strerror(errno));
+ LOGP(DMAIN, LOGL_ERROR, "Could not create %s unix socket: %s\n", path, strerror(errno));
talloc_free(state);
return -1;
}
bfd->when = BSC_FD_READ;
- bfd->cb = ipc_sock_accept;
+ bfd->cb = sock_callback_fn;
bfd->data = state;
+ bfd->priv_nr = n;
rc = osmo_fd_register(bfd);
if (rc < 0) {
- LOGP(DMAIN, LOGL_ERROR, "Could not register listen fd: %d\n",
- rc);
+ LOGP(DMAIN, LOGL_ERROR, "Could not register listen fd: %d\n", rc);
close(bfd->fd);
talloc_free(state);
return rc;
}
- //osmo_signal_register_handler(SS_GLOBAL, pcu_if_signal_cb, NULL);
+ //osmo_signal_register_handler(SS_GLOBAL, IPC_if_signal_cb, NULL);
LOGP(DMAIN, LOGL_INFO, "Started listening on IPC socket: %s\n", path);
return 0;
}
-#ifdef IPCMAGIC
-extern "C" int osmo_ctx_init ( const char * id );
-int magicmain(int argc, char** argv) {
- osmo_ctx_init("main");
- osmo_select_init();
+#if defined(IPCMAGIC) && defined(__cplusplus)
+extern "C" int osmo_ctx_init(const char *id);
+
+extern "C" int magicmain(int argc, char **argv)
+{
+ osmo_ctx_init("main");
+ osmo_select_init();
+
#else
-int main(int argc, char** argv) {
+int main(int argc, char **argv)
+{
#endif
- tall_ctx = talloc_named_const(NULL, 0, "OsmoTRX");
- msgb_talloc_ctx_init(tall_ctx, 0);
- osmo_init_logging2(tall_ctx, &log_info);
- log_enable_multithread();
- LOGP(DMAIN, LOGL_INFO, "Starting %s\n", argv[0]);
- ipc_sock_init(IPC_SOCK_PATH);
- while (true)
- osmo_select_main(0);
- //ipc_sock_close()
- return 0;
+ tall_ctx = talloc_named_const(NULL, 0, "OsmoTRX");
+ msgb_talloc_ctx_init(tall_ctx, 0);
+ osmo_init_logging2(tall_ctx, &log_infox);
+ log_enable_multithread();
+
+ LOGP(DMAIN, LOGL_INFO, "Starting %s\n", argv[0]);
+ ipc_sock_init(IPC_SOCK_PATH, &global_ipc_sock_state, ipc_sock_accept, 0);
+ while (!ipc_exit_requested)
+ osmo_select_main(0);
+ //ipc_sock_close()
+ return 0;
}
diff --git a/Transceiver52M/device/ipc/ipc-driver-test.h b/Transceiver52M/device/ipc/ipc-driver-test.h
new file mode 100644
index 0000000..e0fecea
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc-driver-test.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <osmocom/core/select.h>
+#include "shm.h"
+
+extern struct ipc_sock_state *global_ipc_sock_state;
+
+/* 8 channels are plenty */
+extern struct ipc_sock_state *global_ctrl_socks[8];
+extern struct ipc_shm_io *ios_tx_to_device[8];
+extern struct ipc_shm_io *ios_rx_from_device[8];
+
+struct ipc_sock_state {
+ struct osmo_fd listen_bfd; /* fd for listen socket */
+ struct osmo_fd conn_bfd; /* fd for connection to lcr */
+ struct llist_head upqueue; /* queue for sending messages */
+};
+
+int ipc_sock_init(const char *path, struct ipc_sock_state **global_state_var,
+ int (*sock_callback_fn)(struct osmo_fd *fd, unsigned int what), int n);
+
+int ipc_rx_greeting_req(struct ipc_sk_if_greeting *greeting_req);
+int ipc_rx_info_req(struct ipc_sk_if_info_req *info_req);
+int ipc_rx_open_req(struct ipc_sk_if_open_req *open_req);
+
+int ipc_rx_chan_start_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr);
+int ipc_rx_chan_stop_req(struct ipc_sk_chan_if_op_void *req, uint8_t chan_nr);
+int ipc_rx_chan_setgain_req(struct ipc_sk_chan_if_gain *req, uint8_t chan_nr);
+int ipc_rx_chan_setfreq_req(struct ipc_sk_chan_if_freq_req *req, uint8_t chan_nr);
diff --git a/Transceiver52M/device/ipc/ipc_chan.c b/Transceiver52M/device/ipc/ipc_chan.c
new file mode 100644
index 0000000..1ad920a
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc_chan.c
@@ -0,0 +1,242 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+
+#include <debug.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+
+#include "shm.h"
+#include "ipc-driver-test.h"
+#include "ipc_chan.h"
+#include "ipc_sock.h"
+
+static int ipc_chan_rx(uint8_t msg_type, struct ipc_sk_chan_if *ipc_prim, uint8_t chan_nr)
+{
+ int rc = 0;
+
+ switch (msg_type) {
+ case IPC_IF_MSG_START_REQ:
+ rc = ipc_rx_chan_start_req(&ipc_prim->u.start_req, chan_nr);
+ break;
+ case IPC_IF_MSG_STOP_REQ:
+ rc = ipc_rx_chan_stop_req(&ipc_prim->u.stop_req, chan_nr);
+ break;
+ case IPC_IF_MSG_SETGAIN_REQ:
+ rc = ipc_rx_chan_setgain_req(&ipc_prim->u.set_gain_req, chan_nr);
+ break;
+ case IPC_IF_MSG_SETFREQ_REQ:
+ rc = ipc_rx_chan_setfreq_req(&ipc_prim->u.set_freq_req, chan_nr);
+ break;
+ default:
+ LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int ipc_chan_sock_read(struct osmo_fd *bfd)
+{
+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ struct ipc_sk_chan_if *ipc_prim;
+ struct msgb *msg;
+ int rc;
+
+ msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_chan_sock_rx");
+ if (!msg)
+ return -ENOMEM;
+
+ ipc_prim = (struct ipc_sk_chan_if *)msg->tail;
+
+ rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
+ if (rc == 0)
+ goto close;
+
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ msgb_free(msg);
+ return 0;
+ }
+ goto close;
+ }
+
+ if (rc < (int)sizeof(*ipc_prim)) {
+ LOGP(DMAIN, LOGL_ERROR,
+ "Received %d bytes on Unix Socket, but primitive size "
+ "is %zu, discarding\n",
+ rc, sizeof(*ipc_prim));
+ msgb_free(msg);
+ return 0;
+ }
+
+ rc = ipc_chan_rx(ipc_prim->msg_type, ipc_prim, bfd->priv_nr);
+
+ /* as we always synchronously process the message in IPC_rx() and
+ * its callbacks, we can free the message here. */
+ msgb_free(msg);
+
+ return rc;
+
+close:
+ msgb_free(msg);
+ ipc_sock_close(state);
+ return -1;
+}
+
+int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr)
+{
+ struct ipc_sock_state *state = global_ctrl_socks[chan_nr];
+ struct osmo_fd *conn_bfd;
+
+ if (!state)
+ return -EINVAL;
+
+ if (!state) {
+ LOGP(DMAIN, LOGL_INFO,
+ "IPC socket not created, "
+ "dropping message\n");
+ msgb_free(msg);
+ return -EINVAL;
+ }
+ conn_bfd = &state->conn_bfd;
+ if (conn_bfd->fd <= 0) {
+ LOGP(DMAIN, LOGL_NOTICE,
+ "IPC socket not connected, "
+ "dropping message\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+ msgb_enqueue(&state->upqueue, msg);
+ conn_bfd->when |= BSC_FD_WRITE;
+
+ return 0;
+}
+
+static int ipc_chan_sock_write(struct osmo_fd *bfd)
+{
+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ int rc;
+
+ while (!llist_empty(&state->upqueue)) {
+ struct msgb *msg, *msg2;
+ struct ipc_sk_chan_if *ipc_prim;
+
+ /* peek at the beginning of the queue */
+ msg = llist_entry(state->upqueue.next, struct msgb, list);
+ ipc_prim = (struct ipc_sk_chan_if *)msg->data;
+
+ bfd->when &= ~BSC_FD_WRITE;
+
+ /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
+ if (!msgb_length(msg)) {
+ LOGP(DMAIN, LOGL_ERROR,
+ "message type (%d) with ZERO "
+ "bytes!\n",
+ ipc_prim->msg_type);
+ goto dontsend;
+ }
+
+ /* try to send it over the socket */
+ rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
+ if (rc == 0)
+ goto close;
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ bfd->when |= BSC_FD_WRITE;
+ break;
+ }
+ goto close;
+ }
+
+ dontsend:
+ /* _after_ we send it, we can deueue */
+ msg2 = msgb_dequeue(&state->upqueue);
+ assert(msg == msg2);
+ msgb_free(msg);
+ }
+ return 0;
+
+close:
+ ipc_sock_close(state);
+ return -1;
+}
+
+static int ipc_chan_sock_cb(struct osmo_fd *bfd, unsigned int flags)
+{
+ int rc = 0;
+
+ if (flags & BSC_FD_READ)
+ rc = ipc_chan_sock_read(bfd);
+ if (rc < 0)
+ return rc;
+
+ if (flags & BSC_FD_WRITE)
+ rc = ipc_chan_sock_write(bfd);
+
+ return rc;
+}
+
+int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags)
+{
+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ struct osmo_fd *conn_bfd = &state->conn_bfd;
+ struct sockaddr_un un_addr;
+ socklen_t len;
+ int rc;
+
+ len = sizeof(un_addr);
+ rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);
+ if (rc < 0) {
+ LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");
+ return -1;
+ }
+
+ if (conn_bfd->fd >= 0) {
+ LOGP(DMAIN, LOGL_NOTICE,
+ "osmo-trx connects but we already have "
+ "another active connection ?!?\n");
+ /* We already have one IPC connected, this is all we support */
+ state->listen_bfd.when &= ~BSC_FD_READ;
+ close(rc);
+ return 0;
+ }
+
+ conn_bfd->fd = rc;
+ conn_bfd->when = BSC_FD_READ;
+ conn_bfd->cb = ipc_chan_sock_cb;
+ conn_bfd->data = state;
+
+ if (osmo_fd_register(conn_bfd) != 0) {
+ LOGP(DMAIN, LOGL_ERROR,
+ "Failed to register new connection "
+ "fd\n");
+ close(conn_bfd->fd);
+ conn_bfd->fd = -1;
+ return -1;
+ }
+
+ LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
+
+ /* send current info */
+ //IPC_tx_info_ind();
+
+ return 0;
+}
diff --git a/Transceiver52M/device/ipc/ipc_chan.h b/Transceiver52M/device/ipc/ipc_chan.h
new file mode 100644
index 0000000..fded26e
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc_chan.h
@@ -0,0 +1,10 @@
+#ifndef IPC_CHAN_H
+#define IPC_CHAN_H
+
+#include "shm.h"
+#include "ipc-driver-test.h"
+
+int ipc_chan_sock_send(struct msgb *msg, uint8_t chan_nr);
+int ipc_chan_sock_accept(struct osmo_fd *bfd, unsigned int flags);
+
+#endif // IPC_CHAN_H
diff --git a/Transceiver52M/device/ipc/ipc_shm.c b/Transceiver52M/device/ipc/ipc_shm.c
new file mode 100644
index 0000000..d860ce7
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc_shm.c
@@ -0,0 +1,204 @@
+/*
+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+* Author: Eric Wild <ewild@sysmocom.de>
+*
+* SPDX-License-Identifier: 0BSD
+*
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ PERFORMANCE OF THIS SOFTWARE.
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <shm.h>
+#include "ipc_shm.h"
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#define SAMPLE_SIZE_BYTE sizeof(uint16_t) * 2
+
+struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s)
+{
+ unsigned int i;
+
+ struct ipc_shm_io *r = (struct ipc_shm_io *)malloc(sizeof(struct ipc_shm_io));
+ r->this_stream = s->raw;
+ r->buf_ptrs =
+ (volatile struct ipc_shm_raw_smpl_buf **)malloc(sizeof(struct ipc_shm_raw_smpl_buf *) * s->num_buffers);
+
+ /* save actual ptrs */
+ for (i = 0; i < s->num_buffers; i++)
+ r->buf_ptrs[i] = s->buffers[i];
+
+ r->partial_read_begin_ptr = 0;
+ return r;
+}
+
+struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s)
+{
+ int rv;
+ pthread_mutexattr_t att;
+ pthread_condattr_t t1, t2;
+ struct ipc_shm_io *r = ipc_shm_init_consumer(s);
+ rv = pthread_mutexattr_init(&att);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = pthread_mutexattr_setrobust(&att, PTHREAD_MUTEX_ROBUST);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = pthread_mutexattr_setpshared(&att, PTHREAD_PROCESS_SHARED);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = pthread_mutex_init((pthread_mutex_t *)&r->this_stream->lock, &att);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ pthread_mutexattr_destroy(&att);
+
+ rv = pthread_condattr_setpshared(&t1, PTHREAD_PROCESS_SHARED);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = pthread_condattr_setpshared(&t2, PTHREAD_PROCESS_SHARED);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = pthread_cond_init((pthread_cond_t *)&r->this_stream->cf, &t1);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ rv = pthread_cond_init((pthread_cond_t *)&r->this_stream->ce, &t2);
+ if (rv != 0) {
+ fprintf(stderr, "%s:%d rv:%d", __FILE__, __LINE__, rv);
+ exit(EXIT_FAILURE);
+ }
+
+ pthread_condattr_destroy(&t1);
+ pthread_condattr_destroy(&t2);
+
+ r->this_stream->read_next = 0;
+ r->this_stream->write_next = 0;
+ return r;
+}
+
+void ipc_shm_close(struct ipc_shm_io *r)
+{
+ if (r) {
+ if (r->buf_ptrs)
+ free(r->buf_ptrs);
+ free(r);
+ }
+}
+
+int32_t ipc_shm_enqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data)
+{
+ volatile struct ipc_shm_raw_smpl_buf *buf;
+ int32_t rv;
+ struct timespec tv;
+ clock_gettime(CLOCK_REALTIME, &tv);
+ tv.tv_sec += 1;
+
+ rv = pthread_mutex_timedlock((pthread_mutex_t *)&r->this_stream->lock, &tv);
+ if (rv != 0)
+ return -rv;
+
+ while (((r->this_stream->write_next + 1) & (r->this_stream->num_buffers - 1)) == r->this_stream->read_next &&
+ rv == 0)
+ rv = pthread_cond_timedwait((pthread_cond_t *)&r->this_stream->ce,
+ (pthread_mutex_t *)&r->this_stream->lock, &tv);
+ if (rv != 0)
+ return -rv;
+
+ buf = r->buf_ptrs[r->this_stream->write_next];
+ buf->timestamp = timestamp;
+
+ rv = len_in_sps <= r->this_stream->buffer_size ? len_in_sps : r->this_stream->buffer_size;
+
+ memcpy((void *)buf->samples, data, SAMPLE_SIZE_BYTE * rv);
+ buf->data_len = rv;
+
+ r->this_stream->write_next = (r->this_stream->write_next + 1) & (r->this_stream->num_buffers - 1);
+
+ pthread_cond_signal((pthread_cond_t *)&r->this_stream->cf);
+ pthread_mutex_unlock((pthread_mutex_t *)&r->this_stream->lock);
+
+ return rv;
+}
+
+int32_t ipc_shm_read(struct ipc_shm_io *r, uint16_t *out_buf, uint32_t num_samples, uint64_t *timestamp,
+ uint32_t timeout_seconds)
+{
+ volatile struct ipc_shm_raw_smpl_buf *buf;
+ int32_t rv;
+ uint8_t freeflag = 0;
+ struct timespec tv;
+ clock_gettime(CLOCK_REALTIME, &tv);
+ tv.tv_sec += timeout_seconds;
+
+ rv = pthread_mutex_timedlock((pthread_mutex_t *)&r->this_stream->lock, &tv);
+ if (rv != 0)
+ return -rv;
+
+ while (r->this_stream->write_next == r->this_stream->read_next && rv == 0)
+ rv = pthread_cond_timedwait((pthread_cond_t *)&r->this_stream->cf,
+ (pthread_mutex_t *)&r->this_stream->lock, &tv);
+ if (rv != 0)
+ return -rv;
+
+ buf = r->buf_ptrs[r->this_stream->read_next];
+ if (buf->data_len <= num_samples) {
+ memcpy(out_buf, (void *)&buf->samples[r->partial_read_begin_ptr * 2], SAMPLE_SIZE_BYTE * buf->data_len);
+ r->partial_read_begin_ptr = 0;
+ rv = buf->data_len;
+ buf->data_len = 0;
+ r->this_stream->read_next = (r->this_stream->read_next + 1) & (r->this_stream->num_buffers - 1);
+ freeflag = 1;
+
+ } else /*if (buf->data_len > num_samples)*/ {
+ memcpy(out_buf, (void *)&buf->samples[r->partial_read_begin_ptr * 2], SAMPLE_SIZE_BYTE * num_samples);
+ r->partial_read_begin_ptr += num_samples;
+ buf->data_len -= num_samples;
+ rv = num_samples;
+ }
+
+ *timestamp = buf->timestamp;
+ buf->timestamp += rv;
+
+ if (freeflag)
+ pthread_cond_signal((pthread_cond_t *)&r->this_stream->ce);
+
+ pthread_mutex_unlock((pthread_mutex_t *)&r->this_stream->lock);
+
+ return rv;
+}
diff --git a/Transceiver52M/device/ipc/ipc_shm.h b/Transceiver52M/device/ipc/ipc_shm.h
new file mode 100644
index 0000000..66f59c9
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc_shm.h
@@ -0,0 +1,43 @@
+/*
+* Copyright 2020 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+* Author: Eric Wild <ewild@sysmocom.de>
+*
+* SPDX-License-Identifier: 0BSD
+*
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+*/
+#ifndef IPC_SHM_H
+#define IPC_SHM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <shm.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+struct ipc_shm_io {
+ volatile struct ipc_shm_raw_stream *this_stream; // plus num_buffers at end
+ volatile struct ipc_shm_raw_smpl_buf **volatile buf_ptrs;
+ uint32_t partial_read_begin_ptr;
+};
+
+struct ipc_shm_io *ipc_shm_init_consumer(struct ipc_shm_stream *s);
+struct ipc_shm_io *ipc_shm_init_producer(struct ipc_shm_stream *s);
+void ipc_shm_close(struct ipc_shm_io *r);
+int32_t ipc_shm_enqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data);
+int32_t ipc_shm_tryenqueue(struct ipc_shm_io *r, uint64_t timestamp, uint32_t len_in_sps, uint16_t *data);
+volatile struct ipc_shm_raw_smpl_buf *ipc_shm_dequeue(struct ipc_shm_io *r);
+int32_t ipc_shm_read(struct ipc_shm_io *r, uint16_t *out_buf, uint32_t num_samples, uint64_t *timestamp,
+ uint32_t timeout_seconds);
+
+#endif // IPC_SHM_H
diff --git a/Transceiver52M/device/ipc/ipc_sock.c b/Transceiver52M/device/ipc/ipc_sock.c
new file mode 100644
index 0000000..36d8955
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc_sock.c
@@ -0,0 +1,259 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+
+#include <debug.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+
+#include "shm.h"
+#include "ipc-driver-test.h"
+
+extern volatile int ipc_exit_requested;
+static int ipc_rx(uint8_t msg_type, struct ipc_sk_if *ipc_prim)
+{
+ int rc = 0;
+
+ switch (msg_type) {
+ case IPC_IF_MSG_GREETING_REQ:
+ rc = ipc_rx_greeting_req(&ipc_prim->u.greeting_req);
+ break;
+ case IPC_IF_MSG_INFO_REQ:
+ rc = ipc_rx_info_req(&ipc_prim->u.info_req);
+ break;
+ case IPC_IF_MSG_OPEN_REQ:
+ rc = ipc_rx_open_req(&ipc_prim->u.open_req);
+ break;
+ default:
+ LOGP(DMAIN, LOGL_ERROR, "Received unknown IPC msg type %d\n", msg_type);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+int ipc_sock_send(struct msgb *msg)
+{
+ struct ipc_sock_state *state = global_ipc_sock_state;
+ struct osmo_fd *conn_bfd;
+ //struct ipc_sk_if *ipc_prim = (struct ipc_sk_if *) msg->data;
+
+ if (!state) {
+ LOGP(DMAIN, LOGL_INFO,
+ "IPC socket not created, "
+ "dropping message\n");
+ msgb_free(msg);
+ return -EINVAL;
+ }
+ conn_bfd = &state->conn_bfd;
+ if (conn_bfd->fd <= 0) {
+ LOGP(DMAIN, LOGL_NOTICE,
+ "IPC socket not connected, "
+ "dropping message\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+ msgb_enqueue(&state->upqueue, msg);
+ conn_bfd->when |= BSC_FD_WRITE;
+
+ return 0;
+}
+
+void ipc_sock_close(struct ipc_sock_state *state)
+{
+ struct osmo_fd *bfd = &state->conn_bfd;
+
+ LOGP(DMAIN, LOGL_NOTICE, "IPC socket has LOST connection\n");
+
+ ipc_exit_requested = 1;
+
+ close(bfd->fd);
+ bfd->fd = -1;
+ osmo_fd_unregister(bfd);
+
+ /* re-enable the generation of ACCEPT for new connections */
+ state->listen_bfd.when |= BSC_FD_READ;
+
+ /* flush the queue */
+ while (!llist_empty(&state->upqueue)) {
+ struct msgb *msg = msgb_dequeue(&state->upqueue);
+ msgb_free(msg);
+ }
+}
+
+int ipc_sock_read(struct osmo_fd *bfd)
+{
+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ struct ipc_sk_if *ipc_prim;
+ struct msgb *msg;
+ int rc;
+
+ msg = msgb_alloc(sizeof(*ipc_prim) + 1000, "ipc_sock_rx");
+ if (!msg)
+ return -ENOMEM;
+
+ ipc_prim = (struct ipc_sk_if *)msg->tail;
+
+ rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
+ if (rc == 0)
+ goto close;
+
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ msgb_free(msg);
+ return 0;
+ }
+ goto close;
+ }
+
+ if (rc < (int)sizeof(*ipc_prim)) {
+ LOGP(DMAIN, LOGL_ERROR,
+ "Received %d bytes on Unix Socket, but primitive size "
+ "is %zu, discarding\n",
+ rc, sizeof(*ipc_prim));
+ msgb_free(msg);
+ return 0;
+ }
+
+ rc = ipc_rx(ipc_prim->msg_type, ipc_prim);
+
+ /* as we always synchronously process the message in IPC_rx() and
+ * its callbacks, we can free the message here. */
+ msgb_free(msg);
+
+ return rc;
+
+close:
+ msgb_free(msg);
+ ipc_sock_close(state);
+ return -1;
+}
+
+static int ipc_sock_write(struct osmo_fd *bfd)
+{
+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ int rc;
+
+ while (!llist_empty(&state->upqueue)) {
+ struct msgb *msg, *msg2;
+ struct ipc_sk_if *ipc_prim;
+
+ /* peek at the beginning of the queue */
+ msg = llist_entry(state->upqueue.next, struct msgb, list);
+ ipc_prim = (struct ipc_sk_if *)msg->data;
+
+ bfd->when &= ~BSC_FD_WRITE;
+
+ /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
+ if (!msgb_length(msg)) {
+ LOGP(DMAIN, LOGL_ERROR,
+ "message type (%d) with ZERO "
+ "bytes!\n",
+ ipc_prim->msg_type);
+ goto dontsend;
+ }
+
+ /* try to send it over the socket */
+ rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
+ if (rc == 0)
+ goto close;
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ bfd->when |= BSC_FD_WRITE;
+ break;
+ }
+ goto close;
+ }
+
+ dontsend:
+ /* _after_ we send it, we can deueue */
+ msg2 = msgb_dequeue(&state->upqueue);
+ assert(msg == msg2);
+ msgb_free(msg);
+ }
+ return 0;
+
+close:
+ ipc_sock_close(state);
+ return -1;
+}
+
+static int ipc_sock_cb(struct osmo_fd *bfd, unsigned int flags)
+{
+ int rc = 0;
+
+ if (flags & BSC_FD_READ)
+ rc = ipc_sock_read(bfd);
+ if (rc < 0)
+ return rc;
+
+ if (flags & BSC_FD_WRITE)
+ rc = ipc_sock_write(bfd);
+
+ return rc;
+}
+
+/* accept connection coming from IPC */
+int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags)
+{
+ struct ipc_sock_state *state = (struct ipc_sock_state *)bfd->data;
+ struct osmo_fd *conn_bfd = &state->conn_bfd;
+ struct sockaddr_un un_addr;
+ socklen_t len;
+ int rc;
+
+ len = sizeof(un_addr);
+ rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len);
+ if (rc < 0) {
+ LOGP(DMAIN, LOGL_ERROR, "Failed to accept a new connection\n");
+ return -1;
+ }
+
+ if (conn_bfd->fd >= 0) {
+ LOGP(DMAIN, LOGL_NOTICE,
+ "ip clent connects but we already have "
+ "another active connection ?!?\n");
+ /* We already have one IPC connected, this is all we support */
+ state->listen_bfd.when &= ~BSC_FD_READ;
+ close(rc);
+ return 0;
+ }
+
+ conn_bfd->fd = rc;
+ conn_bfd->when = BSC_FD_READ;
+ conn_bfd->cb = ipc_sock_cb;
+ conn_bfd->data = state;
+
+ if (osmo_fd_register(conn_bfd) != 0) {
+ LOGP(DMAIN, LOGL_ERROR,
+ "Failed to register new connection "
+ "fd\n");
+ close(conn_bfd->fd);
+ conn_bfd->fd = -1;
+ return -1;
+ }
+
+ LOGP(DMAIN, LOGL_NOTICE, "Unix socket connected to external osmo-trx\n");
+
+ /* send current info */
+ //IPC_tx_info_ind();
+
+ return 0;
+}
diff --git a/Transceiver52M/device/ipc/ipc_sock.h b/Transceiver52M/device/ipc/ipc_sock.h
new file mode 100644
index 0000000..ea5c643
--- /dev/null
+++ b/Transceiver52M/device/ipc/ipc_sock.h
@@ -0,0 +1,11 @@
+#ifndef IPC_SOCK_H
+#define IPC_SOCK_H
+
+#include "shm.h"
+#include "ipc-driver-test.h"
+
+int ipc_sock_send(struct msgb *msg);
+int ipc_sock_accept(struct osmo_fd *bfd, unsigned int flags);
+void ipc_sock_close(struct ipc_sock_state *state);
+
+#endif // IPC_SOCK_H
diff --git a/Transceiver52M/device/ipc/ipcb210.cpp b/Transceiver52M/device/ipc/ipcb210.cpp
index 7d030bb..ea43ff2 100644
--- a/Transceiver52M/device/ipc/ipcb210.cpp
+++ b/Transceiver52M/device/ipc/ipcb210.cpp
@@ -1,18 +1,190 @@
+//has to come first outside of NS, or wrapping of c headers fails due to wrong order
+extern "C" {
+#include <osmocom/core/application.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+
+#include "shm.h"
+}
+//#include "../uhd/UHDDevice.h"
+
#include "ipcb210.h"
+//#include "uhdwrap.h"
+//#include "trx_vty.h"
+//#include "Logger.h"
+//#include "Threads.h"
+//#include "Utils.h"
+
+#if 0
+//#include "uhdwrap.h"
+//extern uhd_wrap *uhd_wrap_dev;
+
+//extern "C" void magicmain(int, char **);
+//char *argv[] = {
+// "magic",
+//};
+//void magicthread()
+//{
+// pthread_setname_np(pthread_self(), "magicthread");
+// magicmain(1, argv);
+//}
+#endif
+template <typename... Args> IPC_b210::IPC_b210(Args... args) : IPCDevice(args...)
+{
+#if 0
+ // t = new std::thread(magicthread);
+ // // give the thread some time to start and set up
+ // std::this_thread::sleep_for(std::chrono::seconds(1));
+#endif
+}
+
+IPC_b210::~IPC_b210()
+{
+ //gshutdown = 1;
+ //t->join();
+}
+
+#if 0
+
+bool IPC_b210::start()
+{
+ return uhd_wrap_dev->start();
+}
+
+/** Returns the starting write Timestamp*/
+TIMESTAMP IPC_b210::initialWriteTimestamp(void)
+{
+ return uhd_wrap_dev->initialWriteTimestamp();
+}
+
+/** Returns the starting read Timestamp*/
+TIMESTAMP IPC_b210::initialReadTimestamp(void)
+{
+ return uhd_wrap_dev->initialReadTimestamp();
+}
+
+
+//// NOTE: Assumes sequential reads
+int IPC_b210::readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun)
+{
+#if 0
+ return uhd_wrap_dev->readSamples(bufs, len, overrun, timestamp, underrun);
+#else
+ int rc, num_smpls, expect_smpls;
+ ssize_t avail_smpls;
+ TIMESTAMP expect_timestamp, actual_timestamp;
+ unsigned int i;
+
+ if (bufs.size() != chans) {
+ LOGC(DDEV, ERROR) << "Invalid channel combination " << bufs.size();
+ return -1;
+ }
+
+ *overrun = false;
+ *underrun = false;
+
+ timestamp += uhd_wrap_dev->getTimingOffset();
+
+ /* Check that timestamp is valid */
+ rc = rx_buffers[0]->avail_smpls(timestamp);
+ if (rc < 0) {
+ LOGC(DDEV, ERROR) << rx_buffers[0]->str_code(rc);
+ LOGC(DDEV, ERROR) << rx_buffers[0]->str_status(timestamp);
+ return 0;
+ }
+
+ for (i = 0; i < chans; i++) {
+ /* Receive samples from HW until we have enough */
+ while ((avail_smpls = rx_buffers[i]->avail_smpls(timestamp)) < len) {
+ uint64_t recv_timestamp = 0;
+
+ num_smpls = uhd_wrap_dev->wrap_read((TIMESTAMP *)&recv_timestamp);
+ // memcpy(bufs[i], &uhd_wrap_dev->wrap_buffs[i].front(), num_smpls * 4);
+
+ expect_timestamp = timestamp + avail_smpls;
+
+ LOGCHAN(i, DDEV, DEBUG)
+ "Received timestamp = " << (TIMESTAMP)recv_timestamp << " (" << num_smpls << ")";
+
+ expect_smpls = len - avail_smpls;
+ // if (expect_smpls != num_smpls)
+ // LOGCHAN(i, DDEV, NOTICE)
+ // << "Unexpected recv buffer len: expect " << expect_smpls << " got " << num_smpls
+ // << ", diff=" << expect_smpls - num_smpls;
+
+ //expect_timestamp = timestamp + avail_smpls;
+ if (expect_timestamp != (TIMESTAMP)recv_timestamp)
+ LOGCHAN(i, DDEV, ERROR)
+ << "Unexpected recv buffer timestamp: expect " << expect_timestamp << " got "
+ << recv_timestamp << ", diff=" << recv_timestamp - expect_timestamp;
+
+ rc = rx_buffers[i]->write(&uhd_wrap_dev->wrap_buffs[i].front(), num_smpls,
+ (TIMESTAMP)recv_timestamp);
+ if (rc < 0) {
+ LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc);
+ LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
+ if (rc != smpl_buf::ERROR_OVERFLOW)
+ return 0;
+ }
+ }
+ }
+
+ /* We have enough samples */
+ for (size_t i = 0; i < rx_buffers.size(); i++) {
+ rc = rx_buffers[i]->read(bufs[i], len, timestamp);
+ if ((rc < 0) || (rc != len)) {
+ LOGCHAN(i, DDEV, ERROR) << rx_buffers[i]->str_code(rc) << ". "
+ << rx_buffers[i]->str_status(timestamp) << ", (len=" << len << ")";
+ return 0;
+ }
+ }
+
+ return len;
+#endif
+}
+#endif
+
+#if 0
+int IPC_b210::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, unsigned long long timestamp)
+{
+ return uhd_wrap_dev->writeSamples(bufs, len, underrun, timestamp);
+}
+#endif
+//bool IPC_b210::updateAlignment(TIMESTAMP timestamp)
+//{
+// return drvtest::dev->updateAlignment(timestamp);
+//}
-#include "trx_vty.h"
-#include "Logger.h"
-#include "Threads.h"
-#include "Utils.h"
-#include "IPCDevice.h"
+//double IPC_b210::setTxGain(double dB, size_t chan)
+//{
+// auto v = IPCDevice::setTxGain(dB, chan);
+// return uhd_wrap_dev->setTxGain(v, chan);
+//}
+//double IPC_b210::setRxGain(double dB, size_t chan)
+//{
+// auto v = IPCDevice::setRxGain(dB, chan);
+// return uhd_wrap_dev->setRxGain(v, chan);
+//}
+//bool IPC_b210::stop()
+//{
+// return uhd_wrap_dev->stop();
+//}
+//bool IPC_b210::flush_recv(size_t num_pkts)
+//{
+// return true; //drvtest::dev->flush_recv(num_pkts);
+//}
-RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
- InterfaceType iface, size_t chans, double lo_offset,
- const std::vector < std::string > &tx_paths,
- const std::vector < std::string > &rx_paths)
+RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps, InterfaceType iface, size_t chans, double lo_offset,
+ const std::vector<std::string> &tx_paths, const std::vector<std::string> &rx_paths)
{
if (tx_sps != rx_sps) {
LOGC(DDEV, ERROR) << "IPC Requires tx_sps == rx_sps";
diff --git a/Transceiver52M/device/ipc/ipcb210.h b/Transceiver52M/device/ipc/ipcb210.h
index fbcf1da..ae0f169 100644
--- a/Transceiver52M/device/ipc/ipcb210.h
+++ b/Transceiver52M/device/ipc/ipcb210.h
@@ -1,24 +1,36 @@
#ifndef IPC_B210_H
#define IPC_B210_H
-#include "magicwrap.h"
+#include <thread>
+//#include "magicwrap.h"
#include "IPCDevice.h"
-#include "../uhd/UHDDevice.h"
+//#include "../uhd/UHDDevice.h"
+class IPC_b210 : public IPCDevice {
+ // std::thread *t;
+ // bool flush_recv(size_t num_pkts) override;
+ public:
+ template <typename... Args> IPC_b210(Args... args);
+ virtual ~IPC_b210();
+ // void ipc_sock_close() override {};
+#if 0
+ int readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp,
+ bool *underrun) override;
+ TIMESTAMP initialWriteTimestamp() override;
+ TIMESTAMP initialReadTimestamp() override;
+ bool start() override;
+#endif
-class IPC_b210 : public IPCDevice {
- magicwrap m;
- public:
- template<typename... Args>
- IPC_b210(Args... args): IPCDevice(args...){
- //drvtest::main(0,0);
- }
- virtual ~IPC_b210() {};
+#if 0
+ int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, unsigned long long timestamp) override;
+ bool updateAlignment(TIMESTAMP timestamp) override;
+#endif
+ // double setTxGain(double dB, size_t chan) override;
+ // double setRxGain(double dB, size_t chan) override;
- int foo(){return 32;}
-// void ipc_sock_close() override {};
+ // bool stop() override;
};
#endif // IPC_B210_H
diff --git a/Transceiver52M/device/ipc/magicwrap.cpp b/Transceiver52M/device/ipc/magicwrap.cpp
deleted file mode 100644
index bc4eb26..0000000
--- a/Transceiver52M/device/ipc/magicwrap.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//has to come first outside of NS, or wrapping of c headers fails due to wrong order
-#include <cstdlib>
-#include <chrono>
-#include "magicwrap.h"
-
-namespace drvtest
-{
-extern "C" {
-#define IPCMAGIC
-#include "ipc-driver-test.c"
-}
-} // namespace drvtest
-
-char *argv[] = { { "magic" } };
-magicwrap::magicwrap()
-{
- t = new std::thread([] { drvtest::magicmain(1, argv); });
- // give the thread some time to start and set up
- std::this_thread::sleep_for(std::chrono::seconds(1));
-}
diff --git a/Transceiver52M/device/ipc/magicwrap.h b/Transceiver52M/device/ipc/magicwrap.h
deleted file mode 100644
index 2aa6d23..0000000
--- a/Transceiver52M/device/ipc/magicwrap.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef MAGICWRAP_H
-#define MAGICWRAP_H
-
-#include <thread>
-
-
-class magicwrap
-{
- std::thread* t;
-public:
- magicwrap();
-};
-
-#endif // MAGICWRAP_H
diff --git a/Transceiver52M/device/ipc/shm.c b/Transceiver52M/device/ipc/shm.c
index 6b16f8d..50fcd93 100644
--- a/Transceiver52M/device/ipc/shm.c
+++ b/Transceiver52M/device/ipc/shm.c
@@ -6,117 +6,146 @@
#include "shm.h"
+//#define ENCDECDEBUG
+
/* Convert offsets to pointers */
-struct ipc_shm_stream *ipc_shm_decode_stream(void *tall_ctx, struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_stream *stream_raw)
+struct ipc_shm_stream *ipc_shm_decode_stream(void *tall_ctx, struct ipc_shm_raw_region *root_raw,
+ struct ipc_shm_raw_stream *stream_raw)
{
- unsigned int i;
- struct ipc_shm_stream *stream;
- stream = talloc_zero(tall_ctx, struct ipc_shm_stream);
- stream = talloc_zero_size(tall_ctx, sizeof(struct ipc_shm_stream) +
- sizeof(struct ipc_shm_raw_smpl_buf *) * stream_raw->num_buffers);
- if (!stream)
- return NULL;
- stream->num_buffers = stream_raw->num_buffers;
- stream->buffer_size = stream_raw->buffer_size;
- stream->raw = stream_raw;
- for (i = 0; i < stream->num_buffers; i++) {
- fprintf(stderr, "decode: smpl_buf %d at offset %u\n", i, stream_raw->buffer_offset[i]);
- stream->buffers[i] = (struct ipc_shm_raw_smpl_buf *)(((uint8_t*)root_raw) + stream_raw->buffer_offset[i]);
- }
- return stream;
+ unsigned int i;
+ struct ipc_shm_stream *stream;
+ stream = talloc_zero(tall_ctx, struct ipc_shm_stream);
+ stream = talloc_zero_size(tall_ctx, sizeof(struct ipc_shm_stream) +
+ sizeof(struct ipc_shm_raw_smpl_buf *) * stream_raw->num_buffers);
+ if (!stream)
+ return NULL;
+ stream->num_buffers = stream_raw->num_buffers;
+ stream->buffer_size = stream_raw->buffer_size;
+ stream->raw = stream_raw;
+ for (i = 0; i < stream->num_buffers; i++) {
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "decode: smpl_buf %d at offset %u\n", i, stream_raw->buffer_offset[i]);
+#endif
+ stream->buffers[i] =
+ (struct ipc_shm_raw_smpl_buf *)(((uint8_t *)root_raw) + stream_raw->buffer_offset[i]);
+ }
+ return stream;
}
-struct ipc_shm_channel *ipc_shm_decode_channel(void *tall_ctx, struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_channel *chan_raw)
+struct ipc_shm_channel *ipc_shm_decode_channel(void *tall_ctx, struct ipc_shm_raw_region *root_raw,
+ struct ipc_shm_raw_channel *chan_raw)
{
- struct ipc_shm_channel *chan;
- chan = talloc_zero(tall_ctx, struct ipc_shm_channel);
- if (!chan)
- return NULL;
- fprintf(stderr, "decode: streams at offset %u and %u\n", chan_raw->dl_buf_offset, chan_raw->ul_buf_offset);
- chan->dl_stream = ipc_shm_decode_stream(chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t*)root_raw) + chan_raw->dl_buf_offset));
- chan->ul_stream = ipc_shm_decode_stream(chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t*)root_raw) + chan_raw->ul_buf_offset));
- return chan;
+ struct ipc_shm_channel *chan;
+ chan = talloc_zero(tall_ctx, struct ipc_shm_channel);
+ if (!chan)
+ return NULL;
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "decode: streams at offset %u and %u\n", chan_raw->dl_buf_offset, chan_raw->ul_buf_offset);
+#endif
+ chan->dl_stream = ipc_shm_decode_stream(
+ chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->dl_buf_offset));
+ chan->ul_stream = ipc_shm_decode_stream(
+ chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->ul_buf_offset));
+ return chan;
}
struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_region *root_raw)
{
- unsigned int i;
- struct ipc_shm_region *root;
- root = talloc_zero_size(tall_ctx, sizeof(struct ipc_shm_region) +
- sizeof(struct ipc_shm_channel*) * root_raw->num_chans);
+ unsigned int i;
+ struct ipc_shm_region *root;
+ root = talloc_zero_size(tall_ctx,
+ sizeof(struct ipc_shm_region) + sizeof(struct ipc_shm_channel *) * root_raw->num_chans);
if (!root)
return NULL;
- root->num_chans = root_raw->num_chans;
- for (i = 0; i < root->num_chans; i++) {
- fprintf(stderr, "decode: channel %d at offset %u\n", i, root_raw->chan_offset[i]);
- root->channels[i] = ipc_shm_decode_channel(root, root_raw, (struct ipc_shm_raw_channel *)(((uint8_t*)root_raw) + root_raw->chan_offset[i]));
- }
- return root;
+ root->num_chans = root_raw->num_chans;
+ for (i = 0; i < root->num_chans; i++) {
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "decode: channel %d at offset %u\n", i, root_raw->chan_offset[i]);
+#endif
+ root->channels[i] = ipc_shm_decode_channel(
+ root, root_raw,
+ (struct ipc_shm_raw_channel *)(((uint8_t *)root_raw) + root_raw->chan_offset[i]));
+ }
+ return root;
}
-unsigned int ipc_shm_encode_smpl_buf(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_smpl_buf *smpl_buf_raw, uint32_t buffer_size)
+unsigned int ipc_shm_encode_smpl_buf(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_smpl_buf *smpl_buf_raw,
+ uint32_t buffer_size)
{
- uint8_t* start = (uint8_t*)smpl_buf_raw;
- unsigned int offset = sizeof(struct ipc_shm_raw_smpl_buf);
-
- fprintf(stderr, "encode: smpl_buf at offset %lu\n", (start - (uint8_t*)root_raw));
-
- offset += buffer_size * sizeof(uint16_t); /* samples */
- return offset;
+ uint8_t *start = (uint8_t *)smpl_buf_raw;
+ unsigned int offset = sizeof(struct ipc_shm_raw_smpl_buf);
+ offset += (((uintptr_t)offset + 7) & ~0x07ULL);
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "encode: smpl_buf at offset %lu\n", (start - (uint8_t *)root_raw));
+#endif
+ offset += buffer_size * sizeof(uint16_t) * 2; /* samples */
+ return offset;
}
-unsigned int ipc_shm_encode_stream(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_stream *stream_raw, uint32_t num_buffers, uint32_t buffer_size)
+unsigned int ipc_shm_encode_stream(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_stream *stream_raw,
+ uint32_t num_buffers, uint32_t buffer_size)
{
- unsigned int i;
- ptrdiff_t start = (ptrdiff_t)stream_raw;
- unsigned int offset = sizeof(struct ipc_shm_raw_stream) + sizeof(uint32_t)*num_buffers;
-
- fprintf(stderr, "encode: stream at offset %lu\n", (start - (ptrdiff_t)root_raw));
-
- if (root_raw) {
- stream_raw->num_buffers = num_buffers;
- stream_raw->buffer_size = buffer_size;
- stream_raw->read_next = 0;
- stream_raw->write_next = 0;
- }
- for (i = 0; i < num_buffers; i++) {
- if (root_raw)
- stream_raw->buffer_offset[i] = (start + offset - (ptrdiff_t)root_raw);
- offset += ipc_shm_encode_smpl_buf(root_raw, (struct ipc_shm_raw_smpl_buf *)(start + offset), buffer_size);
- }
- return offset;
+ unsigned int i;
+ ptrdiff_t start = (ptrdiff_t)stream_raw;
+ unsigned int offset = sizeof(struct ipc_shm_raw_stream) + sizeof(uint32_t) * num_buffers;
+ offset += (((uintptr_t)offset + 7) & ~0x07ULL);
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "encode: stream at offset %lu\n", (start - (ptrdiff_t)root_raw));
+#endif
+ if (root_raw) {
+ stream_raw->num_buffers = num_buffers;
+ stream_raw->buffer_size = buffer_size;
+ stream_raw->read_next = 0;
+ stream_raw->write_next = 0;
+ }
+ for (i = 0; i < num_buffers; i++) {
+ if (root_raw)
+ stream_raw->buffer_offset[i] = (start + offset - (ptrdiff_t)root_raw);
+ offset +=
+ ipc_shm_encode_smpl_buf(root_raw, (struct ipc_shm_raw_smpl_buf *)(start + offset), buffer_size);
+ }
+ return offset;
}
-unsigned int ipc_shm_encode_channel(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_channel *chan_raw, uint32_t num_buffers, uint32_t buffer_size)
+unsigned int ipc_shm_encode_channel(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_channel *chan_raw,
+ uint32_t num_buffers, uint32_t buffer_size)
{
- uint8_t* start = (uint8_t*)chan_raw;
- unsigned int offset = sizeof(struct ipc_shm_raw_channel);
-
- fprintf(stderr, "encode: channel at offset %lu\n", (start - (uint8_t*)root_raw));
-
- if (root_raw)
- chan_raw->dl_buf_offset = (start + offset - (uint8_t*)root_raw);
- offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers, buffer_size);
- if (root_raw)
- chan_raw->ul_buf_offset = (start + offset - (uint8_t*)root_raw);
- offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers, buffer_size);
- return offset;
+ uint8_t *start = (uint8_t *)chan_raw;
+ unsigned int offset = sizeof(struct ipc_shm_raw_channel);
+ offset += (((uintptr_t)offset + 7) & ~0x07ULL);
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "encode: channel at offset %lu\n", (start - (uint8_t *)root_raw));
+#endif
+ if (root_raw)
+ chan_raw->dl_buf_offset = (start + offset - (uint8_t *)root_raw);
+ offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers,
+ buffer_size);
+ if (root_raw)
+ chan_raw->ul_buf_offset = (start + offset - (uint8_t *)root_raw);
+ offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers,
+ buffer_size);
+ return offset;
}
/* if root_raw is NULL, then do a dry run, aka only calculate final offset */
-unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers, uint32_t buffer_size)
+unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers,
+ uint32_t buffer_size)
{
- unsigned i;
- ptrdiff_t start = (ptrdiff_t)root_raw;
- unsigned int offset = sizeof(struct ipc_shm_raw_region) + sizeof(uint32_t)*num_chans;
+ unsigned i;
+ uintptr_t start = (uintptr_t)root_raw;
+ unsigned int offset = sizeof(struct ipc_shm_raw_region) + sizeof(uint32_t) * num_chans;
+ offset += (((uintptr_t)offset + 7) & ~0x07ULL);
- if (root_raw)
- root_raw->num_chans = num_chans;
- for (i = 0; i < num_chans; i++) {
- uint32_t ofs = (start + offset - (ptrdiff_t)root_raw);
- if (root_raw)
- root_raw->chan_offset[i] = (start + offset - (ptrdiff_t)root_raw);
- fprintf(stderr, "encode: channel %d chan_offset[i]=%u\n", i, ofs);
- offset += ipc_shm_encode_channel(root_raw, (struct ipc_shm_raw_channel *)(start + offset), num_buffers, buffer_size);
- }
- //TODO: pass maximum size and verify we didn't go through
- return offset;
+ if (root_raw)
+ root_raw->num_chans = num_chans;
+ for (i = 0; i < num_chans; i++) {
+ uint32_t ofs = (start + offset - (uintptr_t)root_raw);
+ if (root_raw)
+ root_raw->chan_offset[i] = (start + offset - (uintptr_t)root_raw);
+#ifdef ENCDECDEBUG
+ fprintf(stderr, "encode: channel %d chan_offset[i]=%u\n", i, ofs);
+#endif
+ offset += ipc_shm_encode_channel(root_raw, (struct ipc_shm_raw_channel *)(start + offset), num_buffers,
+ buffer_size);
+ }
+ //TODO: pass maximum size and verify we didn't go through
+ return offset;
}
diff --git a/Transceiver52M/device/ipc/shm.h b/Transceiver52M/device/ipc/shm.h
index 6565f5b..ddb599e 100644
--- a/Transceiver52M/device/ipc/shm.h
+++ b/Transceiver52M/device/ipc/shm.h
@@ -15,99 +15,64 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
-
-/*
-https://www.softprayog.in/programming/interprocess-communication-using-posix-shared-memory-in-linux
-
-man shm_open: link with -lrt
-Link with -pthread.
-
-#include <sys/mman.h>
-#include <sys/stat.h> // For mode constants
-#include <fcntl.h> // For O_* constants
-#include <semaphore.h>
-
-On start:
-int fd = shm_open(const char *name, int oflag, mode_t mode);
-* name must start with "/" and not contain more slashes.
-* name must be a null-terminted string of up to NAME_MAX (255)
-* oflag: O_CREAT|O_RDWR|O_EXCL
-* mode: check man open
-
-ftruncate(fd, len = sizeof(struct myshamemorystruct) to expand the memory region
-
-shm = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-
-int sem_init(sem_t *&(shm->sem), 1, unsigned int value) == 0;
-
-close(fd); // After a call to mmap(2) the file descriptor may be closed without affecting the memory mapping.
-
-
-On exit:
-int shm_unlink(const char *name);
-
-
-sem_t *sem_open(const char *name, int oflag,
- mode_t mode, unsigned int value);
-* by a name of the form /somename; that is, a null-terminated string of up to NAME_MAX-4 (i.e., 251) characters
- consisting of an initial slash, followed by one or more characters, none of which are slashes.
-
-
-* unamed semaphore: sem_init + sem_destroy
-* Programs using the POSIX semaphores API must be compiled with cc -pthread to link against the real-time library, librt
-*/
+#pragma once
#include <stdint.h>
#include <unistd.h>
#include <limits.h>
+//#include <pthread.h>
+#include <semaphore.h>
/* RAW structures */
struct ipc_shm_raw_smpl_buf {
- uint32_t timestamp;
- uint32_t data_len; /* In samples */
- uint16_t samples[0];
+ uint64_t timestamp;
+ uint32_t data_len; /* In samples */
+ uint16_t samples[0];
};
struct ipc_shm_raw_stream {
- uint32_t num_buffers;
- uint32_t buffer_size; /* In samples */
- uint32_t read_next;
- uint32_t write_next;
- uint32_t buffer_offset[0];
- //struct ipc_shm_smpl_buf buffers[0];
+ pthread_mutex_t lock;
+ pthread_cond_t cf;
+ pthread_cond_t ce;
+ uint32_t num_buffers;
+ uint32_t buffer_size; /* In samples */
+ uint32_t read_next;
+ uint32_t write_next;
+ uint32_t buffer_offset[0];
+ //struct ipc_shm_smpl_buf buffers[0];
};
struct ipc_shm_raw_channel {
- uint32_t dl_buf_offset;
- uint32_t ul_buf_offset;
+ uint32_t dl_buf_offset;
+ uint32_t ul_buf_offset;
};
struct ipc_shm_raw_region {
- uint32_t num_chans;
- uint32_t chan_offset[0];
+ uint32_t num_chans;
+ uint32_t chan_offset[0];
};
-
/* non-raw, Pointer converted structures */
struct ipc_shm_stream {
- uint32_t num_buffers;
- uint32_t buffer_size;
- struct ipc_shm_raw_stream *raw;
- struct ipc_shm_raw_smpl_buf *buffers[0];
+ uint32_t num_buffers;
+ uint32_t buffer_size;
+ volatile struct ipc_shm_raw_stream *raw;
+ volatile struct ipc_shm_raw_smpl_buf *buffers[0];
};
struct ipc_shm_channel {
- struct ipc_shm_stream *dl_stream;
- struct ipc_shm_stream *ul_stream;
+ struct ipc_shm_stream *dl_stream;
+ struct ipc_shm_stream *ul_stream;
};
/* Pointer converted structures */
struct ipc_shm_region {
- uint32_t num_chans;
- struct ipc_shm_channel *channels[0];
+ uint32_t num_chans;
+ struct ipc_shm_channel *channels[0];
};
-unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers, uint32_t buffer_size);
+unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers,
+ uint32_t buffer_size);
struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_region *root_raw);
/****************************************/
/* UNIX SOCKET API */
@@ -121,12 +86,12 @@ struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_
#define IPC_SOCK_API_VERSION 1
/* msg_type */
-#define IPC_IF_MSG_GREETING_REQ 0x00
-#define IPC_IF_MSG_GREETING_CNF 0x01
-#define IPC_IF_MSG_INFO_REQ 0x02
-#define IPC_IF_MSG_INFO_CNF 0x03
-#define IPC_IF_MSG_OPEN_REQ 0x04
-#define IPC_IF_MSG_OPEN_CNF 0x05
+#define IPC_IF_MSG_GREETING_REQ 0x00
+#define IPC_IF_MSG_GREETING_CNF 0x01
+#define IPC_IF_MSG_INFO_REQ 0x02
+#define IPC_IF_MSG_INFO_CNF 0x03
+#define IPC_IF_MSG_OPEN_REQ 0x04
+#define IPC_IF_MSG_OPEN_CNF 0x05
#define MAX_NUM_CHANS 30
#define RF_PATH_NAME_SIZE 25
@@ -136,114 +101,128 @@ struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_
#define FEATURE_MASK_CLOCKREF_INTERNAL (0x1 << 0)
#define FEATURE_MASK_CLOCKREF_EXTERNAL (0x1 << 1)
struct ipc_sk_if_info_chan {
- char tx_path[MAX_NUM_RF_PATHS][RF_PATH_NAME_SIZE];
- char rx_path[MAX_NUM_RF_PATHS][RF_PATH_NAME_SIZE];
-} __attribute__ ((packed));
+ char tx_path[MAX_NUM_RF_PATHS][RF_PATH_NAME_SIZE];
+ char rx_path[MAX_NUM_RF_PATHS][RF_PATH_NAME_SIZE];
+} __attribute__((packed));
struct ipc_sk_if_open_req_chan {
- char tx_path[RF_PATH_NAME_SIZE];
- char rx_path[RF_PATH_NAME_SIZE];
-} __attribute__ ((packed));
+ char tx_path[RF_PATH_NAME_SIZE];
+ char rx_path[RF_PATH_NAME_SIZE];
+} __attribute__((packed));
struct ipc_sk_if_open_cnf_chan {
- char chan_ipc_sk_path[108];
-} __attribute__ ((packed));
+ char chan_ipc_sk_path[108];
+} __attribute__((packed));
struct ipc_sk_if_greeting {
- uint8_t req_version;
-} __attribute__ ((packed));
+ uint8_t req_version;
+} __attribute__((packed));
struct ipc_sk_if_info_req {
- uint8_t spare;
-} __attribute__ ((packed));
+ uint8_t spare;
+} __attribute__((packed));
struct ipc_sk_if_info_cnf {
- uint32_t feature_mask;
- double min_rx_gain;
- double max_rx_gain;
- double min_tx_gain;
- double max_tx_gain;
- double iq_scaling_val;
- uint32_t max_num_chans;
- char dev_desc[200];
- struct ipc_sk_if_info_chan chan_info[0];
-} __attribute__ ((packed));
+ uint32_t feature_mask;
+ double min_rx_gain;
+ double max_rx_gain;
+ double min_tx_gain;
+ double max_tx_gain;
+ double iq_scaling_val_rx;
+ double iq_scaling_val_tx;
+ uint32_t max_num_chans;
+ char dev_desc[200];
+ struct ipc_sk_if_info_chan chan_info[0];
+} __attribute__((packed));
struct ipc_sk_if_open_req {
- uint32_t num_chans;
- uint32_t clockref; /* One of FEATUER_MASK_CLOCKREF_* */
- uint32_t rx_sps;
- uint32_t tx_sps;
- uint32_t bandwidth;
- struct ipc_sk_if_open_req_chan chan_info[0];
-} __attribute__ ((packed));
+ uint32_t num_chans;
+ uint32_t clockref; /* One of FEATUER_MASK_CLOCKREF_* */
+ uint32_t rx_sample_freq_num;
+ uint32_t rx_sample_freq_den;
+ uint32_t tx_sample_freq_num;
+ uint32_t tx_sample_freq_den;
+ uint32_t bandwidth;
+ struct ipc_sk_if_open_req_chan chan_info[0];
+} __attribute__((packed));
struct ipc_sk_if_open_cnf {
- uint8_t return_code;
- char shm_name[SHM_NAME_MAX];
- struct ipc_sk_if_open_cnf_chan chan_info[0];
-} __attribute__ ((packed));
+ uint8_t return_code;
+ uint32_t path_delay;
+ char shm_name[SHM_NAME_MAX];
+ struct ipc_sk_if_open_cnf_chan chan_info[0];
+} __attribute__((packed));
struct ipc_sk_if {
- uint8_t msg_type; /* message type */
- uint8_t spare[2];
+ uint8_t msg_type; /* message type */
+ uint8_t spare[2];
union {
- struct ipc_sk_if_greeting greeting_req;
- struct ipc_sk_if_greeting greeting_cnf;
- struct ipc_sk_if_info_req info_req;
- struct ipc_sk_if_info_cnf info_cnf;
- struct ipc_sk_if_open_req open_req;
- struct ipc_sk_if_open_cnf open_cnf;
+ struct ipc_sk_if_greeting greeting_req;
+ struct ipc_sk_if_greeting greeting_cnf;
+ struct ipc_sk_if_info_req info_req;
+ struct ipc_sk_if_info_cnf info_cnf;
+ struct ipc_sk_if_open_req open_req;
+ struct ipc_sk_if_open_cnf open_cnf;
} u;
-} __attribute__ ((packed));
-
+} __attribute__((packed));
//////////////////
// Channel socket
//////////////////
-#define IPC_IF_MSG_START_REQ 0x00
-#define IPC_IF_MSG_START_CNF 0x01
-#define IPC_IF_MSG_STOP_REQ 0x02
-#define IPC_IF_MSG_STOP_CNF 0x03
-#define IPC_IF_MSG_SETGAIN_REQ 0x04
-#define IPC_IF_MSG_SETGAIN_CNF 0x05
-#define IPC_IF_MSG_SETFREQ_REQ 0x04
-#define IPC_IF_MSG_SETFREQ_CNF 0x05
+#define IPC_IF_CHAN_MSG_OFFSET 50
+#define IPC_IF_MSG_START_REQ IPC_IF_CHAN_MSG_OFFSET + 0x00
+#define IPC_IF_MSG_START_CNF IPC_IF_CHAN_MSG_OFFSET + 0x01
+#define IPC_IF_MSG_STOP_REQ IPC_IF_CHAN_MSG_OFFSET + 0x02
+#define IPC_IF_MSG_STOP_CNF IPC_IF_CHAN_MSG_OFFSET + 0x03
+#define IPC_IF_MSG_SETGAIN_REQ IPC_IF_CHAN_MSG_OFFSET + 0x04
+#define IPC_IF_MSG_SETGAIN_CNF IPC_IF_CHAN_MSG_OFFSET + 0x05
+#define IPC_IF_MSG_SETFREQ_REQ IPC_IF_CHAN_MSG_OFFSET + 0x06
+#define IPC_IF_MSG_SETFREQ_CNF IPC_IF_CHAN_MSG_OFFSET + 0x07
+
+#define IPC_IF_NOTIFY_UNDERFLOW IPC_IF_CHAN_MSG_OFFSET + 0x08
+#define IPC_IF_NOTIFY_OVERFLOW IPC_IF_CHAN_MSG_OFFSET + 0x09
struct ipc_sk_chan_if_op_void {
-} __attribute__ ((packed));
+ // at least one dummy byte, to allow c/c++ compatibility
+ uint8_t dummy;
+} __attribute__((packed));
struct ipc_sk_chan_if_op_rc {
- uint8_t return_code;
-} __attribute__ ((packed));
+ uint8_t return_code;
+} __attribute__((packed));
struct ipc_sk_chan_if_gain {
- double gain;
- uint8_t is_tx;
-} __attribute__ ((packed));
+ double gain;
+ uint8_t is_tx;
+} __attribute__((packed));
struct ipc_sk_chan_if_freq_req {
- double freq;
- uint8_t is_tx;
-} __attribute__ ((packed));
+ double freq;
+ uint8_t is_tx;
+} __attribute__((packed));
struct ipc_sk_chan_if_freq_cnf {
- uint8_t return_code;
-} __attribute__ ((packed));
+ uint8_t return_code;
+} __attribute__((packed));
+
+struct ipc_sk_chan_if_notfiy {
+ uint8_t dummy;
+} __attribute__((packed));
struct ipc_sk_chan_if {
- uint8_t msg_type; /* message type */
- uint8_t spare[2];
+ uint8_t msg_type; /* message type */
+ uint8_t spare[2];
union {
- struct ipc_sk_chan_if_op_void start_req;
- struct ipc_sk_chan_if_op_rc start_cnf;
- struct ipc_sk_chan_if_op_void stop_req;
- struct ipc_sk_chan_if_op_rc stop_cnf;
- struct ipc_sk_chan_if_gain set_gain_req;
- struct ipc_sk_chan_if_gain set_gain_cnf;
- struct ipc_sk_chan_if_freq_req set_freq_req;
- struct ipc_sk_chan_if_freq_cnf set_freq_cnf;
+ struct ipc_sk_chan_if_op_void start_req;
+ struct ipc_sk_chan_if_op_rc start_cnf;
+ struct ipc_sk_chan_if_op_void stop_req;
+ struct ipc_sk_chan_if_op_rc stop_cnf;
+ struct ipc_sk_chan_if_gain set_gain_req;
+ struct ipc_sk_chan_if_gain set_gain_cnf;
+ struct ipc_sk_chan_if_freq_req set_freq_req;
+ struct ipc_sk_chan_if_freq_cnf set_freq_cnf;
+ struct ipc_sk_chan_if_notfiy notify;
} u;
-} __attribute__ ((packed));
+} __attribute__((packed));
diff --git a/Transceiver52M/device/ipc/uhdwrap.cpp b/Transceiver52M/device/ipc/uhdwrap.cpp
new file mode 100644
index 0000000..737b2be
--- /dev/null
+++ b/Transceiver52M/device/ipc/uhdwrap.cpp
@@ -0,0 +1,231 @@
+//has to come first outside of NS, or wrapping of c headers fails due to wrong order
+extern "C" {
+#include <osmocom/core/application.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+
+#include "shm.h"
+#include "ipc_shm.h"
+#include "ipc-driver-test.h"
+}
+#include "../uhd/UHDDevice.h"
+#include "uhdwrap.h"
+
+#include "trx_vty.h"
+#include "Logger.h"
+#include "Threads.h"
+#include "Utils.h"
+
+int uhd_wrap::open(const std::string &args, int ref, bool swap_channels)
+{
+ int rv = uhd_device::open(args, ref, swap_channels);
+ samps_per_buff_rx = rx_stream->get_max_num_samps();
+ samps_per_buff_tx = tx_stream->get_max_num_samps();
+ channel_count = usrp_dev->get_rx_num_channels();
+
+ wrap_rx_buffs = std::vector<std::vector<short> >(channel_count, std::vector<short>(2 * samps_per_buff_rx));
+ for (size_t i = 0; i < wrap_rx_buffs.size(); i++)
+ wrap_rx_buf_ptrs.push_back(&wrap_rx_buffs[i].front());
+
+ wrap_tx_buffs = std::vector<std::vector<short> >(channel_count, std::vector<short>(2 * 5000));
+ for (size_t i = 0; i < wrap_tx_buffs.size(); i++)
+ wrap_tx_buf_ptrs.push_back(&wrap_tx_buffs[i].front());
+
+ return rv;
+}
+
+uhd_wrap::~uhd_wrap()
+{
+ // drvtest::gshutdown = 1;
+ //t->join();
+}
+
+size_t uhd_wrap::bufsizerx()
+{
+ return samps_per_buff_rx;
+}
+
+size_t uhd_wrap::bufsizetx()
+{
+ return samps_per_buff_tx;
+}
+
+int uhd_wrap::chancount()
+{
+ return channel_count;
+}
+
+int uhd_wrap::wrap_read(TIMESTAMP *timestamp)
+{
+ uhd::rx_metadata_t md;
+ size_t num_rx_samps = rx_stream->recv(wrap_rx_buf_ptrs, samps_per_buff_rx, md, 0.1, true);
+ *timestamp = md.time_spec.to_ticks(rx_rate);
+ return num_rx_samps; //uhd_device::readSamples(bufs, len, overrun, timestamp, underrun);
+}
+
+extern "C" void *uhdwrap_open(struct ipc_sk_if_open_req *open_req)
+{
+ unsigned int rx_sps, tx_sps;
+
+ /* FIXME: dev arg string* */
+ /* FIXME: rx frontend bw? */
+ /* FIXME: tx frontend bw? */
+ ReferenceType cref;
+ switch (open_req->clockref) {
+ case FEATURE_MASK_CLOCKREF_EXTERNAL:
+ cref = ReferenceType::REF_EXTERNAL;
+ break;
+ case FEATURE_MASK_CLOCKREF_INTERNAL:
+ default:
+ cref = ReferenceType::REF_INTERNAL;
+ break;
+ }
+
+ std::vector<std::string> tx_paths;
+ std::vector<std::string> rx_paths;
+ for (unsigned int i = 0; i < open_req->num_chans; i++) {
+ tx_paths.push_back(open_req->chan_info[i].tx_path);
+ rx_paths.push_back(open_req->chan_info[i].rx_path);
+ }
+
+ rx_sps = open_req->rx_sample_freq_num / open_req->rx_sample_freq_den;
+ tx_sps = open_req->tx_sample_freq_num / open_req->tx_sample_freq_den;
+ uhd_wrap *uhd_wrap_dev =
+ new uhd_wrap(tx_sps, rx_sps, RadioDevice::NORMAL, open_req->num_chans, 0.0, tx_paths, rx_paths);
+ uhd_wrap_dev->open("", cref, false);
+
+ return uhd_wrap_dev;
+}
+extern "C" int32_t uhdwrap_get_bufsizerx(void *dev)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+ return d->bufsizerx();
+}
+
+extern "C" int32_t uhdwrap_get_timingoffset(void *dev)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+ return d->getTimingOffset();
+}
+
+extern "C" int32_t uhdwrap_read(void *dev, uint32_t num_chans)
+{
+ TIMESTAMP t;
+ uhd_wrap *d = (uhd_wrap *)dev;
+
+ if (num_chans != d->wrap_rx_buf_ptrs.size()) {
+ perror("omg chans?!");
+ }
+
+ int32_t read = d->wrap_read(&t);
+ if (read < 0)
+ return read;
+
+ for (uint32_t i = 0; i < num_chans; i++) {
+ ipc_shm_enqueue(ios_rx_from_device[i], t, read, (uint16_t *)&d->wrap_rx_buffs[i].front());
+ }
+ return read;
+}
+
+extern "C" int32_t uhdwrap_write(void *dev, uint32_t num_chans, bool *underrun)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+
+ uint64_t timestamp;
+ int32_t len;
+ for (uint32_t i = 0; i < num_chans; i++) {
+ len = ipc_shm_read(ios_tx_to_device[i], (uint16_t *)&d->wrap_tx_buffs[i].front(), 5000, &timestamp, 1);
+ if (len < 0)
+ return 0;
+ }
+
+ return d->writeSamples(d->wrap_tx_buf_ptrs, len, underrun, timestamp);
+}
+
+extern "C" double uhdwrap_set_freq(void *dev, double f, size_t chan, bool for_tx)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+ if (for_tx)
+ return d->setTxFreq(f, chan);
+ else
+ return d->setRxFreq(f, chan);
+}
+
+extern "C" double uhdwrap_set_gain(void *dev, double f, size_t chan, bool for_tx)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+ if (for_tx)
+ return d->setTxGain(f, chan);
+ else
+ return d->setRxGain(f, chan);
+}
+
+extern "C" int32_t uhdwrap_start(void *dev, int chan)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+ return d->start();
+}
+
+extern "C" int32_t uhdwrap_stop(void *dev, int chan)
+{
+ uhd_wrap *d = (uhd_wrap *)dev;
+ return d->stop();
+}
+
+extern "C" void uhdwrap_fill_info_cnf(struct ipc_sk_if *ipc_prim)
+{
+ struct ipc_sk_if_info_chan *chan_info;
+
+ uhd::device_addr_t args("");
+ uhd::device_addrs_t devs_found = uhd::device::find(args);
+ if (devs_found.size() < 1) {
+ std::cout << "\n No device found!";
+ exit(0);
+ }
+
+ uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(devs_found[0]);
+ auto rxchans = usrp->get_rx_num_channels();
+ auto txchans = usrp->get_tx_num_channels();
+ auto rx_range = usrp->get_rx_gain_range();
+ auto tx_range = usrp->get_tx_gain_range();
+
+ //auto nboards = usrp->get_num_mboards();
+ auto refs = usrp->get_clock_sources(0);
+ auto devname = usrp->get_mboard_name(0);
+
+ ipc_prim->u.info_cnf.feature_mask = 0;
+ if (std::find(refs.begin(), refs.end(), "internal") != refs.end())
+ ipc_prim->u.info_cnf.feature_mask |= FEATURE_MASK_CLOCKREF_INTERNAL;
+ if (std::find(refs.begin(), refs.end(), "external") != refs.end())
+ ipc_prim->u.info_cnf.feature_mask |= FEATURE_MASK_CLOCKREF_EXTERNAL;
+
+ // at least one duplex channel
+ auto num_chans = rxchans == txchans ? txchans : 1;
+
+ ipc_prim->u.info_cnf.min_rx_gain = rx_range.start();
+ ipc_prim->u.info_cnf.max_rx_gain = rx_range.stop();
+ ipc_prim->u.info_cnf.min_tx_gain = tx_range.start();
+ ipc_prim->u.info_cnf.max_tx_gain = tx_range.stop();
+ ipc_prim->u.info_cnf.iq_scaling_val_rx = 0.3;
+ ipc_prim->u.info_cnf.iq_scaling_val_tx = 1;
+ ipc_prim->u.info_cnf.max_num_chans = num_chans;
+ OSMO_STRLCPY_ARRAY(ipc_prim->u.info_cnf.dev_desc, devname.c_str());
+ chan_info = ipc_prim->u.info_cnf.chan_info;
+ for (unsigned int i = 0; i < ipc_prim->u.info_cnf.max_num_chans; i++) {
+ auto rxant = usrp->get_rx_antennas(i);
+ auto txant = usrp->get_tx_antennas(i);
+ for (unsigned int j = 0; j < txant.size(); j++) {
+ OSMO_STRLCPY_ARRAY(chan_info->tx_path[j], txant[j].c_str());
+ }
+ for (unsigned int j = 0; j < rxant.size(); j++) {
+ OSMO_STRLCPY_ARRAY(chan_info->rx_path[j], rxant[j].c_str());
+ }
+ chan_info++;
+ }
+}
diff --git a/Transceiver52M/device/ipc/uhdwrap.h b/Transceiver52M/device/ipc/uhdwrap.h
new file mode 100644
index 0000000..44999a0
--- /dev/null
+++ b/Transceiver52M/device/ipc/uhdwrap.h
@@ -0,0 +1,66 @@
+#ifndef IPC_UHDWRAP_H
+#define IPC_UHDWRAP_H
+
+#ifdef __cplusplus
+#include "../uhd/UHDDevice.h"
+
+class uhd_wrap : public uhd_device {
+ public:
+ // std::thread *t;
+ size_t samps_per_buff_rx;
+ size_t samps_per_buff_tx;
+ int channel_count;
+
+ std::vector<std::vector<short> > wrap_rx_buffs;
+ std::vector<std::vector<short> > wrap_tx_buffs;
+ std::vector<short *> wrap_rx_buf_ptrs;
+ std::vector<short *> wrap_tx_buf_ptrs;
+
+ template <typename... Args> uhd_wrap(Args... args) : uhd_device(args...)
+ {
+ // t = new std::thread(magicthread);
+ // give the thread some time to start and set up
+ // std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+ virtual ~uhd_wrap();
+
+ // void ipc_sock_close() override {};
+ int wrap_read(TIMESTAMP *timestamp);
+ virtual int open(const std::string &args, int ref, bool swap_channels) override;
+
+ // bool start() override;
+ // bool stop() override;
+ // virtual TIMESTAMP initialWriteTimestamp() override;
+ // virtual TIMESTAMP initialReadTimestamp() override;
+
+ int getTimingOffset()
+ {
+ return ts_offset;
+ }
+ size_t bufsizerx();
+ size_t bufsizetx();
+ int chancount();
+};
+#else
+void *uhdwrap_open(struct ipc_sk_if_open_req *open_req);
+
+int32_t uhdwrap_get_bufsizerx(void *dev);
+
+int32_t uhdwrap_get_timingoffset(void *dev);
+
+int32_t uhdwrap_read(void *dev, uint32_t num_chans);
+
+int32_t uhdwrap_write(void *dev, uint32_t num_chans, bool *underrun);
+
+double uhdwrap_set_freq(void *dev, double f, size_t chan, bool for_tx);
+
+double uhdwrap_set_gain(void *dev, double f, size_t chan, bool for_tx);
+
+int32_t uhdwrap_start(void *dev, int chan);
+
+int32_t uhdwrap_stop(void *dev, int chan);
+
+void uhdwrap_fill_info_cnf(struct ipc_sk_if *ipc_prim);
+#endif
+
+#endif // IPC_B210_H
diff --git a/Transceiver52M/device/uhd/UHDDevice.cpp b/Transceiver52M/device/uhd/UHDDevice.cpp
index ad56250..66e6cfa 100644
--- a/Transceiver52M/device/uhd/UHDDevice.cpp
+++ b/Transceiver52M/device/uhd/UHDDevice.cpp
@@ -1202,6 +1202,7 @@ std::string uhd_device::str_code(uhd::async_metadata_t metadata)
return ost.str();
}
+#ifndef IPCMAGIC
RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
InterfaceType iface, size_t chans, double lo_offset,
const std::vector<std::string>& tx_paths,
@@ -1209,3 +1210,4 @@ RadioDevice *RadioDevice::make(size_t tx_sps, size_t rx_sps,
{
return new uhd_device(tx_sps, rx_sps, iface, chans, lo_offset, tx_paths, rx_paths);
}
+#endif
diff --git a/Transceiver52M/device/uhd/UHDDevice.h b/Transceiver52M/device/uhd/UHDDevice.h
index 1e66246..de29fc9 100644
--- a/Transceiver52M/device/uhd/UHDDevice.h
+++ b/Transceiver52M/device/uhd/UHDDevice.h
@@ -127,7 +127,7 @@ public:
ERROR_UNHANDLED = -4,
};
-private:
+protected:
uhd::usrp::multi_usrp::sptr usrp_dev;
uhd::tx_streamer::sptr tx_stream;
uhd::rx_streamer::sptr rx_stream;