/* * Copyright 2020 sysmocom - s.f.m.c. GmbH * Author: Eric Wild * * 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. */ extern "C" { #include #include #include #include #include #include #include #include #include #include "shm.h" #include "ipc_shm.h" #include "ipc-driver-test.h" } #include "../uhd/UHDDevice.h" #include "uhdwrap.h" #include "Logger.h" #include "Threads.h" #include "Utils.h" // no vty source for cfg params here, so we have to build our own static struct trx_cfg actual_cfg = {}; int uhd_wrap::open() { int rv = uhd_device::open(); 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 >(channel_count, std::vector(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 >(channel_count, std::vector(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) { actual_cfg.num_chans = open_req->num_chans; actual_cfg.swap_channels = false; /* FIXME: this is actually the sps value, not the sample rate! * sample rate is looked up according to the sps rate by uhd backend */ actual_cfg.rx_sps = open_req->rx_sample_freq_num / open_req->rx_sample_freq_den; actual_cfg.tx_sps = open_req->tx_sample_freq_num / open_req->tx_sample_freq_den; /* FIXME: dev arg string* */ /* FIXME: rx frontend bw? */ /* FIXME: tx frontend bw? */ switch (open_req->clockref) { case FEATURE_MASK_CLOCKREF_EXTERNAL: actual_cfg.clock_ref = ReferenceType::REF_EXTERNAL; break; case FEATURE_MASK_CLOCKREF_INTERNAL: default: actual_cfg.clock_ref = ReferenceType::REF_INTERNAL; break; } for (unsigned int i = 0; i < open_req->num_chans; i++) { actual_cfg.chans[i].rx_path = open_req->chan_info[i].tx_path; actual_cfg.chans[i].tx_path = open_req->chan_info[i].rx_path; } uhd_wrap *uhd_wrap_dev = new uhd_wrap(RadioDevice::NORMAL, &actual_cfg); uhd_wrap_dev->open(); 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); /* multi channel rx on b210 will return 0 due to alignment adventures, do not put 0 samples into a ipc buffer... */ 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 = -1; 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, ×tamp, 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" double uhdwrap_set_txatt(void *dev, double a, size_t chan) { uhd_wrap *d = (uhd_wrap *)dev; return d->setPowerAttenuation(a, 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.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->min_rx_gain = rx_range.start(); chan_info->max_rx_gain = rx_range.stop(); chan_info->min_tx_gain = tx_range.start(); chan_info->max_tx_gain = tx_range.stop(); chan_info->nominal_tx_power = 7.5; // FIXME: would require uhd dev + freq info chan_info++; } }