mirror of https://github.com/pvnis/srsRAN_4G.git
Initial commit
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…
Reference in New Issue