Initial commit

master
ismagom 10 years ago
parent 805ccc2414
commit 97a824c3ee

@ -0,0 +1,188 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <stdint.h>
#include <string>
#include "srslte/srslte.h"
/******************************************************************************
* File: mac_interface.h
*
* Description: LTE MAC layer interface
*
* Reference:
*****************************************************************************/
#ifndef MAC_INTERFACE_H
#define MAC_INTERFACE_H
namespace srslte {
namespace ue {
/* Interface PHY -> MAC */
class mac_interface_phy
{
public:
typedef struct {
uint32_t pid;
uint32_t tti;
bool ndi;
uint32_t tbs;
srslte_rnti_type_t rnti_type;
srslte_phy_grant_t phy_grant;
} mac_grant_t;
typedef struct {
bool decode_enabled;
uint16_t rv;
bool generate_ack;
bool default_ack;
uint8_t *payload_ptr;
srslte_softbuffer_rx_t *softbuffer;
srslte_phy_grant_t phy_grant;
} tb_action_dl_t;
typedef struct {
bool tx_enabled;
uint16_t rv;
uint32_t current_tx_nb;
srslte_softbuffer_tx_t *softbuffer;
srslte_phy_grant_t phy_grant;
} tb_action_ul_t;
/* Indicate reception of UL grant.
* payload_ptr points to memory where MAC PDU must be written by MAC layer */
virtual void new_grant_ul(mac_grant_t grant, uint8_t *payload_ptr, tb_action_ul_t *action) = 0;
/* Indicate reception of UL grant + HARQ information throught PHICH in the same TTI. */
virtual void new_grant_ul_ack(mac_grant_t grant, uint8_t *payload_ptr, bool ack, tb_action_ul_t *action) = 0;
/* Indicate reception of HARQ information only through PHICH. */
virtual void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) = 0;
/* Indicate reception of DL grant. */
virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0;
/* Indicate successfull decoding of PDSCH TB. */
virtual void tb_decoded_ok(uint32_t harq_pid) = 0;
/* Indicate successfull decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint8_t *payload) = 0;
};
/* Interface RLC -> MAC */
class mac_interface_rlc
{
public:
/* RLC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
virtual void reconfiguration() = 0;
virtual void reset() = 0;
};
/* Interface MAC -> RLC */
class rlc_interface_mac
{
public:
/* MAC calls RLC to get buffer state for a logical channel. This function should return quickly */
virtual uint32_t get_buffer_state(uint32_t lcid) = 0;
/* MAC calls RLC to get RLC segment of nof_bytes length. Segmentation happens in this function. RLC PDU is stored in payload. */
virtual void read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
/* MAC calls RLC to push an RLC PDU. This function is called from an independent MAC thread. PDU gets placed into the PDCP buffer and higher layer thread gets notified
when the last segment is received
*/
virtual void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) = 0;
};
class mac_interface_params
{
public:
typedef enum {
SPS_DL_SCHED_INTERVAL,
SPS_DL_NOF_PROC,
BCCH_SI_WINDOW_ST,
BCCH_SI_WINDOW_LEN,
PCCH_RECEIVE,
CONTENTION_ID, // Transmitted UE Contention ID
TIMER_TIMEALIGN,
// Random Access parameters. See 5.1.1
RA_CONFIGINDEX,
RA_PREAMBLEINDEX,
RA_MASKINDEX,
RA_NOFPREAMBLES,
RA_NOFGROUPAPREAMBLES,
RA_MESSAGEPOWEROFFSETB,
RA_MESSAGESIZEA,
RA_PCMAX,
RA_DELTAPREAMBLEMSG3,
RA_RESPONSEWINDOW,
RA_POWERRAMPINGSTEP,
RA_PREAMBLETRANSMAX,
RA_INITRECEIVEDPOWER,
RA_CONTENTIONTIMER,
SR_PUCCH_CONFIGURED,
SR_TRANS_MAX,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
HARQ_MAXTX,
HARQ_MAXMSG3TX,
PDSCH_RSPOWER,
PDSCH_PB,
NOF_PARAMS,
} mac_param_t;
/* Sets/gets a parameter */
virtual void set_param(mac_param_t param, int64_t value) = 0;
virtual int64_t get_param(mac_param_t param) = 0;
};
}
}
#endif

@ -0,0 +1,175 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <stdint.h>
#include <string>
#include "srslte/srslte.h"
/******************************************************************************
* File: phy_interface.h
*
* Description: LTE PHY layer interface
*
* Reference:
*****************************************************************************/
#ifndef PHY_INTERFACE_H
#define PHY_INTERFACE_H
namespace srslte {
namespace ue {
class phy_interface_params
{
public:
/* PHY parameters */
typedef enum {
DL_FREQ = 0,
UL_FREQ,
CELLSEARCH_TIMEOUT_PSS_NFRAMES,
CELLSEARCH_TIMEOUT_MIB_NFRAMES,
CELLSEARCH_TIMEOUT_PSS_CORRELATION_THRESHOLD, // integer that will be divided by 10
PUSCH_EN_64QAM,
PUSCH_RS_CYCLIC_SHIFT,
PUSCH_RS_GROUP_ASSIGNMENT,
DMRS_GROUP_HOPPING_EN,
DMRS_SEQUENCE_HOPPING_EN,
PUSCH_HOPPING_N_SB,
PUSCH_HOPPING_INTRA_SF,
PUSCH_HOPPING_OFFSET,
PUCCH_DELTA_SHIFT,
PUCCH_CYCLIC_SHIFT,
PUCCH_N_RB_2,
PUCCH_N_PUCCH_1_0,
PUCCH_N_PUCCH_1_1,
PUCCH_N_PUCCH_1_2,
PUCCH_N_PUCCH_1_3,
PUCCH_N_PUCCH_1,
PUCCH_N_PUCCH_2,
PUCCH_N_PUCCH_SR,
SR_CONFIG_INDEX,
SRS_UE_TXCOMB,
SRS_UE_NRRC,
SRS_UE_DURATION,
SRS_UE_CONFIGINDEX,
SRS_UE_BW,
SRS_UE_HOP,
SRS_UE_CS,
SRS_UE_CYCLICSHIFT,
SRS_CS_BWCFG,
SRS_CS_SFCFG,
SRS_CS_ACKNACKSIMUL,
SRS_IS_CONFIGURED,
CQI_PERIODIC_PMI_IDX,
CQI_PERIODIC_SIMULT_ACK,
CQI_PERIODIC_FORMAT_SUBBAND,
CQI_PERIODIC_FORMAT_SUBBAND_K,
CQI_PERIODIC_CONFIGURED,
UCI_I_OFFSET_ACK,
UCI_I_OFFSET_RI,
UCI_I_OFFSET_CQI,
PRACH_CONFIG_INDEX,
PRACH_ROOT_SEQ_IDX,
PRACH_HIGH_SPEED_FLAG,
PRACH_ZC_CONFIG,
PRACH_FREQ_OFFSET,
NOF_PARAMS,
} phy_param_t;
/* Get/Set PHY parameters */
virtual void set_param(phy_param_t param, int64_t value) = 0;
virtual int64_t get_param(phy_param_t param) = 0;
};
/* Interface MAC -> PHY */
class phy_interface
{
public:
/* Instructs the PHY to configure using the parameters written with set_param()
* These two functions may take a while to return.
*/
virtual void configure_prach_params() = 0;
virtual void configure_ul_params() = 0;
/* Start synchronization with strongest cell in the current carrier frequency */
virtual void sync_start() = 0;
virtual void sync_stop() = 0;
/* Functions to initialize and transmit PRACH in the next opportunity.
* This function returns at the start of the rar reception window, ie the transmission
* TTI + rar_start
*/
typedef struct {
uint32_t preamble_idx;
bool allowed_subframe_enabled;
uint32_t allowed_subframe;
float target_power_dbm;
uint16_t rar_rnti;
uint32_t rar_start;
uint32_t rar_window;
} prach_cfg_t;
virtual void prach_send(prach_cfg_t *cfg) = 0;
/* Indicates the transmission of a SR signal in the next opportunity */
virtual void sr_send() = 0;
/* Time advance commands */
virtual void set_timeadv_rar(uint32_t ta_cmd) = 0;
virtual void set_timeadv(uint32_t ta_cmd) = 0;
/* Sets RAR grant payload */
virtual void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) = 0;
/* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */
virtual void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1) = 0;
virtual uint32_t get_current_tti() = 0;
virtual void reset() = 0;
};
}
}
#endif

@ -0,0 +1,65 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <pthread.h>
#include <stdint.h>
#include <string>
#include <queue>
#include "srsapps/common/threads.h"
/******************************************************************************
* File: task_dispatcher.h
*
* Description: Implements a pool of threads. Pending tasks to execute are
* identified by a pointer.
*
* Reference:
*****************************************************************************/
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
namespace srslte {
class task_dispatcher : public thread
{
public:
task_dispatcher(uint32_t max_pending_tasks);
~task_dispatcher();
void push_task(uint32_t task_code);
virtual void run_task(uint32_t task_code) = 0;
private:
std::queue<uint32_t> pending_tasks;
void run_thread();
pthread_mutex_t mutex;
pthread_cond_t cvar;
bool running;
};
}
#endif

@ -0,0 +1,91 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <stdint.h>
#include <string>
#include <vector>
#include <stack>
#include "srsapps/common/threads.h"
/******************************************************************************
* File: thread_pool.h
*
* Description: Implements a pool of threads. Pending tasks to execute are
* identified by a pointer.
*
* Reference:
*****************************************************************************/
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
namespace srslte {
class thread_pool
{
public:
class worker : public thread
{
public:
void setup(uint32_t id, thread_pool *parent);
void stop();
protected:
virtual void work_imp() = 0;
private:
uint32_t my_id;
thread_pool *my_parent;
bool running;
void run_thread();
void wait_to_start();
void finished();
};
thread_pool(uint32_t nof_workers);
void init_worker(uint32_t id, worker*);
void stop();
worker* wait_worker();
void start_worker(worker*);
void start_worker(uint32_t id);
worker* get_worker(uint32_t id);
uint32_t get_nof_workers();
private:
std::vector<worker*> workers;
std::vector<bool> begin;
std::stack<worker*> available_workers;
pthread_cond_t cvar_start, cvar_stop;
pthread_mutex_t mutex_start, mutex_stop;
uint32_t nof_workers;
};
}
#endif

@ -0,0 +1,75 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 "srsapps/common/task_dispatcher.h"
#include <queue>
namespace srslte {
task_dispatcher::task_dispatcher(uint32_t max_pending_tasks)
{
pthread_cond_init(&cvar, NULL);
pthread_mutex_init(&mutex, NULL);
}
task_dispatcher::~task_dispatcher()
{
running = false;
pthread_cond_signal(&cvar);
wait_thread_finish();
pthread_cond_destroy(&cvar);
pthread_mutex_destroy(&mutex);
}
void task_dispatcher::push_task(uint32_t task_code)
{
pthread_mutex_lock(&mutex);
pending_tasks.push(task_code);
pthread_cond_signal(&cvar);
pthread_mutex_unlock(&mutex);
}
void task_dispatcher::run_thread()
{
running = true;
while(running) {
uint32_t task = 0;
pthread_mutex_lock(&mutex);
while(pending_tasks.empty()) {
pthread_cond_wait(&cvar, &mutex);
}
task = (uint32_t) pending_tasks.front();
pending_tasks.pop();
pthread_mutex_unlock(&mutex);
if (running) {
run_task(task);
}
}
}
}

@ -0,0 +1,157 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 "srsapps/common/thread_pool.h"
namespace srslte {
void thread_pool::worker::setup(uint32_t id, thread_pool *parent)
{
my_id = id;
my_parent = parent;
start();
}
void thread_pool::worker::run_thread()
{
running = true;
while(running) {
wait_to_start();
if (running) {
work_imp();
}
finished();
}
}
void thread_pool::worker::stop()
{
running = false;
}
void thread_pool::worker::wait_to_start()
{
pthread_mutex_lock(&my_parent->mutex_start);
while(!my_parent->begin[my_id]) {
pthread_cond_wait(&my_parent->cvar_start, &my_parent->mutex_start);
}
my_parent->begin[my_id] = false;
pthread_mutex_unlock(&my_parent->mutex_start);
}
void thread_pool::worker::finished()
{
pthread_mutex_lock(&my_parent->mutex_stop);
my_parent->available_workers.push(this);
pthread_cond_signal(&my_parent->cvar_stop);
pthread_mutex_unlock(&my_parent->mutex_stop);
}
thread_pool::thread_pool(uint32_t nof_workers_) : workers(nof_workers_), begin(nof_workers_) {
nof_workers = nof_workers_;
for (int i=0;i<nof_workers;i++) {
workers[i] = NULL;
}
pthread_mutex_init(&mutex_start, NULL);
pthread_mutex_init(&mutex_stop, NULL);
pthread_cond_init(&cvar_start, NULL);
pthread_cond_init(&cvar_stop, NULL);
}
void thread_pool::init_worker(uint32_t id, worker *obj)
{
if (id < nof_workers) {
begin[id] = false;
workers[id] = obj;
available_workers.push(obj);
obj->setup(id, this);
}
}
void thread_pool::stop()
{
for (uint32_t i=0;i<nof_workers;i++) {
if (workers[i]) {
workers[i]->stop();
start_worker(i);
workers[i]->wait_thread_finish();
}
}
pthread_mutex_destroy(&mutex_start);
pthread_mutex_destroy(&mutex_stop);
pthread_cond_destroy(&cvar_start);
pthread_cond_destroy(&cvar_stop);
}
void thread_pool::start_worker(uint32_t id) {
if (workers[id]) {
pthread_mutex_lock(&mutex_start);
begin[id%nof_workers] = true;
pthread_cond_signal(&cvar_start);
pthread_mutex_unlock(&mutex_start);
}
}
void thread_pool::start_worker(worker* x)
{
for (uint32_t i=0;i<nof_workers;i++) {
if (x == workers[i]) {
start_worker(i);
return;
}
}
}
thread_pool::worker* thread_pool::get_worker(uint32_t id)
{
if (id < nof_workers) {
return workers[id];
}
}
uint32_t thread_pool::get_nof_workers()
{
return nof_workers;
}
thread_pool::worker* thread_pool::wait_worker()
{
thread_pool::worker *x;
pthread_mutex_lock(&mutex_stop);
while(!available_workers.empty()) {
pthread_cond_wait(&cvar_stop, &mutex_stop);
}
x = (worker*) available_workers.top();
available_workers.pop();
pthread_mutex_unlock(&mutex_stop);
return x;
}
}

@ -0,0 +1,113 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <pthread.h>
#include <string.h>
#include "srslte/srslte.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/radio/radio.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/phy_params.h"
#ifndef UEPHYWORKERCOMMON_H
#define UEPHYWORKERCOMMON_H
namespace srslte {
namespace ue {
/* Subclass that manages variables common to all workers */
class phch_common {
public:
/* Common variables used by all phy workers */
phy_params *params_db;
log *log_h;
mac_interface_phy *mac;
phch_common();
void init(phy_params *_params, log *_log, radio *_radio, mac_interface_phy *_mac);
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant);
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool sr_enabled;
private:
pthread_mutex_t tx_mutex;
pthread_cond_t tx_cvar;
uint32_t tx_tti_cnt;
bool is_first_of_burst;
radio *radio_h;
float cfo;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
float time_adv_sec;
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[10];
bool is_first_tx;
};
}
}
#endif

@ -0,0 +1,104 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 "srslte/srslte.h"
#include "srsapps/common/log.h"
#include "srsapps/common/threads.h"
#include "srsapps/common/thread_pool.h"
#include "srsapps/radio/radio.h"
#include "srsapps/ue/phy/prach.h"
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/ue/phy/phch_common.h"
#ifndef UEPHYRECV_H
#define UEPHYRECV_H
namespace srslte {
namespace ue {
typedef _Complex float cf_t;
class phch_recv : public thread
{
public:
phch_recv();
bool init(radio* radio_handler, mac_interface_phy *mac, prach *prach_buffer, thread_pool *_workers_pool,
phch_common *_worker_com, log* _log_h, bool do_agc);
void stop();
uint32_t get_current_tti();
void sync_start();
void sync_stop();
bool status_is_sync();
void set_time_adv_sec(float time_adv_sec);
private:
void run_thread();
int sync_sfn();
bool running;
radio *radio_h;
mac_interface_phy *mac;
log *log_h;
thread_pool *workers_pool;
phch_common *worker_com;
prach *prach_buffer;
srslte_ue_sync_t ue_sync;
srslte_ue_mib_t ue_mib;
enum {
IDLE, CELL_SEARCH, SYNCING, SYNC_DONE
} phy_state;
srslte_cell_t cell;
bool cell_is_set;
bool is_sfn_synched;
bool started;
float time_adv_sec;
bool radio_is_streaming;
uint32_t tti;
bool do_agc;
float last_gain;
float cellsearch_cfo;
bool cell_search(int force_N_id_2 = -1);
bool init_cell();
void free_cell();
};
}
}
#endif

@ -0,0 +1,126 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <string.h>
#include "srslte/srslte.h"
#include "srsapps/common/thread_pool.h"
#include "srsapps/common/phy_interface.h"
#include "srsapps/ue/phy/phch_common.h"
#ifndef UEPHYWORKER_H
#define UEPHYWORKER_H
namespace srslte {
namespace ue {
class phch_worker : public thread_pool::worker
{
public:
phch_worker();
void set_common(phch_common *phy);
bool init_cell(srslte_cell_t cell);
void free_cell();
/* Functions used by main PHY thread */
cf_t *get_buffer();
void set_tti(uint32_t tti);
void set_tx_time(srslte_timestamp_t tx_time);
void set_cfo(float cfo);
void set_ul_params();
void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled);
private:
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */
void work_imp();
/* Internal methods */
bool extract_fft_and_pdcch_llr();
/* ... for DL */
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);
bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant);
bool decode_phich(bool *ack);
bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, uint32_t rv);
/* ... for UL */
void encode_pusch(srslte_ra_ul_grant_t *grant, uint32_t rv_idx, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer);
void encode_pucch();
void encode_srs();
void reset_uci();
void set_uci_sr();
void set_uci_cqi();
void set_uci_ack(bool ack);
bool srs_is_ready_to_send();
void normalize();
/* Common objects */
phch_common *phy;
srslte_cell_t cell;
bool cell_initiated;
cf_t *signal_buffer;
uint32_t tti;
bool pregen_enabled;
uint32_t last_dl_pdcch_ncce;
/* Objects for DL */
srslte_ue_dl_t ue_dl;
uint32_t cfi;
uint16_t dl_rnti;
/* Objects for UL */
srslte_ue_ul_t ue_ul;
srslte_timestamp_t tx_time;
srslte_uci_data_t uci_data;
uint16_t ul_rnti;
uint8_t *ul_payload;
// UL configuration parameters
srslte_refsignal_srs_cfg_t srs_cfg;
srslte_pucch_cfg_t pucch_cfg;
srslte_refsignal_dmrs_pusch_cfg_t dmrs_cfg;
srslte_pusch_hopping_cfg_t pusch_hopping;
srslte_pucch_sched_t pucch_sched;
srslte_uci_cfg_t uci_cfg;
srslte_cqi_cfg_t cqi_cfg;
uint32_t I_sr;
float cfo;
bool rar_cqi_request;
};
}
}
#endif

@ -0,0 +1,184 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <string.h>
#include "srslte/srslte.h"
#include "srsapps/ue/phy/phch_common.h"
namespace srslte {
namespace ue {
phch_common::phch_common()
{
params_db = NULL;
log_h = NULL;
radio_h = NULL;
mac = NULL;
sr_enabled = false;
is_first_of_burst = true;
is_first_tx = true;
rar_grant_pending = false;
}
void phch_common::init(phy_params *_params, log *_log, radio *_radio, mac_interface_phy *_mac)
{
params_db = _params;
log_h = _log;
radio_h = _radio;
mac = _mac;
is_first_tx = true;
}
bool phch_common::ul_rnti_active(uint32_t tti) {
if ((tti >= ul_rnti_start && ul_rnti_start >= 0 || ul_rnti_start < 0) &&
(tti < ul_rnti_end && ul_rnti_end >= 0 || ul_rnti_end < 0))
{
return true;
}
}
bool phch_common::dl_rnti_active(uint32_t tti) {
if ((tti >= dl_rnti_start && dl_rnti_start >= 0 || dl_rnti_start < 0) &&
(tti < dl_rnti_end && dl_rnti_end >= 0 || dl_rnti_end < 0))
{
return true;
}
}
// 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;
// PUSCH is at n+6 or n+7 and phch_worker assumes default delay of 4 ttis
if (rar_grant.ul_delay) {
rar_grant_tti = (tti + 3) % 10240;
} else {
rar_grant_tti = (tti + 2) % 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) {
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;
}
}
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;
}
}
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;
}
void phch_common::reset_pending_ack(uint32_t tti) {
pending_ack[tti%10].enabled = false;
}
void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) {
pending_ack[tti%10].enabled = true;
pending_ack[tti%10].I_lowest = I_lowest;
pending_ack[tti%10].n_dmrs = 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[tti%10].I_lowest;
}
if (n_dmrs) {
*n_dmrs = pending_ack[tti%10].n_dmrs;
}
return pending_ack[tti%10].enabled;
}
/* 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)
{
pthread_mutex_lock(&tx_mutex);
// Wait previous TTIs to be transmitted
if (is_first_tx) {
tx_tti_cnt = tti;
is_first_tx = false;
} else {
while(tti != tx_tti_cnt) {
pthread_cond_wait(&tx_cvar, &tx_mutex);
}
}
if (tx_enable) {
radio_h->tx(buffer, nof_samples, tx_time);
is_first_of_burst = false;
} else if (!is_first_of_burst) {
radio_h->tx_end();
is_first_of_burst = true;
} /* else do nothing, just update tti counter */
tx_tti_cnt = (tx_tti_cnt + 1) % 10240;
pthread_cond_signal(&tx_cvar);
pthread_mutex_unlock(&tx_mutex);
}
}
}

@ -0,0 +1,340 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <unistd.h>
#include "srslte/srslte.h"
#include "srsapps/common/log.h"
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/ue/phy/phch_common.h"
#include "srsapps/ue/phy/phch_recv.h"
namespace srslte {
namespace ue {
phch_recv::phch_recv() {
running = false;
}
bool phch_recv::init(radio* _radio_handler, mac_interface_phy *_mac, prach* _prach_buffer, thread_pool* _workers_pool,
phch_common* _worker_com, log* _log_h, bool do_agc_)
{
radio_h = _radio_handler;
log_h = _log_h;
mac = _mac;
workers_pool = _workers_pool;
worker_com = _worker_com;
prach_buffer = _prach_buffer;
running = true;
phy_state = IDLE;
time_adv_sec = 0;
cell_is_set = false;
do_agc = do_agc_;
start();
}
void phch_recv::stop() {
running = false;
}
int radio_recv_wrapper_cs(void *h,void *data, uint32_t nsamples, srslte_timestamp_t *rx_time)
{
radio *radio_h = (radio*) h;
int n = radio_h->rx_now(data, nsamples, rx_time);
return n;
}
double callback_set_rx_gain(void *h, double gain) {
radio *radio_handler = (radio*) h;
return radio_handler->set_rx_gain_th(gain);
}
void phch_recv::set_time_adv_sec(float _time_adv_sec) {
time_adv_sec = _time_adv_sec;
}
bool phch_recv::init_cell() {
if (phy_state == IDLE) {
cell_is_set = false;
if (!srslte_ue_mib_init(&ue_mib, cell))
{
if (!srslte_ue_sync_init(&ue_sync, cell, radio_recv_wrapper_cs, radio_h))
{
for (int i=0;i<workers_pool->get_nof_workers();i++) {
if (((phch_worker*) workers_pool->get_worker(i))->init_cell(cell)) {
Error("Error setting cell: initiating PHCH worker\n");
return false;
}
}
if (do_agc) {
srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo);
cell_is_set = true;
} else {
Error("Error setting cell: initiating ue_sync");
}
} else {
Error("Error setting cell: initiating ue_mib\n");
}
} else {
Error("Error setting cell: Invalid state %d\n", phy_state);
}
return cell_is_set;
}
void phch_recv::free_cell()
{
if (cell_is_set) {
for (int i=0;i<workers_pool->get_nof_workers();i++) {
((phch_worker*) workers_pool->get_worker(i))->free_cell();
}
prach_buffer->free_cell();
}
}
bool phch_recv::cell_search(int force_N_id_2)
{
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
srslte_ue_cellsearch_result_t found_cells[3];
srslte_ue_cellsearch_t cs;
bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t));
if (srslte_ue_cellsearch_init(&cs, radio_recv_wrapper_cs, radio_h)) {
return false;
}
if (do_agc) {
srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_cellsearch_set_nof_frames_to_scan(&cs,
worker_com->params_db->get_param(phy_interface_params::CELLSEARCH_TIMEOUT_PSS_NFRAMES));
srslte_ue_cellsearch_set_threshold(&cs, (float)
worker_com->params_db->get_param(phy_interface_params::CELLSEARCH_TIMEOUT_PSS_CORRELATION_THRESHOLD)/10);
radio_h->set_rx_srate(1920000.0);
radio_h->start_rx();
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
int ret = SRSLTE_ERROR;
if (force_N_id_2 >= 0 && force_N_id_2 < 3) {
ret = srslte_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = srslte_ue_cellsearch_scan(&cs, found_cells, &max_peak_cell);
}
last_gain = srslte_agc_get_gain(&cs.ue_sync.agc);
radio_h->stop_rx();
srslte_ue_cellsearch_free(&cs);
if (ret < 0) {
Error("Error decoding MIB: Error searching PSS\n");
return false;
} else if (ret == 0) {
Error("Error decoding MIB: Could not find any PSS in this frequency\n");
return false;
}
// Save result
cell.id = found_cells[max_peak_cell].cell_id;
cell.cp = found_cells[max_peak_cell].cp;
cellsearch_cfo = found_cells[max_peak_cell].cfo;
Info("\nFound CELL ID: %d CP: %s, CFO: %f\n", cell.id, srslte_cp_string(cell.cp), cellsearch_cfo);
srslte_ue_mib_sync_t ue_mib_sync;
if (srslte_ue_mib_sync_init(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, radio_h)) {
return false;
}
if (do_agc) {
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain);
}
/* Find and decode MIB */
uint32_t sfn, sfn_offset;
radio_h->start_rx();
ret = srslte_ue_mib_sync_decode(&ue_mib_sync,
worker_com->params_db->get_param(phy_interface_params::CELLSEARCH_TIMEOUT_MIB_NFRAMES),
bch_payload, &cell.nof_ports, &sfn_offset);
radio_h->stop_rx();
last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc);
srslte_ue_mib_sync_free(&ue_mib_sync);
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, NULL);
mac->bch_decoded_ok(bch_payload);
return true;
} else {
Warning("Error decoding MIB: Error decoding PBCH\n");
return false;
}
}
int phch_recv::sync_sfn(void) {
cf_t *sf_buffer = NULL;
int ret = SRSLTE_ERROR;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
Error("Error calling ue_sync_get_buffer");
return -1;
}
if (ret == 1) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
uint32_t sfn_offset=0;
srslte_pbch_decode_reset(&ue_mib.pbch);
int n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset);
if (n < 0) {
Error("Error decoding MIB while synchronising SFN");
return -1;
} else if (n == SRSLTE_UE_MIB_FOUND) {
uint32_t sfn;
srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
sfn = (sfn + sfn_offset)%1024;
tti = sfn*10 + srslte_ue_sync_get_sfidx(&ue_sync);
srslte_ue_sync_decode_sss_on_track(&ue_sync, false);
return 1;
}
}
}
return 0;
}
void phch_recv::run_thread()
{
phch_worker *worker = NULL;
cf_t *buffer = NULL;
while(running) {
switch(phy_state) {
case CELL_SEARCH:
if (cell_search()) {
init_cell();
radio_h->set_rx_srate((float) srslte_sampling_freq_hz(cell.nof_prb));
radio_h->set_tx_srate((float) srslte_sampling_freq_hz(cell.nof_prb));
phy_state = SYNCING;
}
break;
case SYNCING:
if (!radio_is_streaming) {
// Start streaming
radio_h->start_rx();
radio_is_streaming = true;
}
switch(sync_sfn()) {
default:
phy_state = IDLE;
break;
case 1:
phy_state = SYNC_DONE;
break;
case 0:
break;
}
break;
case SYNC_DONE:
worker = (phch_worker*) workers_pool->wait_worker();
buffer = worker->get_buffer();
if (srslte_ue_sync_zerocopy(&ue_sync, buffer) == 1) {
float cfo = srslte_ue_sync_get_cfo(&ue_sync)/15000;
worker->set_cfo(cfo);
srslte_timestamp_t rx_time;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
srslte_timestamp_add(&rx_time, 0, 1e-3 - time_adv_sec);
worker->set_tx_time(rx_time);
worker->set_tti(tti);
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
// send prach if we have to
prach_buffer->send(radio_h, cfo, rx_time);
radio_h->tx_end();
/* Setup DL RNTI search to look for RAR as configured by MAC */
uint16_t rar_rnti;
uint32_t rar_start, rar_end;
prach_buffer->get_rar_cfg(&rar_rnti, &rar_start, &rar_end);
worker_com->set_dl_rnti(SRSLTE_RNTI_RAR, rar_rnti, (int) rar_start, (int) rar_end);
} else {
workers_pool->start_worker(worker);
}
}
tti = (tti + 1) % 10240;
break;
case IDLE:
usleep(1000);
break;
}
}
}
uint32_t phch_recv::get_current_tti()
{
return tti;
}
bool phch_recv::status_is_sync()
{
return phy_state == SYNC_DONE;
}
void phch_recv::sync_start()
{
phy_state = CELL_SEARCH;
}
void phch_recv::sync_stop()
{
free_cell();
radio_h->stop_rx();
radio_is_streaming = false;
phy_state = IDLE;
}
}
}

@ -0,0 +1,556 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE 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.
*
* srsLTE 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 <string.h>
#include "srsapps/ue/phy/phch_worker.h"
#include "srsapps/common/mac_interface.h"
#include "srsapps/common/phy_interface.h"
namespace srslte {
namespace ue {
#define log_h phy->log_h
phch_worker::phch_worker()
{
phy = NULL;
signal_buffer = NULL;
bzero(&cell, sizeof(srslte_cell_t));
bzero(&ue_dl, sizeof(srslte_ue_dl_t));
bzero(&ue_ul, sizeof(srslte_ue_ul_t));
bzero(&uci_data, sizeof(srslte_uci_data_t));
cell_initiated = false;
pregen_enabled = false;
rar_cqi_request = false;
cfi = 0;
}
void phch_worker::set_common(phch_common* phy_)
{
phy = phy_;
}
bool phch_worker::init_cell(srslte_cell_t cell_)
{
memcpy(&cell, &cell_, sizeof(srslte_cell_t));
// ue_sync in phy.cc requires a buffer for 2 subframes
signal_buffer = (cf_t*) srslte_vec_malloc(2 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
if (!signal_buffer) {
Error("Allocating memory\n");
return false;
}
if (srslte_ue_dl_init(&ue_dl, cell)) {
Error("Initiating UE DL\n");
return false;
}
if (srslte_ue_ul_init(&ue_ul, cell)) {
Error("Initiating UE UL\n");
return false;
}
srslte_ue_ul_set_normalization(&ue_ul, false);
srslte_ue_ul_set_cfo_enable(&ue_ul, true);
cell_initiated = false;
return true;
}
void phch_worker::free_cell()
{
if (cell_initiated) {
if (signal_buffer) {
free(signal_buffer);
}
srslte_ue_dl_free(&ue_dl);
srslte_ue_ul_free(&ue_ul);
}
}
cf_t* phch_worker::get_buffer()
{
return signal_buffer;
}
void phch_worker::set_tti(uint32_t tti_)
{
tti = tti_;
}
void phch_worker::set_cfo(float cfo_)
{
cfo = cfo_;
}
void phch_worker::set_crnti(uint16_t rnti)
{
srslte_ue_dl_set_rnti(&ue_dl, rnti);
srslte_ue_ul_set_rnti(&ue_ul, rnti);
}
void phch_worker::work_imp()
{
if (!cell_initiated) {
return;
}
reset_uci();
bool ul_grant_available = false;
mac_interface_phy::mac_grant_t dl_mac_grant;
mac_interface_phy::tb_action_dl_t dl_action;
bzero(&dl_action, sizeof(mac_interface_phy::tb_action_dl_t));
mac_interface_phy::mac_grant_t ul_mac_grant;
mac_interface_phy::tb_action_ul_t ul_action;
bzero(&ul_action, sizeof(mac_interface_phy::tb_action_ul_t));
/* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */
if (extract_fft_and_pdcch_llr()) {
/***** Downlink Processing *******/
/* PDCCH DL + PDSCH */
if(decode_pdcch_dl(&dl_mac_grant)) {
/* Send grant to MAC and get action for this TB */
phy->mac->new_grant_dl(dl_mac_grant, &dl_action);
/* Decode PDSCH if instructed to do so */
bool dl_ack = dl_action.default_ack;
if (dl_action.decode_enabled) {
dl_ack = decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, dl_action.softbuffer, dl_action.rv);
phy->mac->tb_decoded_ok(dl_mac_grant.pid);
}
if (dl_action.generate_ack) {
set_uci_ack(dl_ack);
}
}
// Decode PHICH
bool ul_ack;
bool ul_ack_available = decode_phich(&ul_ack);
/***** Uplink Processing + Transmission *******/
/* Generate UCI */
set_uci_sr();
set_uci_cqi();
/* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
/* Send UL grant or HARQ information (from PHICH) to MAC */
if (ul_grant_available && ul_ack_available) {
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_payload, ul_ack, &ul_action);
} else if (ul_grant_available && !ul_ack_available) {
phy->mac->new_grant_ul(ul_mac_grant, ul_payload, &ul_action);
} else if (!ul_grant_available && ul_ack_available) {
phy->mac->harq_recv(tti, ul_ack, &ul_action);
}
/* Set UL CFO before transmission */
srslte_ue_ul_set_cfo(&ue_ul, cfo);
}
/* Transmit PUSCH, PUCCH or SRS */
bool tx_signal = false;
if (ul_grant_available) {
if (ul_action.tx_enabled) {
encode_pusch(&ul_action.phy_grant.ul, ul_action.rv, ul_action.current_tx_nb, ul_action.softbuffer);
tx_signal = true;
}
} else if (dl_action.generate_ack) {
encode_pucch();
tx_signal = true;
} else if (srs_is_ready_to_send()) {
encode_srs();
tx_signal = true;
}
phy->worker_end(tti, tx_signal, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb), tx_time);
}
bool phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = false;
if (phy->get_ul_rnti(tti) || phy->get_dl_rnti(tti)) {
decode_pdcch = true;
}
/* Without a grant, we might need to do fft processing if need to decode PHICH */
if (phy->get_pending_ack(tti) || decode_pdcch) {
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
}
if (decode_pdcch) { /* and not in DRX mode */
if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) {
Error("Extracting PDCCH LLR\n");
return false;
}
}
return (decode_pdcch || phy->get_pending_ack(tti));
}
/********************* Downlink processing functions ****************************/
bool phch_worker::decode_pdcch_dl(srslte::ue::mac_interface_phy::mac_grant_t* grant)
{
dl_rnti = phy->get_dl_rnti(tti);
if (dl_rnti) {
Debug("PDCCH configured to search for DL RNTI 0x%x\n", dl_rnti);
srslte_rnti_type_t type = phy->get_dl_rnti_type();
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
if (srslte_ue_dl_find_dl_dci_type(&ue_dl, &dci_msg, cfi, tti%10, dl_rnti, type) != 1) {
return false;
}
if (srslte_dci_msg_to_dl_grant(&dci_msg, dl_rnti, cell.nof_prb, &dci_unpacked, &grant->phy_grant.dl)) {
return false;
}
/* Fill MAC grant structure */
grant->ndi = dci_unpacked.ndi;
grant->pid = dci_unpacked.harq_process;
grant->tbs = grant->phy_grant.dl.mcs.tbs;
grant->tti = tti;
grant->rnti_type = type;
last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl);
Info("PDCCH: DL DCI %s cce_index=%d, n_data_bits=%d\n", srslte_ra_dl_dci_string(&dci_unpacked),
ue_dl.last_n_cce, dci_msg.nof_bits);
return true;
} else {
return false;
}
}
bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, uint32_t rv)
{
Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti);
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, dl_rnti, rv)) {
if (ue_dl.pdsch_cfg.grant.mcs.mod > 0 && ue_dl.pdsch_cfg.grant.mcs.tbs >= 0) {
return srslte_pdsch_decode_rnti(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffer, ue_dl.sf_symbols,
ue_dl.ce, 0, dl_rnti, payload) == 0;
} else {
Warning("Received grant for TBS=0\n");
}
} else {
Error("Error configuring DL grant\n");
}
return true;
}
bool phch_worker::decode_phich(bool *ack)
{
uint32_t I_lowest, n_dmrs;
if (phy->get_pending_ack(tti, &I_lowest, &n_dmrs)) {
if (ack) {
*ack = srslte_ue_dl_decode_phich(&ue_dl, tti%10, I_lowest, n_dmrs);
}
return true;
} else {
return false;
}
}
/********************* Uplink processing functions ****************************/
bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
{
phy->reset_pending_ack(tti + 4);
srslte_dci_msg_t dci_msg;
srslte_ra_ul_dci_t dci_unpacked;
srslte_dci_rar_grant_t rar_grant;
srslte_rnti_type_t type = phy->get_ul_rnti_type();
bool ret = false;
if (phy->get_pending_rar(tti, &rar_grant)) {
if (srslte_dci_rar_to_ul_grant(&rar_grant, cell.nof_prb, pusch_hopping.hopping_offset, &dci_unpacked, &grant->phy_grant.ul)) {
return false;
}
rar_cqi_request = rar_grant.cqi_request;
ret = true;
} else {
ul_rnti = phy->get_ul_rnti(tti);
if (ul_rnti) {
Debug("PDCCH configured to search for UL RNTI 0x%x\n", ul_rnti);
if (srslte_ue_dl_find_ul_dci(&ue_dl, &dci_msg, cfi, tti%10, ul_rnti) != 1) {
return false;
}
if (srslte_dci_msg_to_ul_grant(&dci_msg, cell.nof_prb, pusch_hopping.hopping_offset, &dci_unpacked, &grant->phy_grant.ul)) {
return false;
}
}
}
if (ret) {
grant->ndi = dci_unpacked.ndi;
grant->pid = 0; // This is computed by MAC from TTI
grant->tbs = grant->phy_grant.ul.mcs.tbs;
grant->tti = tti;
grant->rnti_type = type;
Info("PDCCH: UL DCI Format0 cce_index=%d, n_data_bits=%d\n", ue_dl.last_n_cce, dci_msg.nof_bits);
if (SRSLTE_VERBOSE_ISINFO()) {
srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb);
}
return true;
} else {
return false;
}
}
void phch_worker::reset_uci()
{
bzero(&uci_data, sizeof(srslte_uci_data_t));
}
void phch_worker::set_uci_ack(bool ack)
{
uci_data.uci_ack = ack?1:0;
uci_data.uci_ack_len = 1;
}
void phch_worker::set_uci_sr()
{
uci_data.scheduling_request = false;
if (phy->sr_enabled) {
// Get I_sr parameter
if (srslte_ue_ul_sr_send_tti(I_sr, tti)) {
Info("SR transmission at TTI=%d\n", tti);
uci_data.scheduling_request = true;
phy->sr_enabled = false;
}
}
}
void phch_worker::set_uci_cqi()
{
if (cqi_cfg.configured || rar_cqi_request) {
if (srslte_cqi_send(cqi_cfg.pmi_idx, tti)) {
uci_data.uci_cqi_len = 4;
uint8_t cqi[4] = {1, 1, 1, 1};
uci_data.uci_cqi = cqi;
rar_cqi_request = false;
}
}
}
bool phch_worker::srs_is_ready_to_send() {
if (srs_cfg.configured) {
if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, tti%10) == 1 &&
srslte_refsignal_srs_send_ue(srs_cfg.I_srs, tti) == 1)
{
return true;
}
}
return false;
}
void phch_worker::set_tx_time(srslte_timestamp_t _tx_time)
{
memcpy(&tx_time, &_tx_time, sizeof(srslte_timestamp_t));
}
void phch_worker::normalize() {
srslte_vec_norm_cfc(signal_buffer, 0.9, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint32_t rv_idx, uint32_t current_tx_nb, srslte_softbuffer_tx_t* softbuffer)
{
if (srslte_ue_ul_cfg_grant(&ue_ul, grant, tti, rv_idx, current_tx_nb)) {
Error("Configuring UL grant\n");
}
phy->set_pending_ack(tti + 4, grant->n_prb_tilde[0], grant->ncs_dmrs);
if (srslte_ue_ul_pusch_encode_rnti_softbuffer(&ue_ul,
ul_payload, uci_data,
softbuffer,
ul_rnti,
signal_buffer))
{
Error("Encoding PUSCH\n");
}
Info("PUSCH: TTI=%d, CFO= %.1f KHz TBS=%d, mod=%s, rb_start=%d n_prb=%d, ack=%s, sr=%s, rnti=%d, shortened=%s\n",
tti, cfo*15e3, grant->mcs.tbs, srslte_mod_string(grant->mcs.mod),
grant->n_prb[0], grant->L_prb,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",uci_data.scheduling_request?"yes":"no",
ul_rnti, ue_ul.pusch.shortened?"yes":"no");
normalize();
}
void phch_worker::encode_pucch()
{
if (uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ack_len)
{
if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, tti, signal_buffer)) {
Error("Encoding PUCCH\n");
}
Info("PUCCH: TTI=%d, CFO= %.1f KHz n_cce=%d, ack=%s, sr=%s, shortened=%s\n", tti, cfo*15e3, last_dl_pdcch_ncce,
uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no",uci_data.scheduling_request?"yes":"no",
ue_ul.pucch.shortened?"yes":"no");
}
normalize();
}
void phch_worker::encode_srs()
{
if (srslte_ue_ul_srs_encode(&ue_ul, tti, signal_buffer))
{
Error("Encoding SRS\n");
}
Info("SRS: TTI=%d, CFO= %.1f KHz \n", tti, cfo*15e3);
normalize();
}
void phch_worker::enable_pregen_signals(bool enabled)
{
pregen_enabled = enabled;
}
void phch_worker::set_ul_params()
{
/* PUSCH DMRS signal configuration */
bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t));
dmrs_cfg.group_hopping_en = (bool) phy->params_db->get_param(phy_interface_params::DMRS_GROUP_HOPPING_EN);
dmrs_cfg.sequence_hopping_en = (bool) phy->params_db->get_param(phy_interface_params::DMRS_SEQUENCE_HOPPING_EN);
dmrs_cfg.cyclic_shift = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_RS_CYCLIC_SHIFT);
dmrs_cfg.delta_ss = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_RS_GROUP_ASSIGNMENT);
/* PUSCH Hopping configuration */
bzero(&pusch_hopping, sizeof(srslte_pusch_hopping_cfg_t));
pusch_hopping.n_sb = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_HOPPING_N_SB);
pusch_hopping.hop_mode = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_HOPPING_INTRA_SF) ?
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF :
pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF;
pusch_hopping.hopping_offset = (uint32_t) phy->params_db->get_param(phy_interface_params::PUSCH_HOPPING_OFFSET);
/* PUSCH UCI configuration */
bzero(&uci_cfg, sizeof(srslte_uci_cfg_t));
uci_cfg.I_offset_ack = (uint32_t) phy->params_db->get_param(phy_interface_params::UCI_I_OFFSET_ACK);
uci_cfg.I_offset_cqi = (uint32_t) phy->params_db->get_param(phy_interface_params::UCI_I_OFFSET_CQI);
uci_cfg.I_offset_ri = (uint32_t) phy->params_db->get_param(phy_interface_params::UCI_I_OFFSET_RI);
/* PUCCH configuration */
bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t));
pucch_cfg.delta_pucch_shift = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_DELTA_SHIFT);
pucch_cfg.N_cs = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_CYCLIC_SHIFT);
pucch_cfg.n_rb_2 = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_RB_2);
pucch_cfg.srs_configured = (bool) phy->params_db->get_param(phy_interface_params::SRS_IS_CONFIGURED)?true:false;
pucch_cfg.srs_cs_subf_cfg = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_CS_SFCFG);
pucch_cfg.srs_simul_ack = (bool) phy->params_db->get_param(phy_interface_params::SRS_CS_ACKNACKSIMUL)?true:false;
/* PUCCH Scheduling configuration */
bzero(&pucch_sched, sizeof(srslte_pucch_sched_t));
pucch_sched.n_pucch_1[0] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_0);
pucch_sched.n_pucch_1[1] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_1);
pucch_sched.n_pucch_1[2] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_2);
pucch_sched.n_pucch_1[3] = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1_3);
pucch_sched.N_pucch_1 = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_1);
pucch_sched.n_pucch_2 = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_2);
pucch_sched.n_pucch_sr = (uint32_t) phy->params_db->get_param(phy_interface_params::PUCCH_N_PUCCH_SR);
/* SRS Configuration */
bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t));
srs_cfg.configured = (bool) phy->params_db->get_param(phy_interface_params::SRS_IS_CONFIGURED)?true:false;
srs_cfg.subframe_config = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_CS_SFCFG);
srs_cfg.bw_cfg = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_CS_BWCFG);
srs_cfg.I_srs = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_CONFIGINDEX);
srs_cfg.B = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_BW);
srs_cfg.b_hop = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_HOP);
srs_cfg.n_rrc = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_NRRC);
srs_cfg.k_tc = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_TXCOMB);
srs_cfg.n_srs = (uint32_t) phy->params_db->get_param(phy_interface_params::SRS_UE_CYCLICSHIFT);
srslte_ue_ul_set_cfg(&ue_ul, &dmrs_cfg, &srs_cfg, &pucch_cfg, &pucch_sched, &uci_cfg, &pusch_hopping);
/* CQI configuration */
cqi_cfg.configured = (bool) phy->params_db->get_param(phy_interface_params::CQI_PERIODIC_CONFIGURED)?true:false;
cqi_cfg.pmi_idx = (uint32_t) phy->params_db->get_param(phy_interface_params::CQI_PERIODIC_PMI_IDX);
/* SR configuration */
I_sr = (uint32_t) phy->params_db->get_param(phy_interface_params::SR_CONFIG_INDEX);
if (pregen_enabled) {
srslte_ue_ul_pregen_signals(&ue_ul);
}
}
}
}
Loading…
Cancel
Save