diff --git a/srsapps/common/include/srsapps/common/mac_interface.h b/srsapps/common/include/srsapps/common/mac_interface.h new file mode 100644 index 000000000..d027d2e80 --- /dev/null +++ b/srsapps/common/include/srsapps/common/mac_interface.h @@ -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 +#include +#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 + diff --git a/srsapps/common/include/srsapps/common/phy_interface.h b/srsapps/common/include/srsapps/common/phy_interface.h new file mode 100644 index 000000000..b4f29773f --- /dev/null +++ b/srsapps/common/include/srsapps/common/phy_interface.h @@ -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 +#include +#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 + diff --git a/srsapps/common/include/srsapps/common/task_dispatcher.h b/srsapps/common/include/srsapps/common/task_dispatcher.h new file mode 100644 index 000000000..392bc53cf --- /dev/null +++ b/srsapps/common/include/srsapps/common/task_dispatcher.h @@ -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 +#include +#include +#include +#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 pending_tasks; + void run_thread(); + pthread_mutex_t mutex; + pthread_cond_t cvar; + bool running; +}; +} + +#endif \ No newline at end of file diff --git a/srsapps/common/include/srsapps/common/thread_pool.h b/srsapps/common/include/srsapps/common/thread_pool.h new file mode 100644 index 000000000..c75cec77e --- /dev/null +++ b/srsapps/common/include/srsapps/common/thread_pool.h @@ -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 +#include +#include +#include + +#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 workers; + std::vector begin; + std::stack available_workers; + pthread_cond_t cvar_start, cvar_stop; + pthread_mutex_t mutex_start, mutex_stop; + uint32_t nof_workers; +}; +} + +#endif \ No newline at end of file diff --git a/srsapps/common/src/task_dispatcher.cc b/srsapps/common/src/task_dispatcher.cc new file mode 100644 index 000000000..619a121dd --- /dev/null +++ b/srsapps/common/src/task_dispatcher.cc @@ -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 + +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); + } + } +} + + +} \ No newline at end of file diff --git a/srsapps/common/src/thread_pool.cc b/srsapps/common/src/thread_pool.cc new file mode 100644 index 000000000..0c7c31710 --- /dev/null +++ b/srsapps/common/src/thread_pool.cc @@ -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;isetup(id, this); + } +} + +void thread_pool::stop() +{ + for (uint32_t i=0;istop(); + 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 +#include +#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 \ No newline at end of file diff --git a/srsapps/ue/phy/include/srsapps/ue/phy/phch_recv.h b/srsapps/ue/phy/include/srsapps/ue/phy/phch_recv.h new file mode 100644 index 000000000..b31c055b5 --- /dev/null +++ b/srsapps/ue/phy/include/srsapps/ue/phy/phch_recv.h @@ -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 \ No newline at end of file diff --git a/srsapps/ue/phy/include/srsapps/ue/phy/phch_worker.h b/srsapps/ue/phy/include/srsapps/ue/phy/phch_worker.h new file mode 100644 index 000000000..3dfa2134b --- /dev/null +++ b/srsapps/ue/phy/include/srsapps/ue/phy/phch_worker.h @@ -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 +#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 + diff --git a/srsapps/ue/phy/src/phch_common.cc b/srsapps/ue/phy/src/phch_common.cc new file mode 100644 index 000000000..33090c70c --- /dev/null +++ b/srsapps/ue/phy/src/phch_common.cc @@ -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 +#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); +} + +} +} \ No newline at end of file diff --git a/srsapps/ue/phy/src/phch_recv.cc b/srsapps/ue/phy/src/phch_recv.cc new file mode 100644 index 000000000..3c3ad8fe3 --- /dev/null +++ b/srsapps/ue/phy/src/phch_recv.cc @@ -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 +#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;iget_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;iget_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; +} + +} +} \ No newline at end of file diff --git a/srsapps/ue/phy/src/phch_worker.cc b/srsapps/ue/phy/src/phch_worker.cc new file mode 100644 index 000000000..20a0087ce --- /dev/null +++ b/srsapps/ue/phy/src/phch_worker.cc @@ -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 +#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); + } + +} + + + + + } +} \ No newline at end of file