diff --git a/srslte/CMakeLists.txt b/srslte/CMakeLists.txt index 89a55022d..23a512ef6 100644 --- a/srslte/CMakeLists.txt +++ b/srslte/CMakeLists.txt @@ -46,7 +46,4 @@ ADD_CUSTOM_TARGET (add_srslte_headers SOURCES ${HEADERS_ALL}) ######################################################################## ADD_SUBDIRECTORY(lib) ADD_SUBDIRECTORY(examples) - - add_subdirectory(tutorial_examples) -add_subdirectory(itf) \ No newline at end of file diff --git a/srslte/include/srslte/ue_itf/dl_buffer.h b/srslte/include/srslte/ue_itf/dl_buffer.h new file mode 100644 index 000000000..ddc9fd8a4 --- /dev/null +++ b/srslte/include/srslte/ue_itf/dl_buffer.h @@ -0,0 +1,82 @@ + /** + * + * \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 "srslte/srslte.h" +#include "srslte/ue_itf/queue.h" +#include "srslte/ue_itf/sched_grant.h" +#include "srslte/ue_itf/params.h" + +#ifndef UEDLBUFFER_H +#define UEDLBUFFER_H + +namespace srslte { +namespace ue { + + /* Class for the processing of Downlink buffers. The MAC obtains a buffer for a given TTI and then + * gets ul/dl scheduling grants and/or processes phich/pdsch channels + */ + class SRSLTE_API dl_buffer : public queue::element { + public: + typedef enum { + PDCCH_UL_SEARCH_CRNTI = 0, + PDCCH_UL_SEARCH_RA_PROC, + PDCCH_UL_SEARCH_SPS, + PDCCH_UL_SEARCH_TEMPORAL, + PDCCH_UL_SEARCH_TPC_PUSCH, + PDCCH_UL_SEARCH_TPC_PUCCH + } pdcch_ul_search_t; + + typedef enum { + PDCCH_DL_SEARCH_CRNTI = 0, + PDCCH_DL_SEARCH_SIRNTI, + PDCCH_DL_SEARCH_PRNTI, + PDCCH_DL_SEARCH_RARNTI, + PDCCH_DL_SEARCH_TEMPORAL, + PDCCH_DL_SEARCH_SPS + } pdcch_dl_search_t; + + bool init_cell(srslte_cell_t cell, params *params_db); + void free_cell(); + bool recv_ue_sync(srslte_ue_sync_t *ue_sync, srslte_timestamp_t *rx_time); + bool get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, sched_grant *grant); + bool get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, sched_grant *grant); + bool decode_phich(srslte_phich_alloc_t assignment); + bool decode_pdsch(sched_grant pdsch_grant, uint8_t *payload); // returns true or false for CRC OK/KO + private: + params *params_db; + srslte_cell_t cell; + srslte_ue_dl_t ue_dl; + srslte_phich_t phich; + cf_t *signal_buffer; + uint32_t cfi; + bool sf_symbols_and_ce_done; + bool pdcch_llr_extracted; + uint32_t tti; + }; +} +} +#endif diff --git a/srslte/include/srslte/ue_itf/params.h b/srslte/include/srslte/ue_itf/params.h new file mode 100644 index 000000000..836716fb0 --- /dev/null +++ b/srslte/include/srslte/ue_itf/params.h @@ -0,0 +1,81 @@ +/** + * + * \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 "srslte/srslte.h" + +#ifndef UEH +#define UEH + +namespace srslte { +namespace ue { + class SRSLTE_API params + { + public: + typedef enum { + + DL_FREQ = 0, + UL_FREQ, + + CELLSEARCH_TIMEOUT_PSS_NFRAMES, + CELLSEARCH_TIMEOUT_MIB_NFRAMES, + CELLSEARCH_FORCE_N_ID_2, + CELLSEARCH_CORRELATION_THRESHOLD, // integer that will be divided by 10 + + PUSCH_BETA, + + PUSCH_RS_GROUP_HOPPING_EN, + PUSCH_RS_SEQUENCE_HOPPING_EN, + PUSCH_RS_CYCLIC_SHIFT, + PUSCH_RS_GROUP_ASSIGNMENT, + + PUSCH_HOPPING_N_SB, + PUSCH_HOPPING_INTRA_SF, + PUSCH_HOPPING_OFFSET, + + 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, + } param_t; + + void set_param(param_t param, int64_t value); + int64_t get_param(param_t param); + + private: + int64_t params_db[NOF_PARAMS]; + }; +} +} + +#endif \ No newline at end of file diff --git a/srslte/include/srslte/ue_itf/phy.h b/srslte/include/srslte/ue_itf/phy.h new file mode 100644 index 000000000..787c20aa8 --- /dev/null +++ b/srslte/include/srslte/ue_itf/phy.h @@ -0,0 +1,114 @@ +/** + * + * \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 "srslte/srslte.h" +#include "srslte/ue_itf/dl_buffer.h" +#include "srslte/ue_itf/ul_buffer.h" +#include "srslte/ue_itf/prach.h" +#include "srslte/ue_itf/params.h" +#include "srslte/ue_itf/sched_grant.h" +#include "srslte/ue_itf/queue.h" + +#ifndef UEPHY_H +#define UEPHY_H + +#define SYNC_MODE_CV 0 +#define SYNC_MODE_CALLBACK 1 +#define SYNC_MODE SYNC_MODE_CALLBACK + +namespace srslte { +namespace ue { + +typedef _Complex float cf_t; + +class SRSLTE_API phy +{ +public: + +#if SYNC_MODE==SYNC_MODE_CALLBACK + typedef void (*ue_phy_callback_t) (void); + ue_phy_callback_t tti_clock_callback; + ue_phy_callback_t status_change; + phy(ue_phy_callback_t tti_clock_callback, ue_phy_callback_t status_change); +#else + phy(); +#endif + ~phy(); + + void measure(); // TBD + void dl_bch(); + void start_rxtx(); + void stop_rxtx(); + void send_prach(uint32_t preamble_idx); + + bool status_is_idle(); + bool status_is_rxtx(); + bool status_is_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN]); + + + uint32_t get_tti(); +#if SYNC_MODE==SYNC_MODE_CV + std::condition_variable tti_cv; + std::mutex tti_mutex; +#endif + + ul_buffer* get_ul_buffer(uint32_t tti); + dl_buffer* get_dl_buffer(uint32_t tti); + + void main_radio_loop(); + +private: + enum { + IDLE, MEASURE, RX_BCH, MIB_DECODED, RXTX + } phy_state; + + srslte_cell_t cell; + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + bool is_sfn_synched = false; + bool started = false; + uint32_t current_tti; + + srslte_ue_sync_t ue_sync; + srslte_ue_mib_t ue_mib; + + queue *ul_buffer_queue; + queue *dl_buffer_queue; + prach prach_buffer; + params params_db; + + pthread_t radio_thread; + void *radio_handler; + static void *radio_thread_fnc(void *arg); + void run_rx_bch_state(); + bool rx_bch(); + int sync_sfn(); + void run_rx_tx_state(); +}; + +} +} +#endif \ No newline at end of file diff --git a/srslte/include/srslte/ue_itf/prach.h b/srslte/include/srslte/ue_itf/prach.h new file mode 100644 index 000000000..ce3a10076 --- /dev/null +++ b/srslte/include/srslte/ue_itf/prach.h @@ -0,0 +1,56 @@ + /** + * + * \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 "srslte/srslte.h" +#include "srslte/ue_itf/queue.h" +#include "srslte/ue_itf/params.h" + +#ifndef UEPRACH_H +#define UEPRACH_H + +namespace srslte { +namespace ue { + + class SRSLTE_API prach { + public: + bool init_cell(srslte_cell_t cell, params *params_db); + void free_cell(); + bool ready_to_send(uint32_t preamble_idx); + bool is_ready_to_send(uint32_t current_tti); + bool send(void *radio_handler, srslte_timestamp_t rx_time); + private: + params *params_db; + int preamble_idx; + bool initiated = false; + uint32_t len; + cf_t *buffer[64]; + srslte_prach_t prach; + }; + +} +} +#endif diff --git a/srslte/itf/queue.h b/srslte/include/srslte/ue_itf/queue.h similarity index 97% rename from srslte/itf/queue.h rename to srslte/include/srslte/ue_itf/queue.h index 9cd0e6fa3..577e20542 100644 --- a/srslte/itf/queue.h +++ b/srslte/include/srslte/ue_itf/queue.h @@ -25,11 +25,14 @@ * */ +#include + #ifndef QUEUE_H #define QUEUE_H namespace srslte { - +namespace ue { + class queue { public: @@ -82,5 +85,5 @@ private: }; } - +} #endif \ No newline at end of file diff --git a/srslte/include/srslte/ue_itf/sched_grant.h b/srslte/include/srslte/ue_itf/sched_grant.h new file mode 100644 index 000000000..f335a01c4 --- /dev/null +++ b/srslte/include/srslte/ue_itf/sched_grant.h @@ -0,0 +1,66 @@ + /** + * + * \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 "srslte/srslte.h" +#include "queue.h" + +#ifndef UESCHEDGRANT_H +#define UESCHEDGRANT_H + +namespace srslte { +namespace ue { + + /* Uplink/Downlink scheduling grant generated by a successfully decoded PDCCH */ + class SRSLTE_API sched_grant { + public: + + typedef enum {DOWNLINK=0, UPLINK=1} direction_t; + + uint16_t get_rnti(); + uint32_t get_rv(); + void set_rv(uint32_t rv); + bool get_ndi(); + uint32_t get_current_tti(); + bool get_cqi_request(); + int get_harq_process(); + bool is_uplink(); + bool is_downlink(); + void* get_grant_ptr(); + protected: + union { + srslte_ra_pusch_t ul_grant; + srslte_ra_pdsch_t dl_grant; + }; + direction_t dir; + uint16_t rnti; + uint32_t current_tti; + }; + +} +} + +#endif diff --git a/srslte/include/srslte/ue_itf/ul_buffer.h b/srslte/include/srslte/ue_itf/ul_buffer.h new file mode 100644 index 000000000..d66998256 --- /dev/null +++ b/srslte/include/srslte/ue_itf/ul_buffer.h @@ -0,0 +1,65 @@ + /** + * + * \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 "srslte/srslte.h" +#include "srslte/ue_itf/queue.h" +#include "srslte/ue_itf/sched_grant.h" +#include "srslte/ue_itf/params.h" + +#ifndef UEULBUFFER_H +#define UEULBUFFER_H + + +namespace srslte { +namespace ue { + + /* Uplink scheduling assignment. The MAC instructs the PHY to prepare an UL packet (PUSCH or PUCCH) + * for transmission. The MAC must call generate_pusch() to set the packet ready for transmission + */ + class SRSLTE_API ul_buffer : public queue::element { + public: + bool init_cell(srslte_cell_t cell, params *params_db); + void free_cell(); + void set_tti(uint32_t tti); + void set_current_tx_nb(uint32_t current_tx_nb); + bool generate_pusch(sched_grant pusch_grant, uint8_t *payload, srslte_uci_data_t uci_data); + bool generate_pucch(srslte_uci_data_t uci_data); + bool send_packet(void *radio_handler, srslte_timestamp_t rx_time); + private: + params *params_db; + srslte_cell_t cell; + srslte_ue_ul_t ue_ul; + bool signal_generated; + cf_t* signal_buffer; + uint32_t tti; + uint32_t current_tx_nb; + }; + +} +} + +#endif \ No newline at end of file diff --git a/srslte/itf/ue_phy.cc b/srslte/itf/ue_phy.cc deleted file mode 100644 index f34a91e7e..000000000 --- a/srslte/itf/ue_phy.cc +++ /dev/null @@ -1,577 +0,0 @@ -/** - * - * \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 -#include -#include -#include "srslte/srslte.h" -#include "ue_phy.h" - - -/* - * CLASS SCHED_GRANT - * - */ - -/* Returns the RNTI associated with the UL/DL scheduling grant */ -uint16_t srslte::ue_phy::sched_grant::get_rnti() { - return rnti; -} - -uint32_t srslte::ue_phy::sched_grant::get_rv() { - if (dir == UPLINK) { - return ul_grant.rv_idx; - } else { - return dl_grant.rv_idx; - } -} - -void srslte::ue_phy::sched_grant::set_rv(uint32_t rv) { - if (dir == UPLINK) { - ul_grant.rv_idx = rv; - } else { - dl_grant.rv_idx = rv; - } -} - -bool srslte::ue_phy::sched_grant::get_ndi() { - if (dir == UPLINK) { - return ul_grant.ndi; - } else { - return dl_grant.ndi; - } -} - -bool srslte::ue_phy::sched_grant::get_cqi_request() { - if (dir == UPLINK) { - return ul_grant.ndi; - } else { - return dl_grant.ndi; - } -} - -uint32_t srslte::ue_phy::sched_grant::get_current_tti() { - return current_tti; -} - -int srslte::ue_phy::sched_grant::get_harq_process() { - if (dir == UPLINK) { - return -1; - } else { - return dl_grant.harq_process; - } -} - -bool srslte::ue_phy::sched_grant::is_uplink() { - return dir == UPLINK; -} - -bool srslte::ue_phy::sched_grant::is_downlink() { - return dir == DOWNLINK; -} -void* srslte::ue_phy::sched_grant::get_grant_ptr() { - if (is_uplink()) { - return (void*) &ul_grant; - } else { - return (void*) &dl_grant; - } -} - - -/* - * CLASS UL_BUFFER - * - */ -bool srslte::ue_phy::ul_buffer::init_cell(srslte_cell_t cell_, int64_t *params_db_) { - cell = cell_; - params_db = params_db_; - signal_generated = false; - current_tx_nb = 0; - if (!srslte_ue_ul_init(&ue_ul, cell)) { - signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - return signal_buffer?true:false; - } else { - return false; - } -} - -void srslte::ue_phy::ul_buffer::free_cell() { - if (signal_buffer) { - free(signal_buffer); - } - srslte_ue_ul_free(&ue_ul); -} - -bool srslte::ue_phy::ul_buffer::generate_pusch(sched_grant pusch_grant, - uint8_t *payload, - srslte_uci_data_t uci_data) -{ - if (pusch_grant.is_uplink()) { - fprintf(stderr, "Invalid scheduling grant. Grant is for Downlink\n"); - return false; - } - - srslte_refsignal_drms_pusch_cfg_t drms_cfg; - bzero(&drms_cfg, sizeof(srslte_refsignal_drms_pusch_cfg_t)); - - drms_cfg.beta_pusch = params_db[PARAM_PUSCH_BETA]; - drms_cfg.group_hopping_en = params_db[PARAM_PUSCH_RS_GROUP_HOPPING_EN]; - drms_cfg.sequence_hopping_en = params_db[PARAM_PUSCH_RS_SEQUENCE_HOPPING_EN]; - drms_cfg.cyclic_shift = params_db[PARAM_PUSCH_RS_CYCLIC_SHIFT]; - drms_cfg.delta_ss = params_db[PARAM_PUSCH_RS_GROUP_ASSIGNMENT]; - - srslte_pusch_hopping_cfg_t pusch_hopping; - pusch_hopping.n_sb = params_db[PARAM_PUSCH_HOPPING_N_SB]; - pusch_hopping.hop_mode = params_db[PARAM_PUSCH_HOPPING_INTRA_SF] ? - pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF : - pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF; - pusch_hopping.hopping_offset = params_db[PARAM_PUSCH_HOPPING_OFFSET]; - pusch_hopping.current_tx_nb = current_tx_nb; - - srslte_ue_ul_set_pusch_cfg(&ue_ul, &drms_cfg, &pusch_hopping); - - int n = srslte_ue_ul_pusch_uci_encode_rnti(&ue_ul, (srslte_ra_pusch_t*) pusch_grant.get_grant_ptr(), - payload, uci_data, - tti%10, pusch_grant.get_rnti(), - signal_buffer); - if (n < 0) { - fprintf(stderr, "Error encoding PUSCH\n"); - return false; - } - - signal_generated = true; - - /* This is done by the transmission thread - srslte_vec_sc_prod_cfc(signal_buffer, beta_pusch, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); - float time_adv_sec = TA_OFFSET + ((float) n_ta)*LTE_TS; - srslte_timestamp_t next_tx_time; - srslte_timestamp_copy(&next_tx_time, &last_rx_time); - srslte_timestamp_add(&next_tx_time, 0, 0.003 - time_adv_sec); - */ - // Send through radio - - return true; -} - -bool srslte::ue_phy::ul_buffer::generate_pucch(srslte_uci_data_t uci_data) -{ - return false; -} - -/* - * CLASS DL_BUFFER - * - */ -bool srslte::ue_phy::dl_buffer::init_cell(srslte_cell_t cell_, int64_t *params_db_) -{ - params_db = params_db_; - cell = cell_; - sf_symbols_and_ce_done = false; - pdcch_llr_extracted = false; - tti = 0; - if (srslte_ue_dl_init(&ue_dl, cell)) { - signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - return signal_buffer?true:false; - } else { - return false; - } -} - -void srslte::ue_phy::dl_buffer::free_cell() -{ - if (signal_buffer) { - free(signal_buffer); - } - srslte_ue_dl_free(&ue_dl); -} - -bool srslte::ue_phy::dl_buffer::get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant) -{ - if (!sf_symbols_and_ce_done) { - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { - return false; - } - sf_symbols_and_ce_done = true; - } - if (!pdcch_llr_extracted) { - if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) { - return false; - } - pdcch_llr_extracted = true; - } - - srslte_dci_msg_t dci_msg; - if (srslte_ue_dl_find_ul_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) { - return false; - } - - if (srslte_dci_msg_to_ra_ul(&dci_msg, cell.nof_prb, - params_db[PARAM_PUSCH_HOPPING_OFFSET], - (srslte_ra_pusch_t*) grant->get_grant_ptr())) - { - return false; - } - - return true; -} - -bool srslte::ue_phy::dl_buffer::get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant) -{ - if (!sf_symbols_and_ce_done) { - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { - return false; - } - sf_symbols_and_ce_done = true; - } - if (!pdcch_llr_extracted) { - if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) { - return false; - } - pdcch_llr_extracted = true; - } - - srslte_dci_msg_t dci_msg; - if (srslte_ue_dl_find_dl_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) { - return false; - } - - if (srslte_dci_msg_to_ra_dl(&dci_msg, rnti, cell, cfi, - (srslte_ra_pdsch_t*) grant->get_grant_ptr())) - { - return false; - } - - return true; -} - -bool srslte::ue_phy::dl_buffer::decode_phich(srslte_phich_alloc_t assignment) -{ - if (!sf_symbols_and_ce_done) { - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { - return false; - } - sf_symbols_and_ce_done = true; - } - return false; -} - -bool srslte::ue_phy::dl_buffer::decode_pdsch(sched_grant pdsch_grant, uint8_t *payload) -{ - if (!sf_symbols_and_ce_done) { - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { - return false; - } - sf_symbols_and_ce_done = true; - } - srslte_ra_pdsch_t *ra_dl = (srslte_ra_pdsch_t*) pdsch_grant.get_grant_ptr(); - if (srslte_harq_setup_dl(&ue_dl.harq_process[0], ra_dl->mcs, - pdsch_grant.get_rv(), tti%10, &ra_dl->prb_alloc)) { - fprintf(stderr, "Error configuring HARQ process\n"); - return SRSLTE_ERROR; - } - if (ue_dl.harq_process[0].mcs.mod > 0 && ue_dl.harq_process[0].mcs.tbs >= 0) { - int ret = srslte_pdsch_decode_rnti(&ue_dl.pdsch, &ue_dl.harq_process[0], ue_dl.sf_symbols, - ue_dl.ce, 0, pdsch_grant.get_rnti(), payload); - if (ret == SRSLTE_SUCCESS) { - return true; - } - } - return false; -} - - - - - - - -/* - * CLASS UE_PHY - * - */ -#if SYNC_MODE==SYNC_MODE_CALLBACK -srslte::ue_phy::ue_phy(ue_phy_callback_t tti_clock_callback_, ue_phy_callback_t status_change_) -{ - tti_clock_callback = tti_clock_callback_; - status_change = status_change_; - ul_buffer_queue = new queue(6, sizeof(ul_buffer)); - dl_buffer_queue = new queue(6, sizeof(dl_buffer)); - - started = true; - - pthread_create(&radio_thread, NULL, radio_thread_fnc, this); -} - -#else -srslte::ue_phy::ue_phy() -{ - -} - -#endif - -srslte::ue_phy::~ue_phy() -{ - started = false; - - pthread_join(radio_thread, NULL); - - delete ul_buffer_queue; - delete dl_buffer_queue; - - if (prach_initiated) { - for (uint32_t i=0;i<64;i++) { - if (prach_buffer[i]) { - free(prach_buffer[i]); - } - } - srslte_prach_free(&prach); - } -} - -bool srslte::ue_phy::init_prach() -{ - - if (srslte_prach_init(&prach, srslte_symbol_sz(cell.nof_prb), - srslte_prach_get_preamble_format(params_db[PARAMS_PRACH_CONFIG_INDEX]), - params_db[PARAMS_PRACH_ROOT_SEQ_IDX], - params_db[PARAMS_PRACH_HIGH_SPEED_FLAG]?true:false, - params_db[PARAMS_PRACH_ZC_CONFIG])) { - return false; - } - - prach_len = prach.N_seq + prach.N_cp; - for (uint32_t i=0;i<64;i++) { - prach_buffer[i] = (cf_t*) srslte_vec_malloc(prach_len*sizeof(cf_t)); - if(!prach_buffer[i]) { - return false; - } - if(srslte_prach_gen(&prach, i, params_db[PARAMS_PRACH_FREQ_OFFSET], prach_buffer[i])){ - return false; - } - } - prach_initiated = true; - return true; -} - -// FIXME: Add PRACH power control -void srslte::ue_phy::send_prach(uint32_t preamble_idx) -{ - if (prach_initiated && phy_state == RXTX) { - prach_ready_to_send = true; - } -} - -// Do fast measurement on RSSI and/or PSS autocorrelation energy or PSR -void srslte::ue_phy::measure() -{ - if (phy_state == IDLE) { - // capture and do measurement - status_change(); - } -} - -void srslte::ue_phy::dl_bch() -{ - if (phy_state == IDLE) { - phy_state = RX_BCH; - status_change(); - } -} - -void srslte::ue_phy::start_rxtx() -{ - if (phy_state == MIB_DECODED) { - // Set sampling freq to MIB PRB - // start radio streaming - phy_state = RXTX; - status_change(); - } -} - -void srslte::ue_phy::stop_rxtx() -{ - // stop radio - phy_state = IDLE; - status_change(); - } - -bool srslte::ue_phy::status_is_idle() { - return phy_state == IDLE; -} - -bool srslte::ue_phy::status_is_rxtx() { - return phy_state == RXTX; -} - -bool srslte::ue_phy::status_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN]) -{ - if (phy_state == MIB_DECODED) { - memcpy(payload, bch_payload, SRSLTE_BCH_PAYLOAD_LEN*sizeof(uint8_t)); - } -} - - -static void* radio_thread_fnc(void *arg) { - srslte::ue_phy* ue_phy = (srslte::ue_phy*) arg; - ue_phy->main_radio_loop(); - return NULL; -} - -int radio_recv_wrapper_cs(void*,void*,uint32_t,srslte_timestamp_t*); - -bool srslte::ue_phy::rx_bch() -{ - 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_handler)) { - return false; - } - - srslte_ue_cellsearch_set_nof_frames_to_scan(&cs, params_db[PARAM_CELLSEARCH_TIMEOUT_PSS_NFRAMES]); - srslte_ue_cellsearch_set_threshold(&cs, (float) params_db[PARAM_CELLSEARCH_CORRELATION_THRESHOLD]/10); - - // set sampling freq 1.92 MHz - // set frequency, gain etc - // start radio streaming - - /* 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; - uint32_t force_N_id_2 = params_db[PARAM_CELLSEARCH_FORCE_N_ID_2]; - 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); - } - // Stop radio - - srslte_ue_cellsearch_free(&cs); - - if (ret < 0) { - fprintf(stderr, "Error searching cell"); - return false; - } else if (ret == 0) { - fprintf(stderr, "Could not find any cell in this frequency"); - return false; - } - - // Save result - cell.id = found_cells[max_peak_cell].cell_id; - cell.cp = found_cells[max_peak_cell].cp; - - printf("Found CELL PHY_ID: %d, CP: %s PSR: %.1f AbsPower: %.1f dBm", - cell.id, srslte_cp_string(cell.cp), - found_cells[max_peak_cell].psr, 30+10*log10(found_cells[max_peak_cell].peak)); - - srslte_ue_mib_sync_t ue_mib; - - if (srslte_ue_mib_sync_init(&ue_mib, cell.id, cell.cp, radio_recv_wrapper_cs, radio_handler)) { - return false; - } - - uint32_t sfn, sfn_offset; - - /* Find and decode MIB */ - - // Start RX stream again - - ret = srslte_ue_mib_sync_decode(&ue_mib, params_db[PARAM_CELLSEARCH_TIMEOUT_MIB_NFRAMES], - bch_payload, &cell.nof_ports, &sfn_offset); - // Stop RX stream again - srslte_ue_mib_sync_free(&ue_mib); - - if (ret == 1) { - srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); - sfn = (sfn + sfn_offset)%1024; - current_tti = sfn*10+1; - printf("MIB decoded: %d ports, SFN: %d, TTI: %d", cell.nof_ports, sfn, current_tti); - return true; - } else { - printf("Error decoding MIB"); - return false; - } -} - -void srslte::ue_phy::run_rx_bch_state() { - if (rx_bch()) { - for(uint32_t i=0;i<6;i++) { - get_ul_buffer(i)->init_cell(cell, params_db); - get_dl_buffer(i)->init_cell(cell, params_db); - } - // init also ue_mib for sfn synch - phy_state = MIB_DECODED; - status_change(); - } else { - phy_state = IDLE; - } -} - -void srslte::ue_phy::run_rx_tx_state() -{ - // if not synched -> go through mib - // else receive sync frame on dl_frame - // if have to send prach, send it - // if ul ready to send send -} - -void srslte::ue_phy::main_radio_loop() { - while(started) { - switch(phy_state) { - case IDLE: - case MIB_DECODED: - break; - case RX_BCH: - run_rx_bch_state(); - break; - case RXTX: - run_rx_tx_state(); - break; - } - } -} - -void srslte::ue_phy::set_param(param_t param, int64_t value) -{ - params_db[param] = value; -} - -srslte::ue_phy::ul_buffer* srslte::ue_phy::get_ul_buffer(uint32_t tti) -{ - return (srslte::ue_phy::ul_buffer*) ul_buffer_queue->get(tti); -} - -srslte::ue_phy::dl_buffer* srslte::ue_phy::get_dl_buffer(uint32_t tti) -{ - return (srslte::ue_phy::dl_buffer*) dl_buffer_queue->get(tti); -} - - diff --git a/srslte/itf/ue_phy.h b/srslte/itf/ue_phy.h deleted file mode 100644 index 78aab3dc2..000000000 --- a/srslte/itf/ue_phy.h +++ /dev/null @@ -1,233 +0,0 @@ -/** - * - * \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 "srslte/srslte.h" -#include "queue.h" - -#ifndef UEPHY_H -#define UEPHY_H - -#define SYNC_MODE_CV 0 -#define SYNC_MODE_CALLBACK 1 -#define SYNC_MODE SYNC_MODE_CALLBACK - -namespace srslte { - -typedef _Complex float cf_t; - -class ue_phy -{ -public: - - typedef enum {DOWNLINK=0, UPLINK=1} direction_t; - - typedef enum { - PDCCH_UL_SEARCH_CRNTI = 0, - PDCCH_UL_SEARCH_RA_PROC, - PDCCH_UL_SEARCH_SPS, - PDCCH_UL_SEARCH_TEMPORAL, - PDCCH_UL_SEARCH_TPC_PUSCH, - PDCCH_UL_SEARCH_TPC_PUCCH - } pdcch_ul_search_t; - - typedef enum { - PDCCH_DL_SEARCH_CRNTI = 0, - PDCCH_DL_SEARCH_SIRNTI, - PDCCH_DL_SEARCH_PRNTI, - PDCCH_DL_SEARCH_RARNTI, - PDCCH_DL_SEARCH_TEMPORAL, - PDCCH_DL_SEARCH_SPS - } pdcch_dl_search_t; - - /* Uplink/Downlink scheduling grant generated by a successfully decoded PDCCH */ - class sched_grant { - public: - uint16_t get_rnti(); - uint32_t get_rv(); - void set_rv(uint32_t rv); - bool get_ndi(); - uint32_t get_current_tti(); - bool get_cqi_request(); - int get_harq_process(); - bool is_uplink(); - bool is_downlink(); - void* get_grant_ptr(); - protected: - union { - srslte_ra_pusch_t ul_grant; - srslte_ra_pdsch_t dl_grant; - }; - direction_t dir; - uint16_t rnti; - uint32_t current_tti; - }; - - /* Uplink scheduling assignment. The MAC instructs the PHY to prepare an UL packet (PUSCH or PUCCH) - * for transmission. The MAC must call generate_pusch() to set the packet ready for transmission - */ - class ul_buffer : public queue::element { - public: - bool init_cell(srslte_cell_t cell, int64_t *params_db); - void free_cell(); - void set_tti(uint32_t tti); - void set_current_tx_nb(uint32_t current_tx_nb); - bool generate_pusch(sched_grant pusch_grant, uint8_t *payload, srslte_uci_data_t uci_data); - bool generate_pucch(srslte_uci_data_t uci_data); - private: - int64_t *params_db; - srslte_cell_t cell; - srslte_ue_ul_t ue_ul; - bool signal_generated; - cf_t* signal_buffer; - uint32_t tti; - uint32_t current_tx_nb; - }; - - /* Class for the processing of Downlink buffers. The MAC obtains a buffer for a given TTI and then - * gets ul/dl scheduling grants and/or processes phich/pdsch channels - */ - class dl_buffer : public queue::element { - public: - bool init_cell(srslte_cell_t cell, int64_t *params_db); - void free_cell(); - bool get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant); - bool get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, ue_phy::sched_grant *grant); - bool decode_phich(srslte_phich_alloc_t assignment); - bool decode_pdsch(sched_grant pdsch_grant, uint8_t *payload); // returns true or false for CRC OK/KO - private: - int64_t *params_db; - srslte_cell_t cell; - srslte_ue_dl_t ue_dl; - srslte_phich_t phich; - cf_t *signal_buffer; - uint32_t cfi; - bool sf_symbols_and_ce_done; - bool pdcch_llr_extracted; - uint32_t tti; - }; - -#if SYNC_MODE==SYNC_MODE_CALLBACK - typedef void (*ue_phy_callback_t) (void); - ue_phy_callback_t tti_clock_callback; - ue_phy_callback_t status_change; - ue_phy(ue_phy_callback_t tti_clock_callback, ue_phy_callback_t status_change); -#else - ue_phy(); -#endif - ~ue_phy(); - - void measure(); // TBD - void dl_bch(); - void start_rxtx(); - void stop_rxtx(); - bool init_prach(); - void send_prach(uint32_t preamble_idx); - - bool status_is_idle(); - bool status_is_rxtx(); - bool status_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN]); - - typedef enum { - - PARAM_DL_FREQ = 0, - PARAM_UL_FREQ, - - PARAM_CELLSEARCH_TIMEOUT_PSS_NFRAMES, - PARAM_CELLSEARCH_TIMEOUT_MIB_NFRAMES, - PARAM_CELLSEARCH_FORCE_N_ID_2, - PARAM_CELLSEARCH_CORRELATION_THRESHOLD, // integer that will be divided by 10 - - PARAM_PUSCH_BETA, - - PARAM_PUSCH_RS_GROUP_HOPPING_EN, - PARAM_PUSCH_RS_SEQUENCE_HOPPING_EN, - PARAM_PUSCH_RS_CYCLIC_SHIFT, - PARAM_PUSCH_RS_GROUP_ASSIGNMENT, - - PARAM_PUSCH_HOPPING_N_SB, - PARAM_PUSCH_HOPPING_INTRA_SF, - PARAM_PUSCH_HOPPING_OFFSET, - - PARAMS_UCI_I_OFFSET_ACK, - PARAMS_UCI_I_OFFSET_RI, - PARAMS_UCI_I_OFFSET_CQI, - - PARAMS_PRACH_CONFIG_INDEX, - PARAMS_PRACH_ROOT_SEQ_IDX, - PARAMS_PRACH_HIGH_SPEED_FLAG, - PARAMS_PRACH_ZC_CONFIG, - PARAMS_PRACH_FREQ_OFFSET, - - PARAM_NOF_PARAMS, - } param_t; - - - void set_param(param_t param, int64_t value); - - uint32_t get_tti(); -#if SYNC_MODE==SYNC_MODE_CV - std::condition_variable tti_cv; - std::mutex tti_mutex; -#endif - - ul_buffer* get_ul_buffer(uint32_t tti); - dl_buffer* get_dl_buffer(uint32_t tti); - - void main_radio_loop(); - -private: - enum { - IDLE, MEASURE, RX_BCH, MIB_DECODED, RXTX - } phy_state; - - int64_t *params_db; - - srslte_cell_t cell; - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - bool is_sfn_synched = false; - bool started = false; - uint32_t current_tti; - - bool prach_initiated = false; - bool prach_ready_to_send = false; - uint32_t prach_len; - cf_t *prach_buffer[64]; - srslte_prach_t prach; - - queue *ul_buffer_queue; - queue *dl_buffer_queue; - - pthread_t radio_thread; - void *radio_handler; - static void* radio_thread_fnc(void *arg); - void run_rx_bch_state(); - bool rx_bch(); - void run_rx_tx_state(); -}; - -} -#endif \ No newline at end of file diff --git a/srslte/lib/CMakeLists.txt b/srslte/lib/CMakeLists.txt index b887feeb3..5d852a91d 100644 --- a/srslte/lib/CMakeLists.txt +++ b/srslte/lib/CMakeLists.txt @@ -77,8 +77,20 @@ FOREACH (_file ${cmakefiles}) ENDIF () ENDFOREACH() +######################################################################## +# Create C++ library +######################################################################## +FILE(GLOB modules *) +SET(SOURCES_CPP_ALL "") +FOREACH (_module ${modules}) + IF(IS_DIRECTORY ${_module}) + FILE(GLOB_RECURSE tmp "${_module}/src/*.cc") + LIST(APPEND SOURCES_CPP_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_module}) +ENDFOREACH() - - - +ADD_LIBRARY(srslte++ SHARED ${SOURCES_CPP_ALL}) +TARGET_LINK_LIBRARIES(srslte++ srslte m pthread ${FFTW3F_LIBRARIES}) +INSTALL(TARGETS srslte++ DESTINATION ${LIBRARY_DIR}) +LIBLTE_SET_PIC(srslte++) diff --git a/srslte/lib/ue_itf/src/dl_buffer.cc b/srslte/lib/ue_itf/src/dl_buffer.cc new file mode 100644 index 000000000..699b9adff --- /dev/null +++ b/srslte/lib/ue_itf/src/dl_buffer.cc @@ -0,0 +1,171 @@ +/** + * + * \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 +#include +#include +#include "srslte/srslte.h" + +#include "srslte/ue_itf/sched_grant.h" +#include "srslte/ue_itf/dl_buffer.h" +#include "srslte/ue_itf/phy.h" +#include "srslte/ue_itf/params.h" + + +namespace srslte { +namespace ue { + +bool dl_buffer::init_cell(srslte_cell_t cell_, params *params_db_) +{ + params_db = params_db_; + cell = cell_; + sf_symbols_and_ce_done = false; + pdcch_llr_extracted = false; + tti = 0; + if (srslte_ue_dl_init(&ue_dl, cell)) { + signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + return signal_buffer?true:false; + } else { + return false; + } +} + +void dl_buffer::free_cell() +{ + if (signal_buffer) { + free(signal_buffer); + } + srslte_ue_dl_free(&ue_dl); +} + +// FIXME: Avoid this memcpy modifying ue_sync to directly write into provided pointer +bool dl_buffer::recv_ue_sync(srslte_ue_sync_t *ue_sync, srslte_timestamp_t *rx_time) +{ + cf_t *sf_buffer = NULL; + if (srslte_ue_sync_get_buffer(ue_sync, &sf_buffer)) { + return false; + } + memcpy(signal_buffer, sf_buffer, sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + srslte_ue_sync_get_last_timestamp(ue_sync, rx_time); +} + +bool dl_buffer::get_ul_grant(pdcch_ul_search_t mode, uint32_t rnti, sched_grant *grant) +{ + if (!sf_symbols_and_ce_done) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + return false; + } + sf_symbols_and_ce_done = true; + } + if (!pdcch_llr_extracted) { + if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) { + return false; + } + pdcch_llr_extracted = true; + } + + srslte_dci_msg_t dci_msg; + if (srslte_ue_dl_find_ul_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) { + return false; + } + + if (srslte_dci_msg_to_ra_ul(&dci_msg, cell.nof_prb, + params_db->get_param(params::PUSCH_HOPPING_OFFSET), + (srslte_ra_pusch_t*) grant->get_grant_ptr())) + { + return false; + } + + return true; +} + +bool dl_buffer::get_dl_grant(pdcch_dl_search_t mode, uint32_t rnti, sched_grant *grant) +{ + if (!sf_symbols_and_ce_done) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + return false; + } + sf_symbols_and_ce_done = true; + } + if (!pdcch_llr_extracted) { + if (srslte_pdcch_extract_llr(&ue_dl.pdcch, ue_dl.sf_symbols, ue_dl.ce, 0, tti%10, cfi)) { + return false; + } + pdcch_llr_extracted = true; + } + + srslte_dci_msg_t dci_msg; + if (srslte_ue_dl_find_dl_dci(&ue_dl, &dci_msg, cfi, tti%10, rnti)) { + return false; + } + + if (srslte_dci_msg_to_ra_dl(&dci_msg, rnti, cell, cfi, + (srslte_ra_pdsch_t*) grant->get_grant_ptr())) + { + return false; + } + + return true; +} + +bool dl_buffer::decode_phich(srslte_phich_alloc_t assignment) +{ + if (!sf_symbols_and_ce_done) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + return false; + } + sf_symbols_and_ce_done = true; + } + return false; +} + +bool dl_buffer::decode_pdsch(sched_grant pdsch_grant, uint8_t *payload) +{ + if (!sf_symbols_and_ce_done) { + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, signal_buffer, tti%10, &cfi) < 0) { + return false; + } + sf_symbols_and_ce_done = true; + } + srslte_ra_pdsch_t *ra_dl = (srslte_ra_pdsch_t*) pdsch_grant.get_grant_ptr(); + if (srslte_harq_setup_dl(&ue_dl.harq_process[0], ra_dl->mcs, + pdsch_grant.get_rv(), tti%10, &ra_dl->prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + return SRSLTE_ERROR; + } + if (ue_dl.harq_process[0].mcs.mod > 0 && ue_dl.harq_process[0].mcs.tbs >= 0) { + int ret = srslte_pdsch_decode_rnti(&ue_dl.pdsch, &ue_dl.harq_process[0], ue_dl.sf_symbols, + ue_dl.ce, 0, pdsch_grant.get_rnti(), payload); + if (ret == SRSLTE_SUCCESS) { + return true; + } + } + return false; +} + +} +} \ No newline at end of file diff --git a/srslte/itf/queue.cc b/srslte/lib/ue_itf/src/params.cc similarity index 62% rename from srslte/itf/queue.cc rename to srslte/lib/ue_itf/src/params.cc index 2fc95b585..6fb7cb663 100644 --- a/srslte/itf/queue.cc +++ b/srslte/lib/ue_itf/src/params.cc @@ -24,26 +24,24 @@ * and at http://www.gnu.org/licenses/. * */ -#include -#include "queue.h" -srslte::queue::queue(uint32_t nof_elements, uint32_t element_size) -{ - buffer_of_elements = (queue::element**) malloc(sizeof(queue::element*) * nof_elements); - for (int i=0;i +#include +#include +#include "srslte/srslte.h" -srslte::queue::~queue() -{ - for (int i=0;i +#include +#include +#include "srslte/srslte.h" + +#include "srslte/ue_itf/phy.h" +#include "srslte/ue_itf/prach.h" +#include "srslte/ue_itf/ul_buffer.h" +#include "srslte/ue_itf/dl_buffer.h" + +namespace srslte { +namespace ue { + +#if SYNC_MODE==SYNC_MODE_CALLBACK +phy::phy(ue_phy_callback_t tti_clock_callback_, ue_phy_callback_t status_change_) +{ + tti_clock_callback = tti_clock_callback_; + status_change = status_change_; + ul_buffer_queue = new queue(6, sizeof(ul_buffer)); + dl_buffer_queue = new queue(6, sizeof(dl_buffer)); + + started = true; + + pthread_create(&radio_thread, NULL, radio_thread_fnc, this); +} + +#else +phy() +{ + +} + +#endif + +phy::~phy() +{ + started = false; + + pthread_join(radio_thread, NULL); + + for (int i=0;i<6;i++) { + ((ul_buffer*) ul_buffer_queue->get(i))->free_cell(); + ((dl_buffer*) dl_buffer_queue->get(i))->free_cell(); + } + + delete ul_buffer_queue; + delete dl_buffer_queue; + + prach_buffer.free_cell(); +} + + +// FIXME: Add PRACH power control +void phy::send_prach(uint32_t preamble_idx) +{ + if (phy_state == RXTX) { + prach_buffer.ready_to_send(preamble_idx); + } +} + +// Do fast measurement on RSSI and/or PSS autocorrelation energy or PSR +void phy::measure() +{ + if (phy_state == IDLE) { + // capture and do measurement + status_change(); + } +} + +void phy::dl_bch() +{ + if (phy_state == IDLE) { + phy_state = RX_BCH; + status_change(); + } +} + +void phy::start_rxtx() +{ + if (phy_state == MIB_DECODED) { + // Set sampling freq to MIB PRB + // start radio streaming + phy_state = RXTX; + status_change(); + } +} + +void phy::stop_rxtx() +{ + // stop radio + phy_state = IDLE; + status_change(); + } + +bool phy::status_is_idle() { + return phy_state == IDLE; +} + +bool phy::status_is_rxtx() { + return phy_state == RXTX; +} + +bool phy::status_is_bch_decoded(uint8_t payload[SRSLTE_BCH_PAYLOAD_LEN]) +{ + if (phy_state == MIB_DECODED) { + memcpy(payload, bch_payload, SRSLTE_BCH_PAYLOAD_LEN*sizeof(uint8_t)); + } +} + + +void* phy::radio_thread_fnc(void *arg) { + phy* phy = static_cast(arg); + phy->main_radio_loop(); + return NULL; +} + +int radio_recv_wrapper_cs(void*,void*,uint32_t,srslte_timestamp_t*) +{ + +} + + +void phy::run_rx_bch_state() { + phy_state = IDLE; + if (rx_bch()) { + for(uint32_t i=0;i<6;i++) { + get_ul_buffer(i)->init_cell(cell, ¶ms_db); + get_dl_buffer(i)->init_cell(cell, ¶ms_db); + } + if (srslte_ue_mib_init(&ue_mib, cell)) { + fprintf(stderr, "Error initiating UE mib\n"); + } else { + if (srslte_ue_sync_init(&ue_sync, cell, radio_recv_wrapper_cs, radio_handler)) { + fprintf(stderr, "Error initiating ue_sync"); + } else { + phy_state = MIB_DECODED; + } + } + } + status_change(); +} + +void phy::main_radio_loop() { + while(started) { + switch(phy_state) { + case IDLE: + case MIB_DECODED: + break; + case RX_BCH: + run_rx_bch_state(); + break; + case RXTX: + run_rx_tx_state(); + break; + } + } +} + +ul_buffer* phy::get_ul_buffer(uint32_t tti) +{ + return (ul_buffer*) ul_buffer_queue->get(tti); +} + +dl_buffer* phy::get_dl_buffer(uint32_t tti) +{ + return (dl_buffer*) dl_buffer_queue->get(tti); +} + +bool phy::rx_bch() +{ + 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_handler)) { + return false; + } + + srslte_ue_cellsearch_set_nof_frames_to_scan(&cs, params_db.get_param(params::CELLSEARCH_TIMEOUT_PSS_NFRAMES)); + srslte_ue_cellsearch_set_threshold(&cs, (float) params_db.get_param(params::CELLSEARCH_CORRELATION_THRESHOLD)/10); + + // set sampling freq 1.92 MHz + // set frequency, gain etc + // start radio streaming + + /* 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; + uint32_t force_N_id_2 = params_db.get_param(params::CELLSEARCH_FORCE_N_ID_2); + 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); + } + // Stop radio + + srslte_ue_cellsearch_free(&cs); + + if (ret < 0) { + fprintf(stderr, "Error searching cell"); + return false; + } else if (ret == 0) { + fprintf(stderr, "Could not find any cell in this frequency"); + return false; + } + + // Save result + cell.id = found_cells[max_peak_cell].cell_id; + cell.cp = found_cells[max_peak_cell].cp; + + printf("Found CELL PHY_ID: %d, CP: %s PSR: %.1f AbsPower: %.1f dBm", + cell.id, srslte_cp_string(cell.cp), + found_cells[max_peak_cell].psr, 30+10*log10(found_cells[max_peak_cell].peak)); + + 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_handler)) { + return false; + } + + uint32_t sfn, sfn_offset; + + /* Find and decode MIB */ + + // Start RX stream again + + ret = srslte_ue_mib_sync_decode(&ue_mib_sync, params_db.get_param(params::CELLSEARCH_TIMEOUT_MIB_NFRAMES), + bch_payload, &cell.nof_ports, &sfn_offset); + // Stop RX stream again + srslte_ue_mib_sync_free(&ue_mib_sync); + + if (ret == 1) { + srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); + sfn = (sfn + sfn_offset)%1024; + current_tti = sfn*10+1; + printf("MIB decoded: %d ports, SFN: %d, TTI: %d", cell.nof_ports, sfn, current_tti); + return true; + } else { + printf("Error decoding MIB"); + return false; + } +} + + +int phy::sync_sfn(void) { + + cf_t *sf_buffer = NULL; + int ret = SRSLTE_ERROR; + + ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer); + if (ret < 0) { + fprintf(stderr, "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) { + fprintf(stderr, "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; + current_tti = sfn*10; + return 1; + } + } + } + return 0; +} + + +void phy::run_rx_tx_state() +{ + int ret; + if (!is_sfn_synched) { + ret = sync_sfn(); + switch(ret) { + default: + phy_state = IDLE; + break; + case 1: + is_sfn_synched = true; + break; + case 0: + break; + } + } else { + // Receive alligned buffer for the current tti + srslte_timestamp_t rx_time; + get_dl_buffer(current_tti)->recv_ue_sync(&ue_sync, &rx_time); + + // send prach if we have to + if (prach_buffer.is_ready_to_send(current_tti)) { + prach_buffer.send(radio_handler, rx_time); + } + // send ul buffer if we have to + if (get_ul_buffer(current_tti)->is_ready_to_send()) { + get_ul_buffer(current_tti)->send_packet(radio_handler, rx_time); + } + } + current_tti++; + tti_clock_callback(); +} + +} +} \ No newline at end of file diff --git a/srslte/lib/ue_itf/src/prach.cc b/srslte/lib/ue_itf/src/prach.cc new file mode 100644 index 000000000..299539479 --- /dev/null +++ b/srslte/lib/ue_itf/src/prach.cc @@ -0,0 +1,114 @@ +/** + * + * \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 +#include +#include +#include "srslte/srslte.h" + +#include "srslte/ue_itf/prach.h" +#include "srslte/ue_itf/phy.h" +#include "srslte/ue_itf/params.h" + +namespace srslte { +namespace ue { + + +void prach::free_cell() +{ + if (initiated) { + for (uint32_t i=0;i<64;i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + srslte_prach_free(&prach); + } +} + +bool prach::init_cell(srslte_cell_t cell, params *params_db_) +{ + params_db = params_db_; + preamble_idx = -1; + if (srslte_prach_init(&prach, srslte_symbol_sz(cell.nof_prb), + srslte_prach_get_preamble_format(params_db->get_param(params::PRACH_CONFIG_INDEX)), + params_db->get_param(params::PRACH_ROOT_SEQ_IDX), + params_db->get_param(params::PRACH_HIGH_SPEED_FLAG)?true:false, + params_db->get_param(params::PRACH_ZC_CONFIG))) { + return false; + } + + len = prach.N_seq + prach.N_cp; + for (uint32_t i=0;i<64;i++) { + buffer[i] = (cf_t*) srslte_vec_malloc(len*sizeof(cf_t)); + if(!buffer[i]) { + return false; + } + if(srslte_prach_gen(&prach, i, params_db->get_param(params::PRACH_FREQ_OFFSET), buffer[i])){ + return false; + } + } + initiated = true; + return true; +} + +bool prach::ready_to_send(uint32_t preamble_idx_) +{ + if (initiated && preamble_idx_ < 64) { + preamble_idx = preamble_idx_; + return true; + } else { + return false; + } +} + +bool prach::is_ready_to_send(uint32_t current_tti) { + if (preamble_idx >= 0 && preamble_idx < 64) { + uint32_t config_idx = (uint32_t) params_db->get_param(params::PRACH_CONFIG_INDEX); + srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx); + if (prach_sfn == SRSLTE_PRACH_SFN_EVEN && ((current_tti/10)%2)==0 || + prach_sfn == SRSLTE_PRACH_SFN_ANY) + { + srslte_prach_sf_config_t sf_config; + srslte_prach_sf_config(config_idx, &sf_config); + for (int i=0;i +#include "srslte/ue_itf/queue.h" + +namespace srslte { +namespace ue { + queue::queue(uint32_t nof_elements, uint32_t element_size) + { + buffer_of_elements = (queue::element**) malloc(sizeof(queue::element*) * nof_elements); + for (int i=0;i +#include +#include +#include "srslte/srslte.h" + +#include "srslte/ue_itf/sched_grant.h" + +namespace srslte { +namespace ue { + + /* Returns the RNTI associated with the UL/DL scheduling grant */ + uint16_t sched_grant::get_rnti() { + return rnti; + } + + uint32_t sched_grant::get_rv() { + if (dir == UPLINK) { + return ul_grant.rv_idx; + } else { + return dl_grant.rv_idx; + } + } + + void sched_grant::set_rv(uint32_t rv) { + if (dir == UPLINK) { + ul_grant.rv_idx = rv; + } else { + dl_grant.rv_idx = rv; + } + } + + bool sched_grant::get_ndi() { + if (dir == UPLINK) { + return ul_grant.ndi; + } else { + return dl_grant.ndi; + } + } + + bool sched_grant::get_cqi_request() { + if (dir == UPLINK) { + return ul_grant.ndi; + } else { + return dl_grant.ndi; + } + } + + uint32_t sched_grant::get_current_tti() { + return current_tti; + } + + int sched_grant::get_harq_process() { + if (dir == UPLINK) { + return -1; + } else { + return dl_grant.harq_process; + } + } + + bool sched_grant::is_uplink() { + return dir == UPLINK; + } + + bool sched_grant::is_downlink() { + return dir == DOWNLINK; + } + void* sched_grant::get_grant_ptr() { + if (is_uplink()) { + return (void*) &ul_grant; + } else { + return (void*) &dl_grant; + } + } +} // namespace ue +} // namespace srslte + diff --git a/srslte/lib/ue_itf/src/ul_buffer.cc b/srslte/lib/ue_itf/src/ul_buffer.cc new file mode 100644 index 000000000..a88136733 --- /dev/null +++ b/srslte/lib/ue_itf/src/ul_buffer.cc @@ -0,0 +1,125 @@ +/** + * + * \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 +#include +#include +#include "srslte/srslte.h" + +#include "srslte/ue_itf/sched_grant.h" +#include "srslte/ue_itf/ul_buffer.h" +#include "srslte/ue_itf/phy.h" +#include "srslte/ue_itf/params.h" + +namespace srslte { +namespace ue { + +bool ul_buffer::init_cell(srslte_cell_t cell_, params *params_db) { + cell = cell_; + params_db = params_db; + signal_generated = false; + current_tx_nb = 0; + if (!srslte_ue_ul_init(&ue_ul, cell)) { + signal_buffer = (cf_t*) srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + return signal_buffer?true:false; + } else { + return false; + } +} + +void ul_buffer::free_cell() { + if (signal_buffer) { + free(signal_buffer); + } + srslte_ue_ul_free(&ue_ul); +} + +bool ul_buffer::generate_pusch(sched_grant pusch_grant, + uint8_t *payload, + srslte_uci_data_t uci_data) +{ + if (pusch_grant.is_uplink()) { + fprintf(stderr, "Invalid scheduling grant. Grant is for Downlink\n"); + return false; + } + + srslte_refsignal_drms_pusch_cfg_t drms_cfg; + bzero(&drms_cfg, sizeof(srslte_refsignal_drms_pusch_cfg_t)); + + drms_cfg.beta_pusch = params_db->get_param(params::PUSCH_BETA); + drms_cfg.group_hopping_en = params_db->get_param(params::PUSCH_RS_GROUP_HOPPING_EN); + drms_cfg.sequence_hopping_en = params_db->get_param(params::PUSCH_RS_SEQUENCE_HOPPING_EN); + drms_cfg.cyclic_shift = params_db->get_param(params::PUSCH_RS_CYCLIC_SHIFT); + drms_cfg.delta_ss = params_db->get_param(params::PUSCH_RS_GROUP_ASSIGNMENT); + + srslte_pusch_hopping_cfg_t pusch_hopping; + pusch_hopping.n_sb = params_db->get_param(params::PUSCH_HOPPING_N_SB); + pusch_hopping.hop_mode = params_db->get_param(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 = params_db->get_param(params::PUSCH_HOPPING_OFFSET); + pusch_hopping.current_tx_nb = current_tx_nb; + + srslte_ue_ul_set_pusch_cfg(&ue_ul, &drms_cfg, &pusch_hopping); + + int n = srslte_ue_ul_pusch_uci_encode_rnti(&ue_ul, (srslte_ra_pusch_t*) pusch_grant.get_grant_ptr(), + payload, uci_data, + tti%10, pusch_grant.get_rnti(), + signal_buffer); + if (n < 0) { + fprintf(stderr, "Error encoding PUSCH\n"); + return false; + } + + signal_generated = true; + + /* This is done by the transmission thread + srslte_vec_sc_prod_cfc(signal_buffer, beta_pusch, signal_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); + float time_adv_sec = TA_OFFSET + ((float) n_ta)*LTE_TS; + srslte_timestamp_t next_tx_time; + srslte_timestamp_copy(&next_tx_time, &last_rx_time); + srslte_timestamp_add(&next_tx_time, 0, 0.003 - time_adv_sec); + */ + // Send through radio + + return true; +} + +bool ul_buffer::generate_pucch(srslte_uci_data_t uci_data) +{ + fprintf(stderr, "Not implemented\n"); + return false; +} + +bool ul_buffer::send_packet(void *radio_handler, srslte_timestamp_t rx_time) +{ + // send packet through usrp +} + +} // namespace ue +} // namespace srslte + diff --git a/srslte/itf/CMakeLists.txt b/srslte/lib/ue_itf/test/CMakeLists.txt similarity index 82% rename from srslte/itf/CMakeLists.txt rename to srslte/lib/ue_itf/test/CMakeLists.txt index 6bf1e39e6..2b2574e97 100644 --- a/srslte/itf/CMakeLists.txt +++ b/srslte/lib/ue_itf/test/CMakeLists.txt @@ -20,7 +20,5 @@ # -ADD_LIBRARY(srslte++ SHARED ue_phy.cc) -TARGET_LINK_LIBRARIES(srslte++ srslte m ${FFTW3F_LIBRARIES}) -INSTALL(TARGETS srslte++ DESTINATION ${LIBRARY_DIR}) -LIBLTE_SET_PIC(srslte++) +ADD_EXECUTABLE(ue_itf_test ue_itf_test.cc) +TARGET_LINK_LIBRARIES(ue_itf_test srslte++) diff --git a/srslte/lib/ue_itf/test/ue_itf_test.cc b/srslte/lib/ue_itf/test/ue_itf_test.cc new file mode 100644 index 000000000..bc302849a --- /dev/null +++ b/srslte/lib/ue_itf/test/ue_itf_test.cc @@ -0,0 +1,74 @@ +/** + * + * \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 + +#include "srslte/ue_itf/phy.h" + +void tti_callback(); +void status_change(); + +srslte::ue::phy phy = srslte::ue::phy(tti_callback, status_change); +void tti_callback() { + printf("called tti callback\n"); +} + +bool status_changed; +void status_change() { + printf("called status change\n"); + status_changed=true; +} + +int main(int argc, char *argv[]) +{ + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + sleep(1); + + /* Instruct the PHY to decode BCH */ + status_changed=false; + phy.dl_bch(); + while(!status_changed); + if (!phy.status_is_bch_decoded(bch_payload)) { + printf("Could not decode BCH\n"); + exit(-1); + } + srslte_vec_fprint_hex(stdout, bch_payload, SRSLTE_BCH_PAYLOAD_LEN); + + /* Instruct the PHY to start RX streaming and synchronize */ + status_changed=false; + phy.start_rxtx(); + while(!status_changed); + if (!phy.status_is_rxtx()) { + printf("Could not start RX\n"); + exit(-1); + } + /* go to idle and process each tti */ + while(1) { + sleep(1); + } +} \ No newline at end of file