mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
10 KiB
C++
365 lines
10 KiB
C++
/**
|
|
*
|
|
* \section COPYRIGHT
|
|
*
|
|
* Copyright 2013-2015 Software Radio Systems Limited
|
|
*
|
|
* \section LICENSE
|
|
*
|
|
* This file is part of the srsUE library.
|
|
*
|
|
* srsUE is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* srsUE is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* A copy of the GNU Affero General Public License can be found in
|
|
* the LICENSE file in the top-level directory of this distribution
|
|
* and at http://www.gnu.org/licenses/.
|
|
*
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include "srslte/srslte.h"
|
|
#include "phy/phch_common.h"
|
|
|
|
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__)
|
|
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__)
|
|
#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__)
|
|
#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__)
|
|
|
|
namespace srsue {
|
|
|
|
cf_t zeros[50000];
|
|
|
|
phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_)
|
|
{
|
|
config = NULL;
|
|
args = NULL;
|
|
log_h = NULL;
|
|
radio_h = NULL;
|
|
mac = NULL;
|
|
max_mutex = max_mutex_;
|
|
nof_mutex = 0;
|
|
rx_gain_offset = 0;
|
|
|
|
bzero(&dl_metrics, sizeof(dl_metrics_t));
|
|
dl_metrics_read = true;
|
|
dl_metrics_count = 0;
|
|
bzero(&ul_metrics, sizeof(ul_metrics_t));
|
|
ul_metrics_read = true;
|
|
ul_metrics_count = 0;
|
|
bzero(&sync_metrics, sizeof(sync_metrics_t));
|
|
sync_metrics_read = true;
|
|
sync_metrics_count = 0;
|
|
|
|
bzero(zeros, 50000*sizeof(cf_t));
|
|
|
|
// FIXME: This is an ugly fix to avoid the TX filters to empty
|
|
for (int i=0;i<50000;i++) {
|
|
zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I);
|
|
}
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac)
|
|
{
|
|
log_h = _log;
|
|
radio_h = _radio;
|
|
rrc = _rrc;
|
|
mac = _mac;
|
|
config = _config;
|
|
args = _args;
|
|
is_first_tx = true;
|
|
sr_last_tx_tti = -1;
|
|
|
|
for (uint32_t i=0;i<nof_mutex;i++) {
|
|
pthread_mutex_init(&tx_mutex[i], NULL);
|
|
}
|
|
}
|
|
|
|
void phch_common::set_nof_mutex(uint32_t nof_mutex_) {
|
|
nof_mutex = nof_mutex_;
|
|
assert(nof_mutex <= max_mutex);
|
|
}
|
|
|
|
bool phch_common::ul_rnti_active(uint32_t tti) {
|
|
if ((((int)tti >= ul_rnti_start && ul_rnti_start >= 0) || ul_rnti_start < 0) &&
|
|
(((int)tti < ul_rnti_end && ul_rnti_end >= 0) || ul_rnti_end < 0))
|
|
{
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool phch_common::dl_rnti_active(uint32_t tti) {
|
|
Debug("tti=%d, dl_rnti_start=%d, dl_rnti_end=%d, dl_rnti=0x%x\n", tti, dl_rnti_start, dl_rnti_end, dl_rnti);
|
|
if ((((int)tti >= dl_rnti_start && dl_rnti_start >= 0) || dl_rnti_start < 0) &&
|
|
(((int)tti < dl_rnti_end && dl_rnti_end >= 0) || dl_rnti_end < 0))
|
|
{
|
|
bool ret = true;
|
|
// FIXME: This scheduling decision belongs to RRC
|
|
if (dl_rnti_type == SRSLTE_RNTI_SI) {
|
|
if (dl_rnti_end - dl_rnti_start > 1) { // This is not a SIB1
|
|
if ((tti/10)%2 == 0 && (tti%10) == 5) { // Skip subframe #5 for which SFN mod 2 = 0
|
|
ret = false;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
srslte::radio* phch_common::get_radio()
|
|
{
|
|
return radio_h;
|
|
}
|
|
|
|
// Unpack RAR grant as defined in Section 6.2 of 36.213
|
|
void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
|
|
{
|
|
srslte_dci_rar_grant_unpack(&rar_grant, grant_payload);
|
|
rar_grant_pending = true;
|
|
if (MSG3_DELAY_MS < 0) {
|
|
fprintf(stderr, "Error MSG3_DELAY_MS can't be negative\n");
|
|
}
|
|
if (rar_grant.ul_delay) {
|
|
rar_grant_tti = (tti + MSG3_DELAY_MS + 1) % 10240;
|
|
} else {
|
|
rar_grant_tti = (tti + MSG3_DELAY_MS) % 10240;
|
|
}
|
|
}
|
|
|
|
bool phch_common::get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant_)
|
|
{
|
|
if (rar_grant_pending && tti >= rar_grant_tti) {
|
|
if (rar_grant_) {
|
|
rar_grant_pending = false;
|
|
memcpy(rar_grant_, &rar_grant, sizeof(srslte_dci_rar_grant_t));
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Common variables used by all phy workers */
|
|
uint16_t phch_common::get_ul_rnti(uint32_t tti) {
|
|
if (ul_rnti_active(tti)) {
|
|
return ul_rnti;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
srslte_rnti_type_t phch_common::get_ul_rnti_type() {
|
|
return ul_rnti_type;
|
|
}
|
|
void phch_common::set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) {
|
|
ul_rnti = rnti_value;
|
|
ul_rnti_type = type;
|
|
ul_rnti_start = tti_start;
|
|
ul_rnti_end = tti_end;
|
|
}
|
|
uint16_t phch_common::get_dl_rnti(uint32_t tti) {
|
|
if (dl_rnti_active(tti)) {
|
|
return dl_rnti;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
srslte_rnti_type_t phch_common::get_dl_rnti_type() {
|
|
return dl_rnti_type;
|
|
}
|
|
void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) {
|
|
dl_rnti = rnti_value;
|
|
dl_rnti_type = type;
|
|
dl_rnti_start = tti_start;
|
|
dl_rnti_end = tti_end;
|
|
if (log_h) {
|
|
Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value);
|
|
}
|
|
}
|
|
|
|
void phch_common::reset_pending_ack(uint32_t tti) {
|
|
pending_ack[TTIMOD(tti)].enabled = false;
|
|
}
|
|
|
|
void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) {
|
|
pending_ack[TTIMOD(tti)].enabled = true;
|
|
pending_ack[TTIMOD(tti)].I_lowest = I_lowest;
|
|
pending_ack[TTIMOD(tti)].n_dmrs = n_dmrs;
|
|
Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs);
|
|
}
|
|
|
|
bool phch_common::get_pending_ack(uint32_t tti) {
|
|
return get_pending_ack(tti, NULL, NULL);
|
|
}
|
|
|
|
bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) {
|
|
if (I_lowest) {
|
|
*I_lowest = pending_ack[TTIMOD(tti)].I_lowest;
|
|
}
|
|
if (n_dmrs) {
|
|
*n_dmrs = pending_ack[TTIMOD(tti)].n_dmrs;
|
|
}
|
|
return pending_ack[TTIMOD(tti)].enabled;
|
|
}
|
|
|
|
bool phch_common::is_any_pending_ack() {
|
|
for (int i=0;i<TTIMOD_SZ;i++) {
|
|
if (pending_ack[i].enabled) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* The transmisison of UL subframes must be in sequence. Each worker uses this function to indicate
|
|
* that all processing is done and data is ready for transmission or there is no transmission at all (tx_enable).
|
|
* In that case, the end of burst message will be send to the radio
|
|
*/
|
|
void phch_common::worker_end(uint32_t tti, bool tx_enable,
|
|
cf_t *buffer, uint32_t nof_samples,
|
|
srslte_timestamp_t tx_time)
|
|
{
|
|
|
|
// Wait previous TTIs to be transmitted
|
|
if (is_first_tx) {
|
|
is_first_tx = false;
|
|
} else {
|
|
pthread_mutex_lock(&tx_mutex[tti%nof_mutex]);
|
|
}
|
|
|
|
radio_h->set_tti(tti);
|
|
if (tx_enable) {
|
|
radio_h->tx_single(buffer, nof_samples, tx_time);
|
|
is_first_of_burst = false;
|
|
} else {
|
|
if (TX_MODE_CONTINUOUS) {
|
|
if (!is_first_of_burst) {
|
|
radio_h->tx_single(zeros, nof_samples, tx_time);
|
|
}
|
|
} else {
|
|
if (!is_first_of_burst) {
|
|
radio_h->tx_end();
|
|
is_first_of_burst = true;
|
|
}
|
|
}
|
|
}
|
|
// Trigger next transmission
|
|
pthread_mutex_unlock(&tx_mutex[(tti+1)%nof_mutex]);
|
|
}
|
|
|
|
|
|
void phch_common::set_cell(const srslte_cell_t &c) {
|
|
cell = c;
|
|
}
|
|
|
|
uint32_t phch_common::get_nof_prb() {
|
|
return cell.nof_prb;
|
|
}
|
|
|
|
void phch_common::set_dl_metrics(const dl_metrics_t &m) {
|
|
if(dl_metrics_read) {
|
|
dl_metrics = m;
|
|
dl_metrics_count = 1;
|
|
dl_metrics_read = false;
|
|
} else {
|
|
dl_metrics_count++;
|
|
dl_metrics.mcs = dl_metrics.mcs + (m.mcs - dl_metrics.mcs)/dl_metrics_count;
|
|
dl_metrics.n = dl_metrics.n + (m.n - dl_metrics.n)/dl_metrics_count;
|
|
dl_metrics.rsrp = dl_metrics.rsrp + (m.rsrp - dl_metrics.rsrp)/dl_metrics_count;
|
|
dl_metrics.rsrq = dl_metrics.rsrq + (m.rsrq - dl_metrics.rsrq)/dl_metrics_count;
|
|
dl_metrics.rssi = dl_metrics.rssi + (m.rssi - dl_metrics.rssi)/dl_metrics_count;
|
|
dl_metrics.sinr = dl_metrics.sinr + (m.sinr - dl_metrics.sinr)/dl_metrics_count;
|
|
dl_metrics.pathloss = dl_metrics.pathloss + (m.pathloss - dl_metrics.pathloss)/dl_metrics_count;
|
|
dl_metrics.turbo_iters = dl_metrics.turbo_iters + (m.turbo_iters - dl_metrics.turbo_iters)/dl_metrics_count;
|
|
}
|
|
}
|
|
|
|
void phch_common::get_dl_metrics(dl_metrics_t &m) {
|
|
m = dl_metrics;
|
|
dl_metrics_read = true;
|
|
}
|
|
|
|
void phch_common::set_ul_metrics(const ul_metrics_t &m) {
|
|
if(ul_metrics_read) {
|
|
ul_metrics = m;
|
|
ul_metrics_count = 1;
|
|
ul_metrics_read = false;
|
|
} else {
|
|
ul_metrics_count++;
|
|
ul_metrics.mcs = ul_metrics.mcs + (m.mcs - ul_metrics.mcs)/ul_metrics_count;
|
|
ul_metrics.power = ul_metrics.power + (m.power - ul_metrics.power)/ul_metrics_count;
|
|
}
|
|
}
|
|
|
|
void phch_common::get_ul_metrics(ul_metrics_t &m) {
|
|
m = ul_metrics;
|
|
ul_metrics_read = true;
|
|
}
|
|
|
|
void phch_common::set_sync_metrics(const sync_metrics_t &m) {
|
|
|
|
if(sync_metrics_read) {
|
|
sync_metrics = m;
|
|
sync_metrics_count = 1;
|
|
sync_metrics_read = false;
|
|
} else {
|
|
sync_metrics_count++;
|
|
sync_metrics.cfo = sync_metrics.cfo + (m.cfo - sync_metrics.cfo)/sync_metrics_count;
|
|
sync_metrics.sfo = sync_metrics.sfo + (m.sfo - sync_metrics.sfo)/sync_metrics_count;
|
|
}
|
|
}
|
|
|
|
void phch_common::get_sync_metrics(sync_metrics_t &m) {
|
|
m = sync_metrics;
|
|
sync_metrics_read = true;
|
|
}
|
|
|
|
void phch_common::reset() {
|
|
sr_enabled = false;
|
|
is_first_of_burst = true;
|
|
is_first_tx = true;
|
|
rar_grant_pending = false;
|
|
pathloss = 0;
|
|
cur_pathloss = 0;
|
|
cur_pusch_power = 0;
|
|
p0_preamble = 0;
|
|
cur_radio_power = 0;
|
|
sr_last_tx_tti = -1;
|
|
cur_pusch_power = 0;
|
|
avg_rsrp = 0;
|
|
avg_rsrp_dbm = 0;
|
|
avg_rsrq_db = 0;
|
|
|
|
pcell_meas_enabled = false;
|
|
pcell_report_period = 20;
|
|
|
|
bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ);
|
|
|
|
}
|
|
|
|
void phch_common::reset_ul()
|
|
{
|
|
is_first_tx = true;
|
|
is_first_of_burst = true;
|
|
for (uint32_t i=0;i<nof_mutex;i++) {
|
|
pthread_mutex_trylock(&tx_mutex[i]);
|
|
pthread_mutex_unlock(&tx_mutex[i]);
|
|
}
|
|
radio_h->tx_end();
|
|
}
|
|
|
|
}
|