From 7780b1aba592789523f90ac66840dd07f36f93ee Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 23 Apr 2019 10:53:11 +0200 Subject: [PATCH] add tdd/ca support --- .clang-format | 6 +- lib/examples/CMakeLists.txt | 6 +- lib/examples/cell_measurement.c | 421 ---- lib/examples/cell_search.c | 59 +- lib/examples/pdsch_enodeb.c | 377 ++-- lib/examples/pdsch_ue.c | 847 ++++---- lib/examples/synch_file.c | 14 +- lib/examples/usrp_capture.c | 8 +- lib/examples/usrp_capture_sync.c | 24 +- lib/examples/usrp_txrx.c | 10 +- lib/include/srslte/common/bcd_helpers.h | 3 +- lib/include/srslte/common/block_queue.h | 2 +- lib/include/srslte/common/bounded_bitset.h | 329 +++ lib/include/srslte/common/common.h | 24 +- lib/include/srslte/common/liblte_ssl.h | 21 + lib/include/srslte/common/log_filter.h | 2 +- lib/include/srslte/common/metrics_hub.h | 20 + lib/include/srslte/common/nas_pcap.h | 21 + lib/include/srslte/common/pdu.h | 37 +- lib/include/srslte/common/pdu_queue.h | 5 +- lib/include/srslte/common/timers.h | 11 +- .../srslte/interfaces/enb_interfaces.h | 48 +- .../srslte/interfaces/epc_interfaces.h | 5 +- .../srslte/interfaces/sched_interface.h | 65 +- lib/include/srslte/interfaces/ue_interfaces.h | 398 ++-- .../srslte/phy/ch_estimation/chest_common.h | 29 +- .../srslte/phy/ch_estimation/chest_dl.h | 157 +- .../srslte/phy/ch_estimation/chest_ul.h | 60 +- .../srslte/phy/ch_estimation/refsignal_dl.h | 40 +- .../srslte/phy/ch_estimation/refsignal_ul.h | 231 +- lib/include/srslte/phy/common/phy_common.h | 187 +- lib/include/srslte/phy/enb/enb_dl.h | 145 +- lib/include/srslte/phy/enb/enb_ul.h | 98 +- .../srslte/phy/fec/turbodecoder_iter.h | 2 +- lib/include/srslte/phy/mimo/layermap.h | 29 +- lib/include/srslte/phy/mimo/precoding.h | 40 +- lib/include/srslte/phy/phch/cqi.h | 115 +- lib/include/srslte/phy/phch/dci.h | 286 +-- lib/include/srslte/phy/phch/pbch.h | 42 +- lib/include/srslte/phy/phch/pcfich.h | 40 +- lib/include/srslte/phy/phch/pdcch.h | 116 +- lib/include/srslte/phy/phch/pdsch.h | 127 +- lib/include/srslte/phy/phch/pdsch_cfg.h | 47 +- lib/include/srslte/phy/phch/phich.h | 91 +- lib/include/srslte/phy/phch/pmch.h | 93 +- lib/include/srslte/phy/phch/prach.h | 89 +- lib/include/srslte/phy/phch/pucch.h | 248 +-- lib/include/srslte/phy/phch/pucch_cfg.h | 86 + lib/include/srslte/phy/phch/pusch.h | 101 +- lib/include/srslte/phy/phch/pusch_cfg.h | 68 +- lib/include/srslte/phy/phch/ra.h | 246 +-- lib/include/srslte/phy/phch/ra_dl.h | 69 + lib/include/srslte/phy/phch/ra_ul.h | 67 + lib/include/srslte/phy/phch/regs.h | 11 +- lib/include/srslte/phy/phch/sch.h | 126 +- lib/include/srslte/phy/phch/uci.h | 104 +- lib/include/srslte/phy/phch/uci_cfg.h | 71 + lib/include/srslte/phy/rf/rf.h | 12 +- lib/include/srslte/phy/rf/rf_utils.h | 3 +- lib/include/srslte/phy/sync/sss.h | 5 +- lib/include/srslte/phy/sync/sync.h | 22 +- lib/include/srslte/phy/ue/ue_cell_search.h | 7 +- lib/include/srslte/phy/ue/ue_dl.h | 328 ++- lib/include/srslte/phy/ue/ue_mib.h | 19 +- lib/include/srslte/phy/ue/ue_phy.h | 14 +- lib/include/srslte/phy/ue/ue_sync.h | 41 +- lib/include/srslte/phy/ue/ue_ul.h | 181 +- lib/include/srslte/phy/utils/debug.h | 37 +- .../srslte/phy/{common => utils}/phy_logger.h | 24 +- lib/include/srslte/phy/utils/ringbuffer.h | 20 + lib/include/srslte/radio/radio.h | 50 +- lib/include/srslte/radio/radio_multi.h | 94 +- lib/include/srslte/radio/radio_sync.h | 54 + lib/include/srslte/srslte.h | 14 +- lib/include/srslte/upper/rlc_interface.h | 2 +- lib/src/common/arch_select.cc | 2 +- lib/src/common/log_filter.cc | 1 + lib/src/common/pdu.cc | 81 +- lib/src/common/pdu_queue.cc | 19 +- lib/src/common/threads.c | 4 +- lib/src/phy/CMakeLists.txt | 56 +- lib/src/phy/agc/agc.c | 8 +- lib/src/phy/ch_estimation/chest_common.c | 32 +- lib/src/phy/ch_estimation/chest_dl.c | 686 +++--- lib/src/phy/ch_estimation/chest_ul.c | 249 +-- lib/src/phy/ch_estimation/refsignal_dl.c | 543 ++--- lib/src/phy/ch_estimation/refsignal_ul.c | 426 ++-- .../phy/ch_estimation/test/chest_test_dl.c | 167 +- .../ch_estimation/test/chest_test_dl_mex.c | 159 -- .../test/chest_test_dl_mex.mexa64 | Bin 12713 -> 0 bytes .../phy/ch_estimation/test/chest_test_ul.c | 44 +- .../ch_estimation/test/chest_test_ul_mex.c | 181 -- .../ch_estimation/test/refsignal_pusch_mex.c | 151 -- .../ch_estimation/test/refsignal_srs_mex.c | 165 -- .../ch_estimation/test/refsignal_ul_test.c | 30 +- lib/src/phy/common/phy_common.c | 229 +- lib/src/phy/common/sequence.c | 13 +- lib/src/phy/dft/dft_fftw.c | 13 +- lib/src/phy/dft/dft_precoding.c | 4 +- lib/src/phy/dft/ofdm.c | 46 +- lib/src/phy/dft/test/ofdm_test.c | 4 +- lib/src/phy/enb/enb_dl.c | 367 ++-- lib/src/phy/enb/enb_ul.c | 338 +-- lib/src/phy/fec/crc.c | 10 +- lib/src/phy/fec/rm_conv.c | 10 +- lib/src/phy/fec/rm_turbo.c | 20 +- lib/src/phy/fec/tc_interl_lte.c | 5 +- lib/src/phy/fec/tc_interl_umts.c | 4 +- lib/src/phy/fec/test/crc_test.c | 2 +- lib/src/phy/fec/test/rm_turbo_rx_mex.c | 99 - lib/src/phy/fec/test/turbodecoder_test.c | 4 +- lib/src/phy/fec/test/turbodecoder_test_mex.c | 106 - lib/src/phy/fec/test/viterbi_test.c | 2 +- lib/src/phy/fec/test/viterbi_test_mex.c | 89 - lib/src/phy/fec/turbocoder.c | 15 +- lib/src/phy/fec/turbodecoder.c | 31 +- lib/src/phy/fec/turbodecoder_sse.c | 1 - lib/src/phy/fec/viterbi.c | 26 +- lib/src/phy/io/filesource.c | 3 +- lib/src/phy/mimo/layermap.c | 129 +- lib/src/phy/mimo/precoding.c | 193 +- lib/src/phy/mimo/test/CMakeLists.txt | 47 +- lib/src/phy/mimo/test/layermap_test.c | 15 +- lib/src/phy/mimo/test/precoder_mex.c | 145 -- lib/src/phy/mimo/test/precoder_test.c | 48 +- lib/src/phy/mimo/test/predecoder_mex.c | 213 -- lib/src/phy/modem/demod_hard.c | 1 - lib/src/phy/modem/demod_soft.c | 20 +- lib/src/phy/modem/mod.c | 9 +- lib/src/phy/modem/modem_table.c | 1 - lib/src/phy/modem/test/modem_test.c | 11 +- lib/src/phy/modem/test/soft_demod_test.c | 7 +- lib/src/phy/phch/cqi.c | 340 +-- lib/src/phy/phch/dci.c | 1870 +++++++++-------- lib/src/phy/phch/dci_sz_table.h | 132 -- lib/src/phy/phch/pbch.c | 72 +- lib/src/phy/phch/pcfich.c | 76 +- lib/src/phy/phch/pdcch.c | 265 ++- lib/src/phy/phch/pdsch.c | 991 ++++----- lib/src/phy/phch/phich.c | 129 +- lib/src/phy/phch/pmch.c | 263 ++- lib/src/phy/phch/prach.c | 337 ++- lib/src/phy/phch/prach_tables.h | 200 ++ lib/src/phy/phch/pucch.c | 1492 +++++++------ lib/src/phy/phch/pusch.c | 520 ++--- lib/src/phy/phch/ra.c | 758 +------ lib/src/phy/phch/ra_dl.c | 732 +++++++ lib/src/phy/phch/ra_ul.c | 321 +++ lib/src/phy/phch/regs.c | 82 +- lib/src/phy/phch/sch.c | 549 +++-- lib/src/phy/phch/sequences.c | 2 +- lib/src/phy/phch/tbs_tables.h | 5 - lib/src/phy/phch/test/CMakeLists.txt | 166 +- lib/src/phy/phch/test/dlsch_encode_test_mex.c | 157 -- lib/src/phy/phch/test/pbch_file_test.c | 93 +- lib/src/phy/phch/test/pbch_test.c | 66 +- lib/src/phy/phch/test/pbch_test_mex.c | 202 -- lib/src/phy/phch/test/pcfich_file_test.c | 114 +- lib/src/phy/phch/test/pcfich_test.c | 73 +- lib/src/phy/phch/test/pcfich_test_mex.c | 171 -- lib/src/phy/phch/test/pdcch_file_test.c | 141 +- lib/src/phy/phch/test/pdcch_test.c | 334 +-- lib/src/phy/phch/test/pdcch_test_mex.c | 225 -- lib/src/phy/phch/test/pdsch_pdcch_file_test.c | 45 +- lib/src/phy/phch/test/pdsch_test.c | 473 ++--- lib/src/phy/phch/test/pdsch_test_mex.c | 342 --- lib/src/phy/phch/test/phich_file_test.c | 104 +- lib/src/phy/phch/test/phich_test.c | 89 +- lib/src/phy/phch/test/phich_test_mex.c | 173 -- lib/src/phy/phch/test/pmch_file_test.c | 94 +- lib/src/phy/phch/test/pmch_test.c | 280 ++- lib/src/phy/phch/test/prach_detect_test_mex.c | 129 -- lib/src/phy/phch/test/prach_test.c | 80 +- lib/src/phy/phch/test/prach_test_mex.c | 115 - lib/src/phy/phch/test/prach_test_multi.c | 67 +- lib/src/phy/phch/test/prach_test_usrp.c | 63 +- lib/src/phy/phch/test/pucch_encode_test_mex.c | 229 -- lib/src/phy/phch/test/pucch_test.c | 119 +- lib/src/phy/phch/test/pucch_test_mex.c | 227 -- lib/src/phy/phch/test/pusch_encode_test_mex.c | 251 --- lib/src/phy/phch/test/pusch_test.c | 289 ++- lib/src/phy/phch/test/pusch_test_mex.c | 309 --- lib/src/phy/phch/test/ulsch_encode_test_mex.c | 220 -- lib/src/phy/phch/uci.c | 452 ++-- lib/src/phy/resampling/interp.c | 6 +- lib/src/phy/rf/rf_blade_imp.c | 93 +- lib/src/phy/rf/rf_blade_imp.h | 6 +- lib/src/phy/rf/rf_dev.h | 191 +- lib/src/phy/rf/rf_imp.c | 25 +- lib/src/phy/rf/rf_soapy_imp.c | 28 +- lib/src/phy/rf/rf_soapy_imp.h | 6 +- lib/src/phy/rf/rf_uhd_imp.c | 61 +- lib/src/phy/rf/rf_uhd_imp.h | 12 +- lib/src/phy/rf/rf_utils.c | 60 +- lib/src/phy/rf/rf_zmq_imp.c | 4 +- lib/src/phy/rf/rf_zmq_imp.h | 4 +- lib/src/phy/scrambling/test/scrambling_test.c | 4 +- lib/src/phy/sync/cfo.c | 8 +- lib/src/phy/sync/cp.c | 4 +- lib/src/phy/sync/pss.c | 41 +- lib/src/phy/sync/sss.c | 7 +- lib/src/phy/sync/sync.c | 306 ++- lib/src/phy/sync/test/CMakeLists.txt | 3 +- lib/src/phy/sync/test/cfo_test.c | 2 +- lib/src/phy/sync/test/cp_mex.c | 93 - lib/src/phy/sync/test/pss_file.c | 71 +- lib/src/phy/sync/test/pss_mex.c | 101 - lib/src/phy/sync/test/pss_usrp.c | 168 +- lib/src/phy/sync/test/sss_mex.c | 127 -- lib/src/phy/sync/test/sync_test.c | 8 +- lib/src/phy/ue/ue_cell_search.c | 89 +- lib/src/phy/ue/ue_dl.c | 1695 +++++++++------ lib/src/phy/ue/ue_mib.c | 102 +- lib/src/phy/ue/ue_sync.c | 295 +-- lib/src/phy/ue/ue_ul.c | 1093 ++++++---- lib/src/phy/utils/convolution.c | 17 +- lib/src/phy/utils/mat.c | 1 - lib/src/phy/{common => utils}/phy_logger.c | 25 +- lib/src/phy/utils/ringbuffer.c | 5 +- lib/src/phy/utils/test/vector_test.c | 12 +- lib/src/phy/utils/vector.c | 7 +- lib/src/phy/utils/vector_simd.c | 1 - lib/src/radio/CMakeLists.txt | 2 +- lib/src/radio/radio.cc | 220 +- lib/src/radio/radio_multi.cc | 596 +++++- lib/src/radio/radio_sync.cc | 196 ++ lib/src/radio/test/CMakeLists.txt | 3 +- lib/src/radio/test/benchmark_radio.cc | 480 ++++- lib/src/upper/rlc.cc | 44 +- .../srslte_asn1_rrc_connection_reconf_test.cc | 90 + lib/test/phy/CMakeLists.txt | 20 + lib/test/phy/phy_dl_test.c | 512 +++-- srsenb/enb.conf.example | 2 +- srsenb/hdr/mac/mac.h | 2 +- srsenb/hdr/mac/scheduler.h | 78 +- srsenb/hdr/mac/scheduler_harq.h | 89 +- srsenb/hdr/mac/scheduler_metric.h | 51 +- srsenb/hdr/mac/scheduler_ue.h | 56 +- srsenb/hdr/mac/ue.h | 61 +- srsenb/hdr/parser.h | 2 +- srsenb/hdr/phy/phch_worker.h | 144 -- srsenb/hdr/phy/phy.h | 15 +- .../hdr/phy/{phch_common.h => phy_common.h} | 88 +- srsenb/hdr/phy/prach_worker.h | 17 +- srsenb/hdr/phy/sf_worker.h | 144 ++ srsenb/hdr/phy/txrx.h | 22 +- srsenb/sib.conf.example | 4 +- srsenb/src/enb.cc | 25 +- srsenb/src/enb_cfg_parser.cc | 67 +- srsenb/src/mac/mac.cc | 130 +- srsenb/src/mac/scheduler.cc | 702 ++++--- srsenb/src/mac/scheduler_harq.cc | 129 +- srsenb/src/mac/scheduler_metric.cc | 277 +-- srsenb/src/mac/scheduler_ue.cc | 491 ++--- srsenb/src/mac/ue.cc | 116 +- srsenb/src/main.cc | 14 +- srsenb/src/phy/phch_worker.cc | 1238 ----------- srsenb/src/phy/phy.cc | 73 +- .../src/phy/{phch_common.cc => phy_common.cc} | 197 +- srsenb/src/phy/prach_worker.cc | 14 +- srsenb/src/phy/sf_worker.cc | 1014 +++++++++ srsenb/src/phy/txrx.cc | 53 +- srsenb/src/upper/gtpu.cc | 2 +- srsenb/src/upper/pdcp.cc | 6 +- srsenb/src/upper/rlc.cc | 6 +- srsenb/src/upper/rrc.cc | 80 +- srsenb/test/mac/CMakeLists.txt | 10 + srsenb/test/mac/scheduler_test_rand.cc | 945 +++++++++ srsepc/hdr/mbms-gw/mbms-gw.h | 9 +- srsepc/hdr/spgw/gtpc.h | 2 +- srsepc/src/main.cc | 2 + srsepc/src/mme/mme.cc | 2 +- srsepc/src/mme/mme_gtpc.cc | 14 +- srsepc/src/mme/nas.cc | 3 +- srsepc/src/mme/s1ap_mngmt_proc.cc | 8 +- srsepc/src/mme/s1ap_nas_transport.cc | 5 +- srsepc/src/spgw/spgw.cc | 4 +- srsue/hdr/mac/demux.h | 54 +- srsue/hdr/mac/dl_harq.h | 397 +--- srsue/hdr/mac/dl_sps.h | 5 +- srsue/hdr/mac/mac.h | 109 +- srsue/hdr/mac/mux.h | 25 +- srsue/hdr/mac/proc_bsr.h | 59 +- srsue/hdr/mac/proc_phr.h | 14 +- srsue/hdr/mac/proc_ra.h | 90 +- srsue/hdr/mac/proc_sr.h | 17 +- srsue/hdr/mac/ul_harq.h | 419 +--- srsue/hdr/mac/ul_sps.h | 3 +- srsue/hdr/phy/async_scell_recv.h | 175 ++ srsue/hdr/phy/cc_worker.h | 137 ++ srsue/hdr/phy/phch_common.h | 239 --- srsue/hdr/phy/phch_worker.h | 200 -- srsue/hdr/phy/phy.h | 105 +- srsue/hdr/phy/phy_common.h | 246 +++ srsue/hdr/phy/phy_metrics.h | 8 +- srsue/hdr/phy/prach.h | 24 +- srsue/hdr/phy/sf_worker.h | 112 + srsue/hdr/phy/{phch_recv.h => sync.h} | 134 +- srsue/hdr/ue.h | 2 +- srsue/hdr/ue_base.h | 24 +- srsue/hdr/ue_metrics_interface.h | 2 +- srsue/hdr/upper/rrc.h | 74 +- srsue/src/mac/demux.cc | 91 +- srsue/src/mac/dl_harq.cc | 402 ++++ srsue/src/mac/mac.cc | 583 ++--- srsue/src/mac/mux.cc | 28 +- srsue/src/mac/proc_bsr.cc | 432 ++-- srsue/src/mac/proc_phr.cc | 95 +- srsue/src/mac/proc_ra.cc | 344 +-- srsue/src/mac/proc_sr.cc | 29 +- srsue/src/mac/ul_harq.cc | 401 ++++ srsue/src/main.cc | 52 +- srsue/src/metrics_csv.cc | 63 +- srsue/src/metrics_stdout.cc | 56 +- srsue/src/phy/async_scell_recv.cc | 583 +++++ srsue/src/phy/cc_worker.cc | 1419 +++++++++++++ srsue/src/phy/phch_common.cc | 565 ----- srsue/src/phy/phch_worker.cc | 1851 ---------------- srsue/src/phy/phy.cc | 371 ++-- srsue/src/phy/phy_common.cc | 874 ++++++++ srsue/src/phy/prach.cc | 152 +- srsue/src/phy/sf_worker.cc | 508 +++++ srsue/src/phy/{phch_recv.cc => sync.cc} | 626 +++--- srsue/src/ue.cc | 145 +- srsue/src/ue_base.cc | 2 +- srsue/src/upper/nas.cc | 6 + srsue/src/upper/pcsc_usim.cc | 17 +- srsue/src/upper/rrc.cc | 697 +++--- srsue/src/upper/usim.cc | 6 +- srsue/src/upper/usim_base.cc | 7 +- srsue/test/CMakeLists.txt | 6 +- srsue/test/mac/CMakeLists.txt | 23 - srsue/test/mac/mac_test.cc | 522 ----- srsue/test/mac_test.cc | 186 ++ srsue/test/metrics_test.cc | 20 +- srsue/test/phy/CMakeLists.txt | 25 - srsue/test/phy/ue_itf_test_prach.cc | 403 ---- srsue/test/phy/ue_itf_test_sib1.cc | 224 -- srsue/test/upper/ip_test.cc | 648 ------ srsue/test/upper/pcsc_usim_test.cc | 4 +- srsue/ue.conf.example | 26 +- 341 files changed, 28069 insertions(+), 27717 deletions(-) delete mode 100644 lib/examples/cell_measurement.c create mode 100644 lib/include/srslte/common/bounded_bitset.h create mode 100644 lib/include/srslte/phy/phch/pucch_cfg.h create mode 100644 lib/include/srslte/phy/phch/ra_dl.h create mode 100644 lib/include/srslte/phy/phch/ra_ul.h create mode 100644 lib/include/srslte/phy/phch/uci_cfg.h rename lib/include/srslte/phy/{common => utils}/phy_logger.h (64%) create mode 100644 lib/include/srslte/radio/radio_sync.h delete mode 100644 lib/src/phy/ch_estimation/test/chest_test_dl_mex.c delete mode 100755 lib/src/phy/ch_estimation/test/chest_test_dl_mex.mexa64 delete mode 100644 lib/src/phy/ch_estimation/test/chest_test_ul_mex.c delete mode 100644 lib/src/phy/ch_estimation/test/refsignal_pusch_mex.c delete mode 100644 lib/src/phy/ch_estimation/test/refsignal_srs_mex.c delete mode 100644 lib/src/phy/fec/test/rm_turbo_rx_mex.c delete mode 100644 lib/src/phy/fec/test/turbodecoder_test_mex.c delete mode 100644 lib/src/phy/fec/test/viterbi_test_mex.c delete mode 100644 lib/src/phy/mimo/test/precoder_mex.c delete mode 100644 lib/src/phy/mimo/test/predecoder_mex.c delete mode 100644 lib/src/phy/phch/dci_sz_table.h create mode 100644 lib/src/phy/phch/prach_tables.h create mode 100644 lib/src/phy/phch/ra_dl.c create mode 100644 lib/src/phy/phch/ra_ul.c delete mode 100644 lib/src/phy/phch/test/dlsch_encode_test_mex.c delete mode 100644 lib/src/phy/phch/test/pbch_test_mex.c delete mode 100644 lib/src/phy/phch/test/pcfich_test_mex.c delete mode 100644 lib/src/phy/phch/test/pdcch_test_mex.c delete mode 100644 lib/src/phy/phch/test/pdsch_test_mex.c delete mode 100644 lib/src/phy/phch/test/phich_test_mex.c delete mode 100644 lib/src/phy/phch/test/prach_detect_test_mex.c delete mode 100644 lib/src/phy/phch/test/prach_test_mex.c delete mode 100644 lib/src/phy/phch/test/pucch_encode_test_mex.c delete mode 100644 lib/src/phy/phch/test/pucch_test_mex.c delete mode 100644 lib/src/phy/phch/test/pusch_encode_test_mex.c delete mode 100644 lib/src/phy/phch/test/pusch_test_mex.c delete mode 100644 lib/src/phy/phch/test/ulsch_encode_test_mex.c delete mode 100644 lib/src/phy/sync/test/cp_mex.c delete mode 100644 lib/src/phy/sync/test/pss_mex.c delete mode 100644 lib/src/phy/sync/test/sss_mex.c rename lib/src/phy/{common => utils}/phy_logger.c (79%) create mode 100644 lib/src/radio/radio_sync.cc create mode 100644 lib/test/asn1/srslte_asn1_rrc_connection_reconf_test.cc delete mode 100644 srsenb/hdr/phy/phch_worker.h rename srsenb/hdr/phy/{phch_common.h => phy_common.h} (61%) create mode 100644 srsenb/hdr/phy/sf_worker.h delete mode 100644 srsenb/src/phy/phch_worker.cc rename srsenb/src/phy/{phch_common.cc => phy_common.cc} (64%) create mode 100644 srsenb/src/phy/sf_worker.cc create mode 100644 srsenb/test/mac/scheduler_test_rand.cc create mode 100644 srsue/hdr/phy/async_scell_recv.h create mode 100644 srsue/hdr/phy/cc_worker.h delete mode 100644 srsue/hdr/phy/phch_common.h delete mode 100644 srsue/hdr/phy/phch_worker.h create mode 100644 srsue/hdr/phy/phy_common.h create mode 100644 srsue/hdr/phy/sf_worker.h rename srsue/hdr/phy/{phch_recv.h => sync.h} (79%) create mode 100644 srsue/src/mac/dl_harq.cc create mode 100644 srsue/src/mac/ul_harq.cc create mode 100644 srsue/src/phy/async_scell_recv.cc create mode 100644 srsue/src/phy/cc_worker.cc delete mode 100644 srsue/src/phy/phch_common.cc delete mode 100644 srsue/src/phy/phch_worker.cc create mode 100644 srsue/src/phy/phy_common.cc create mode 100644 srsue/src/phy/sf_worker.cc rename srsue/src/phy/{phch_recv.cc => sync.cc} (73%) delete mode 100644 srsue/test/mac/CMakeLists.txt delete mode 100644 srsue/test/mac/mac_test.cc create mode 100644 srsue/test/mac_test.cc delete mode 100644 srsue/test/phy/CMakeLists.txt delete mode 100644 srsue/test/phy/ue_itf_test_prach.cc delete mode 100644 srsue/test/phy/ue_itf_test_sib1.cc delete mode 100644 srsue/test/upper/ip_test.cc diff --git a/.clang-format b/.clang-format index 2820c2edb..539a35b83 100644 --- a/.clang-format +++ b/.clang-format @@ -18,7 +18,7 @@ AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: true #Changed -BinPackArguments: true +BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: true #Changed @@ -90,6 +90,10 @@ PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left #Changed +RawStringFormats: + - Delimiter: pb + Language: TextProto + BasedOnStyle: google ReflowComments: true SortIncludes: true SortUsingDeclarations: true diff --git a/lib/examples/CMakeLists.txt b/lib/examples/CMakeLists.txt index 2ab3d45fa..89b5a71dd 100644 --- a/lib/examples/CMakeLists.txt +++ b/lib/examples/CMakeLists.txt @@ -51,8 +51,7 @@ find_package(SRSGUI) if(SRSGUI_FOUND) include_directories(${SRSGUI_INCLUDE_DIRS}) target_link_libraries(pdsch_ue ${SRSGUI_LIBRARIES}) -else(SRSGUI_FOUND) - add_definitions(-DDISABLE_GRAPHICS) + add_definitions(-DENABLE_GUI) endif(SRSGUI_FOUND) @@ -65,9 +64,6 @@ if(RF_FOUND) add_executable(cell_search cell_search.c) target_link_libraries(cell_search srslte_phy srslte_common srslte_rf) - add_executable(cell_measurement cell_measurement.c) - target_link_libraries(cell_measurement srslte_phy srslte_common srslte_rf) - add_executable(usrp_capture usrp_capture.c) target_link_libraries(usrp_capture srslte_phy srslte_rf) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c deleted file mode 100644 index 421be629c..000000000 --- a/lib/examples/cell_measurement.c +++ /dev/null @@ -1,421 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \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 -#include -#include -#include -#include -#include - -#define ENABLE_AGC_DEFAULT - -#include "srslte/srslte.h" -#include "srslte/phy/rf/rf.h" -#include "srslte/phy/rf/rf_utils.h" -#include "srslte/common/crash_handler.h" - -cell_search_cfg_t cell_detect_config = { - SRSLTE_DEFAULT_MAX_FRAMES_PBCH, - SRSLTE_DEFAULT_MAX_FRAMES_PSS, - SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES, - 0 -}; - -/********************************************************************** - * Program arguments processing - ***********************************************************************/ -typedef struct { - int nof_subframes; - bool disable_plots; - int force_N_id_2; - char *rf_args; - float rf_freq; - float rf_gain; -}prog_args_t; - -void args_default(prog_args_t *args) { - args->nof_subframes = -1; - args->force_N_id_2 = -1; // Pick the best - args->rf_args = ""; - args->rf_freq = -1.0; -#ifdef ENABLE_AGC_DEFAULT - args->rf_gain = -1; -#else - args->rf_gain = 50; -#endif -} - -void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [aglnv] -f rx_frequency (in Hz)\n", prog); - printf("\t-a RF args [Default %s]\n", args->rf_args); - printf("\t-g RF RX gain [Default %.2f dB]\n", args->rf_gain); - printf("\t-l Force N_id_2 [Default best]\n"); - printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); - printf("\t-v [set srslte_verbose to debug, default none]\n"); -} - -int parse_args(prog_args_t *args, int argc, char **argv) { - int opt; - args_default(args); - while ((opt = getopt(argc, argv, "aglnvf")) != -1) { - switch (opt) { - case 'a': - args->rf_args = argv[optind]; - break; - case 'g': - args->rf_gain = atof(argv[optind]); - break; - case 'f': - args->rf_freq = atof(argv[optind]); - break; - case 'n': - args->nof_subframes = atoi(argv[optind]); - break; - case 'l': - args->force_N_id_2 = atoi(argv[optind]); - break; - case 'v': - srslte_verbose++; - break; - default: - usage(args, argv[0]); - return -1; - } - } - if (args->rf_freq < 0) { - usage(args, argv[0]); - return -1; - } - return 0; -} -/**********************************************************************/ - -/* TODO: Do something with the output data */ -uint8_t *data[SRSLTE_MAX_CODEWORDS]; - -bool go_exit = false; -void sig_int_handler(int signo) -{ - printf("SIGINT received. Exiting...\n"); - if (signo == SIGINT) { - go_exit = true; - } -} - -int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *q) { - DEBUG(" ---- Receive %d samples ---- \n", nsamples); - - return srslte_rf_recv(h, data[0], nsamples, 1); -} - -enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state; - -#define MAX_SINFO 10 -#define MAX_NEIGHBOUR_CELLS 128 - -int main(int argc, char **argv) { - int ret; - cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL, NULL}; - prog_args_t prog_args; - srslte_cell_t cell; - int64_t sf_cnt; - srslte_ue_sync_t ue_sync; - srslte_ue_mib_t ue_mib; - srslte_rf_t rf; - srslte_ue_dl_t ue_dl; - srslte_ofdm_t fft; - srslte_chest_dl_t chest; - uint32_t nframes=0; - uint32_t nof_trials = 0; - uint32_t sfn = 0; // system frame number - int n; - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - int sfn_offset; - float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0; - cf_t *ce[SRSLTE_MAX_PORTS]; - float cfo = 0; - bool acks[SRSLTE_MAX_CODEWORDS] = {false}; - - srslte_debug_handle_crash(argc, argv); - - if (parse_args(&prog_args, argc, argv)) { - exit(-1); - } - - printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, prog_args.rf_args)) { - fprintf(stderr, "Error opening rf\n"); - exit(-1); - } - if (prog_args.rf_gain > 0) { - srslte_rf_set_rx_gain(&rf, prog_args.rf_gain); - } else { - printf("Starting AGC thread...\n"); - if (srslte_rf_start_gain_thread(&rf, false)) { - fprintf(stderr, "Error opening rf\n"); - exit(-1); - } - srslte_rf_set_rx_gain(&rf, 50); - } - - sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - data[i] = srslte_vec_malloc(sizeof(uint8_t) * 1500*8); - } - - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGINT); - sigprocmask(SIG_UNBLOCK, &sigset, NULL); - signal(SIGINT, sig_int_handler); - - srslte_rf_set_master_clock_rate(&rf, 30.72e6); - - /* set receiver frequency */ - srslte_rf_set_rx_freq(&rf, (double) prog_args.rf_freq); - srslte_rf_rx_wait_lo_locked(&rf); - printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.rf_freq/1000000); - - cell_detect_config.init_agc = (prog_args.rf_gain<0); - - uint32_t ntrial=0; - do { - ret = rf_search_and_decode_mib(&rf, 1, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); - if (ret < 0) { - fprintf(stderr, "Error searching for cell\n"); - exit(-1); - } else if (ret == 0 && !go_exit) { - printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++); - } - } while (ret == 0 && !go_exit); - - if (go_exit) { - exit(0); - } - - /* set sampling frequency */ - int srate = srslte_sampling_freq_hz(cell.nof_prb); - if (srate != -1) { - if (srate < 10e6) { - srslte_rf_set_master_clock_rate(&rf, 4*srate); - } else { - srslte_rf_set_master_clock_rate(&rf, srate); - } - printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); - float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate); - if (srate_rf != srate) { - fprintf(stderr, "Could not set sampling rate\n"); - exit(-1); - } - } else { - fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb); - exit(-1); - } - - INFO("Stopping RF and flushing buffer...\n"); - srslte_rf_stop_rx_stream(&rf); - srslte_rf_flush_buffer(&rf); - - if (srslte_ue_sync_init_multi(&ue_sync, cell.nof_prb, cell.id==1000, srslte_rf_recv_wrapper, 1, (void*) &rf)) { - fprintf(stderr, "Error initiating ue_sync\n"); - return -1; - } - if (srslte_ue_sync_set_cell(&ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); - return -1; - } - if (srslte_ue_dl_init(&ue_dl, sf_buffer, cell.nof_prb, 1)) { - fprintf(stderr, "Error initiating UE downlink processing module\n"); - return -1; - } - if (srslte_ue_dl_set_cell(&ue_dl, cell)) { - fprintf(stderr, "Error initiating UE downlink processing module\n"); - return -1; - } - if (srslte_ue_mib_init(&ue_mib, sf_buffer, cell.nof_prb)) { - fprintf(stderr, "Error initaiting UE MIB decoder\n"); - return -1; - } - if (srslte_ue_mib_set_cell(&ue_mib, cell)) { - fprintf(stderr, "Error initaiting UE MIB decoder\n"); - return -1; - } - - /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ - srslte_ue_dl_set_rnti(&ue_dl, SRSLTE_SIRNTI); - - /* Initialize subframe counter */ - sf_cnt = 0; - - int sf_re = SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); - - cf_t *sf_symbols = srslte_vec_malloc(sf_re * sizeof(cf_t)); - - for (int i=0;i 0) { for (int i=0;i<3;i++) { @@ -241,16 +237,13 @@ int main(int argc, char **argv) { cell.cp = found_cells[i].cp; int ret = rf_mib_decoder(&rf, 1, &cell_detect_config, &cell, NULL); if (ret < 0) { - fprintf(stderr, "Error decoding MIB\n"); + ERROR("Error decoding MIB\n"); exit(-1); } if (ret == SRSLTE_UE_MIB_FOUND) { - printf("Found CELL ID %d. %d PRB, %d ports\n", - cell.id, - cell.nof_prb, - cell.nof_ports); + printf("Found CELL ID %d. %d PRB, %d ports\n", cell.id, cell.nof_prb, cell.nof_ports); if (cell.nof_ports > 0) { - memcpy(&results[n_found_cells].cell, &cell, sizeof(srslte_cell_t)); + results[n_found_cells].cell = cell; results[n_found_cells].freq = channels[freq].fd; results[n_found_cells].dl_earfcn = channels[freq].id; results[n_found_cells].power = found_cells[i].peak; diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index e980e4eee..cae9a39b4 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -34,8 +34,6 @@ #include #include #include "srslte/common/crash_handler.h" -#include -#include #include "srslte/common/gen_mch_tables.h" #include "srslte/srslte.h" @@ -59,12 +57,14 @@ char *output_file_name = NULL; #define DOWN_KEY 66 srslte_cell_t cell = { - 25, // nof_prb - 1, // nof_ports - 0, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_NORM, // PHICH length - SRSLTE_PHICH_R_1 // PHICH resources + 25, // nof_prb + 1, // nof_ports + 0, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1, // PHICH resources + SRSLTE_FDD, + }; uint16_t c = -1; @@ -75,8 +75,7 @@ uint32_t cfi = 2; uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; - -char mimo_type_str[32] = "single"; +srslte_tm_t transmission_mode = SRSLTE_TM1; uint32_t nof_tb = 1; uint32_t multiplex_pmi = 0; uint32_t multiplex_nof_layers = 1; @@ -98,10 +97,10 @@ srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; srslte_pdsch_cfg_t pdsch_cfg; srslte_pmch_t pmch; -srslte_pdsch_cfg_t pmch_cfg; +srslte_pmch_cfg_t pmch_cfg; srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; -srslte_ra_dl_dci_t ra_dl; +srslte_dci_dl_t dci_dl; int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0}; cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL}; @@ -145,7 +144,7 @@ void usage(char *prog) { printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); printf("\t-M MBSFN area id [Default %d]\n", mbsfn_area_id); - printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); + printf("\t-x Transmission mode [1-4] [Default %d]\n", transmission_mode + 1); printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi); printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers); printf("\t-u listen TCP/UDP port for input data (if mbsfn is active then the stream is over mbsfn only) (-1 is random) [Default %d]\n", net_port); @@ -194,8 +193,7 @@ void parse_args(int argc, char **argv) { cell.id = atoi(argv[optind]); break; case 'x': - strncpy(mimo_type_str, argv[optind], 31); - mimo_type_str[31] = 0; + transmission_mode = (srslte_tm_t)(atoi(argv[optind]) - 1); break; case 'b': multiplex_pmi = (uint32_t) atoi(argv[optind]); @@ -231,28 +229,18 @@ void parse_args(int argc, char **argv) { void base_init() { int i; - /* Select transmission mode */ - if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) { - ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd and multiplex"); - exit(-1); - } - /* Configure cell and PDSCH in function of the transmission mode */ - switch(pdsch_cfg.mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + switch (transmission_mode) { + case SRSLTE_TM1: cell.nof_ports = 1; break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - cell.nof_ports = 2; - break; - case SRSLTE_MIMO_TYPE_CDD: - cell.nof_ports = 2; - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_TM2: + case SRSLTE_TM3: + case SRSLTE_TM4: cell.nof_ports = 2; break; default: - ERROR("Transmission mode not implemented."); + ERROR("Transmission mode %d not implemented or invalid\n", transmission_mode); exit(-1); } @@ -291,7 +279,7 @@ void base_init() { if (output_file_name) { if (strcmp(output_file_name, "NULL")) { if (srslte_filesink_init(&fsink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", output_file_name); + ERROR("Error opening file %s\n", output_file_name); exit(-1); } null_file_sink = false; @@ -313,12 +301,12 @@ void base_init() { if (net_port > 0) { if (srslte_netsource_init(&net_source, "127.0.0.1", net_port, SRSLTE_NETSOURCE_UDP)) { - fprintf(stderr, "Error creating input UDP socket at port %d\n", net_port); + ERROR("Error creating input UDP socket at port %d\n", net_port); exit(-1); } if (null_file_sink) { if (srslte_netsink_init(&net_sink, "127.0.0.1", net_port+1, SRSLTE_NETSINK_TCP)) { - fprintf(stderr, "Error sink\n"); + ERROR("Error sink\n"); exit(-1); } } @@ -331,7 +319,7 @@ void base_init() { /* create ifft object */ for (i = 0; i < cell.nof_ports; i++) { if (srslte_ofdm_tx_init(&ifft[i], SRSLTE_CP_NORM, sf_buffer[i], output_buffer[i], cell.nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); + ERROR("Error creating iFFT object\n"); exit(-1); } @@ -339,18 +327,18 @@ void base_init() { } if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, sf_buffer[0], output_buffer[0], cell.nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); + ERROR("Error creating iFFT object\n"); exit(-1); } srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2); srslte_ofdm_set_normalize(&ifft_mbsfn, true); if (srslte_pbch_init(&pbch)) { - fprintf(stderr, "Error creating PBCH object\n"); + ERROR("Error creating PBCH object\n"); exit(-1); } if (srslte_pbch_set_cell(&pbch, cell)) { - fprintf(stderr, "Error creating PBCH object\n"); + ERROR("Error creating PBCH object\n"); exit(-1); } @@ -358,33 +346,33 @@ void base_init() { if (srslte_regs_init(®s, cell)) { - fprintf(stderr, "Error initiating regs\n"); + ERROR("Error initiating regs\n"); exit(-1); } if (srslte_pcfich_init(&pcfich, 1)) { - fprintf(stderr, "Error creating PBCH object\n"); + ERROR("Error creating PBCH object\n"); exit(-1); } if (srslte_pcfich_set_cell(&pcfich, ®s, cell)) { - fprintf(stderr, "Error creating PBCH object\n"); + ERROR("Error creating PBCH object\n"); exit(-1); } if (srslte_pdcch_init_enb(&pdcch, cell.nof_prb)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); exit(-1); } if (srslte_pdcch_set_cell(&pdcch, ®s, cell)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); exit(-1); } if (srslte_pdsch_init_enb(&pdsch, cell.nof_prb)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); exit(-1); } if (srslte_pdsch_set_cell(&pdsch, cell)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); exit(-1); } @@ -392,8 +380,8 @@ void base_init() { if(mbsfn_area_id > -1){ - if (srslte_pmch_init(&pmch, cell.nof_prb)) { - fprintf(stderr, "Error creating PMCH object\n"); + if (srslte_pmch_init(&pmch, cell.nof_prb, 1)) { + ERROR("Error creating PMCH object\n"); } srslte_pmch_set_area_id(&pmch, mbsfn_area_id); } @@ -401,12 +389,12 @@ void base_init() { for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); if (!softbuffers[i]) { - fprintf(stderr, "Error allocating soft buffer\n"); + ERROR("Error allocating soft buffer\n"); exit(-1); } if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); + ERROR("Error initiating soft buffer\n"); exit(-1); } } @@ -500,53 +488,53 @@ uint32_t prbset_to_bitmask() { int update_radl() { + ZERO_OBJECT(dci_dl); + /* Configure cell and PDSCH in function of the transmission mode */ - switch(pdsch_cfg.mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - pdsch_cfg.nof_layers = 1; - nof_tb = 1; - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - pdsch_cfg.nof_layers = 2; + switch (transmission_mode) { + case SRSLTE_TM1: + case SRSLTE_TM2: nof_tb = 1; + dci_dl.format = SRSLTE_DCI_FORMAT1; break; - case SRSLTE_MIMO_TYPE_CDD: - pdsch_cfg.nof_layers = 2; + case SRSLTE_TM3: + dci_dl.format = SRSLTE_DCI_FORMAT2A; nof_tb = 2; break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - pdsch_cfg.nof_layers = multiplex_nof_layers; + case SRSLTE_TM4: + dci_dl.format = SRSLTE_DCI_FORMAT2; nof_tb = multiplex_nof_layers; + if (multiplex_nof_layers == 1) { + dci_dl.pinfo = (uint8_t)(multiplex_pmi + 1); + } else { + dci_dl.pinfo = (uint8_t)multiplex_pmi; + } break; default: ERROR("Transmission mode not implemented."); exit(-1); } - bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); - ra_dl.harq_process = 0; - ra_dl.mcs_idx = mcs_idx; - ra_dl.ndi = 0; - ra_dl.rv_idx = rvidx[0]; - ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; - ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); - ra_dl.tb_en[0] = 1; + dci_dl.rnti = UE_CRNTI; + dci_dl.pid = 0; + dci_dl.tb[0].mcs_idx = mcs_idx; + dci_dl.tb[0].ndi = 0; + dci_dl.tb[0].rv = rvidx[0]; + dci_dl.tb[0].cw_idx = 0; + dci_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); if (nof_tb > 1) { - ra_dl.mcs_idx_1 = mcs_idx; - ra_dl.ndi_1 = 0; - ra_dl.rv_idx_1 = rvidx[1]; - ra_dl.tb_en[1] = 1; + dci_dl.tb[1].mcs_idx = mcs_idx; + dci_dl.tb[1].ndi = 0; + dci_dl.tb[1].rv = rvidx[1]; + dci_dl.tb[1].cw_idx = 1; + } else { + SRSLTE_DCI_TB_DISABLE(dci_dl.tb[1]); } - srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); - srslte_ra_dl_grant_t dummy_grant; - srslte_ra_nbits_t dummy_nbits[SRSLTE_MAX_CODEWORDS]; - srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &dummy_grant); - srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, dummy_nbits); - srslte_ra_dl_grant_fprint(stdout, &dummy_grant); - dummy_grant.sf_type = SRSLTE_SF_NORM; - if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { + srslte_dci_dl_fprint(stdout, &dci_dl, cell.nof_prb); + if (transmission_mode != SRSLTE_TM1) { printf("\nTransmission mode key table:\n"); printf(" Mode | 1TB | 2TB |\n"); printf("----------+---------+-----+\n"); @@ -602,40 +590,40 @@ int update_control() { } else { switch (input[0]) { case 'q': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - multiplex_pmi = 0; + transmission_mode = SRSLTE_TM4; + multiplex_pmi = 0; multiplex_nof_layers = 1; break; case 'w': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - multiplex_pmi = 1; + transmission_mode = SRSLTE_TM4; + multiplex_pmi = 1; multiplex_nof_layers = 1; break; case 'e': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - multiplex_pmi = 2; + transmission_mode = SRSLTE_TM4; + multiplex_pmi = 2; multiplex_nof_layers = 1; break; case 'r': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - multiplex_pmi = 3; + transmission_mode = SRSLTE_TM4; + multiplex_pmi = 3; multiplex_nof_layers = 1; break; case 'a': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - multiplex_pmi = 0; + transmission_mode = SRSLTE_TM4; + multiplex_pmi = 0; multiplex_nof_layers = 2; break; case 's': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - multiplex_pmi = 1; + transmission_mode = SRSLTE_TM4; + multiplex_pmi = 1; multiplex_nof_layers = 2; break; case 'z': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD; + transmission_mode = SRSLTE_TM3; break; case 'x': - pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; + transmission_mode = SRSLTE_TM2; break; default: last_mcs_idx = mcs_idx; @@ -670,8 +658,11 @@ void *net_thread_fnc(void *arg) { n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm); if (n > 0) { // FIXME: I assume that both transport blocks have same size in case of 2 tb are active - - int nbytes = 1 + (((mbsfn_area_id > -1)?(pmch_cfg.grant.mcs[0].tbs):(pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs)) - 1) / 8; + + int nbytes = 1 + (((mbsfn_area_id > -1) ? (pmch_cfg.pdsch_cfg.grant.tb[0].tbs) + : (pdsch_cfg.grant.tb[0].tbs + pdsch_cfg.grant.tb[1].tbs)) - + 1) / + 8; rpm += n; INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes); wpm = 0; @@ -695,9 +686,9 @@ void *net_thread_fnc(void *arg) { memcpy(data2, &data2[wpm], rpm * sizeof(uint8_t)); } } else if (n == 0) { - rpm = 0; + rpm = 0; } else { - fprintf(stderr, "Error receiving from network\n"); + ERROR("Error receiving from network\n"); exit(-1); } } while(n >= 0); @@ -712,10 +703,9 @@ int main(int argc, char **argv) { float sss_signal5[SRSLTE_SSS_LEN]; // for subframe 5 uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; int i; - cf_t *sf_symbols[SRSLTE_MAX_PORTS]; - cf_t *slot1_symbols[SRSLTE_MAX_PORTS]; + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; srslte_dci_msg_t dci_msg; - srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30]; + srslte_dci_location_t locations[SRSLTE_NOF_SF_X_FRAME][30]; uint32_t sfn; srslte_refsignal_t csr_refs; srslte_refsignal_t mbsfn_refs; @@ -753,34 +743,32 @@ int main(int argc, char **argv) { /* Generate PSS/SSS signals */ srslte_pss_generate(pss_signal, N_id_2); srslte_sss_generate(sss_signal0, sss_signal5, cell.id); - /* Generate reference signals */ if(srslte_refsignal_cs_init(&csr_refs, cell.nof_prb)) { - fprintf(stderr, "Error initializing equalizer\n"); + ERROR("Error initializing equalizer\n"); exit(-1); } - if(mbsfn_area_id > -1) { + if (mbsfn_area_id > -1) { if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell.nof_prb)) { - fprintf(stderr, "Error initializing equalizer\n"); + ERROR("Error initializing equalizer\n"); exit(-1); } if (srslte_refsignal_mbsfn_set_cell(&mbsfn_refs, cell, mbsfn_area_id)) { - fprintf(stderr, "Error initializing MBSFNR signal\n"); + ERROR("Error initializing MBSFNR signal\n"); exit(-1); } } - + if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){ - fprintf(stderr, "Error setting cell\n"); + ERROR("Error setting cell\n"); exit(-1); } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { sf_symbols[i] = sf_buffer[i%cell.nof_ports]; - slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; } @@ -803,18 +791,17 @@ int main(int argc, char **argv) { srslte_rf_set_master_clock_rate(&rf, srate); } printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); - float srate_rf = srslte_rf_set_tx_srate(&rf, (double) srate); + float srate_rf = srslte_rf_set_tx_srate(&rf, (double)srate); if (srate_rf != srate) { - fprintf(stderr, "Could not set sampling rate\n"); + ERROR("Could not set sampling rate\n"); exit(-1); } } else { - fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb); + ERROR("Invalid number of PRB %d\n", cell.nof_prb); exit(-1); } printf("Set TX gain: %.1f dB\n", srslte_rf_set_tx_gain(&rf, rf_gain)); - printf("Set TX freq: %.2f MHz\n", - srslte_rf_set_tx_freq(&rf, rf_freq) / 1000000); + printf("Set TX freq: %.2f MHz\n", srslte_rf_set_tx_freq(&rf, cell.nof_ports, rf_freq) / 1000000); } #endif @@ -828,10 +815,16 @@ int main(int argc, char **argv) { exit(-1); } } - pmch_cfg.grant.mcs[0].tbs = 1096; + pmch_cfg.pdsch_cfg.grant.tb[0].tbs = 1096; + + srslte_dl_sf_cfg_t dl_sf; + ZERO_OBJECT(dl_sf); + /* Initiate valid DCI locations */ - for (i=0;i -1){ - srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]); - } else { + + if (mch_table[sf_idx] == 1 && mbsfn_area_id > -1) { + srslte_refsignal_mbsfn_put_sf(cell, 0, csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]); + } else { + dl_sf.tti = nf * 10 + sf_idx; for (i = 0; i < cell.nof_ports; i++) { - srslte_refsignal_cs_put_sf(cell, (uint32_t) i, csr_refs.pilots[i / 2][sf_idx], sf_symbols[i]); + srslte_refsignal_cs_put_sf(&csr_refs, &dl_sf, (uint32_t)i, sf_symbols[i]); } } - + srslte_pbch_mib_pack(&cell, sfn, bch_payload); if (sf_idx == 0) { - srslte_pbch_encode(&pbch, bch_payload, slot1_symbols, nf%4); + srslte_pbch_encode(&pbch, bch_payload, sf_symbols, nf % 4); } - srslte_pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx); + dl_sf.tti = nf * 10 + sf_idx; + dl_sf.cfi = cfi; + + srslte_pcfich_encode(&pcfich, &dl_sf, sf_symbols); /* Update DL resource allocation from control port */ if (update_control(sf_idx)) { - fprintf(stderr, "Error updating parameters from control port\n"); + ERROR("Error updating parameters from control port\n"); } /* Transmit PDCCH + PDSCH only when there is data to send */ @@ -890,10 +895,10 @@ int main(int argc, char **argv) { INFO("Transmitting packet from port\n"); } } else { - INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs); + INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.tb[0].tbs + pdsch_cfg.grant.tb[1].tbs); for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - if (pdsch_cfg.grant.tb_en[tb]) { - for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) { + if (pdsch_cfg.grant.tb[tb].enabled) { + for (i = 0; i < pdsch_cfg.grant.tb[tb].tbs / 8; i++) { data[tb][i] = (uint8_t) rand(); } } @@ -904,57 +909,38 @@ int main(int argc, char **argv) { } else { send_data = false; } - } + } if (send_data) { - if(mch_table[sf_idx] == 0 || mbsfn_area_id < 0) { // PDCCH + PDSCH - srslte_dci_format_t dci_format; - switch(pdsch_cfg.mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - dci_format = SRSLTE_DCI_FORMAT1; - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - case SRSLTE_MIMO_TYPE_CDD: - dci_format = SRSLTE_DCI_FORMAT2A; - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - dci_format = SRSLTE_DCI_FORMAT2; - if (multiplex_nof_layers == 1) { - ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); - } else { - ra_dl.pinfo = (uint8_t) multiplex_pmi; - } - break; - default: - fprintf(stderr, "Wrong MIMO configuration\n"); - exit(SRSLTE_ERROR); - } + if (mch_table[sf_idx] == 0 || mbsfn_area_id < 0) { // PDCCH + PDSCH + dl_sf.sf_type = SRSLTE_SF_NORM; + /* Encode PDCCH */ INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); - srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false); - if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) { - fprintf(stderr, "Error encoding DCI message\n"); + + dci_msg.location = locations[sf_idx][0]; + srslte_dci_msg_pack_pdsch(&cell, &dl_sf, NULL, &dci_dl, &dci_msg); + if (srslte_pdcch_encode(&pdcch, &dl_sf, &dci_msg, sf_symbols)) { + ERROR("Error encoding DCI message\n"); exit(-1); } /* Configure pdsch_cfg parameters */ - srslte_ra_dl_grant_t grant; - srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { - fprintf(stderr, "Error configuring PDSCH\n"); + if (srslte_ra_dl_dci_to_grant(&cell, &dl_sf, transmission_mode, &dci_dl, &pdsch_cfg.grant)) { + ERROR("Error configuring PDSCH\n"); exit(-1); } /* Encode PDSCH */ - if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); + if (srslte_pdsch_encode(&pdsch, &dl_sf, &pdsch_cfg, data, sf_symbols)) { + ERROR("Error encoding PDSCH\n"); exit(-1); } if (net_port > 0 && net_packet_ready) { if (null_file_sink) { for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs); - if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) { - fprintf(stderr, "Error sending data through UDP socket\n"); + srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.tb[tb].tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.tb[tb].tbs - 1) / 8) < 0) { + ERROR("Error sending data through UDP socket\n"); } } } @@ -964,48 +950,37 @@ int main(int argc, char **argv) { } } }else{ // We're sending MCH on subframe 1 - PDCCH + PMCH + dl_sf.sf_type = SRSLTE_SF_MBSFN; - /* Encode PDCCH */ - //INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); - //srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false); - //if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) { - // fprintf(stderr, "Error encoding DCI message\n"); - // exit(-1); - // } - /* Configure pmch_cfg parameters */ - srslte_ra_dl_grant_t grant; - grant.tb_en[0] = true; - grant.tb_en[1] = false; - - grant.mcs[0].idx = 2; - grant.nof_prb = cell.nof_prb; - grant.sf_type = SRSLTE_SF_MBSFN; - srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb); - grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); - for(int i = 0; i < 2; i++){ - for(int j = 0; j < grant.nof_prb; j++){ - grant.prb_idx[i][j] = true; - } - } - for(int i = 0; i < grant.mcs[0].tbs/8;i++) - { - data_mbms[i] = i%255; - } - - if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) { - fprintf(stderr, "Error configuring PMCH\n"); + /* Force 1 word and MCS 2 */ + dci_dl.rnti = SRSLTE_MRNTI; + dci_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci_dl.type0_alloc.rbg_bitmask = 0xffffffff; + dci_dl.tb[0].mcs_idx = 2; + dci_dl.format = SRSLTE_DCI_FORMAT1; + + /* Configure pdsch_cfg parameters */ + if (srslte_ra_dl_dci_to_grant(&cell, &dl_sf, SRSLTE_TM1, &dci_dl, &pmch_cfg.pdsch_cfg.grant)) { + ERROR("Error configuring PDSCH\n"); exit(-1); - } + } + + for (int i = 0; i < pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8; i++) { + data_mbms[i] = i % 255; + } + + pmch_cfg.area_id = mbsfn_area_id; + /* Encode PMCH */ - if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data_mbms, mbsfn_area_id, sf_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); + if (srslte_pmch_encode(&pmch, &dl_sf, &pmch_cfg, data_mbms, sf_symbols)) { + ERROR("Error encoding PDSCH\n"); exit(-1); } if (net_port > 0 && net_packet_ready) { if (null_file_sink) { - srslte_bit_pack_vector(data[0], data_tmp, pmch_cfg.grant.mcs[0].tbs); - if (srslte_netsink_write(&net_sink, data_tmp, 1+(pmch_cfg.grant.mcs[0].tbs-1)/8) < 0) { - fprintf(stderr, "Error sending data through UDP socket\n"); + srslte_bit_pack_vector(data[0], data_tmp, pmch_cfg.pdsch_cfg.grant.tb[0].tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pmch_cfg.pdsch_cfg.grant.tb[0].tbs - 1) / 8) < 0) { + ERROR("Error sending data through UDP socket\n"); } } net_packet_ready = false; diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 7ee89c695..73ead7900 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -36,24 +36,24 @@ #include #include #include + #include "srslte/common/gen_mch_tables.h" #include "srslte/common/crash_handler.h" -#include #include "srslte/phy/io/filesink.h" #include "srslte/srslte.h" #define ENABLE_AGC_DEFAULT #ifndef DISABLE_RF + #include "srslte/phy/rf/rf.h" #include "srslte/phy/rf/rf_utils.h" -cell_search_cfg_t cell_detect_config = { - SRSLTE_DEFAULT_MAX_FRAMES_PBCH, - SRSLTE_DEFAULT_MAX_FRAMES_PSS, - SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES, - 0 -}; +cell_search_cfg_t cell_detect_config = {.max_frames_pbch = SRSLTE_DEFAULT_MAX_FRAMES_PBCH, + .max_frames_pss = SRSLTE_DEFAULT_MAX_FRAMES_PSS, + .nof_valid_pss_frames = SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES, + .init_agc = 0, + .force_tdd = false}; #else #warning Compiling pdsch_ue with no RF support @@ -61,17 +61,20 @@ cell_search_cfg_t cell_detect_config = { //#define STDOUT_COMPACT -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI + #include "srsgui/srsgui.h" + void init_plots(); -pthread_t plot_thread; -sem_t plot_sem; -uint32_t plot_sf_idx=0; -bool plot_track = true; -bool enable_mbsfn_plot = false; -#endif -char *output_file_name; -#define PRINT_CHANGE_SCHEDULIGN + +pthread_t plot_thread; +sem_t plot_sem; +uint32_t plot_sf_idx = 0; +bool plot_track = true; +bool enable_mbsfn_plot = false; +#endif /* ENABLE_GUI */ +char* output_file_name; +//#define PRINT_CHANGE_SCHEDULING //#define CORRECT_SAMPLE_OFFSET @@ -108,22 +111,27 @@ typedef struct { int32_t mbsfn_area_id; uint8_t non_mbsfn_region; uint8_t mbsfn_sf_mask; + int tdd_special_sf; + int sf_config; int verbose; }prog_args_t; -void args_default(prog_args_t *args) { - args->disable_plots = false; - args->disable_plots_except_constellation = false; +void args_default(prog_args_t* args) +{ + args->disable_plots = false; + args->disable_plots_except_constellation = false; args->nof_subframes = -1; args->rnti = SRSLTE_SIRNTI; args->force_N_id_2 = -1; // Pick the best + args->tdd_special_sf = -1; + args->sf_config = -1; args->input_file_name = NULL; - args->disable_cfo = false; - args->time_offset = 0; - args->file_nof_prb = 25; - args->file_nof_ports = 1; - args->file_cell_id = 0; - args->file_offset_time = 0; + args->disable_cfo = false; + args->time_offset = 0; + args->file_nof_prb = 25; + args->file_nof_ports = 1; + args->file_cell_id = 0; + args->file_offset_time = 0; args->file_offset_freq = 0; args->rf_dev = ""; args->rf_args = ""; @@ -132,23 +140,23 @@ void args_default(prog_args_t *args) { args->enable_cfo_ref = false; args->average_subframe = false; #ifdef ENABLE_AGC_DEFAULT - args->rf_gain = -1.0; + args->rf_gain = -1.0; #else - args->rf_gain = 50.0; + args->rf_gain = 50.0; #endif - args->net_port = -1; - args->net_address = "127.0.0.1"; - args->net_port_signal = -1; + args->net_port = -1; + args->net_address = "127.0.0.1"; + args->net_port_signal = -1; args->net_address_signal = "127.0.0.1"; args->decimate = 0; - args->cpu_affinity = -1; + args->cpu_affinity = -1; args->mbsfn_area_id = -1; - args->non_mbsfn_region = 2; + args->non_mbsfn_region = 2; args->mbsfn_sf_mask = 32; } void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [adgpPoOcildFRDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); + printf("Usage: %s [adgpPoOcildFRDnruMNvTG] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-I RF dev [Default %s]\n", args->rf_dev); printf("\t-a RF args [Default %s]\n", args->rf_args); @@ -157,7 +165,7 @@ void usage(prog_args_t *args, char *prog) { printf("\t-g RF fix RX gain [Default AGC]\n"); #else printf("\t-g Set RX gain [Default %.1f dB]\n", args->rf_gain); -#endif +#endif #else printf("\t RF is disabled.\n"); #endif @@ -167,19 +175,21 @@ void usage(prog_args_t *args, char *prog) { printf("\t-p nof_prb for input file [Default %d]\n", args->file_nof_prb); printf("\t-P nof_ports for input file [Default %d]\n", args->file_nof_ports); printf("\t-c cell_id for input file [Default %d]\n", args->file_cell_id); - printf("\t-r RNTI in Hex [Default 0x%x]\n",args->rnti); + printf("\t-r RNTI in Hex [Default 0x%x]\n", args->rnti); printf("\t-l Force N_id_2 [Default best]\n"); - printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo?"Disabled":"Enabled"); - printf("\t-F Enable RS-based CFO correction [Default %s]\n", !args->enable_cfo_ref?"Disabled":"Enabled"); - printf("\t-R Average channel estimates on 1 ms [Default %s]\n", !args->average_subframe?"Disabled":"Enabled"); + printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo ? "Disabled" : "Enabled"); + printf("\t-F Enable RS-based CFO correction [Default %s]\n", !args->enable_cfo_ref ? "Disabled" : "Enabled"); + printf("\t-R Average channel estimates on 1 ms [Default %s]\n", !args->average_subframe ? "Disabled" : "Enabled"); printf("\t-t Add time offset [Default %d]\n", args->time_offset); -#ifndef DISABLE_GRAPHICS + printf("\t-T Set TDD special subframe configuration [Default %d]\n", args->tdd_special_sf); + printf("\t-G Set TDD uplink/downlink configuration [Default %d]\n", args->sf_config); +#ifdef ENABLE_GUI printf("\t-d disable plots [Default enabled]\n"); printf("\t-D disable all but constellation plots [Default enabled]\n"); -#else +#else /* ENABLE_GUI */ printf("\t plots are disabled. Graphics library not available\n"); -#endif - printf("\t-y set the cpu affinity mask [Default %d] \n ",args->cpu_affinity); +#endif /* ENABLE_GUI */ + printf("\t-y set the cpu affinity mask [Default %d] \n ", args->cpu_affinity); printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); printf("\t-s remote UDP port to send input signal (-1 does nothing with it) [Default %d]\n", args->net_port_signal); printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal); @@ -193,7 +203,8 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "adAogliIpPcOCtdDFRnvrfuUsSZyWMNB")) != -1) { + + while ((opt = getopt(argc, argv, "adAogliIpPcOCtdDFRnvrfuUsSZyWMNBTG")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -240,6 +251,12 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'f': args->rf_freq = strtod(argv[optind], NULL); break; + case 'T': + args->tdd_special_sf = atoi(argv[optind]); + break; + case 'G': + args->sf_config = atoi(argv[optind]); + break; case 'n': args->nof_subframes = atoi(argv[optind]); break; @@ -299,12 +316,13 @@ void parse_args(prog_args_t *args, int argc, char **argv) { exit(-1); } } + /**********************************************************************/ -/* TODO: Do something with the output data */ uint8_t *data[SRSLTE_MAX_CODEWORDS]; -bool go_exit = false; +bool go_exit = false; + void sig_int_handler(int signo) { printf("SIGINT received. Exiting...\n"); @@ -319,112 +337,118 @@ cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}; #ifndef DISABLE_RF -int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { + +int srslte_rf_recv_wrapper(void* h, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* t) +{ DEBUG(" ---- Receive %d samples ---- \n", nsamples); - void *ptr[SRSLTE_MAX_PORTS]; - for (int i=0;i -1) { + +#ifdef ENABLE_GUI + if (prog_args.mbsfn_area_id > -1) { enable_mbsfn_plot = true; } -#endif - - for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { - data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8); +#endif /* ENABLE_GUI */ + + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + data[i] = srslte_vec_malloc(sizeof(uint8_t) * 1500 * 8); if (!data[i]) { ERROR("Allocating data"); go_exit = true; } } + uint8_t mch_table[10]; - bzero(&mch_table[0], sizeof(uint8_t)*10); - if(prog_args.mbsfn_area_id > -1) { + bzero(&mch_table[0], sizeof(uint8_t) * 10); + if (prog_args.mbsfn_area_id > -1) { generate_mcch_table(mch_table, prog_args.mbsfn_sf_mask); } - if(prog_args.cpu_affinity > -1) { - + if (prog_args.cpu_affinity > -1) { + cpu_set_t cpuset; pthread_t thread; - + thread = pthread_self(); - for(int i = 0; i < 8;i++){ - if(((prog_args.cpu_affinity >> i) & 0x01) == 1){ + for (int i = 0; i < 8; i++) { + if (((prog_args.cpu_affinity >> i) & 0x01) == 1) { printf("Setting pdsch_ue with affinity to core %d\n", i); - CPU_SET((size_t) i , &cpuset); + CPU_SET((size_t)i, &cpuset); } - if(pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset)){ - fprintf(stderr, "Error setting main thread affinity to %d \n", prog_args.cpu_affinity); - exit(-1); + if (pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset)) { + ERROR("Error setting main thread affinity to %d \n", prog_args.cpu_affinity); + exit(-1); } - } + } } - + if (prog_args.net_port > 0) { if (srslte_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSLTE_NETSINK_UDP)) { - fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port); + ERROR("Error initiating UDP socket to %s:%d\n", prog_args.net_address, prog_args.net_port); exit(-1); } srslte_netsink_set_nonblocking(&net_sink); } if (prog_args.net_port_signal > 0) { - if (srslte_netsink_init(&net_sink_signal, prog_args.net_address_signal, - prog_args.net_port_signal, SRSLTE_NETSINK_UDP)) { - fprintf(stderr, "Error initiating UDP socket to %s:%d\n", prog_args.net_address_signal, prog_args.net_port_signal); + if (srslte_netsink_init( + &net_sink_signal, prog_args.net_address_signal, prog_args.net_port_signal, SRSLTE_NETSINK_UDP)) { + ERROR("Error initiating UDP socket to %s:%d\n", prog_args.net_address_signal, prog_args.net_port_signal); exit(-1); } srslte_netsink_set_nonblocking(&net_sink_signal); } - + + float search_cell_cfo = 0; + #ifndef DISABLE_RF if (!prog_args.input_file_name) { - + printf("Opening RF device with %d RX antennas...\n", prog_args.rf_nof_rx_ant); if (srslte_rf_open_devname(&rf, prog_args.rf_dev, prog_args.rf_args, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error opening rf\n"); @@ -432,89 +456,93 @@ int main(int argc, char **argv) { } /* Set receiver gain */ if (prog_args.rf_gain > 0) { - srslte_rf_set_rx_gain(&rf, prog_args.rf_gain); + srslte_rf_set_rx_gain(&rf, prog_args.rf_gain); } else { printf("Starting AGC thread...\n"); if (srslte_rf_start_gain_thread(&rf, false)) { - fprintf(stderr, "Error opening rf\n"); + ERROR("Error opening rf\n"); exit(-1); } srslte_rf_set_rx_gain(&rf, srslte_rf_get_rx_gain(&rf)); cell_detect_config.init_agc = srslte_rf_get_rx_gain(&rf); } - + sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGINT); sigprocmask(SIG_UNBLOCK, &sigset, NULL); signal(SIGINT, sig_int_handler); - - srslte_rf_set_master_clock_rate(&rf, 30.72e6); + + srslte_rf_set_master_clock_rate(&rf, 30.72e6); /* set receiver frequency */ - printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq)/1000000); - srslte_rf_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq); + printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq) / 1000000); + srslte_rf_set_rx_freq(&rf, prog_args.rf_nof_rx_ant, prog_args.rf_freq + prog_args.file_offset_freq); srslte_rf_rx_wait_lo_locked(&rf); - - uint32_t ntrial=0; + uint32_t ntrial = 0; do { - ret = rf_search_and_decode_mib(&rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); + ret = rf_search_and_decode_mib( + &rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &search_cell_cfo); if (ret < 0) { - fprintf(stderr, "Error searching for cell\n"); - exit(-1); + ERROR("Error searching for cell\n"); + exit(-1); } else if (ret == 0 && !go_exit) { printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++); - } - } while (ret == 0 && !go_exit); - + } + } while (ret == 0 && !go_exit); + if (go_exit) { - srslte_rf_close(&rf); + srslte_rf_close(&rf); exit(0); } /* set sampling frequency */ - int srate = srslte_sampling_freq_hz(cell.nof_prb); - if (srate != -1) { - if (srate < 10e6) { - srslte_rf_set_master_clock_rate(&rf, 4*srate); + int srate = srslte_sampling_freq_hz(cell.nof_prb); + if (srate != -1) { + if (srate < 10e6) { + srslte_rf_set_master_clock_rate(&rf, 4 * srate); } else { - srslte_rf_set_master_clock_rate(&rf, srate); + srslte_rf_set_master_clock_rate(&rf, srate); } - printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate); if (srate_rf != srate) { - fprintf(stderr, "Could not set sampling rate\n"); + ERROR("Could not set sampling rate\n"); exit(-1); } } else { - fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb); + ERROR("Invalid number of PRB %d\n", cell.nof_prb); exit(-1); } INFO("Stopping RF and flushing buffer...\r"); } #endif - + /* If reading from file, go straight to PDSCH decoding. Otherwise, decode MIB first */ if (prog_args.input_file_name) { /* preset cell configuration */ - cell.id = prog_args.file_cell_id; - cell.cp = SRSLTE_CP_NORM; + cell.id = prog_args.file_cell_id; + cell.cp = SRSLTE_CP_NORM; cell.phich_length = SRSLTE_PHICH_NORM; cell.phich_resources = SRSLTE_PHICH_R_1; - cell.nof_ports = prog_args.file_nof_ports; - cell.nof_prb = prog_args.file_nof_prb; - - if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb, - prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) { - fprintf(stderr, "Error initiating ue_sync\n"); - exit(-1); + cell.nof_ports = prog_args.file_nof_ports; + cell.nof_prb = prog_args.file_nof_prb; + + if (srslte_ue_sync_init_file_multi(&ue_sync, + prog_args.file_nof_prb, + prog_args.input_file_name, + prog_args.file_offset_time, + prog_args.file_offset_freq, + prog_args.rf_nof_rx_ant)) { + ERROR("Error initiating ue_sync\n"); + exit(-1); } } else { #ifndef DISABLE_RF - int decimate = 1; + int decimate = 0; if (prog_args.decimate) { if (prog_args.decimate > 4 || prog_args.decimate < 0) { printf("Invalid decimation factor, setting to 1 \n"); @@ -522,86 +550,103 @@ int main(int argc, char **argv) { decimate = prog_args.decimate; } } - - if (srslte_ue_sync_init_multi_decim(&ue_sync, cell.nof_prb, cell.id == 1000, srslte_rf_recv_wrapper, - prog_args.rf_nof_rx_ant, (void*)&rf, decimate)) { - fprintf(stderr, "Error initiating ue_sync\n"); - exit(-1); + if (srslte_ue_sync_init_multi_decim(&ue_sync, + cell.nof_prb, + cell.id == 1000, + srslte_rf_recv_wrapper, + prog_args.rf_nof_rx_ant, + (void*)&rf, + decimate)) { + ERROR("Error initiating ue_sync\n"); + exit(-1); } - if (srslte_ue_sync_set_cell(&ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); + ERROR("Error initiating ue_sync\n"); exit(-1); } #endif } - for (int i=0;i= 0 && prog_args.sf_config >= 0) { + dl_sf.tdd_config.ss_config = prog_args.tdd_special_sf; + dl_sf.tdd_config.sf_config = prog_args.sf_config; + dl_sf.tdd_config.configured = true; + } + + srslte_chest_dl_cfg_t chest_pdsch_cfg; + chest_pdsch_cfg.cfo_estimate_enable = prog_args.enable_cfo_ref; + chest_pdsch_cfg.cfo_estimate_sf_mask = 1023; + chest_pdsch_cfg.interpolate_subframe = !prog_args.average_subframe; + + // Special configuration for MBSFN channel estimation + srslte_chest_dl_cfg_t chest_mbsfn_cfg; + chest_mbsfn_cfg.filter_type = SRSLTE_CHEST_FILTER_TRIANGLE; + chest_mbsfn_cfg.filter_coef[0] = 0.1; + chest_mbsfn_cfg.interpolate_subframe = true; + chest_mbsfn_cfg.noise_alg = SRSLTE_NOISE_ALG_PSS; + + // Allocate softbuffer buffers + srslte_softbuffer_rx_t rx_softbuffers[SRSLTE_MAX_CODEWORDS]; + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + pdsch_cfg.softbuffers.rx[i] = &rx_softbuffers[i]; + srslte_softbuffer_rx_init(pdsch_cfg.softbuffers.rx[i], cell.nof_prb); + } - srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 1023); - srslte_chest_dl_average_subframe(&ue_dl.chest, prog_args.average_subframe); + pdsch_cfg.rnti = prog_args.rnti; /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ - srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); - + srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); + /* Configure MBSFN area id and non-MBSFN Region */ if (prog_args.mbsfn_area_id > -1) { srslte_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id); srslte_ue_dl_set_non_mbsfn_region(&ue_dl, prog_args.non_mbsfn_region); } - /* Initialize subframe counter */ - sf_cnt = 0; - -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI if (!prog_args.disable_plots) { - init_plots(cell); + init_plots(cell); sleep(1); } -#endif +#endif /* ENABLE_GUI */ #ifndef DISABLE_RF if (!prog_args.input_file_name) { srslte_rf_start_rx_stream(&rf, false); } #endif - - // Variables for measurements - uint32_t nframes=0; - uint8_t ri = 0, pmi = 0; - float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, procrate = 0.0, - sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0; - bool decode_pdsch = false; - - for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) { - bzero(sinr[i], sizeof(float)*SRSLTE_MAX_CODEBOOKS); - } #ifndef DISABLE_RF if (prog_args.rf_gain < 0 && !prog_args.input_file_name) { @@ -613,19 +658,32 @@ int main(int argc, char **argv) { cell_detect_config.init_agc); } #endif -#ifdef PRINT_CHANGE_SCHEDULIGN - srslte_ra_dl_dci_t old_dl_dci; - bzero(&old_dl_dci, sizeof(srslte_ra_dl_dci_t)); +#ifdef PRINT_CHANGE_SCHEDULING + srslte_ra_dl_grant_t old_dl_dci; + bzero(&old_dl_dci, sizeof(srslte_ra_dl_grant_t)); #endif ue_sync.cfo_correct_enable_track = !prog_args.disable_cfo; - + srslte_pbch_decode_reset(&ue_mib.pbch); - + INFO("\nEntering main loop...\n\n"); + + // Variables for measurements + uint32_t nframes = 0; + float rsrp0 = 0.0, rsrp1 = 0.0, rsrq = 0.0, snr = 0.0, enodebrate = 0.0, uerate = 0.0, procrate = 0.0, + sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]; + bool decode_pdsch = false; + + for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) { + bzero(sinr[i], sizeof(float) * SRSLTE_MAX_CODEBOOKS); + } + /* Main loop */ + uint64_t sf_cnt = 0; + uint32_t sfn = 0; + uint32_t last_decoded_tm = 0; while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { - bool acks [SRSLTE_MAX_CODEWORDS] = {false}; char input[128]; PRINT_LINE_INIT(); @@ -644,230 +702,224 @@ int main(int argc, char **argv) { /* If a new line is detected set verbose level to Debug */ if (fgets(input, sizeof(input), stdin)) { srslte_verbose = SRSLTE_VERBOSE_DEBUG; - ue_dl.pkt_errors = 0; - ue_dl.pkts_total = 0; - ue_dl.nof_detected = 0; + pkt_errors = 0; + pkt_total = 0; + nof_detected = 0; nof_trials = 0; } } - ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); + cf_t* buffers[SRSLTE_MAX_PORTS] = {}; + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + buffers[p] = sf_buffer[p]; + } + ret = srslte_ue_sync_zerocopy(&ue_sync, buffers); if (ret < 0) { - fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); + ERROR("Error calling srslte_ue_sync_work()\n"); } #ifdef CORRECT_SAMPLE_OFFSET - float sample_offset = (float) srslte_ue_sync_get_last_sample_offset(&ue_sync)+srslte_ue_sync_get_sfo(&ue_sync)/1000; + float sample_offset = + (float)srslte_ue_sync_get_last_sample_offset(&ue_sync) + srslte_ue_sync_get_sfo(&ue_sync) / 1000; srslte_ue_dl_set_sample_offset(&ue_dl, sample_offset); #endif - + /* srslte_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */ if (ret == 1) { - uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync); + bool acks[SRSLTE_MAX_CODEWORDS] = {false}; + struct timeval t[3]; + + uint32_t sf_idx = srslte_ue_sync_get_sfidx(&ue_sync); switch (state) { case DECODE_MIB: - if (sfidx == 0) { + if (sf_idx == 0) { + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + int sfn_offset; n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); if (n < 0) { - fprintf(stderr, "Error decoding UE MIB\n"); + ERROR("Error decoding UE MIB\n"); exit(-1); - } else if (n == SRSLTE_UE_MIB_FOUND) { + } else if (n == SRSLTE_UE_MIB_FOUND) { srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); srslte_cell_fprint(stdout, &cell, sfn); printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset); - sfn = (sfn + sfn_offset)%1024; - state = DECODE_PDSCH; + sfn = (sfn + sfn_offset) % 1024; + state = DECODE_PDSCH; } } break; case DECODE_PDSCH: + if (prog_args.rnti != SRSLTE_SIRNTI) { - decode_pdsch = true; + decode_pdsch = true; + if (srslte_sfidx_tdd_type(dl_sf.tdd_config, sf_idx) == SRSLTE_TDD_SF_U) { + decode_pdsch = false; + } } else { /* We are looking for SIB1 Blocks, search only in appropiate places */ - if ((sfidx == 5 && (sfn%2)==0) ||mch_table[sfidx] == 1) { - decode_pdsch = true; + if ((sf_idx == 5 && (sfn % 2) == 0) || mch_table[sf_idx] == 1) { + decode_pdsch = true; } else { - decode_pdsch = false; + decode_pdsch = false; } } + uint32_t tti = sfn * 10 + sf_idx; + gettimeofday(&t[1], NULL); if (decode_pdsch) { - if(mch_table[sfidx] == 0 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe - if (cell.nof_ports == 1) { - /* Transmission mode 1 */ - n = srslte_ue_dl_decode(&ue_dl, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); - } else { - /* Transmission mode 2 */ - n = srslte_ue_dl_decode(&ue_dl, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); - - if (n < 1) { - /* Transmission mode 3 */ - n = srslte_ue_dl_decode(&ue_dl, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); - } + srslte_sf_t sf_type; + if (mch_table[sf_idx] == 0 || prog_args.mbsfn_area_id < 0) { // Not an MBSFN subframe + sf_type = SRSLTE_SF_NORM; - if (n < 1) { - /* Transmission mode 4 */ - n = srslte_ue_dl_decode(&ue_dl, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); - } - } + // Set PDSCH channel estimation + ue_dl_cfg.chest_cfg = chest_pdsch_cfg; + } else { + sf_type = SRSLTE_SF_MBSFN; - // Feed-back ue_sync with chest_dl CFO estimation - if (sfidx == 5 && prog_args.enable_cfo_ref) { - srslte_ue_sync_set_cfo_ref(&ue_sync, srslte_chest_dl_get_cfo(&ue_dl.chest)); - } + // Set MBSFN channel estimation + ue_dl_cfg.chest_cfg = chest_mbsfn_cfg; + } - }else{ // MBSFN subframe - n = srslte_ue_dl_decode_mbsfn(&ue_dl, - data[0], - sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); - if(n>0){ - if(output_file_name){ - //srslte_filesink_init(&sink, output_file_name, SRSLTE_BYTE_BIN); - // srslte_filesink_write(&sink, data, n); - //srslte_filesink_free(&sink); + n = 0; + for (uint32_t tm = 0; tm < 4 && !n; tm++) { + dl_sf.tti = tti; + dl_sf.sf_type = sf_type; + ue_dl_cfg.cfg.tm = (srslte_tm_t)tm; + + if ((ue_dl_cfg.cfg.tm == SRSLTE_TM1 && cell.nof_ports == 1) || + (ue_dl_cfg.cfg.tm > SRSLTE_TM1 && cell.nof_ports > 1)) { + n = srslte_ue_dl_find_and_decode(&ue_dl, &dl_sf, &ue_dl_cfg, &pdsch_cfg, data, acks); + if (n > 0) { + nof_detected++; + last_decoded_tm = tm; + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (pdsch_cfg.grant.tb[tb].enabled) { + if (!acks[tb]) { + if (sf_type == SRSLTE_SF_NORM) { + pkt_errors++; + } else { + pmch_pkt_errors++; + } + } + if (sf_type == SRSLTE_SF_NORM) { + pkt_total++; + } else { + pmch_pkt_total++; + } + } + } } - INFO("mbsfn PDU size is %d\n", n); } } + // Feed-back ue_sync with chest_dl CFO estimation + if (sf_idx == 5 && prog_args.enable_cfo_ref) { + srslte_ue_sync_set_cfo_ref(&ue_sync, ue_dl.chest_res.cfo); + } + gettimeofday(&t[2], NULL); get_time_interval(t); - if (n < 0) { - // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); - } else if (n > 0) { - + + if (n > 0) { + /* Send data if socket active */ if (prog_args.net_port > 0) { - if(sfidx == 1) { - srslte_netsink_write(&net_sink, data[0], 1+(n-1)/8); + if (sf_idx == 1) { + srslte_netsink_write(&net_sink, data[0], 1 + (n - 1) / 8); } else { - // FIXME: UDP Data transmission does not work + // FIXME: UDP Data transmission does not work for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - if (ue_dl.pdsch_cfg.grant.tb_en[tb]) { - srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); + if (pdsch_cfg.grant.tb[tb].enabled) { + srslte_netsink_write(&net_sink, data[tb], 1 + (pdsch_cfg.grant.tb[tb].tbs - 1) / 8); } } } } - #ifdef PRINT_CHANGE_SCHEDULIGN - if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx || - memcmp(&ue_dl.dl_dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) || - memcmp(&ue_dl.dl_dci.type1_alloc, &old_dl_dci.type1_alloc, sizeof(srslte_ra_type1_t)) || - memcmp(&ue_dl.dl_dci.type2_alloc, &old_dl_dci.type2_alloc, sizeof(srslte_ra_type2_t))) - { - memcpy(&old_dl_dci, &ue_dl.dl_dci, sizeof(srslte_ra_dl_dci_t)); +#ifdef PRINT_CHANGE_SCHEDULING + if (pdsch_cfg.dci.cw[0].mcs_idx != old_dl_dci.cw[0].mcs_idx || + memcmp(&pdsch_cfg.dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) || + memcmp(&pdsch_cfg.dci.type1_alloc, &old_dl_dci.type1_alloc, sizeof(srslte_ra_type1_t)) || + memcmp(&pdsch_cfg.dci.type2_alloc, &old_dl_dci.type2_alloc, sizeof(srslte_ra_type2_t))) { + old_dl_dci = pdsch_cfg.dci; fflush(stdout); - printf("Format: %s\n", srslte_dci_format_string(ue_dl.dci_format)); + printf("DCI %s\n", srslte_dci_format_string(pdsch_cfg.dci.dci_format)); srslte_ra_pdsch_fprint(stdout, &old_dl_dci, cell.nof_prb); - srslte_ra_dl_grant_fprint(stdout, &ue_dl.pdsch_cfg.grant); } - #endif +#endif + } - } - nof_trials++; - uint32_t nof_bits = ((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0)); - rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); - rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); - rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); - noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f); - enodebrate = SRSLTE_VEC_EMA(nof_bits/1000.0f, enodebrate, 0.05f); - uerate = SRSLTE_VEC_EMA(nof_bits/1000.0f, uerate, 0.001f); - float elapsed = (float) t[0].tv_usec + t[0].tv_sec*1.0e+6f; + uint32_t enb_bits = ((pdsch_cfg.grant.tb[0].enabled ? pdsch_cfg.grant.tb[0].tbs : 0) + + (pdsch_cfg.grant.tb[1].enabled ? pdsch_cfg.grant.tb[1].tbs : 0)); + uint32_t ue_bits = ((acks[0] ? pdsch_cfg.grant.tb[0].tbs : 0) + (acks[1] ? pdsch_cfg.grant.tb[1].tbs : 0)); + rsrq = SRSLTE_VEC_EMA(ue_dl.chest_res.rsrp_dbm, rsrq, 0.1f); + rsrp0 = SRSLTE_VEC_EMA(ue_dl.chest_res.rsrp_port_dbm[0], rsrp0, 0.05f); + rsrp1 = SRSLTE_VEC_EMA(ue_dl.chest_res.rsrp_port_dbm[1], rsrp1, 0.05f); + snr = SRSLTE_VEC_EMA(ue_dl.chest_res.snr_db, snr, 0.05f); + enodebrate = SRSLTE_VEC_EMA(enb_bits / 1000.0f, enodebrate, 0.05f); + uerate = SRSLTE_VEC_EMA(ue_bits / 1000.0f, uerate, 0.001f); + float elapsed = (float)t[0].tv_usec + t[0].tv_sec * 1.0e+6f; if (elapsed != 0.0f) { - procrate = SRSLTE_VEC_EMA(nof_bits/elapsed, procrate, 0.01f); + procrate = SRSLTE_VEC_EMA(ue_bits / elapsed, procrate, 0.01f); } - + nframes++; if (isnan(rsrq)) { - rsrq = 0; + rsrq = 0; } - if (isnan(noise)) { - noise = 0; + if (isnan(snr)) { + snr = 0; } if (isnan(rsrp0)) { - rsrp0 = 0; + rsrp0 = 0; } if (isnan(rsrp1)) { - rsrp1 = 0; + rsrp1 = 0; } } // Plot and Printf - if (sfidx == 5) { - float gain = prog_args.rf_gain; + if (sf_idx == 5) { + float gain = prog_args.rf_gain; if (gain < 0) { - gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); + gain = 10 * log10(srslte_agc_get_gain(&ue_sync.agc)); } - + /* Print transmission scheme */ - if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - PRINT_LINE(" Tx scheme: %s (codebook_idx=%d)", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type), - ue_dl.pdsch_cfg.codebook_idx); - } else { - PRINT_LINE(" Tx scheme: %s", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type)); - } /* Print basic Parameters */ - PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); - PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); PRINT_LINE(" CFO: %+7.2f Hz", srslte_ue_sync_get_cfo(&ue_sync)); - PRINT_LINE(" RSRP: %+5.1f dBm | %+5.1f dBm", 10 * log10(rsrp0)+30, 10 * log10(rsrp1)+30); - PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); - PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); - PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); - PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); - if(prog_args.mbsfn_area_id > -1){ - PRINT_LINE(" PMCH-BLER: %5.2f%%", (float) 100 * ue_dl.pmch_pkt_errors/ue_dl.pmch_pkts_total); + PRINT_LINE(" RSRP: %+5.1f dBm | %+5.1f dBm", rsrp0, rsrp1); + PRINT_LINE(" SNR: %+5.1f dB", snr); + PRINT_LINE(" TM: %d", last_decoded_tm + 1); + PRINT_LINE( + " Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); + PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float)nof_detected / nof_trials)); + PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float)100 * pkt_errors / pkt_total); + + if (prog_args.mbsfn_area_id > -1) { + PRINT_LINE(" PMCH-BLER: %5.2f%%", (float)100 * pkt_errors / pmch_pkt_total); } - PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx, - ue_dl.pdsch_cfg.grant.mcs[0].tbs); - PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx, - ue_dl.pdsch_cfg.grant.mcs[1].tbs); + + PRINT_LINE(" TB 0: mcs=%d; tbs=%d", pdsch_cfg.grant.tb[0].mcs_idx, pdsch_cfg.grant.tb[0].tbs); + PRINT_LINE(" TB 1: mcs=%d; tbs=%d", pdsch_cfg.grant.tb[1].mcs_idx, pdsch_cfg.grant.tb[1].tbs); /* MIMO: if tx and rx antennas are bigger than 1 */ if (cell.nof_ports > 1 && ue_dl.pdsch.nof_rx_antennas > 1) { + uint32_t ri = 0; + float cn = 0; /* Compute condition number */ - if (srslte_ue_dl_ri_select(&ue_dl, NULL, &cn)) { + if (srslte_ue_dl_select_ri(&ue_dl, &ri, &cn)) { /* Condition number calculation is not supported for the number of tx & rx antennas*/ PRINT_LINE(" κ: NA"); } else { /* Print condition number */ - PRINT_LINE(" κ: %.1f dB (Condition number, 0 dB => Best)", cn); - } - } - PRINT_LINE(""); - - /* Spatial multiplex only */ - if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - - /* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */ - if (!srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL)) { - for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) { - for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) { - sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.5f); - } - } - - /* Print Multiplex stats */ - PRINT_LINE("SINR (dB) Vs RI and PMI:"); - PRINT_LINE(" | RI | 1 | 2 |"); - PRINT_LINE(" -------+-------+-------+"); - PRINT_LINE(" P | 0 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0) ? '*' : ' ', - 10 * log10(sinr[1][0]), (ri == 2 && pmi == 0) ? '*' : ' '); - PRINT_LINE(" M | 1 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1) ? '*' : ' ', - 10 * log10(sinr[1][1]), (ri == 2 && pmi == 1) ? '*' : ' '); - PRINT_LINE(" I | 2 | %5.2f%c|-------+ ", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2) ? '*' : ' '); - PRINT_LINE(" | 3 | %5.2f%c| ", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3) ? '*' : ' '); - PRINT_LINE(""); + PRINT_LINE(" κ: %.1f dB, RI=%d (Condition number, 0 dB => Best)", cn, ri); } + PRINT_LINE(""); } PRINT_LINE("Press enter maximum printing debug log of 1 subframe."); PRINT_LINE(""); @@ -876,54 +928,49 @@ int main(int argc, char **argv) { } break; } - if (sfidx == 9) { - sfn++; + if (sf_idx == 9) { + sfn++; if (sfn == 1024) { - sfn = 0; + sfn = 0; PRINT_LINE_ADVANCE_CURSOR(); - ue_dl.pdsch_pkt_errors = 0; - ue_dl.pdsch_pkts_total = 0; - ue_dl.pmch_pkt_errors = 0; - ue_dl.pmch_pkts_total = 0; - /* - ue_dl.pkt_errors = 0; - ue_dl.pkts_total = 0; - ue_dl.nof_detected = 0; - nof_trials = 0; - */ - } + pkt_errors = 0; + pkt_total = 0; + pmch_pkt_errors = 0; + pmch_pkt_total = 0; + } } - - #ifndef DISABLE_GRAPHICS + +#ifdef ENABLE_GUI if (!prog_args.disable_plots) { - if ((sfn%3) == 0 && decode_pdsch) { - plot_sf_idx = srslte_ue_sync_get_sfidx(&ue_sync); - plot_track = true; + if ((sfn % 3) == 0 && decode_pdsch) { + plot_sf_idx = sf_idx; + plot_track = true; sem_post(&plot_sem); } } - #endif +#endif /* ENABLE_GUI */ } else if (ret == 0) { - printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", - srslte_sync_get_peak_value(&ue_sync.sfind), - ue_sync.frame_total_cnt, ue_sync.state); - #ifndef DISABLE_GRAPHICS + printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", + srslte_sync_get_peak_value(&ue_sync.sfind), + ue_sync.frame_total_cnt, + ue_sync.state); +#ifdef ENABLE_GUI if (!prog_args.disable_plots) { plot_sf_idx = srslte_ue_sync_get_sfidx(&ue_sync); - plot_track = false; - sem_post(&plot_sem); + plot_track = false; + sem_post(&plot_sem); } - #endif +#endif /* ENABLE_GUI */ } - - sf_cnt++; + + sf_cnt++; } // Main loop - -#ifndef DISABLE_GRAPHICS + +#ifdef ENABLE_GUI if (!prog_args.disable_plots) { if (!pthread_kill(plot_thread, 0)) { pthread_kill(plot_thread, SIGHUP); - pthread_join(plot_thread, NULL); + pthread_join(plot_thread, NULL); } } #endif @@ -943,63 +990,53 @@ int main(int argc, char **argv) { #ifndef DISABLE_RF if (!prog_args.input_file_name) { srslte_ue_mib_free(&ue_mib); - srslte_rf_close(&rf); + srslte_rf_close(&rf); } #endif - + printf("\nBye\n"); exit(0); } - - - - - - - /********************************************************************** * Plotting Functions ***********************************************************************/ -#ifndef DISABLE_GRAPHICS - +#ifdef ENABLE_GUI plot_real_t p_sync, pce; -plot_scatter_t pscatequal, pscatequal_pdcch, pscatequal_pmch; +plot_scatter_t pscatequal, pscatequal_pdcch, pscatequal_pmch; -float tmp_plot[110*15*2048]; -float tmp_plot2[110*15*2048]; -float tmp_plot3[110*15*2048]; +float tmp_plot[110 * 15 * 2048]; +float tmp_plot2[110 * 15 * 2048]; +float tmp_plot3[110 * 15 * 2048]; void *plot_thread_run(void *arg) { - int i; + int i; uint32_t nof_re = SRSLTE_SF_LEN_RE(ue_dl.cell.nof_prb, ue_dl.cell.cp); - - + sdrgui_init(); - + plot_scatter_init(&pscatequal); plot_scatter_setTitle(&pscatequal, "PDSCH - Equalized Symbols"); plot_scatter_setXAxisScale(&pscatequal, -4, 4); plot_scatter_setYAxisScale(&pscatequal, -4, 4); plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0); - - - if(enable_mbsfn_plot) { + + if (enable_mbsfn_plot) { plot_scatter_init(&pscatequal_pmch); plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols"); plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4); plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4); plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1); } - + if (!prog_args.disable_plots_except_constellation) { plot_real_init(&pce); plot_real_setTitle(&pce, "Channel Response - Magnitude"); plot_real_setLabels(&pce, "Index", "dB"); plot_real_setYAxisScale(&pce, -40, 40); - + plot_real_init(&p_sync); plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value"); plot_real_setYAxisScale(&p_sync, 0, 1); @@ -1009,92 +1046,90 @@ void *plot_thread_run(void *arg) { plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4); plot_scatter_setYAxisScale(&pscatequal_pdcch, -4, 4); - plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, (enable_mbsfn_plot)?2:1); + plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, (enable_mbsfn_plot) ? 2 : 1); plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0); plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1); } - - while(1) { + + while (1) { sem_wait(&plot_sem); - - uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re; - uint32_t nof_symbols_pmch = ue_dl.pmch_cfg.nbits[0].nof_re; - if (!prog_args.disable_plots_except_constellation) { + + uint32_t nof_symbols = pdsch_cfg.grant.nof_re; + if (!prog_args.disable_plots_except_constellation) { for (i = 0; i < nof_re; i++) { - tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i])); + tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[0][i])); if (isinf(tmp_plot[i])) { tmp_plot[i] = -80; } } int sz = srslte_symbol_sz(ue_dl.cell.nof_prb); - bzero(tmp_plot2, sizeof(float)*sz); - int g = (sz - 12*ue_dl.cell.nof_prb)/2; - for (i = 0; i < 12*ue_dl.cell.nof_prb; i++) { - tmp_plot2[g+i] = 20 * log10(cabs(ue_dl.ce[0][i])); - if (isinf(tmp_plot2[g+i])) { - tmp_plot2[g+i] = -80; + bzero(tmp_plot2, sizeof(float) * sz); + int g = (sz - 12 * ue_dl.cell.nof_prb) / 2; + for (i = 0; i < 12 * ue_dl.cell.nof_prb; i++) { + tmp_plot2[g + i] = 20 * log10(cabs(ue_dl.chest_res.ce[0][0][i])); + if (isinf(tmp_plot2[g + i])) { + tmp_plot2[g + i] = -80; } } plot_real_setNewData(&pce, tmp_plot2, sz); - + if (!prog_args.input_file_name) { if (plot_track) { - srslte_pss_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); - int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1); - srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, - 1/pss_obj->conv_output_avg[max], - tmp_plot2, - pss_obj->frame_size+pss_obj->fft_size-1); - plot_real_setNewData(&p_sync, tmp_plot2, pss_obj->frame_size); + srslte_pss_t* pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); + int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size + pss_obj->fft_size - 1); + srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, + 1 / pss_obj->conv_output_avg[max], + tmp_plot2, + pss_obj->frame_size + pss_obj->fft_size - 1); + plot_real_setNewData(&p_sync, tmp_plot2, pss_obj->frame_size); } else { - int max = srslte_vec_max_fi(ue_sync.sfind.pss.conv_output_avg, ue_sync.sfind.pss.frame_size+ue_sync.sfind.pss.fft_size-1); - srslte_vec_sc_prod_fff(ue_sync.sfind.pss.conv_output_avg, - 1/ue_sync.sfind.pss.conv_output_avg[max], - tmp_plot2, - ue_sync.sfind.pss.frame_size+ue_sync.sfind.pss.fft_size-1); - plot_real_setNewData(&p_sync, tmp_plot2, ue_sync.sfind.pss.frame_size); + int max = srslte_vec_max_fi(ue_sync.sfind.pss.conv_output_avg, + ue_sync.sfind.pss.frame_size + ue_sync.sfind.pss.fft_size - 1); + srslte_vec_sc_prod_fff(ue_sync.sfind.pss.conv_output_avg, + 1 / ue_sync.sfind.pss.conv_output_avg[max], + tmp_plot2, + ue_sync.sfind.pss.frame_size + ue_sync.sfind.pss.fft_size - 1); + plot_real_setNewData(&p_sync, tmp_plot2, ue_sync.sfind.pss.frame_size); } - } - - plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36*ue_dl.pdcch.nof_cce[0]); + + plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36 * ue_dl.pdcch.nof_cce[0]); } - + plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols); - - if(enable_mbsfn_plot) { - plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch); + + if (enable_mbsfn_plot) { + plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols); } if (plot_sf_idx == 1) { if (prog_args.net_port_signal > 0) { - srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7], - srslte_ue_sync_sf_len(&ue_sync)); + srslte_netsink_write( + &net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync) / 7], srslte_ue_sync_sf_len(&ue_sync)); } } - } - return NULL; } -void init_plots() { +void init_plots() +{ if (sem_init(&plot_sem, 0, 0)) { perror("sem_init"); exit(-1); } - + pthread_attr_t attr; struct sched_param param; - param.sched_priority = 0; + param.sched_priority = 0; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_OTHER); pthread_attr_setschedparam(&attr, ¶m); if (pthread_create(&plot_thread, NULL, plot_thread_run, NULL)) { perror("pthread_create"); exit(-1); - } + } } -#endif +#endif /* ENABLE_GUI */ diff --git a/lib/examples/synch_file.c b/lib/examples/synch_file.c index c73e8d9dc..855106a2f 100644 --- a/lib/examples/synch_file.c +++ b/lib/examples/synch_file.c @@ -128,11 +128,11 @@ int main(int argc, char **argv) { printf("Initializing...");fflush(stdout); if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); + ERROR("Error opening file %s\n", input_file_name); exit(-1); } if (srslte_filesink_init(&fsink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", output_file_name); + ERROR("Error opening file %s\n", output_file_name); exit(-1); } @@ -153,7 +153,7 @@ int main(int argc, char **argv) { } if (srslte_cfo_init(&cfocorr, frame_length)) { - fprintf(stderr, "Error initiating CFO\n"); + ERROR("Error initiating CFO\n"); return -1; } @@ -164,19 +164,19 @@ int main(int argc, char **argv) { */ for (N_id_2=0;N_id_2<3;N_id_2++) { if (srslte_pss_init(&pss[N_id_2], frame_length)) { - fprintf(stderr, "Error initializing PSS object\n"); + ERROR("Error initializing PSS object\n"); exit(-1); } if (srslte_pss_set_N_id_2(&pss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); + ERROR("Error initializing N_id_2\n"); exit(-1); } if (srslte_sss_init(&sss[N_id_2], 128)) { - fprintf(stderr, "Error initializing SSS object\n"); + ERROR("Error initializing SSS object\n"); exit(-1); } if (srslte_sss_set_N_id_2(&sss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); + ERROR("Error initializing N_id_2\n"); exit(-1); } } diff --git a/lib/examples/usrp_capture.c b/lib/examples/usrp_capture.c index a0136e913..af150c4cf 100644 --- a/lib/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -125,7 +125,7 @@ int main(int argc, char **argv) { printf("Opening RF device...\n"); if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { - fprintf(stderr, "Error opening rf\n"); + ERROR("Error opening rf\n"); exit(-1); } srslte_rf_set_master_clock_rate(&rf, 30.72e6); @@ -135,7 +135,7 @@ int main(int argc, char **argv) { sigaddset(&sigset, SIGINT); sigprocmask(SIG_UNBLOCK, &sigset, NULL); - printf("Set RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, rf_freq) / 1000000); + printf("Set RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, nof_rx_antennas, rf_freq) / 1000000); printf("Set RX gain: %.2f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain)); float srate = srslte_rf_set_rx_srate(&rf, rf_rate); if (srate != rf_rate) { @@ -146,7 +146,7 @@ int main(int argc, char **argv) { } srate = srslte_rf_set_rx_srate(&rf, rf_rate); if (srate != rf_rate) { - fprintf(stderr, "Errror setting samplign frequency %.2f MHz\n", rf_rate*1e-6); + ERROR("Errror setting samplign frequency %.2f MHz\n", rf_rate * 1e-6); exit(-1); } } @@ -160,7 +160,7 @@ int main(int argc, char **argv) { && keep_running){ n = srslte_rf_recv_with_time_multi(&rf, (void**) buffer, buflen, true, NULL, NULL); if (n < 0) { - fprintf(stderr, "Error receiving samples\n"); + ERROR("Error receiving samples\n"); exit(-1); } diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index 424521e3a..68a372514 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -105,11 +105,11 @@ void parse_args(int argc, char **argv) { int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv_with_time_multi(h, (void**) data, nsamples, true, NULL, NULL); + return srslte_rf_recv_with_time_multi(h, (void**)data[0], nsamples, true, NULL, NULL); } int main(int argc, char **argv) { - cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL, NULL}; + cf_t* buffer[SRSLTE_MAX_PORTS] = {NULL}; int n; srslte_rf_t rf; srslte_filesink_t sink; @@ -124,12 +124,12 @@ int main(int argc, char **argv) { printf("Opening RF device...\n"); if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { - fprintf(stderr, "Error opening rf\n"); + ERROR("Error opening rf\n"); exit(-1); } - srslte_rf_set_master_clock_rate(&rf, 30.72e6); + srslte_rf_set_master_clock_rate(&rf, 30.72e6); - for (int i = 0; i< SRSLTE_MAX_PORTS; i++) { + for (int i = 0; i < nof_rx_antennas; i++) { buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); } @@ -138,7 +138,7 @@ int main(int argc, char **argv) { sigaddset(&sigset, SIGINT); sigprocmask(SIG_UNBLOCK, &sigset, NULL); - printf("Set RX freq: %.6f MHz\n", srslte_rf_set_rx_freq(&rf, rf_freq) / 1000000); + printf("Set RX freq: %.6f MHz\n", srslte_rf_set_rx_freq(&rf, nof_rx_antennas, rf_freq) / 1000000); printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain)); int srate = srslte_sampling_freq_hz(nof_prb); if (srate != -1) { @@ -150,11 +150,11 @@ int main(int argc, char **argv) { printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate); if (srate_rf != srate) { - fprintf(stderr, "Could not set sampling rate\n"); + ERROR("Could not set sampling rate\n"); exit(-1); } } else { - fprintf(stderr, "Invalid number of PRB %d\n", nof_prb); + ERROR("Invalid number of PRB %d\n", nof_prb); exit(-1); } srslte_rf_rx_wait_lo_locked(&rf); @@ -170,7 +170,7 @@ int main(int argc, char **argv) { exit(-1); } if (srslte_ue_sync_set_cell(&ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); + ERROR("Error initiating ue_sync\n"); exit(-1); } @@ -180,9 +180,9 @@ int main(int argc, char **argv) { while((subframe_count < nof_subframes || nof_subframes == -1) && !stop_capture) { - n = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer); + n = srslte_ue_sync_zerocopy(&ue_sync, buffer); if (n < 0) { - fprintf(stderr, "Error receiving samples\n"); + ERROR("Error receiving samples\n"); exit(-1); } if (n == 1) { @@ -207,7 +207,7 @@ int main(int argc, char **argv) { srslte_rf_close(&rf); srslte_ue_sync_free(&ue_sync); - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int i = 0; i < nof_rx_antennas; i++) { if (buffer[i]) { free(buffer[i]); } diff --git a/lib/examples/usrp_txrx.c b/lib/examples/usrp_txrx.c index 42f610d65..741bb6391 100644 --- a/lib/examples/usrp_txrx.c +++ b/lib/examples/usrp_txrx.c @@ -89,7 +89,7 @@ void parse_args(int argc, char **argv) { case 'p': nof_prb = atoi(argv[optind]); if (!srslte_nofprb_isvalid(nof_prb)) { - fprintf(stderr, "Invalid number of UL RB %d\n", nof_prb); + ERROR("Invalid number of UL RB %d\n", nof_prb); exit(-1); } break; @@ -139,7 +139,7 @@ int main(int argc, char **argv) { srslte_rf_t rf; printf("Opening RF device...\n"); if (srslte_rf_open(&rf, rf_args)) { - fprintf(stderr, "Error opening rf\n"); + ERROR("Error opening rf\n"); exit(-1); } srslte_rf_set_master_clock_rate(&rf, 30.72e6); @@ -159,9 +159,9 @@ int main(int argc, char **argv) { printf("Set TX/RX rate: %.2f MHz\n", (float) srate / 1000000); printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_rx_gain)); printf("Set TX gain: %.1f dB\n", srslte_rf_set_tx_gain(&rf, srslte_rf_tx_gain)); - printf("Set TX/RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, rf_freq) / 1000000); - srslte_rf_set_tx_freq(&rf, rf_freq); - + printf("Set TX/RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, 0, rf_freq) / 1000000); + srslte_rf_set_tx_freq(&rf, 0, rf_freq); + sleep(1); if (input_filename) { diff --git a/lib/include/srslte/common/bcd_helpers.h b/lib/include/srslte/common/bcd_helpers.h index 7adf585cc..b3ce9aa64 100644 --- a/lib/include/srslte/common/bcd_helpers.h +++ b/lib/include/srslte/common/bcd_helpers.h @@ -28,10 +28,11 @@ #define SRSLTE_BCD_HELPERS_H #include -#include #include #include +#include "srslte/asn1/rrc_asn1.h" + namespace srslte { /****************************************************************************** diff --git a/lib/include/srslte/common/block_queue.h b/lib/include/srslte/common/block_queue.h index 107c93272..dbcb80cb2 100644 --- a/lib/include/srslte/common/block_queue.h +++ b/lib/include/srslte/common/block_queue.h @@ -209,4 +209,4 @@ private: } -#endif // SRSLTE_BLOCK_QUEUE_H \ No newline at end of file +#endif // SRSLTE_BLOCK_QUEUE_H diff --git a/lib/include/srslte/common/bounded_bitset.h b/lib/include/srslte/common/bounded_bitset.h new file mode 100644 index 000000000..66d1065d0 --- /dev/null +++ b/lib/include/srslte/common/bounded_bitset.h @@ -0,0 +1,329 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSLTE_DYN_BITSET_H +#define SRSLTE_DYN_BITSET_H + +#include +#include + +#define CEILFRAC(x, y) ((((x)-1) / (y)) + 1) + +namespace srslte { + +template +class bounded_bitset +{ + typedef uint64_t word_t; + static const size_t bits_per_word = 8 * sizeof(word_t); + +public: + constexpr bounded_bitset() : buffer(), cur_size(0) {} + + constexpr bounded_bitset(size_t cur_size_) : buffer(), cur_size(cur_size_) {} + + constexpr size_t max_size() const noexcept { return N; } + + size_t size() const noexcept { return cur_size; } + + void resize(size_t new_size) noexcept + { + if (new_size > max_size()) { + printf("ERROR: bitset resize out of bounds: %lu>=%lu\n", max_size(), new_size); + return; + } + cur_size = new_size; + sanitize_(); + for (size_t i = nof_words_(); i < sizeof(buffer); ++i) { + get_word_(i) = static_cast(0); + } + } + + void set(size_t pos) noexcept + { + if (pos >= size()) { + printf("ERROR: bitset out of bounds: %lu>=%lu\n", pos, size()); + return; + } + pos = reversed ? size() - 1 - pos : pos; + get_word_(pos) |= maskbit(pos); + } + + void reset(size_t pos) noexcept + { + if (pos >= size()) { + printf("ERROR: bitset out of bounds: %lu>=%lu\n", pos, size()); + return; + } + pos = reversed ? size() - 1 - pos : pos; + get_word_(pos) &= ~(maskbit(pos)); + } + + void reset() noexcept + { + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] = static_cast(0); + } + } + + bool test(size_t pos) const noexcept + { + if (pos >= size()) { + printf("ERROR: bitset out of bounds: %lu>=%lu\n", pos, size()); + return false; + } + return test_(pos); + } + + bounded_bitset& flip() noexcept + { + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] = ~buffer[i]; + } + sanitize_(); + return *this; + } + + bounded_bitset& fill(size_t startpos, size_t endpos, bool value = true) noexcept + { + if (endpos > size() or startpos > endpos) { + printf("ERROR: bounds (%lu, %lu) are not valid for bitset of size: %lu\n", startpos, endpos, size()); + return *this; + } + // NOTE: can be optimized + if (value) { + for (size_t i = startpos; i < endpos; ++i) { + set(i); + } + } else { + for (size_t i = startpos; i < endpos; ++i) { + reset(i); + } + } + return *this; + } + + bool all() const noexcept + { + const size_t nw = nof_words_(); + if (nw == 0) { + return true; + } + word_t allset = ~static_cast(0); + for (size_t i = 0; i < nw - 1; i++) { + if (buffer[i] != allset) { + return false; + } + } + return buffer[nw - 1] == (allset >> (nw * bits_per_word - size())); + } + + bool any() const noexcept + { + for (size_t i = 0; i < nof_words_(); ++i) { + if (buffer[i] != static_cast(0)) { + return true; + } + } + return false; + } + + bool any(size_t start, size_t stop) const noexcept + { + if (start > stop or stop > size()) { + printf("ERROR: bounds (%lu, %lu) are not valid for bitset of size: %lu\n", start, stop, size()); + return false; + } + // NOTE: can be optimized + for (size_t i = start; i < stop; ++i) { + if (test_(i)) { + return true; + } + } + return false; + } + + bool none() const noexcept { return !any(); } + + size_t count() const noexcept + { + size_t result = 0; + for (size_t i = 0; i < nof_words_(); i++) { + // result += __builtin_popcountl(buffer[i]); + word_t w = buffer[i]; + for (; w; w >>= 1) { + result += (w & 1); + } + } + return result; + } + + bool operator==(bounded_bitset& other) const noexcept + { + if (size() != other.size()) { + return false; + } + for (uint32_t i = 0; i < nof_words_(); ++i) { + if (buffer[i] != other.buffer[i]) + return false; + } + return true; + } + + bool operator!=(bounded_bitset& other) const noexcept { return not(*this == other); } + + bounded_bitset& operator|=(const bounded_bitset& other) noexcept + { + if (other.size() != size()) { + printf("ERROR: operator|= called for bitsets of different sizes (%lu!=%lu)\n", size(), other.size()); + return *this; + } + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] |= other.buffer[i]; + } + return *this; + } + + bounded_bitset& operator&=(const bounded_bitset& other) noexcept + { + if (other.size() != size()) { + printf("ERROR: operator&= called for bitsets of different sizes (%lu!=%lu)\n", size(), other.size()); + return *this; + } + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] &= other.buffer[i]; + } + return *this; + } + + bounded_bitset operator~() const noexcept + { + bounded_bitset ret(*this); + ret.flip(); + return ret; + } + + std::string to_string() const noexcept + { + std::string s; + s.assign(size(), '0'); + if (not reversed) { + for (size_t i = size(); i > 0; --i) { + if (test(i - 1)) { + s[size() - i] = '1'; + } + } + } else { + for (size_t i = 0; i < size(); ++i) { + if (test(i)) { + s[i] = '1'; + } + } + } + return s; + } + + uint64_t to_uint64() const noexcept + { + if (nof_words_() > 1) { + printf("ERROR: cannot convert bitset of size %lu bits to uint64_t\n", size()); + return 0; + } + return get_word_(0); + } + + std::string to_hex() const noexcept + { + size_t nof_digits = (size() - 1) / 4 + 1; + char cstr[CEILFRAC(CEILFRAC(N, bits_per_word) * bits_per_word, 4) + 1]; + size_t count = 0; + + for (int i = nof_words_() - 1; i >= 0; --i) { + count += sprintf(&cstr[count], "%016lx", buffer[i]); + } + + size_t skip = nof_words_() * bits_per_word / 4 - nof_digits; + // printf("bitstring: %s\n", to_string().c_str()); + return std::string(&cstr[skip], &cstr[nof_digits + skip + 1]); + } + +private: + word_t buffer[(N - 1) / bits_per_word + 1]; + size_t cur_size; + + void sanitize_() + { + if (N % bits_per_word != 0) { + buffer[nof_words_() - 1] &= ~((~static_cast(0)) << (size() % bits_per_word)); + } + } + + bool test_(size_t pos) const noexcept + { + pos = reversed ? size() - 1 - pos : pos; + return ((get_word_(pos) & maskbit(pos)) != static_cast(0)); + } + + size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; } + + word_t& get_word_(size_t pos) noexcept { return buffer[pos / bits_per_word]; } + + const word_t& get_word_(size_t pos) const { return buffer[pos / bits_per_word]; } + + size_t word_idx_(size_t pos) const { return pos / bits_per_word; } + + static word_t maskbit(size_t pos) { return (static_cast(1)) << (pos % bits_per_word); } +}; + +template +inline bounded_bitset operator&(const bounded_bitset& lhs, + const bounded_bitset& rhs)noexcept +{ + bounded_bitset res(lhs); + res &= rhs; + return res; +} + +template +inline bounded_bitset operator|(const bounded_bitset& lhs, + const bounded_bitset& rhs) noexcept +{ + bounded_bitset res(lhs); + res |= rhs; + return res; +} + +template +inline bounded_bitset fliplr(const bounded_bitset& other) noexcept +{ + bounded_bitset ret(other.size()); + ret.reset(); + for (uint32_t i = 0; i < ret.size(); ++i) { + if (other.test(i)) { + ret.set(ret.size() - 1 - i); + } + } + return ret; +} + +} // namespace srslte + +#endif // SRSLTE_DYN_BITSET_H diff --git a/lib/include/srslte/common/common.h b/lib/include/srslte/common/common.h index be6b4a56e..383bcdb23 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -46,18 +46,24 @@ #define SRSLTE_N_MCH_LCIDS 32 -#define HARQ_DELAY_MS 4 -#define MSG3_DELAY_MS 2 // Delay added to HARQ_DELAY_MS -#define TTI_RX(tti) (tti>HARQ_DELAY_MS?((tti-HARQ_DELAY_MS)%10240):(10240+tti-HARQ_DELAY_MS)) -#define TTI_TX(tti) ((tti+HARQ_DELAY_MS)%10240) -#define TTI_RX_ACK(tti) ((tti+(2*HARQ_DELAY_MS))%10240) +#define TX_DELAY 4 +#define MSG3_DELAY_MS 2 // Delay added to TX_DELAY -#define UL_PIDOF(tti) (tti%(2*HARQ_DELAY_MS)) +#define TTI_SUB(a, b) ((((a) + 10240) - (b)) % 10240) -#define TTIMOD_SZ (((2*HARQ_DELAY_MS) < 10)?10:20) +#define TTI_TX(tti) ((tti + TX_DELAY) % 10240) + +// Use only in FDD mode!! +#define FDD_HARQ_DELAY_MS 4 +#define TTI_RX(tti) (TTI_SUB(tti, FDD_HARQ_DELAY_MS)) +#define TTI_RX_ACK(tti) ((tti + (2 * FDD_HARQ_DELAY_MS)) % 10240) + +#define TTIMOD_SZ 20 #define TTIMOD(tti) (tti%TTIMOD_SZ) -#define ASYNC_DL_SCHED (HARQ_DELAY_MS <= 4) +#define PHICH_MAX_SF 6 // Maximum PHICH in a subframe (1 in FDD, > 1 in TDD, see table 9.1.2-1 36.213) + +#define ASYNC_DL_SCHED (FDD_HARQ_DELAY_MS <= 4) // Cat 4 UE - Max number of DL-SCH transport block bits received within a TTI // 3GPP 36.306 Table 4.1.1 @@ -76,8 +82,6 @@ #define pool_allocate_blocking (pool->allocate(NULL, true)) #endif -#define ZERO_OBJECT(x) memset(&(x), 0x0, sizeof((x))) - #include "srslte/srslte.h" /******************************************************************************* diff --git a/lib/include/srslte/common/liblte_ssl.h b/lib/include/srslte/common/liblte_ssl.h index 2ac4e794f..a28e25bcd 100644 --- a/lib/include/srslte/common/liblte_ssl.h +++ b/lib/include/srslte/common/liblte_ssl.h @@ -1,3 +1,24 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + #ifndef SRSLTE_LIBLTE_SSL_H #define SRSLTE_LIBLTE_SSL_H diff --git a/lib/include/srslte/common/log_filter.h b/lib/include/srslte/common/log_filter.h index e0dbf4b5b..87e59bb68 100644 --- a/lib/include/srslte/common/log_filter.h +++ b/lib/include/srslte/common/log_filter.h @@ -81,7 +81,7 @@ public: void set_time_src(time_itf *source, time_format_t format); -private: +protected: logger *logger_h; bool do_tti; diff --git a/lib/include/srslte/common/metrics_hub.h b/lib/include/srslte/common/metrics_hub.h index eda6d0991..231425935 100644 --- a/lib/include/srslte/common/metrics_hub.h +++ b/lib/include/srslte/common/metrics_hub.h @@ -1,3 +1,23 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ /****************************************************************************** * File: metrics_hub.h diff --git a/lib/include/srslte/common/nas_pcap.h b/lib/include/srslte/common/nas_pcap.h index 061ba5010..3eaf01afc 100644 --- a/lib/include/srslte/common/nas_pcap.h +++ b/lib/include/srslte/common/nas_pcap.h @@ -1,3 +1,24 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + #ifndef SRSLTE_NAS_PCAP_H #define SRSLTE_NAS_PCAP_H diff --git a/lib/include/srslte/common/pdu.h b/lib/include/srslte/common/pdu.h index 848db29e8..742519e81 100644 --- a/lib/include/srslte/common/pdu.h +++ b/lib/include/srslte/common/pdu.h @@ -223,20 +223,30 @@ public: } virtual ~sch_subh(){} - + + /* 3GPP 36.321 (R.10) Combined Tables 6.2.1-1, 6.2.1-2, 6.2.1-4 */ typedef enum { - PHR_REPORT = 26, - CRNTI = 27, - CON_RES_ID = 28, - MTCH_MAX_LCID = 28, - TRUNC_BSR = 28, - TA_CMD = 29, - SHORT_BSR = 29, - DRX_CMD = 30, - LONG_BSR = 30, - MCH_SCHED_INFO = 30, - PADDING = 31, - SDU = 0 + /* Values of LCID for DL-SCH */ + SCELL_ACTIVATION = 0b11011, + CON_RES_ID = 0b11100, + TA_CMD = 0b11101, + DRX_CMD = 0b11110, + + /* Values of LCID for UL-SCH */ + PHR_REPORT_EXT = 0b11001, + PHR_REPORT = 0b11010, + CRNTI = 0b11011, + TRUNC_BSR = 0b11100, + SHORT_BSR = 0b11101, + LONG_BSR = 0b11110, + + /* Values of LCID for MCH */ + MTCH_MAX_LCID = 0b11100, + MCH_SCHED_INFO = 0b11110, + + /* Common */ + PADDING = 0b11111, + SDU = 0b00000 } cetype; // Size of MAC CEs @@ -260,6 +270,7 @@ public: uint16_t get_c_rnti(); uint64_t get_con_res_id(); uint8_t get_ta_cmd(); + uint8_t get_activation_deactivation_cmd(); float get_phr(); int get_bsr(uint32_t buff_size[4]); diff --git a/lib/include/srslte/common/pdu_queue.h b/lib/include/srslte/common/pdu_queue.h index 5866ce3b3..bda5adc9b 100644 --- a/lib/include/srslte/common/pdu_queue.h +++ b/lib/include/srslte/common/pdu_queue.h @@ -49,7 +49,7 @@ public: class process_callback { public: - virtual void process_pdu(uint8_t *buff, uint32_t len, channel_t channel, uint32_t tstamp) = 0; + virtual void process_pdu(uint8_t* buff, uint32_t len, channel_t channel) = 0; }; pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {} @@ -57,7 +57,7 @@ public: uint8_t* request(uint32_t len); void deallocate(uint8_t* pdu); - void push(uint8_t *ptr, uint32_t len, channel_t channel = DCH, uint32_t tstamp = 0); + void push(uint8_t* ptr, uint32_t len, channel_t channel = DCH); bool process_pdus(); @@ -68,7 +68,6 @@ private: typedef struct { uint8_t ptr[MAX_PDU_LEN]; uint32_t len; - uint32_t tstamp; channel_t channel; #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED char debug_name[128]; diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index 046dae3e1..bfb038158 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -40,6 +40,8 @@ #include #include +#include "srslte/srslte.h" + namespace srslte { class timer_callback @@ -143,12 +145,12 @@ public: used_timers[i] = false; nof_used_timers--; } else { - fprintf(stderr, "Error releasing timer id=%d: nof_used_timers=%d, nof_timers=%d\n", i, nof_used_timers, nof_timers); + ERROR("Error releasing timer id=%d: nof_used_timers=%d, nof_timers=%d\n", i, nof_used_timers, nof_timers); } } uint32_t get_unique_id() { if (nof_used_timers >= nof_timers) { - fprintf(stderr, "Error getting unique timer id: no more timers available\n"); + ERROR("Error getting unique timer id: no more timers available\n"); return 0; } else { for (uint32_t i=0;i PHY */ @@ -109,7 +130,6 @@ public: virtual void configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch) = 0; - virtual void set_conf_dedicated_ack(uint16_t rnti, bool rrc_completed) = 0; virtual void set_config_dedicated(uint16_t rnti, asn1::rrc::phys_cfg_ded_s* dedicated) = 0; }; diff --git a/lib/include/srslte/interfaces/epc_interfaces.h b/lib/include/srslte/interfaces/epc_interfaces.h index 26341a198..84f31cd88 100644 --- a/lib/include/srslte/interfaces/epc_interfaces.h +++ b/lib/include/srslte/interfaces/epc_interfaces.h @@ -18,6 +18,7 @@ * and at http://www.gnu.org/licenses/. * */ + #ifndef SRSLTE_EPC_INTERFACES_H #define SRSLTE_EPC_INTERFACES_H @@ -37,7 +38,7 @@ enum nas_timer_type { /****************** * MME Interfaces * ******************/ -class gtpc_interface_nas // NAS -> GTP-C +class gtpc_interface_nas // NAS -> GTP-C { public: virtual bool send_create_session_request(uint64_t imsi) = 0; @@ -98,7 +99,7 @@ public: /******************* * SPGW Interfaces * *******************/ -class gtpu_interface_gtpc //GTP-C -> GTP-U +class gtpu_interface_gtpc // GTP-C -> GTP-U { public: virtual in_addr_t get_s1u_addr() = 0; diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index 5cd8f5f4d..12318f81c 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -24,6 +24,7 @@ * */ +#include "srslte/common/common.h" #include "srslte/srslte.h" #ifndef SRSLTE_SCHED_INTERFACE_H @@ -103,26 +104,18 @@ public: } ue_bearer_cfg_t; typedef struct { - - bool continuous_pusch; - + /* ue capabilities, etc */ - - uint32_t maxharq_tx; + + uint32_t maxharq_tx; + bool continuous_pusch; + + srslte_uci_offset_cfg_t uci_offset; + srslte_pucch_cfg_t pucch_cfg; + uint32_t aperiodic_cqi_period; // if 0 is periodic CQI - uint32_t beta_ack_index; - uint32_t beta_ri_index; - uint32_t beta_cqi_index; - - srslte_pucch_cfg_t pucch_cfg; - uint32_t n_pucch_cqi; - uint32_t sr_I; - uint32_t sr_N_pucch; - bool sr_enabled; - uint32_t cqi_pucch; - uint32_t cqi_idx; - bool cqi_enabled; - + srslte_dl_cfg_t dl_cfg; + ue_bearer_cfg_t ue_bearers[MAX_LC]; } ue_cfg_t; @@ -134,10 +127,10 @@ public: typedef struct { - uint32_t lcid; - uint32_t lcid_buffer_size; - uint32_t stop; - uint8_t *mtch_payload; + uint32_t lcid; + uint32_t lcid_buffer_size; + uint32_t stop; + uint8_t* mtch_payload; } dl_mtch_sched_t; typedef struct { @@ -149,10 +142,7 @@ public: } dl_pdu_mch_t; typedef struct { - uint32_t rnti; - srslte_dci_format_t dci_format; - srslte_ra_dl_dci_t dci; - srslte_dci_location_t dci_location; + srslte_dci_dl_t dci; uint32_t tbs[SRSLTE_MAX_TB]; bool mac_ce_ta; bool mac_ce_rnti; @@ -161,12 +151,10 @@ public: } dl_sched_data_t; typedef struct { - uint32_t rnti; - bool needs_pdcch; - uint32_t current_tx_nb; - uint32_t tbs; - srslte_ra_ul_dci_t dci; - srslte_dci_location_t dci_location; + bool needs_pdcch; + uint32_t current_tx_nb; + uint32_t tbs; + srslte_dci_ul_t dci; } ul_sched_data_t; typedef struct { @@ -175,17 +163,14 @@ public: } dl_sched_rar_grant_t; typedef struct { - uint32_t rarnti; - uint32_t tbs; - srslte_ra_dl_dci_t dci; - srslte_dci_location_t dci_location; - uint32_t nof_grants; - dl_sched_rar_grant_t grants[MAX_RAR_LIST]; + uint32_t tbs; + srslte_dci_dl_t dci; + uint32_t nof_grants; + dl_sched_rar_grant_t msg3_grant[MAX_RAR_LIST]; } dl_sched_rar_t; typedef struct { - srslte_ra_dl_dci_t dci; - srslte_dci_location_t dci_location; + srslte_dci_dl_t dci; enum bc_type { BCCH, PCCH diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 02cb25e90..0f1fce236 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -345,9 +345,6 @@ public: /* MUX calls BSR to let it generate a padding BSR if there is space in PDU */ virtual bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) = 0; - - /* MAX calls BSR to set the Tx TTI */ - virtual void set_tx_tti(uint32_t tti) = 0; }; @@ -359,91 +356,82 @@ class mac_interface_phy { public: typedef struct { - uint32_t nof_mbsfn_services; - } mac_phy_cfg_mbsfn_t; - - - + uint32_t nof_mbsfn_services; + } mac_phy_cfg_mbsfn_t; + typedef struct { - uint32_t pid; - uint32_t tti; - uint32_t last_tti; - bool ndi[SRSLTE_MAX_CODEWORDS]; - bool last_ndi[SRSLTE_MAX_CODEWORDS]; - uint32_t n_bytes[SRSLTE_MAX_CODEWORDS]; - int rv[SRSLTE_MAX_CODEWORDS]; - bool tb_en[SRSLTE_MAX_CODEWORDS]; - bool tb_cw_swap; - uint16_t rnti; - bool is_from_rar; - bool is_sps_release; - bool has_cqi_request; - srslte_rnti_type_t rnti_type; - srslte_phy_grant_t phy_grant; - } mac_grant_t; - + uint32_t tbs; + bool ndi; + bool ndi_present; + int rv; + } mac_tb_t; + + typedef struct { + mac_tb_t tb[SRSLTE_MAX_TB]; + uint32_t pid; + uint16_t rnti; + bool is_sps_release; + } mac_grant_dl_t; + typedef struct { - bool decode_enabled[SRSLTE_MAX_TB]; - int rv[SRSLTE_MAX_TB]; - uint16_t rnti; - bool generate_ack; - bool default_ack[SRSLTE_MAX_TB]; - // If non-null, called after tb_decoded_ok to determine if ack needs to be sent - bool (*generate_ack_callback)(void*); - void *generate_ack_callback_arg; - uint8_t *payload_ptr[SRSLTE_MAX_TB]; - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB]; - srslte_phy_grant_t phy_grant; + mac_tb_t tb; + uint32_t pid; + uint16_t rnti; + bool phich_available; + bool hi_value; + } mac_grant_ul_t; + + typedef struct { + bool enabled; + uint32_t rv; + uint8_t* payload; + union { + srslte_softbuffer_rx_t* rx; + srslte_softbuffer_tx_t* tx; + } softbuffer; + } tb_action_t; + + typedef struct { + tb_action_t tb[SRSLTE_MAX_TB]; + + bool generate_ack; } tb_action_dl_t; typedef struct { - bool tx_enabled; - bool expect_ack; - uint32_t rv[SRSLTE_MAX_TB]; - uint16_t rnti; + tb_action_t tb; uint32_t current_tx_nb; - int32_t tti_offset; // relative offset between grant and UL tx/HARQ rx - srslte_softbuffer_tx_t *softbuffers; - srslte_phy_grant_t phy_grant; - uint8_t *payload_ptr[SRSLTE_MAX_TB]; + bool expect_ack; } tb_action_ul_t; - - /* Indicate reception of UL grant. + + /* Query the MAC for the current RNTI to look for + */ + virtual uint16_t get_dl_sched_rnti(uint32_t tti) = 0; + virtual uint16_t get_ul_sched_rnti(uint32_t tti) = 0; + + /* Indicate reception of UL dci. * payload_ptr points to memory where MAC PDU must be written by MAC layer */ - virtual void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) = 0; + virtual void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, 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, bool ack, tb_action_ul_t *action) = 0; + /* Indicate reception of DL dci. */ + virtual void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) = 0; - /* Obtain action for a new MCH subframe. */ - virtual void new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action) = 0; + /* Indicate successful decoding of PDSCH AND PCH TB. */ + virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 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 successful decoding of PDSCH TB. */ - virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0; - /* Indicate successful decoding of BCH TB through PBCH */ virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0; - /* Indicate successful decoding of PCH TB through PDSCH */ - virtual void pch_decoded_ok(uint32_t len) = 0; - /* Indicate successful decoding of MCH TB through PMCH */ - virtual void mch_decoded_ok(uint32_t len) = 0; - + virtual void mch_decoded(uint32_t len, bool crc) = 0; + + /* Obtain action for a new MCH subframe. */ + virtual void new_mch_dl(srslte_pdsch_grant_t phy_grant, tb_action_dl_t* action) = 0; + /* Communicate the number of mbsfn services available */ virtual void set_mbsfn_config(uint32_t nof_mbsfn_services) = 0; - - /* Function called every start of a subframe (TTI). Warning, this function is called - * from a high priority thread and should terminate asap - */ - + /* Indicate new TTI */ + virtual void run_tti(const uint32_t tti) = 0; }; /* Interface RRC -> MAC shared between different RATs */ @@ -453,53 +441,200 @@ public: // Class to handle UE specific RNTIs between RRC and MAC typedef struct { uint16_t crnti; + uint16_t rar_rnti; uint16_t temp_rnti; uint16_t tpc_rnti; uint16_t sps_rnti; uint64_t contention_id; } ue_rnti_t; - typedef struct { + typedef struct ul_harq_cfg_t { uint32_t max_harq_msg3_tx; uint32_t max_harq_tx; - } ul_harq_params_t; + ul_harq_cfg_t() { reset(); } + void reset() + { + max_harq_msg3_tx = 5; + max_harq_tx = 5; + } + } ul_harq_cfg_t; }; /* Interface RRC -> MAC */ class mac_interface_rrc : public mac_interface_rrc_common { public: - - typedef struct { - asn1::rrc::mac_main_cfg_s main; - asn1::rrc::rach_cfg_common_s rach; - asn1::rrc::sched_request_cfg_c sr; - ul_harq_params_t ul_harq_params; - uint32_t prach_config_index; - } mac_cfg_t; + typedef struct bsr_cfg_t { + int periodic_timer; + int retx_timer; + bsr_cfg_t() { reset(); } + void reset() + { + periodic_timer = -1; + retx_timer = 2560; + } + } bsr_cfg_t; + + typedef struct phr_cfg_t { + bool enabled; + int periodic_timer; + int prohibit_timer; + int db_pathloss_change; + bool extended; + phr_cfg_t() { reset(); } + void reset() + { + enabled = false; + periodic_timer = -1; + prohibit_timer = -1; + db_pathloss_change = -1; + extended = false; + } + } phr_cfg_t; + + typedef struct sr_cfg_t { + bool enabled; + int dsr_transmax; + sr_cfg_t() { reset(); } + void reset() { enabled = false; } + } sr_cfg_t; + + typedef struct rach_cfg_t { + bool enabled; + uint32_t nof_preambles; + uint32_t nof_groupA_preambles; + int32_t messagePowerOffsetGroupB; + uint32_t messageSizeGroupA; + uint32_t responseWindowSize; + uint32_t powerRampingStep; + uint32_t preambleTransMax; + int32_t iniReceivedTargetPower; + uint32_t contentionResolutionTimer; + uint32_t new_ra_msg_len; + rach_cfg_t() { reset(); } + void reset() { enabled = false; } + } rach_cfg_t; + + class mac_cfg_t + { + public: + // Default constructor with default values as in 36.331 9.2.2 + mac_cfg_t() { time_alignment_timer = -1; } + + void set_defaults() + { + bsr_cfg.reset(); + phr_cfg.reset(); + sr_cfg.reset(); + rach_cfg.reset(); + harq_cfg.reset(); + time_alignment_timer = -1; + } + + // Called only if section is present + void set_sched_request_cfg(asn1::rrc::sched_request_cfg_c& cfg) + { + sr_cfg.enabled = cfg.type() == asn1::rrc::setup_e::setup; + if (sr_cfg.enabled) { + sr_cfg.dsr_transmax = cfg.setup().dsr_trans_max.to_number(); + } + } + + // MAC-MainConfig section is always present + void set_mac_main_cfg(asn1::rrc::mac_main_cfg_s& cfg) + { + // Update values only if each section is present + if (cfg.phr_cfg_present) { + phr_cfg.enabled = cfg.phr_cfg.type() == asn1::rrc::setup_e::setup; + if (phr_cfg.enabled) { + phr_cfg.prohibit_timer = cfg.phr_cfg.setup().prohibit_phr_timer.to_number(); + phr_cfg.periodic_timer = cfg.phr_cfg.setup().periodic_phr_timer.to_number(); + phr_cfg.db_pathloss_change = cfg.phr_cfg.setup().dl_pathloss_change.to_number(); + } + } + if (cfg.mac_main_cfg_v1020_present) { + typedef asn1::rrc::mac_main_cfg_s::mac_main_cfg_v1020_s_ mac_main_cfg_v1020_t; + mac_main_cfg_v1020_t* mac_main_cfg_v1020 = cfg.mac_main_cfg_v1020.get(); + phr_cfg.extended = mac_main_cfg_v1020->extended_phr_r10_present; + } + if (cfg.ul_sch_cfg_present) { + bsr_cfg.periodic_timer = cfg.ul_sch_cfg.periodic_bsr_timer.to_number(); + bsr_cfg.retx_timer = cfg.ul_sch_cfg.retx_bsr_timer.to_number(); + if (cfg.ul_sch_cfg.max_harq_tx_present) { + harq_cfg.max_harq_tx = cfg.ul_sch_cfg.max_harq_tx.to_number(); + } + } + // TimeAlignmentDedicated overwrites Common?? + time_alignment_timer = cfg.time_align_timer_ded.to_number(); + } + + // RACH-Common section is always present + void set_rach_cfg_common(asn1::rrc::rach_cfg_common_s& cfg) + { + + // Preamble info + rach_cfg.nof_preambles = cfg.preamb_info.nof_ra_preambs.to_number(); + if (cfg.preamb_info.preambs_group_a_cfg_present) { + rach_cfg.nof_groupA_preambles = cfg.preamb_info.preambs_group_a_cfg.size_of_ra_preambs_group_a.to_number(); + rach_cfg.messageSizeGroupA = cfg.preamb_info.preambs_group_a_cfg.msg_size_group_a.to_number(); + rach_cfg.messagePowerOffsetGroupB = cfg.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number(); + } else { + rach_cfg.nof_groupA_preambles = 0; + } + + // Power ramping + rach_cfg.powerRampingStep = cfg.pwr_ramp_params.pwr_ramp_step.to_number(); + rach_cfg.iniReceivedTargetPower = cfg.pwr_ramp_params.preamb_init_rx_target_pwr.to_number(); + + // Supervision info + rach_cfg.preambleTransMax = cfg.ra_supervision_info.preamb_trans_max.to_number(); + rach_cfg.responseWindowSize = cfg.ra_supervision_info.ra_resp_win_size.to_number(); + rach_cfg.contentionResolutionTimer = cfg.ra_supervision_info.mac_contention_resolution_timer.to_number(); + + // HARQ Msg3 + harq_cfg.max_harq_msg3_tx = cfg.max_harq_msg3_tx; + } + + void set_time_alignment(asn1::rrc::time_align_timer_e time_alignment_timer) + { + this->time_alignment_timer = time_alignment_timer.to_number(); + } + + bsr_cfg_t& get_bsr_cfg() { return bsr_cfg; } + phr_cfg_t& get_phr_cfg() { return phr_cfg; } + rach_cfg_t& get_rach_cfg() { return rach_cfg; } + sr_cfg_t& get_sr_cfg() { return sr_cfg; } + ul_harq_cfg_t& get_harq_cfg() { return harq_cfg; } + int get_time_alignment_timer() { return time_alignment_timer; } + + private: + bsr_cfg_t bsr_cfg; + phr_cfg_t phr_cfg; + sr_cfg_t sr_cfg; + rach_cfg_t rach_cfg; + ul_harq_cfg_t harq_cfg; + int time_alignment_timer; + }; - virtual void clear_rntis() = 0; + virtual void clear_rntis() = 0; /* Instructs the MAC to start receiving BCCH */ - virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; + virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; + virtual void bcch_stop_rx() = 0; /* Instructs the MAC to start receiving PCCH */ - virtual void pcch_start_rx() = 0; + virtual void pcch_start_rx() = 0; /* RRC 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 setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; /* Instructs the MAC to start receiving an MCH */ - virtual void mch_start_rx(uint32_t lcid) = 0; + virtual void mch_start_rx(uint32_t lcid) = 0; virtual uint32_t get_current_tti() = 0; - virtual void set_config(mac_cfg_t *mac_cfg) = 0; - virtual void set_config_main(asn1::rrc::mac_main_cfg_s* main_cfg) = 0; - virtual void set_config_rach(asn1::rrc::rach_cfg_common_s* rach_cfg, uint32_t prach_config_index) = 0; - virtual void set_config_sr(asn1::rrc::sched_request_cfg_c* sr_cfg) = 0; - virtual void get_config(mac_cfg_t *mac_cfg) = 0; - + virtual void set_config(mac_cfg_t& mac_cfg) = 0; + virtual void get_rntis(ue_rnti_t *rntis) = 0; virtual void set_contention_id(uint64_t uecri) = 0; virtual void set_ho_rnti(uint16_t crnti, uint16_t target_pci) = 0; @@ -517,21 +652,30 @@ public: * */ +typedef struct { + uint32_t radio_idx; + uint32_t channel_idx; +} carrier_map_t; + typedef struct { bool ul_pwr_ctrl_en; float prach_gain; int pdsch_max_its; - bool attach_enable_64qam; int nof_phy_threads; int worker_cpu_mask; int sync_cpu_affinity; - + + uint32_t ue_category; + uint32_t nof_carriers; + uint32_t nof_radios; uint32_t nof_rx_ant; - std::string equalizer_mode; - int cqi_max; - int cqi_fixed; - float snr_ema_coeff; + uint32_t nof_rf_channels; + carrier_map_t carrier_map[SRSLTE_MAX_CARRIERS]; + std::string equalizer_mode; + int cqi_max; + int cqi_fixed; + float snr_ema_coeff; std::string snr_estim_alg; bool cfo_is_doppler; bool cfo_integer_enabled; @@ -540,16 +684,17 @@ typedef struct { float cfo_ref_ema; float cfo_loop_bw_pss; float cfo_loop_bw_ref; - float cfo_loop_ref_min; - float cfo_loop_pss_tol; - float sfo_ema; - uint32_t sfo_correct_period; + float cfo_loop_ref_min; + float cfo_loop_pss_tol; + float sfo_ema; + uint32_t sfo_correct_period; uint32_t cfo_loop_pss_conv; - uint32_t cfo_ref_mask; - bool average_subframe_enabled; + uint32_t cfo_ref_mask; + bool interpolate_subframe_enabled; bool estimator_fil_auto; - float estimator_fil_stddev; - uint32_t estimator_fil_order; + float estimator_fil_stddev; + uint32_t estimator_fil_order; + float snr_to_cqi_offset; std::string sss_algorithm; bool rssi_sensor_enabled; bool sic_pss_enabled; @@ -565,7 +710,6 @@ typedef struct { class phy_interface_mac_common { public: - /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ virtual void set_crnti(uint16_t rnti) = 0; @@ -573,8 +717,11 @@ public: 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; + /* Activate / Disactivate SCell*/ + virtual void set_activation_deactivation_scell(uint32_t cmd) = 0; + + /* Sets RAR dci payload */ + virtual void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) = 0; virtual uint32_t get_current_tti() = 0; @@ -586,24 +733,24 @@ public: class phy_interface_mac : public phy_interface_mac_common { public: - + typedef struct { + bool is_transmitted; + uint32_t tti_ra; + uint32_t f_id; + uint32_t preamble_format; + } prach_info_t; + /* Configure PRACH using parameters written by RRC */ virtual void configure_prach_params() = 0; - virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0; - virtual int prach_tx_tti() = 0; + virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) = 0; + virtual prach_info_t prach_get_info() = 0; + /* Indicates the transmission of a SR signal in the next opportunity */ virtual void sr_send() = 0; virtual int sr_last_tx_tti() = 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 void pdcch_ul_search_reset() = 0; - virtual void pdcch_dl_search_reset() = 0; - virtual void set_mch_period_stop(uint32_t stop) = 0; - }; class phy_interface_rrc @@ -632,19 +779,15 @@ public: asn1::rrc::phys_cfg_ded_s dedicated; phy_cfg_common_t common; phy_cfg_mbsfn_t mbsfn; - bool enable_64qam; - } phy_cfg_t; + } phy_cfg_t; virtual void get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn = NULL) = 0; virtual uint32_t get_current_earfcn() = 0; virtual uint32_t get_current_pci() = 0; - virtual void get_config(phy_cfg_t *phy_cfg) = 0; - virtual void set_config(phy_cfg_t *phy_cfg) = 0; - virtual void set_config_dedicated(asn1::rrc::phys_cfg_ded_s* dedicated) = 0; - virtual void set_config_common(phy_cfg_common_t *common) = 0; + virtual void set_config(phy_cfg_t* config) = 0; + virtual void set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config) = 0; virtual void set_config_tdd(asn1::rrc::tdd_cfg_s* tdd) = 0; - virtual void set_config_64qam_en(bool enable) = 0; virtual void set_config_mbsfn_sib2(asn1::rrc::sib_type2_s* sib2) = 0; virtual void set_config_mbsfn_sib13(asn1::rrc::sib_type13_r9_s* sib13) = 0; virtual void set_config_mbsfn_mcch(asn1::rrc::mcch_msg_s* mcch) = 0; @@ -656,7 +799,7 @@ public: typedef struct { enum {CELL_FOUND = 0, CELL_NOT_FOUND, ERROR} found; - enum {MORE_FREQS = 0, NO_MORE_FREQS} last_freq; + enum { MORE_FREQS = 0, NO_MORE_FREQS } last_freq; } cell_search_ret_t; typedef struct { @@ -669,9 +812,6 @@ public: virtual bool cell_select(phy_cell_t *cell = NULL) = 0; virtual bool cell_is_camping() = 0; - /* Configure UL using parameters written with set_param() */ - virtual void configure_ul_params(bool pregen_disabled = false) = 0; - virtual void reset() = 0; }; diff --git a/lib/include/srslte/phy/ch_estimation/chest_common.h b/lib/include/srslte/phy/ch_estimation/chest_common.h index 276d9c55e..60a593fcc 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_common.h +++ b/lib/include/srslte/phy/ch_estimation/chest_common.h @@ -30,26 +30,23 @@ #include #include "srslte/config.h" -#define SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN 65 +#define SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN 64 +typedef enum SRSLTE_API { + SRSLTE_CHEST_FILTER_GAUSS = 0, + SRSLTE_CHEST_FILTER_TRIANGLE, + SRSLTE_CHEST_FILTER_NONE +} srslte_chest_filter_t; -SRSLTE_API void srslte_chest_average_pilots(cf_t *input, - cf_t *output, - float *filter, - uint32_t nof_ref, - uint32_t nof_symbols, - uint32_t filter_len); +SRSLTE_API void srslte_chest_average_pilots( + cf_t* input, cf_t* output, float* filter, uint32_t nof_ref, uint32_t nof_symbols, uint32_t filter_len); -SRSLTE_API void srslte_chest_set_smooth_filter3_coeff(float *smooth_filter, - float w); +SRSLTE_API uint32_t srslte_chest_set_smooth_filter3_coeff(float* smooth_filter, float w); -SRSLTE_API float srslte_chest_estimate_noise_pilots(cf_t *noisy, - cf_t *noiseless, - cf_t *noise_vec, - uint32_t nof_pilots); +SRSLTE_API float srslte_chest_estimate_noise_pilots(cf_t* noisy, cf_t* noiseless, cf_t* noise_vec, uint32_t nof_pilots); -SRSLTE_API void srslte_chest_set_triangle_filter(float *fil, - int filter_len); +SRSLTE_API uint32_t srslte_chest_set_triangle_filter(float* fil, int filter_len); -#endif // SRSLTE_CHEST_COMMON_H +SRSLTE_API uint32_t srslte_chest_set_smooth_filter_gauss(float* filter, uint32_t order, float std_dev); +#endif // SRSLTE_CHEST_COMMON_H diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index 653ee0075..7c25fa97b 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -51,18 +51,34 @@ #include "srslte/phy/common/phy_common.h" #include "srslte/phy/sync/pss.h" - -typedef enum { - SRSLTE_NOISE_ALG_REFS, - SRSLTE_NOISE_ALG_PSS, +typedef struct SRSLTE_API { + cf_t* ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + uint32_t nof_re; + float noise_estimate; + float noise_estimate_dbm; + float snr_db; + float rsrp; + float rsrp_dbm; + float rsrp_neigh_dbm; + float rsrp_port_dbm[SRSLTE_MAX_PORTS]; + float rsrq; + float rsrq_db; + float rssi_dbm; + float cfo; +} srslte_chest_dl_res_t; + +typedef enum SRSLTE_API { + SRSLTE_NOISE_ALG_REFS = 0, + SRSLTE_NOISE_ALG_PSS, SRSLTE_NOISE_ALG_EMPTY, -} srslte_chest_dl_noise_alg_t; +} srslte_chest_dl_noise_alg_t; + +typedef struct SRSLTE_API { + srslte_cell_t cell; + uint32_t nof_rx_antennas; -typedef struct { - srslte_cell_t cell; srslte_refsignal_t csr_refs; srslte_refsignal_t **mbsfn_refs; - cf_t *pilot_estimates; cf_t *pilot_estimates_average; @@ -74,131 +90,72 @@ typedef struct { float snr_vector[12000]; float pilot_power[12000]; #endif - bool smooth_filter_auto; - uint32_t smooth_filter_len; - float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN]; srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_lin_t srslte_interp_lin; srslte_interp_lin_t srslte_interp_lin_3; srslte_interp_lin_t srslte_interp_lin_mbsfn; + float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp_corr[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float cfo; - bool rsrp_neighbour; - - bool cfo_estimate_enable; - uint32_t cfo_estimate_sf_mask; - /* Use PSS for noise estimation in LS linear interpolation mode */ cf_t pss_signal[SRSLTE_PSS_LEN]; cf_t tmp_pss[SRSLTE_PSS_LEN]; cf_t tmp_pss_noisy[SRSLTE_PSS_LEN]; - srslte_chest_dl_noise_alg_t noise_alg; - int last_nof_antennas; - - bool average_subframe; } srslte_chest_dl_t; +typedef struct SRSLTE_API { -SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t *q, - uint32_t max_prb); - -SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q); - - -SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, - uint16_t mbsfn_area_id); - -SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, - srslte_cell_t cell); - -SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, - float *filter, - uint32_t filter_len); + srslte_chest_dl_noise_alg_t noise_alg; + srslte_chest_filter_t filter_type; + float filter_coef[2]; -SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, - float w); - -SRSLTE_API void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, - uint32_t order, - float std_dev); - -SRSLTE_API void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t* q, - bool enable); - -SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, - srslte_chest_dl_noise_alg_t noise_estimation_alg); - - - -SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - uint32_t sf_idx, - uint32_t nof_rx_antennas); - -SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q, - cf_t *input, - cf_t *ce[SRSLTE_MAX_PORTS], - uint32_t sf_idx); - -SRSLTE_API int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - uint32_t sf_idx, - uint32_t nof_rx_antennas, - uint16_t mbsfn_area_id); - - -SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, - cf_t *input, - cf_t *ce, - uint32_t sf_idx, - uint32_t port_id, - uint32_t rxant_id); + uint16_t mbsfn_area_id; + bool interpolate_subframe; + bool rsrp_neighbour; + bool cfo_estimate_enable; + uint32_t cfo_estimate_sf_mask; -SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, - bool enable, - uint32_t mask); +} srslte_chest_dl_cfg_t; -SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, - bool enable); +SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t* q, uint32_t max_prb, uint32_t nof_rx_antennas); -SRSLTE_API void srslte_chest_dl_set_rsrp_neighbour(srslte_chest_dl_t *q, - bool rsrp_for_neighbour); +SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t* q); -SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); +SRSLTE_API int srslte_chest_dl_res_init(srslte_chest_dl_res_t* q, uint32_t max_prb); -SRSLTE_API float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q); +SRSLTE_API void srslte_chest_dl_res_set_identity(srslte_chest_dl_res_t* q); -SRSLTE_API float srslte_chest_dl_get_snr(srslte_chest_dl_t *q); +SRSLTE_API void srslte_chest_dl_res_set_ones(srslte_chest_dl_res_t* q); -SRSLTE_API float srslte_chest_dl_get_snr_ant_port(srslte_chest_dl_t *q, - uint32_t ant_idx, - uint32_t port_idx); +SRSLTE_API void srslte_chest_dl_res_free(srslte_chest_dl_res_t* q); -SRSLTE_API float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q); +/* These functions change the internal object state */ -SRSLTE_API float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q); +SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t* q, uint16_t mbsfn_area_id); -SRSLTE_API float srslte_chest_dl_get_rsrq_ant_port(srslte_chest_dl_t *q, - uint32_t ant_idx, - uint32_t port); +SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t* q, srslte_cell_t cell); -SRSLTE_API float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t *q, - uint32_t ant_idx, - uint32_t port); +/* These functions do not change the internal state */ -SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, - uint32_t port); +SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + cf_t* input[SRSLTE_MAX_PORTS], + srslte_chest_dl_res_t* res); -SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q); +SRSLTE_API int srslte_chest_dl_estimate_cfg(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* input[SRSLTE_MAX_PORTS], + srslte_chest_dl_res_t* res); -SRSLTE_API float srslte_chest_dl_get_rsrp_neighbour(srslte_chest_dl_t *q); +/* These functions are exceptions and return values from last call to chest_dl_estimate */ +SRSLTE_API float srslte_chest_dl_get_rsrq_ant_port(srslte_chest_dl_t* q, uint32_t ant_idx, uint32_t port_idx); +SRSLTE_API float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t* q, uint32_t ant_idx, uint32_t port); #endif // SRSLTE_CHEST_DL_H diff --git a/lib/include/srslte/phy/ch_estimation/chest_ul.h b/lib/include/srslte/phy/ch_estimation/chest_ul.h index df5c11db6..28e2dbd05 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_ul.h +++ b/lib/include/srslte/phy/ch_estimation/chest_ul.h @@ -44,9 +44,21 @@ #include "srslte/config.h" #include "srslte/phy/ch_estimation/chest_common.h" -#include "srslte/phy/resampling/interp.h" #include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/pucch_cfg.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/resampling/interp.h" + +typedef struct SRSLTE_API { + cf_t* ce; + uint32_t nof_re; + float noise_estimate; + float noise_estimate_dbm; + float snr; + float snr_db; + float cfo; +} srslte_chest_ul_res_t; typedef struct { srslte_cell_t cell; @@ -68,11 +80,8 @@ typedef struct { uint32_t smooth_filter_len; float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN]; - srslte_interp_linsrslte_vec_t srslte_interp_linvec; - - float pilot_power; - float noise_estimate; - + srslte_interp_linsrslte_vec_t srslte_interp_linvec; + } srslte_chest_ul_t; @@ -81,41 +90,20 @@ SRSLTE_API int srslte_chest_ul_init(srslte_chest_ul_t *q, SRSLTE_API void srslte_chest_ul_free(srslte_chest_ul_t *q); -SRSLTE_API int srslte_chest_ul_set_cell(srslte_chest_ul_t *q, - srslte_cell_t cell); - - -SRSLTE_API void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pucch_cfg_t *pucch_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg); - -SRSLTE_API void srslte_chest_ul_set_smooth_filter(srslte_chest_ul_t *q, - float *filter, - uint32_t filter_len); +SRSLTE_API int srslte_chest_ul_res_init(srslte_chest_ul_res_t* q, uint32_t max_prb); -SRSLTE_API void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q, - float w); +SRSLTE_API void srslte_chest_ul_res_set_identity(srslte_chest_ul_res_t* q); -SRSLTE_API int srslte_chest_ul_estimate(srslte_chest_ul_t *q, - cf_t *input, - cf_t *ce, - uint32_t nof_prb, - uint32_t sf_idx, - uint32_t cyclic_shift_for_dmrs, - uint32_t n_prb[2]); +SRSLTE_API void srslte_chest_ul_res_free(srslte_chest_ul_res_t* q); -SRSLTE_API int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, - cf_t *input, - cf_t *ce, - srslte_pucch_format_t format, - uint32_t n_pucch, - uint32_t sf_idx, - uint8_t *pucch2_ack_bits); +SRSLTE_API int srslte_chest_ul_set_cell(srslte_chest_ul_t* q, srslte_cell_t cell); -SRSLTE_API float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q); +SRSLTE_API void srslte_chest_ul_pregen(srslte_chest_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* cfg); -SRSLTE_API float srslte_chest_ul_get_snr(srslte_chest_ul_t *q); +SRSLTE_API int srslte_chest_ul_estimate_pusch( + srslte_chest_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_pusch_cfg_t* cfg, cf_t* input, srslte_chest_ul_res_t* res); +SRSLTE_API int srslte_chest_ul_estimate_pucch( + srslte_chest_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, cf_t* input, srslte_chest_ul_res_t* res); #endif // SRSLTE_CHEST_UL_H diff --git a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h index 06809186e..de304fe05 100644 --- a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h @@ -39,10 +39,9 @@ #include "srslte/phy/common/phy_common.h" // Number of references in a subframe: there are 2 symbols for port_id=0,1 x 2 slots x 2 refs per prb -#define SRSLTE_REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb)) #define SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb, port_id) ((2 + 18)*(nof_prb)) -#define SRSLTE_REFSIGNAL_MAX_NUM_SF(nof_prb) SRSLTE_REFSIGNAL_NUM_SF(nof_prb, 0) +#define SRSLTE_REFSIGNAL_MAX_NUM_SF(nof_prb) (8 * nof_prb) #define SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(nof_prb) SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb,0) #define SRSLTE_REFSIGNAL_PILOT_IDX(i,l,cell) (2*cell.nof_prb*(l)+(i)) @@ -53,14 +52,13 @@ /** Cell-Specific Reference Signal */ typedef struct SRSLTE_API { - srslte_cell_t cell; - cf_t *pilots[2][SRSLTE_NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 + srslte_cell_t cell; + cf_t* pilots[2][SRSLTE_NOF_SF_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 srslte_sf_t type; uint16_t mbsfn_area_id; } srslte_refsignal_t; - SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_t *q, uint32_t max_prb); @@ -69,39 +67,29 @@ SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, SRSLTE_API void srslte_refsignal_free(srslte_refsignal_t *q); -SRSLTE_API int srslte_refsignal_cs_put_sf(srslte_cell_t cell, - uint32_t port_id, - cf_t *pilots, - cf_t *sf_symbols); +SRSLTE_API int +srslte_refsignal_cs_put_sf(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id, cf_t* sf_symbols); -SRSLTE_API int srslte_refsignal_cs_get_sf(srslte_cell_t cell, - uint32_t port_id, - cf_t *sf_symbols, - cf_t *pilots); +SRSLTE_API int srslte_refsignal_cs_get_sf( + srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id, cf_t* sf_symbols, cf_t* pilots); -SRSLTE_API uint32_t srslte_refsignal_cs_fidx(srslte_cell_t cell, - uint32_t l, - uint32_t port_id, - uint32_t m); +SRSLTE_API uint32_t srslte_refsignal_cs_fidx(srslte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m); SRSLTE_API uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id); -SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id, - uint32_t ref_symbol_idx); +SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx); + +SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id); -SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id); +SRSLTE_API uint32_t srslte_refsignal_cs_nof_re(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id); SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, uint32_t max_prb); -SRSLTE_API int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t * q, - srslte_cell_t cell, uint16_t mbsfn_area_id); +SRSLTE_API int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t* q, srslte_cell_t cell, uint16_t mbsfn_area_id); -SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell, - uint32_t port_id, - cf_t *sf_symbols, - cf_t *pilots); +SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell, uint32_t port_id, cf_t* sf_symbols, cf_t* pilots); SRSLTE_API uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l); diff --git a/lib/include/srslte/phy/ch_estimation/refsignal_ul.h b/lib/include/srslte/phy/ch_estimation/refsignal_ul.h index 7b393e8d9..c99d381a9 100644 --- a/lib/include/srslte/phy/ch_estimation/refsignal_ul.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_ul.h @@ -36,8 +36,9 @@ #define SRSLTE_REFSIGNAL_UL_H #include "srslte/config.h" -#include "srslte/phy/phch/pucch.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/pucch_cfg.h" +#include "srslte/phy/phch/pusch_cfg.h" #define SRSLTE_NOF_GROUPS_U 30 #define SRSLTE_NOF_SEQUENCES_U 2 @@ -50,15 +51,16 @@ typedef struct SRSLTE_API { uint32_t cyclic_shift; uint32_t delta_ss; - bool group_hopping_en; - bool sequence_hopping_en; -}srslte_refsignal_dmrs_pusch_cfg_t; - + bool group_hopping_en; + bool sequence_hopping_en; +} srslte_refsignal_dmrs_pusch_cfg_t; typedef struct SRSLTE_API { - // Common Configuration + + // Common Configuration uint32_t subframe_config; - uint32_t bw_cfg; + uint32_t bw_cfg; + bool simul_ack; // Dedicated configuration uint32_t B; @@ -67,18 +69,16 @@ typedef struct SRSLTE_API { uint32_t I_srs; uint32_t k_tc; uint32_t n_rrc; - bool configured; -}srslte_refsignal_srs_cfg_t; + bool configured; +} srslte_refsignal_srs_cfg_t; /** Uplink DeModulation Reference Signal (DMRS) */ typedef struct SRSLTE_API { - srslte_cell_t cell; - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - srslte_pucch_cfg_t pucch_cfg; - srslte_refsignal_srs_cfg_t srs_cfg; - + srslte_cell_t cell; + + float* tmp_arg; + uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]; - float *tmp_arg; uint32_t n_prs_pusch[SRSLTE_NOF_DELTA_SS][SRSLTE_NSLOTS_X_FRAME]; // We precompute n_prs needed for cyclic shift alpha at srslte_refsignal_dl_init() uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME]; uint32_t u_pucch[SRSLTE_NSLOTS_X_FRAME]; @@ -86,11 +86,11 @@ typedef struct SRSLTE_API { } srslte_refsignal_ul_t; typedef struct { - cf_t **r[SRSLTE_NOF_CSHIFT][SRSLTE_NSUBFRAMES_X_FRAME]; + cf_t** r[SRSLTE_NOF_CSHIFT][SRSLTE_NOF_SF_X_FRAME]; } srslte_refsignal_ul_dmrs_pregen_t; typedef struct { - cf_t *r[SRSLTE_NSUBFRAMES_X_FRAME]; + cf_t* r[SRSLTE_NOF_SF_X_FRAME]; } srslte_refsignal_srs_pregen_t; SRSLTE_API int srslte_refsignal_ul_init(srslte_refsignal_ul_t *q, @@ -101,112 +101,95 @@ SRSLTE_API int srslte_refsignal_ul_set_cell(srslte_refsignal_ul_t *q, SRSLTE_API void srslte_refsignal_ul_free(srslte_refsignal_ul_t *q); -SRSLTE_API void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pucch_cfg_t *pucch_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg); - -SRSLTE_API void srslte_refsignal_r_uv_arg_1prb(float *arg, - uint32_t u); - -SRSLTE_API uint32_t srslte_refsignal_dmrs_N_rs(srslte_pucch_format_t format, - srslte_cp_t cp); - -SRSLTE_API uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m, - srslte_pucch_format_t format, - srslte_cp_t cp); - -SRSLTE_API bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *cfg, - uint32_t nof_prb); - -SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_t *q, - srslte_refsignal_ul_dmrs_pregen_t *pregen, - uint32_t max_prb); - -SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t *q, - srslte_refsignal_ul_dmrs_pregen_t *pregen); - -SRSLTE_API void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t *q, - srslte_refsignal_ul_dmrs_pregen_t *pregen); - -SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen_put(srslte_refsignal_ul_t *q, - srslte_refsignal_ul_dmrs_pregen_t *pregen, - uint32_t nof_prb, - uint32_t sf_idx, - uint32_t cyclic_shift_for_dmrs, - uint32_t n_prb[2], - cf_t *sf_symbols); - -SRSLTE_API int srslte_refsignal_dmrs_pusch_gen(srslte_refsignal_ul_t *q, - uint32_t nof_prb, - uint32_t sf_idx, - uint32_t cyclic_shift_for_dmrs, - cf_t *r_pusch); - -SRSLTE_API void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t *q, - cf_t *r_pusch, - uint32_t nof_prb, - uint32_t n_prb[2], - cf_t *sf_symbols); - -SRSLTE_API void srslte_refsignal_dmrs_pusch_get(srslte_refsignal_ul_t *q, - cf_t *sf_symbols, - uint32_t nof_prb, - uint32_t n_prb[2], - cf_t *r_pusch); - -SRSLTE_API int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, - srslte_pucch_format_t format, - uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format - uint32_t sf_idx, - uint8_t pucch2_bits[2], - cf_t *r_pucch); - -SRSLTE_API int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t* q, - srslte_pucch_format_t format, - uint32_t n_pucch, - cf_t *r_pucch, - cf_t *output); - -SRSLTE_API int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t* q, - srslte_pucch_format_t format, - uint32_t n_pucch, - cf_t *input, - cf_t *r_pucch); - -SRSLTE_API int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t *q, - srslte_refsignal_srs_pregen_t *pregen); - -SRSLTE_API int srslte_refsignal_srs_pregen_put(srslte_refsignal_ul_t *q, - srslte_refsignal_srs_pregen_t *pregen, - uint32_t tti, - cf_t *sf_symbols); - -SRSLTE_API void srslte_refsignal_srs_pregen_free(srslte_refsignal_ul_t *q, - srslte_refsignal_srs_pregen_t *pregen); - -SRSLTE_API int srslte_refsignal_srs_gen(srslte_refsignal_ul_t *q, - uint32_t sf_idx, - cf_t *r_srs); - -SRSLTE_API int srslte_refsignal_srs_put(srslte_refsignal_ul_t *q, - uint32_t tti, - cf_t *r_srs, - cf_t *sf_symbols); - -SRSLTE_API int srslte_refsignal_srs_send_cs(uint32_t subframe_config, - uint32_t sf_idx); - -SRSLTE_API int srslte_refsignal_srs_send_ue(uint32_t I_srs, - uint32_t tti); - -SRSLTE_API uint32_t srslte_refsignal_srs_rb_start_cs(uint32_t bw_cfg, - uint32_t nof_prb); - -SRSLTE_API uint32_t srslte_refsignal_srs_rb_L_cs(uint32_t bw_cfg, - uint32_t nof_prb); - -SRSLTE_API uint32_t srslte_refsignal_srs_M_sc(srslte_refsignal_ul_t *q); +SRSLTE_API void srslte_refsignal_r_uv_arg_1prb(float* arg, uint32_t u); + +SRSLTE_API uint32_t srslte_refsignal_dmrs_N_rs(srslte_pucch_format_t format, srslte_cp_t cp); + +SRSLTE_API uint32_t srslte_refsignal_dmrs_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp); + +SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_dmrs_pregen_t* pregen, uint32_t max_prb); + +SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t* q, + srslte_refsignal_ul_dmrs_pregen_t* pregen, + srslte_refsignal_dmrs_pusch_cfg_t* cfg); + +SRSLTE_API void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t* q, + srslte_refsignal_ul_dmrs_pregen_t* pregen); + +SRSLTE_API int srslte_refsignal_dmrs_pusch_pregen_put(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf_cfg, + srslte_refsignal_ul_dmrs_pregen_t* pregen, + srslte_pusch_cfg_t* pusch_cfg, + cf_t* sf_symbols); + +SRSLTE_API int srslte_refsignal_dmrs_pusch_gen(srslte_refsignal_ul_t* q, + srslte_refsignal_dmrs_pusch_cfg_t* cfg, + uint32_t nof_prb, + uint32_t sf_idx, + uint32_t cyclic_shift_for_dmrs, + cf_t* r_pusch); + +SRSLTE_API void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t* q, + srslte_pusch_cfg_t* pusch_cfg, + cf_t* r_pusch, + cf_t* sf_symbols); + +SRSLTE_API void srslte_refsignal_dmrs_pusch_get(srslte_refsignal_ul_t* q, + srslte_pusch_cfg_t* pusch_cfg, + cf_t* sf_symbols, + cf_t* r_pusch); + +SRSLTE_API int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + cf_t* r_pucch); + +SRSLTE_API int +srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t* q, srslte_pucch_cfg_t* cfg, cf_t* r_pucch, cf_t* output); + +SRSLTE_API int +srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t* q, srslte_pucch_cfg_t* cfg, cf_t* input, cf_t* r_pucch); + +SRSLTE_API int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t* q, + srslte_refsignal_srs_pregen_t* pregen, + srslte_refsignal_srs_cfg_t* cfg, + srslte_refsignal_dmrs_pusch_cfg_t* dmrs); + +SRSLTE_API int srslte_refsignal_srs_pregen_put(srslte_refsignal_ul_t* q, + srslte_refsignal_srs_pregen_t* pregen, + srslte_refsignal_srs_cfg_t* cfg, + uint32_t tti, + cf_t* sf_symbols); + +SRSLTE_API void srslte_refsignal_srs_pregen_free(srslte_refsignal_ul_t* q, srslte_refsignal_srs_pregen_t* pregen); + +SRSLTE_API int srslte_refsignal_srs_gen(srslte_refsignal_ul_t* q, + srslte_refsignal_srs_cfg_t* cfg, + srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg, + uint32_t sf_idx, + cf_t* r_srs); + +SRSLTE_API int srslte_refsignal_srs_put( + srslte_refsignal_ul_t* q, srslte_refsignal_srs_cfg_t* cfg, uint32_t tti, cf_t* r_srs, cf_t* sf_symbols); + +SRSLTE_API void srslte_refsignal_srs_pusch_shortened(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_refsignal_srs_cfg_t* srs_cfg, + srslte_pusch_cfg_t* pusch_cfg); + +SRSLTE_API void srslte_refsignal_srs_pucch_shortened(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_refsignal_srs_cfg_t* srs_cfg, + srslte_pucch_cfg_t* pucch_cfg); + +SRSLTE_API int srslte_refsignal_srs_send_cs(uint32_t subframe_config, uint32_t sf_idx); + +SRSLTE_API int srslte_refsignal_srs_send_ue(uint32_t I_srs, uint32_t tti); + +SRSLTE_API uint32_t srslte_refsignal_srs_rb_start_cs(uint32_t bw_cfg, uint32_t nof_prb); + +SRSLTE_API uint32_t srslte_refsignal_srs_rb_L_cs(uint32_t bw_cfg, uint32_t nof_prb); + +SRSLTE_API uint32_t srslte_refsignal_srs_M_sc(srslte_refsignal_ul_t* q, srslte_refsignal_srs_cfg_t* cfg); #endif // SRSLTE_REFSIGNAL_UL_H diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 82c2dfaa8..80a5e8a20 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -42,13 +42,15 @@ #include "srslte/config.h" -#define SRSLTE_NSUBFRAMES_X_FRAME 10 -#define SRSLTE_NSLOTS_X_FRAME (2*SRSLTE_NSUBFRAMES_X_FRAME) +#define SRSLTE_NOF_SF_X_FRAME 10 +#define SRSLTE_NSLOTS_X_FRAME (2 * SRSLTE_NOF_SF_X_FRAME) #define SRSLTE_NSOFT_BITS 250368 // Soft buffer size for Category 1 UE #define SRSLTE_PC_MAX 23 // Maximum TX power for Category 1 UE (in dBm) +#define SRSLTE_MAX_RADIOS 3 // Maximum number of supported RF devices +#define SRSLTE_MAX_CARRIERS 5 // Maximum number of supported simultaneous carriers #define SRSLTE_MAX_PORTS 4 #define SRSLTE_MAX_LAYERS 4 #define SRSLTE_MAX_CODEWORDS 2 @@ -66,9 +68,8 @@ #define SRSLTE_MAX_MBSFN_AREA_IDS 256 #define SRSLTE_PMCH_RV 0 -typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t; -typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; - +typedef enum { SRSLTE_CP_NORM = 0, SRSLTE_CP_EXT } srslte_cp_t; +typedef enum { SRSLTE_SF_NORM = 0, SRSLTE_SF_MBSFN } srslte_sf_t; #define SRSLTE_CRNTI_START 0x000B #define SRSLTE_CRNTI_END 0xFFF3 @@ -78,7 +79,14 @@ typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; #define SRSLTE_PRNTI 0xFFFE #define SRSLTE_MRNTI 0xFFFD -#define SRSLTE_CELL_ID_UNKNOWN 1000 +#define SRSLTE_RNTI_ISRAR(rnti) (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END) +#define SRSLTE_RNTI_ISUSER(rnti) (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) +#define SRSLTE_RNTI_ISSI(rnti) (rnti == SRSLTE_SIRNTI) +#define SRSLTE_RNTI_ISPA(rnti) (rnti == SRSLTE_PRNTI) +#define SRSLTE_RNTI_ISMBSFN(rnti) (rnti == SRSLTE_MRNTI) +#define SRSLTE_RNTI_ISSIRAPA(rnti) (SRSLTE_RNTI_ISSI(rnti) || SRSLTE_RNTI_ISRAR(rnti) || SRSLTE_RNTI_ISPA(rnti)) + +#define SRSLTE_CELL_ID_UNKNOWN 1000 #define SRSLTE_MAX_NSYMB 7 @@ -105,15 +113,19 @@ typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; #define SRSLTE_CP_LEN_NORM(symbol, symbol_sz) (((symbol)==0)?SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_NORM_0_LEN):SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_NORM_LEN)) #define SRSLTE_CP_LEN_EXT(symbol_sz) (SRSLTE_CP_LEN((symbol_sz),SRSLTE_CP_EXT_LEN)) -#define SRSLTE_SLOT_LEN(symbol_sz) (symbol_sz*15/2) -#define SRSLTE_SF_LEN(symbol_sz) (symbol_sz*15) -#define SRSLTE_SF_LEN_MAX (SRSLTE_SF_LEN(SRSLTE_SYMBOL_SZ_MAX)) +#define SRSLTE_CP_SZ(symbol_sz, cp) \ + (SRSLTE_CP_LEN(symbol_sz, (SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_NORM_LEN : SRSLTE_CP_EXT_LEN))) +#define SRSLTE_SYMBOL_SZ(symbol_sz, cp) (symbol_sz + SRSLTE_CP_SZ(symbol_sz, cp)) +#define SRSLTE_SLOT_LEN(symbol_sz) (symbol_sz * 15 / 2) +#define SRSLTE_SF_LEN(symbol_sz) (symbol_sz * 15) +#define SRSLTE_SF_LEN_MAX (SRSLTE_SF_LEN(SRSLTE_SYMBOL_SZ_MAX)) #define SRSLTE_SLOT_LEN_PRB(nof_prb) (SRSLTE_SLOT_LEN(srslte_symbol_sz(nof_prb))) #define SRSLTE_SF_LEN_PRB(nof_prb) (SRSLTE_SF_LEN(srslte_symbol_sz(nof_prb))) #define SRSLTE_SLOT_LEN_RE(nof_prb, cp) (nof_prb*SRSLTE_NRE*SRSLTE_CP_NSYMB(cp)) #define SRSLTE_SF_LEN_RE(nof_prb, cp) (2*SRSLTE_SLOT_LEN_RE(nof_prb, cp)) +#define SRSLTE_NOF_RE(cell) (2 * SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)) #define SRSLTE_TA_OFFSET (10e-6) @@ -133,76 +145,135 @@ typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; || l == 0 \ || l == SRSLTE_CP_NSYMB(cp) - 3) - +#define SRSLTE_NOF_CTRL_SYMBOLS(cell, cfi) (cfi + (cell.nof_prb < 10 ? 1 : 0)) #define SRSLTE_SYMBOL_HAS_REF_MBSFN(l, s) ((l == 2 && s == 0) || (l == 0 && s == 1) || (l == 4 && s == 1)) #define SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(non_mbsfn_region,symbol_sz) ((non_mbsfn_region == 1)?(SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)):(2*SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)- SRSLTE_CP_LEN_NORM(1, symbol_sz))) +#define SRSLTE_FDD_NOF_HARQ (TX_DELAY + FDD_HARQ_DELAY_MS) +#define SRSLTE_MAX_HARQ_PROC 15 - -#define SRSLTE_NOF_LTE_BANDS 38 +#define SRSLTE_NOF_LTE_BANDS 58 #define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500 #define SRSLTE_DEFAULT_MAX_FRAMES_PSS 10 #define SRSLTE_DEFAULT_NOF_VALID_PSS_FRAMES 10 +#define ZERO_OBJECT(x) memset(&(x), 0x0, sizeof((x))) typedef enum SRSLTE_API { SRSLTE_PHICH_NORM = 0, SRSLTE_PHICH_EXT } srslte_phich_length_t; -typedef enum SRSLTE_API { - SRSLTE_PHICH_R_1_6 = 0, - SRSLTE_PHICH_R_1_2, - SRSLTE_PHICH_R_1, +typedef enum SRSLTE_API { + SRSLTE_PHICH_R_1_6 = 0, + SRSLTE_PHICH_R_1_2, + SRSLTE_PHICH_R_1, SRSLTE_PHICH_R_2 - -} srslte_phich_resources_t; +} srslte_phich_r_t; -typedef enum { - SRSLTE_RNTI_USER = 0, /* Cell RNTI */ - SRSLTE_RNTI_SI, /* System Information RNTI */ - SRSLTE_RNTI_RAR, /* Random Access RNTI */ - SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */ - SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */ - SRSLTE_RNTI_PCH, /* Paging RNTI */ - SRSLTE_RNTI_MBSFN, - SRSLTE_RNTI_NOF_TYPES -} srslte_rnti_type_t; +typedef enum SRSLTE_API { SRSLTE_FDD = 0, SRSLTE_TDD = 1 } srslte_frame_type_t; typedef struct SRSLTE_API { - uint32_t nof_prb; - uint32_t nof_ports; - uint32_t id; - srslte_cp_t cp; + uint32_t sf_config; + uint32_t ss_config; + bool configured; +} srslte_tdd_config_t; + +typedef enum SRSLTE_API { + SRSLTE_TDD_SF_D = 0, + SRSLTE_TDD_SF_U = 1, + SRSLTE_TDD_SF_S = 2, +} srslte_tdd_sf_t; + +typedef struct { + uint8_t mbsfn_area_id; + uint8_t non_mbsfn_region_length; + uint8_t mbsfn_mcs; + bool enable; + bool is_mcch; +} srslte_mbsfn_cfg_t; + +// Common cell constant properties that require object reconfiguration +typedef struct SRSLTE_API { + uint32_t nof_prb; + uint32_t nof_ports; + uint32_t id; + srslte_cp_t cp; srslte_phich_length_t phich_length; - srslte_phich_resources_t phich_resources; -}srslte_cell_t; + srslte_phich_r_t phich_resources; + srslte_frame_type_t frame_type; +} srslte_cell_t; + +// Common downlink properties that may change every subframe +typedef struct SRSLTE_API { + srslte_tdd_config_t tdd_config; + uint32_t tti; + uint32_t cfi; + srslte_sf_t sf_type; + uint32_t non_mbsfn_region; +} srslte_dl_sf_cfg_t; + +typedef struct SRSLTE_API { + srslte_tdd_config_t tdd_config; + uint32_t tti; + bool shortened; +} srslte_ul_sf_cfg_t; typedef enum SRSLTE_API { - SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, - SRSLTE_MIMO_TYPE_TX_DIVERSITY, - SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX, - SRSLTE_MIMO_TYPE_CDD -} srslte_mimo_type_t; + SRSLTE_TM1 = 0, + SRSLTE_TM2, + SRSLTE_TM3, + SRSLTE_TM4, + SRSLTE_TM5, + SRSLTE_TM6, + SRSLTE_TM7, + SRSLTE_TM8, + SRSLTE_TMINV // Invalid Transmission Mode +} srslte_tm_t; typedef enum SRSLTE_API { - SRSLTE_MIMO_DECODER_ZF, - SRSLTE_MIMO_DECODER_MMSE -} srslte_mimo_decoder_t; + SRSLTE_TXSCHEME_PORT0, + SRSLTE_TXSCHEME_DIVERSITY, + SRSLTE_TXSCHEME_SPATIALMUX, + SRSLTE_TXSCHEME_CDD +} srslte_tx_scheme_t; + +typedef enum SRSLTE_API { SRSLTE_MIMO_DECODER_ZF, SRSLTE_MIMO_DECODER_MMSE } srslte_mimo_decoder_t; typedef enum SRSLTE_API { SRSLTE_MOD_BPSK = 0, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM, - SRSLTE_MOD_LAST } srslte_mod_t; +typedef enum { + SRSLTE_DCI_FORMAT0 = 0, + SRSLTE_DCI_FORMAT1, + SRSLTE_DCI_FORMAT1A, + SRSLTE_DCI_FORMAT1C, + SRSLTE_DCI_FORMAT1B, + SRSLTE_DCI_FORMAT1D, + SRSLTE_DCI_FORMAT2, + SRSLTE_DCI_FORMAT2A, + SRSLTE_DCI_FORMAT2B, + // SRSLTE_DCI_FORMAT3, + // SRSLTE_DCI_FORMAT3A, + SRSLTE_DCI_NOF_FORMATS +} srslte_dci_format_t; + +typedef enum { + SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL = 0, /* No cell selection no pucch3 */ + SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, + SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, + SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_ERROR, +} srslte_ack_nack_feedback_mode_t; + typedef struct SRSLTE_API { - int id; + int id; float fd; } srslte_earfcn_t; @@ -226,6 +297,18 @@ SRSLTE_API bool srslte_cellid_isvalid(uint32_t cell_id); SRSLTE_API bool srslte_nofprb_isvalid(uint32_t nof_prb); +SRSLTE_API srslte_tdd_sf_t srslte_sfidx_tdd_type(srslte_tdd_config_t tdd_config, uint32_t sf_idx); + +SRSLTE_API uint32_t srslte_tdd_nof_harq(srslte_tdd_config_t tdd_config); + +SRSLTE_API uint32_t srslte_sfidx_tdd_nof_up(srslte_tdd_config_t tdd_config); + +SRSLTE_API uint32_t srslte_sfidx_tdd_nof_gp(srslte_tdd_config_t tdd_config); + +SRSLTE_API uint32_t srslte_sfidx_tdd_nof_dw(srslte_tdd_config_t tdd_config); + +SRSLTE_API uint32_t srslte_sfidx_tdd_nof_dw_slot(srslte_tdd_config_t tdd_config, uint32_t slot, srslte_cp_t cp); + SRSLTE_API bool srslte_sfidx_isvalid(uint32_t sf_idx); SRSLTE_API bool srslte_portid_isvalid(uint32_t port_id); @@ -274,11 +357,13 @@ SRSLTE_API char *srslte_mod_string(srslte_mod_t mod); SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod); -SRSLTE_API int srslte_band_get_band(uint32_t dl_earfcn); +SRSLTE_API int srslte_band_get_band(uint32_t dl_earfcn); + +SRSLTE_API bool srslte_band_is_tdd(uint32_t band); SRSLTE_API float srslte_band_fd(uint32_t dl_earfcn); -SRSLTE_API float srslte_band_fu(uint32_t ul_earfcn); +SRSLTE_API float srslte_band_fu(uint32_t ul_earfcn); SRSLTE_API uint32_t srslte_band_ul_earfcn(uint32_t dl_earfcn); @@ -296,13 +381,13 @@ SRSLTE_API int srslte_band_get_fd_region(enum band_geographical_area region, srslte_earfcn_t *earfcn, uint32_t max_elems); -SRSLTE_API int srslte_str2mimotype(char *mimo_type_str, - srslte_mimo_type_t *type); +SRSLTE_API int srslte_str2mimotype(char* mimo_type_str, srslte_tx_scheme_t* type); -SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type); +SRSLTE_API char* srslte_mimotype2str(srslte_tx_scheme_t mimo_type); /* Returns the interval tti1-tti2 mod 10240 */ -SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, - uint32_t tti2); +SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2); + +SRSLTE_API uint32_t srslte_print_check(char* s, size_t max_len, uint32_t cur_len, const char* format, ...); #endif // SRSLTE_PHY_COMMON_H diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index 5e0d2bf5e..a96e50051 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -40,11 +40,9 @@ #include +#include "srslte/phy/ch_estimation/refsignal_dl.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/dft/ofdm.h" -#include "srslte/phy/sync/pss.h" -#include "srslte/phy/sync/sss.h" -#include "srslte/phy/ch_estimation/refsignal_dl.h" #include "srslte/phy/phch/dci.h" #include "srslte/phy/phch/pbch.h" #include "srslte/phy/phch/pcfich.h" @@ -52,10 +50,14 @@ #include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/pdsch_cfg.h" #include "srslte/phy/phch/phich.h" +#include "srslte/phy/phch/pmch.h" #include "srslte/phy/phch/ra.h" #include "srslte/phy/phch/regs.h" +#include "srslte/phy/sync/pss.h" +#include "srslte/phy/sync/sss.h" #include "srslte/phy/enb/enb_ul.h" +#include "srslte/phy/ue/ue_dl.h" #include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/debug.h" @@ -65,12 +67,13 @@ typedef struct SRSLTE_API { srslte_cell_t cell; - cf_t *sf_symbols[SRSLTE_MAX_PORTS]; - cf_t *slot1_symbols[SRSLTE_MAX_PORTS]; - + srslte_dl_sf_cfg_t dl_sf; + + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + srslte_ofdm_t ifft[SRSLTE_MAX_PORTS]; - - srslte_ofdm_t ifft_mbsfn; + srslte_ofdm_t ifft_mbsfn; + srslte_pbch_t pbch; srslte_pcfich_t pcfich; srslte_regs_t regs; @@ -81,39 +84,18 @@ typedef struct SRSLTE_API { srslte_refsignal_t csr_signal; srslte_refsignal_t mbsfnr_signal; - srslte_pdsch_cfg_t pdsch_cfg; - srslte_pdsch_cfg_t pmch_cfg; - srslte_ra_dl_dci_t dl_dci; - - srslte_dci_format_t dci_format; - uint32_t cfi; - - cf_t pss_signal[SRSLTE_PSS_LEN]; - float sss_signal0[SRSLTE_SSS_LEN]; - float sss_signal5[SRSLTE_SSS_LEN]; - - float tx_amp; - float rho_b; - - uint8_t tmp[1024*128]; - -} srslte_enb_dl_t; -typedef struct { - uint16_t rnti; - srslte_dci_format_t dci_format; - srslte_ra_dl_dci_t grant; - srslte_dci_location_t location; - srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_TB]; - uint8_t *data[SRSLTE_MAX_TB]; -} srslte_enb_dl_pdsch_t; + cf_t pss_signal[SRSLTE_PSS_LEN]; + float sss_signal0[SRSLTE_SSS_LEN]; + float sss_signal5[SRSLTE_SSS_LEN]; + +} srslte_enb_dl_t; typedef struct { - uint16_t rnti; uint8_t ack; uint32_t n_prb_lowest; - uint32_t n_dmrs; -} srslte_enb_dl_phich_t; + uint32_t n_dmrs; +} srslte_enb_dl_phich_t; /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_enb_dl_init(srslte_enb_dl_t *q, @@ -125,92 +107,31 @@ SRSLTE_API void srslte_enb_dl_free(srslte_enb_dl_t *q); SRSLTE_API int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell); -SRSLTE_API void srslte_enb_dl_set_cfi(srslte_enb_dl_t *q, - uint32_t cfi); - -SRSLTE_API void srslte_enb_dl_set_power_allocation(srslte_enb_dl_t *q, - float rho_a, - float rho_b); - -SRSLTE_API void srslte_enb_dl_apply_power_allocation(srslte_enb_dl_t *q); - -SRSLTE_API void srslte_enb_dl_prepare_power_allocation(srslte_enb_dl_t *q); - -SRSLTE_API void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, - float amp); - -SRSLTE_API void srslte_enb_dl_set_non_mbsfn_region(srslte_enb_dl_t *q, uint8_t non_mbsfn_region); - -SRSLTE_API void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q); - -SRSLTE_API void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, - uint32_t sf_idx); - -SRSLTE_API void srslte_enb_dl_put_refs(srslte_enb_dl_t *q, - uint32_t sf_idx); - -SRSLTE_API void srslte_enb_dl_put_mib(srslte_enb_dl_t *q, - uint32_t tti); - -SRSLTE_API void srslte_enb_dl_put_pcfich(srslte_enb_dl_t *q, - uint32_t sf_idx); - -SRSLTE_API void srslte_enb_dl_put_phich(srslte_enb_dl_t *q, - uint8_t ack, - uint32_t n_prb_lowest, - uint32_t n_dmrs, - uint32_t sf_idx); +SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t* q, uint16_t rnti); -SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t *q, - uint32_t tti); +SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t* q, uint16_t rnti); -SRSLTE_API void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q, - uint32_t tti); +SRSLTE_API void srslte_enb_dl_put_base(srslte_enb_dl_t* q, srslte_dl_sf_cfg_t* dl_sf); -SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q); +SRSLTE_API void srslte_enb_dl_put_phich(srslte_enb_dl_t* q, srslte_phich_grant_t* grant, bool ack); -SRSLTE_API void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q); +SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t* q, srslte_dci_cfg_t* dci_cfg, srslte_dci_dl_t* dci_dl); -SRSLTE_API int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, - uint16_t rnti); +SRSLTE_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t* q, srslte_dci_cfg_t* dci_cfg, srslte_dci_ul_t* dci_ul); -SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, - uint16_t rnti); +SRSLTE_API int +srslte_enb_dl_put_pdsch(srslte_enb_dl_t* q, srslte_pdsch_cfg_t* pdsch, uint8_t* data[SRSLTE_MAX_CODEWORDS]); -SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, - srslte_ra_dl_grant_t *grant, - srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, - int rv_idx[SRSLTE_MAX_CODEWORDS], - uint32_t sf_idx, - uint8_t *data[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t mimo_type); +SRSLTE_API int srslte_enb_dl_put_pmch(srslte_enb_dl_t* q, srslte_pmch_cfg_t* pmch_cfg, uint8_t* data); -SRSLTE_API int srslte_enb_dl_put_pmch(srslte_enb_dl_t *q, - srslte_ra_dl_grant_t *grant, - srslte_softbuffer_tx_t *softbuffer, - uint32_t sf_idx, - uint8_t *data_mbms); +SRSLTE_API void srslte_enb_dl_gen_signal(srslte_enb_dl_t* q); -SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, - srslte_ra_dl_dci_t *grant, - srslte_dci_format_t format, - srslte_dci_location_t location, - uint16_t rnti, - uint32_t sf_idx); +SRSLTE_API bool srslte_enb_dl_gen_cqi_periodic( + srslte_cell_t* cell, srslte_dl_cfg_t* dl_cfg, uint32_t tti, uint32_t ri, srslte_cqi_cfg_t* cqi_cfg); -SRSLTE_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, - srslte_ra_ul_dci_t *grant, - srslte_dci_location_t location, - uint16_t rnti, - uint32_t sf_idx); +SRSLTE_API bool +srslte_enb_dl_gen_cqi_aperiodic(srslte_cell_t* cell, srslte_dl_cfg_t* dl_cfg, uint32_t ri, srslte_cqi_cfg_t* cqi_cfg); -SRSLTE_API void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint32_t tti, - uint32_t rv_idx, - uint16_t rnti, - uint32_t cfi); +SRSLTE_API void srslte_enb_dl_save_signal(srslte_enb_dl_t* q); #endif // SRSLTE_ENB_DL_H diff --git a/lib/include/srslte/phy/enb/enb_ul.h b/lib/include/srslte/phy/enb/enb_ul.h index 49d174807..18948fc67 100644 --- a/lib/include/srslte/phy/enb/enb_ul.h +++ b/lib/include/srslte/phy/enb/enb_ul.h @@ -40,10 +40,11 @@ #include +#include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/dft/ofdm.h" -#include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/phch/prach.h" +#include "srslte/phy/phch/pucch.h" #include "srslte/phy/phch/pusch.h" #include "srslte/phy/phch/pusch_cfg.h" #include "srslte/phy/phch/ra.h" @@ -53,51 +54,18 @@ #include "srslte/config.h" -typedef struct { - uint32_t n_prb_lowest; - uint32_t n_dmrs; -} srslte_enb_ul_phich_info_t; - -typedef struct { - bool uci_cfg_en; - bool srs_cfg_en; - srslte_uci_cfg_t uci_cfg; - srslte_refsignal_srs_cfg_t srs_cfg; - srslte_pucch_sched_t pucch_sched; -} srslte_enb_ul_user_t; - typedef struct SRSLTE_API { srslte_cell_t cell; - - cf_t *sf_symbols; - cf_t *ce; - + + cf_t* sf_symbols; + srslte_chest_ul_res_t chest_res; + srslte_ofdm_t fft; srslte_chest_ul_t chest; - - srslte_pusch_t pusch; - srslte_pucch_t pucch; - srslte_prach_t prach; - - srslte_pusch_cfg_t pusch_cfg; - - srslte_pusch_hopping_cfg_t hopping_cfg; - - // Configuration for each user - srslte_enb_ul_user_t **users; - -} srslte_enb_ul_t; + srslte_pusch_t pusch; + srslte_pucch_t pucch; -typedef struct { - uint16_t rnti; - srslte_ra_ul_dci_t grant; - srslte_dci_location_t location; - uint32_t rv_idx; - uint32_t current_tx_nb; - uint8_t *data; - srslte_softbuffer_rx_t *softbuffer; - bool needs_pdcch; -} srslte_enb_ul_pusch_t; +} srslte_enb_ul_t; /* This function shall be called just after the initial synchronization */ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, @@ -106,12 +74,8 @@ SRSLTE_API int srslte_enb_ul_init(srslte_enb_ul_t *q, SRSLTE_API void srslte_enb_ul_free(srslte_enb_ul_t *q); -SRSLTE_API int srslte_enb_ul_set_cell(srslte_enb_ul_t *q, - srslte_cell_t cell, - srslte_prach_cfg_t* prach_cfg, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_pucch_cfg_t *pucch_cfg); +SRSLTE_API int +srslte_enb_ul_set_cell(srslte_enb_ul_t* q, srslte_cell_t cell, srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg); SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti); @@ -119,38 +83,18 @@ SRSLTE_API int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, SRSLTE_API void srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint16_t rnti); -SRSLTE_API int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, - srslte_uci_cfg_t *uci_cfg, - srslte_pucch_sched_t *pucch_sched, - srslte_refsignal_srs_cfg_t *srs_cfg); - - SRSLTE_API void srslte_enb_ul_fft(srslte_enb_ul_t *q); -SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, - uint16_t rnti, - uint32_t pdcch_n_cce, - uint32_t sf_rx, - srslte_uci_data_t *uci_data); - -SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, - srslte_ra_ul_grant_t *grant, - srslte_softbuffer_rx_t *softbuffer, - uint16_t rnti, - uint32_t rv_idx, - uint32_t current_tx_nb, - uint8_t *data, - srslte_cqi_value_t *cqi_value, - srslte_uci_data_t *uci_data, - uint32_t tti); - -SRSLTE_API int srslte_enb_ul_detect_prach(srslte_enb_ul_t *q, - uint32_t tti, - uint32_t freq_offset, - cf_t *signal, - uint32_t *indices, - float *offsets, - float *peak2avg); +SRSLTE_API int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q, + srslte_ul_sf_cfg_t* ul_sf, + srslte_pucch_cfg_t* cfg, + srslte_pucch_res_t* res); + +SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t* q, + srslte_ul_sf_cfg_t* ul_sf, + srslte_pusch_cfg_t* cfg, + srslte_pusch_res_t* res); +SRSLTE_API uint32_t srslte_enb_ul_get_pucch_prb_idx(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns); #endif // SRSLTE_ENB_UL_H diff --git a/lib/include/srslte/phy/fec/turbodecoder_iter.h b/lib/include/srslte/phy/fec/turbodecoder_iter.h index 7864829b5..d0873122b 100644 --- a/lib/include/srslte/phy/fec/turbodecoder_iter.h +++ b/lib/include/srslte/phy/fec/turbodecoder_iter.h @@ -142,7 +142,7 @@ void MAKE_CALL(run_tdec_iteration)(srslte_tdec_t * h, llr_t * input) h->n_iter++; } else { - fprintf(stderr, "Error CB index not set (call srslte_tdec_new_cb() first\n"); + ERROR("Error CB index not set (call srslte_tdec_new_cb() first\n"); } } diff --git a/lib/include/srslte/phy/mimo/layermap.h b/lib/include/srslte/phy/mimo/layermap.h index d6328a7ad..473fbdaea 100644 --- a/lib/include/srslte/phy/mimo/layermap.h +++ b/lib/include/srslte/phy/mimo/layermap.h @@ -57,13 +57,12 @@ SRSLTE_API int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], int nof_layers, int nof_symbols[SRSLTE_MAX_CODEWORDS]); -SRSLTE_API int srslte_layermap_type(cf_t *d[SRSLTE_MAX_CODEWORDS], - cf_t *x[SRSLTE_MAX_LAYERS], - int nof_cw, - int nof_layers, - int nof_symbols[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t type); - +SRSLTE_API int srslte_layermap_type(cf_t* d[SRSLTE_MAX_CODEWORDS], + cf_t* x[SRSLTE_MAX_LAYERS], + int nof_cw, + int nof_layers, + int nof_symbols[SRSLTE_MAX_CODEWORDS], + srslte_tx_scheme_t type); /* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x" */ @@ -82,13 +81,13 @@ SRSLTE_API int srslte_layerdemap_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], int nof_cw, int nof_layer_symbols, int nof_symbols[SRSLTE_MAX_CODEWORDS]); - -SRSLTE_API int srslte_layerdemap_type(cf_t *x[SRSLTE_MAX_LAYERS], - cf_t *d[SRSLTE_MAX_CODEWORDS], - int nof_layers, - int nof_cw, - int nof_layer_symbols, - int nof_symbols[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t type); + +SRSLTE_API int srslte_layerdemap_type(cf_t* x[SRSLTE_MAX_LAYERS], + cf_t* d[SRSLTE_MAX_CODEWORDS], + int nof_layers, + int nof_cw, + int nof_layer_symbols, + int nof_symbols[SRSLTE_MAX_CODEWORDS], + srslte_tx_scheme_t type); #endif // SRSLTE_LAYERMAP_H diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index 5caf4f0ca..4be4af9db 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -65,14 +65,14 @@ SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], int nof_symbols, float scaling); -SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], - cf_t *y[SRSLTE_MAX_PORTS], - int nof_layers, - int nof_ports, - int codebook_idx, - int nof_symbols, - float scaling, - srslte_mimo_type_t type); +SRSLTE_API int srslte_precoding_type(cf_t* x[SRSLTE_MAX_LAYERS], + cf_t* y[SRSLTE_MAX_PORTS], + int nof_layers, + int nof_ports, + int codebook_idx, + int nof_symbols, + float scaling, + srslte_tx_scheme_t type); /* Estimates the vector "x" based on the received signal "y" and the channel estimates "h" */ @@ -111,18 +111,18 @@ SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder); -SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], - cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - cf_t *x[SRSLTE_MAX_LAYERS], - float *csi[SRSLTE_MAX_CODEWORDS], - int nof_rxant, - int nof_ports, - int nof_layers, - int codebook_idx, - int nof_symbols, - srslte_mimo_type_t type, - float scaling, - float noise_estimate); +SRSLTE_API int srslte_predecoding_type(cf_t* y[SRSLTE_MAX_PORTS], + cf_t* h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t* x[SRSLTE_MAX_LAYERS], + float* csi[SRSLTE_MAX_CODEWORDS], + int nof_rxant, + int nof_ports, + int nof_layers, + int codebook_idx, + int nof_symbols, + srslte_tx_scheme_t type, + float scaling, + float noise_estimate); SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, diff --git a/lib/include/srslte/phy/phch/cqi.h b/lib/include/srslte/phy/phch/cqi.h index 481fce494..f35d56a84 100644 --- a/lib/include/srslte/phy/phch/cqi.h +++ b/lib/include/srslte/phy/phch/cqi.h @@ -45,16 +45,30 @@ #define SRSLTE_PMI_MAX_BITS 4 #define SRSLTE_CQI_STR_MAX_CHAR 64 +typedef enum { + SRSLTE_CQI_MODE_10, + SRSLTE_CQI_MODE_11, + SRSLTE_CQI_MODE_12, + SRSLTE_CQI_MODE_20, + SRSLTE_CQI_MODE_21, + SRSLTE_CQI_MODE_22, + SRSLTE_CQI_MODE_30, + SRSLTE_CQI_MODE_31, + SRSLTE_CQI_MODE_NA, +} srslte_cqi_report_mode_t; + typedef struct { - bool configured; - uint32_t pmi_idx; + bool periodic_configured; + bool aperiodic_configured; + uint32_t pmi_idx; uint32_t ri_idx; - bool ri_idx_present; - bool simul_cqi_ack; - bool format_is_subband; - uint32_t subband_size; -} srslte_cqi_periodic_cfg_t; - + bool ri_idx_present; + bool format_is_subband; + uint32_t subband_size; + srslte_cqi_report_mode_t periodic_mode; + srslte_cqi_report_mode_t aperiodic_mode; +} srslte_cqi_report_cfg_t; + /* Table 5.2.2.6.2-1: Fields for channel quality information feedback for higher layer configured subband CQI reports (transmission mode 1, transmission mode 2, transmission mode 3, transmission mode 7 and transmission mode 8 configured without PMI/RI reporting). */ @@ -68,11 +82,6 @@ typedef struct SRSLTE_API { uint8_t wideband_cqi_cw1; // if RI > 1 then 4-bit width otherwise 0-bit width uint32_t subband_diff_cqi_cw1; // if RI > 1 then 2N-bit width otherwise 0-bit width uint32_t pmi; // if RI > 1 then 2-bit width otherwise 1-bit width - uint32_t N; - bool ri_present; - bool pmi_present; - bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false - bool rank_is_not_one; // If rank > 1 then true otherwise false } srslte_cqi_hl_subband_t; /* Table 5.2.2.6.3-1: Fields for channel quality information feedback for UE selected subband CQI @@ -83,7 +92,6 @@ typedef struct SRSLTE_API { uint8_t wideband_cqi; // 4-bit width uint8_t subband_diff_cqi; // 2-bit width uint32_t position_subband; // L-bit width - uint32_t L; } srslte_cqi_ue_subband_t; /* Table 5.2.3.3.1-1: Fields for channel quality information feedback for wideband CQI reports @@ -101,15 +109,11 @@ typedef struct SRSLTE_API { uint8_t wideband_cqi; // 4-bit width uint8_t spatial_diff_cqi; // If Rank==1 then it is 0-bit width otherwise it is 3-bit width uint8_t pmi; - bool pmi_present; - bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false - bool rank_is_not_one; // If rank > 1 then true otherwise false } srslte_cqi_format2_wideband_t; typedef struct SRSLTE_API { uint8_t subband_cqi; // 4-bit width uint8_t subband_label; // 1- or 2-bit width - bool subband_label_2_bits; // false, label=1-bit, true label=2-bits } srslte_cqi_format2_subband_t; typedef enum { @@ -117,7 +121,20 @@ typedef enum { SRSLTE_CQI_TYPE_SUBBAND, SRSLTE_CQI_TYPE_SUBBAND_UE, SRSLTE_CQI_TYPE_SUBBAND_HL -} srslte_cqi_type_t; +} srslte_cqi_type_t; + +typedef struct SRSLTE_API { + bool data_enable; + bool ri_present; + bool pmi_present; + bool four_antenna_ports; // If cell has 4 antenna ports then true otherwise false + bool rank_is_not_one; // If rank > 1 then true otherwise false + bool subband_label_2_bits; // false, label=1-bit, true label=2-ack_value + uint32_t L; + uint32_t N; + srslte_cqi_type_t type; + uint32_t ri_len; +} srslte_cqi_cfg_t; typedef struct { union { @@ -126,60 +143,32 @@ typedef struct { srslte_cqi_ue_subband_t subband_ue; srslte_cqi_hl_subband_t subband_hl; }; - srslte_cqi_type_t type; + bool data_crc; } srslte_cqi_value_t; +SRSLTE_API int srslte_cqi_size(srslte_cqi_cfg_t* cfg); -SRSLTE_API int srslte_cqi_size(srslte_cqi_value_t *value); - -SRSLTE_API int srslte_cqi_value_pack(srslte_cqi_value_t *value, - uint8_t buff[SRSLTE_CQI_MAX_BITS]); - -SRSLTE_API int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, - uint8_t buff[SRSLTE_CQI_MAX_BITS]); - -SRSLTE_API int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, - uint8_t buff[SRSLTE_CQI_MAX_BITS]); - -SRSLTE_API int srslte_cqi_format2_wideband_pack(srslte_cqi_format2_wideband_t *msg, - uint8_t buff[SRSLTE_CQI_MAX_BITS]); +SRSLTE_API int srslte_cqi_value_pack(srslte_cqi_cfg_t* cfg, srslte_cqi_value_t* value, uint8_t* buff); -SRSLTE_API int srslte_cqi_format2_subband_pack(srslte_cqi_format2_subband_t *msg, - uint8_t buff[SRSLTE_CQI_MAX_BITS]); +SRSLTE_API int srslte_cqi_value_unpack(srslte_cqi_cfg_t* cfg, + uint8_t buff[SRSLTE_CQI_MAX_BITS], + srslte_cqi_value_t* value); -SRSLTE_API int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], - srslte_cqi_value_t *value); +SRSLTE_API int srslte_cqi_value_tostring(srslte_cqi_cfg_t* cfg, + srslte_cqi_value_t* value, + char* buff, + uint32_t buff_len); -SRSLTE_API int srslte_cqi_value_tostring(srslte_cqi_value_t *value, char *buff, uint32_t buff_len); +SRSLTE_API bool srslte_cqi_periodic_send(srslte_cqi_report_cfg_t* periodic_cfg,uint32_t tti, srslte_frame_type_t frame_type); +SRSLTE_API bool srslte_cqi_periodic_ri_send(srslte_cqi_report_cfg_t* periodic_cfg, + uint32_t tti, + srslte_frame_type_t frame_type); -SRSLTE_API int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], - srslte_cqi_hl_subband_t *msg); - -SRSLTE_API int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], - srslte_cqi_ue_subband_t *msg); - -SRSLTE_API int srslte_cqi_format2_wideband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], - srslte_cqi_format2_wideband_t *msg); - -SRSLTE_API int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], - srslte_cqi_format2_subband_t *msg); - -SRSLTE_API bool srslte_cqi_send(uint32_t I_cqi_pmi, - uint32_t tti); - -SRSLTE_API bool srslte_ri_send(uint32_t I_cqi_pmi, - uint32_t I_ri, - uint32_t tti); +SRSLTE_API int srslte_cqi_hl_get_no_subbands(int nof_prb); SRSLTE_API uint8_t srslte_cqi_from_snr(float snr); -SRSLTE_API float srslte_cqi_to_coderate(uint32_t cqi); - -SRSLTE_API int srslte_cqi_hl_get_subband_size(int num_prbs); - -SRSLTE_API int srslte_cqi_hl_get_no_subbands(int num_prbs); - -SRSLTE_API void srslte_cqi_to_str(const uint8_t *cqi_value, int cqi_len, char *str, int str_len); +SRSLTE_API float srslte_cqi_to_coderate(uint32_t cqi); #endif // SRSLTE_CQI_H diff --git a/lib/include/srslte/phy/phch/dci.h b/lib/include/srslte/phy/phch/dci.h index 1a7bfbb0f..b1eb94ee6 100644 --- a/lib/include/srslte/phy/phch/dci.h +++ b/lib/include/srslte/phy/phch/dci.h @@ -44,42 +44,22 @@ #include "srslte/phy/phch/ra.h" #define SRSLTE_DCI_MAX_BITS 128 - #define SRSLTE_RAR_GRANT_LEN 20 -SRSLTE_API extern int harq_pid_len; - -typedef enum { - SRSLTE_DCI_FORMAT0 = 0, - SRSLTE_DCI_FORMAT1, - SRSLTE_DCI_FORMAT1A, - SRSLTE_DCI_FORMAT1C, - SRSLTE_DCI_FORMAT1B, - SRSLTE_DCI_FORMAT1D, - SRSLTE_DCI_FORMAT2, - SRSLTE_DCI_FORMAT2A, - SRSLTE_DCI_FORMAT2B, - //SRSLTE_DCI_FORMAT3, - //SRSLTE_DCI_FORMAT3A, - SRSLTE_DCI_NOF_FORMATS -} srslte_dci_format_t; - -// Each type is for a different interface to packing/unpacking functions -typedef struct SRSLTE_API { - enum { - SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED, - SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED, - SRSLTE_DCI_MSG_TYPE_MCCH_CHANGE, - SRSLTE_DCI_MSG_TYPE_TPC_COMMAND, - SRSLTE_DCI_MSG_TYPE_RA_PROC_PDCCH - } type; - srslte_dci_format_t format; -}srslte_dci_msg_type_t; - -typedef enum { - SRSLTE_DCI_SPEC_COMMON_ = 0, - SRSLTE_DCI_SPEC_UE = 1 -} dci_spec_t; +#define SRSLTE_DCI_IS_TB_EN(tb) (!(tb.mcs_idx == 0 && tb.rv == 1)) +#define SRSLTE_DCI_TB_DISABLE(tb) \ + do { \ + tb.mcs_idx = 0; \ + tb.rv = 1; \ + } while (0) +#define SRSLTE_DCI_HEXDEBUG 0 + +typedef struct { + bool multiple_csi_request_enabled; + bool cif_enabled; + bool srs_request_enabled; + bool ra_format_enabled; +} srslte_dci_cfg_t; typedef struct SRSLTE_API { uint32_t L; // Aggregation level @@ -87,110 +67,182 @@ typedef struct SRSLTE_API { } srslte_dci_location_t; typedef struct SRSLTE_API { - uint8_t data[SRSLTE_DCI_MAX_BITS]; - uint32_t nof_bits; - srslte_dci_format_t format; + uint8_t payload[SRSLTE_DCI_MAX_BITS]; + uint32_t nof_bits; + srslte_dci_location_t location; + srslte_dci_format_t format; + uint16_t rnti; } srslte_dci_msg_t; +typedef struct SRSLTE_API { + uint32_t mcs_idx; + int rv; + bool ndi; + uint32_t cw_idx; +} srslte_dci_tb_t; + +typedef struct SRSLTE_API { + + uint16_t rnti; + srslte_dci_format_t format; + srslte_dci_location_t location; + + // Resource Allocation + srslte_ra_type_t alloc_type; + union { + srslte_ra_type0_t type0_alloc; + srslte_ra_type1_t type1_alloc; + srslte_ra_type2_t type2_alloc; + }; + + // Codeword information + srslte_dci_tb_t tb[SRSLTE_MAX_CODEWORDS]; + bool tb_cw_swap; + uint32_t pinfo; + + // Power control + bool pconf; + bool power_offset; + uint8_t tpc_pucch; + + // RA order + bool is_ra_order; + uint32_t ra_preamble; + uint32_t ra_mask_idx; + + // Release 10 + uint32_t cif; + bool cif_present; + bool srs_request; + bool srs_request_present; + + // Other parameters + uint32_t pid; + uint32_t dai; + bool is_tdd; + bool is_dwpts; + bool sram_id; + + // For debugging purposes +#if SRSLTE_DCI_HEXDEBUG + uint32_t nof_bits; + char hex_str[SRSLTE_DCI_MAX_BITS]; +#endif +} srslte_dci_dl_t; + +/** Unpacked DCI Format0 message */ +typedef struct SRSLTE_API { + + uint16_t rnti; + srslte_dci_format_t format; + srslte_dci_location_t location; + + srslte_ra_type2_t type2_alloc; + /* 36.213 Table 8.4-2: SRSLTE_RA_PUSCH_HOP_HALF is 0 for < 10 Mhz and 10 for > 10 Mhz. + * SRSLTE_RA_PUSCH_HOP_QUART is 00 for > 10 Mhz and SRSLTE_RA_PUSCH_HOP_QUART_NEG is 01 for > 10 Mhz. + */ + enum { + SRSLTE_RA_PUSCH_HOP_DISABLED = -1, + SRSLTE_RA_PUSCH_HOP_QUART = 0, + SRSLTE_RA_PUSCH_HOP_QUART_NEG = 1, + SRSLTE_RA_PUSCH_HOP_HALF = 2, + SRSLTE_RA_PUSCH_HOP_TYPE2 = 3 + } freq_hop_fl; + + // Codeword information + srslte_dci_tb_t tb; + uint32_t n_dmrs; + bool cqi_request; + + // TDD parametres + uint32_t dai; + uint32_t ul_idx; + bool is_tdd; + + // Power control + uint8_t tpc_pusch; + + // Release 10 + uint32_t cif; + bool cif_present; + bool multiple_csi_request_present; + uint32_t srs_request; + bool srs_request_present; + srslte_ra_type_t ra_type; + bool ra_type_present; + + // For debugging purposes +#ifdef SRSLTE_DCI_HEXDEBUG + uint32_t nof_bits; + char hex_str[SRSLTE_DCI_MAX_BITS]; +#endif + +} srslte_dci_ul_t; + typedef struct SRSLTE_API { uint32_t rba; uint32_t trunc_mcs; uint32_t tpc_pusch; bool ul_delay; - bool cqi_request; - bool hopping_flag; + bool cqi_request; + bool hopping_flag; } srslte_dci_rar_grant_t; -/* Converts a received PDSCH DL scheduling DCI message - * to ra structures ready to be passed to the harq setup function - */ -SRSLTE_API int srslte_dci_msg_to_dl_grant(srslte_dci_msg_t *msg, - uint16_t msg_rnti, - uint32_t nof_prb, - uint32_t nof_ports, - srslte_ra_dl_dci_t *dl_dci, - srslte_ra_dl_grant_t *grant); +SRSLTE_API void srslte_dci_rar_unpack(uint8_t payload[SRSLTE_RAR_GRANT_LEN], srslte_dci_rar_grant_t* rar); + +SRSLTE_API void srslte_dci_rar_pack(srslte_dci_rar_grant_t* rar, uint8_t payload[SRSLTE_RAR_GRANT_LEN]); + +SRSLTE_API int srslte_dci_rar_to_ul_dci(srslte_cell_t* cell, srslte_dci_rar_grant_t* rar, srslte_dci_ul_t* dci_ul); + +SRSLTE_API int srslte_dci_msg_pack_pusch(srslte_cell_t* cell, + srslte_dl_sf_cfg_t* sf, + srslte_dci_cfg_t* cfg, + srslte_dci_ul_t* dci, + srslte_dci_msg_t* msg); + +SRSLTE_API int srslte_dci_msg_unpack_pusch(srslte_cell_t* cell, + srslte_dl_sf_cfg_t* sf, + srslte_dci_cfg_t* cfg, + srslte_dci_msg_t* msg, + srslte_dci_ul_t* dci); + +SRSLTE_API int srslte_dci_msg_pack_pdsch(srslte_cell_t* cell, + srslte_dl_sf_cfg_t* sf, + srslte_dci_cfg_t* cfg, srslte_dci_dl_t* dci, srslte_dci_msg_t* msg); -SRSLTE_API int srslte_dci_msg_to_ul_grant(srslte_dci_msg_t *msg, - uint32_t nof_prb, - uint32_t n_rb_ho, - srslte_ra_ul_dci_t *ul_dci, - srslte_ra_ul_grant_t *grant, - uint32_t harq_pid); +SRSLTE_API int srslte_dci_msg_unpack_pdsch(srslte_cell_t* cell, + srslte_dl_sf_cfg_t* sf, + srslte_dci_cfg_t* cfg, + srslte_dci_msg_t* msg, + srslte_dci_dl_t* dci); -SRSLTE_API int srslte_dci_rar_to_ul_grant(srslte_dci_rar_grant_t *rar, - uint32_t nof_prb, - uint32_t n_rb_ho, - srslte_ra_ul_dci_t *ul_dci, - srslte_ra_ul_grant_t *grant); +SRSLTE_API uint32_t srslte_dci_format_sizeof(srslte_cell_t* cell, + srslte_dl_sf_cfg_t* sf, + srslte_dci_cfg_t* cfg, + srslte_dci_format_t format); -SRSLTE_API void srslte_dci_rar_grant_unpack(srslte_dci_rar_grant_t *rar, - uint8_t grant[SRSLTE_RAR_GRANT_LEN]); +SRSLTE_API void srslte_dci_dl_fprint(FILE* f, + srslte_dci_dl_t* dci, + uint32_t nof_prb); -SRSLTE_API void srslte_dci_rar_grant_pack(srslte_dci_rar_grant_t *rar, - uint8_t grant[SRSLTE_RAR_GRANT_LEN]); +SRSLTE_API uint32_t srslte_dci_dl_info(srslte_dci_dl_t* dci_dl, + char* str, + uint32_t str_len); -SRSLTE_API void srslte_dci_rar_grant_fprint(FILE *stream, - srslte_dci_rar_grant_t *rar); +SRSLTE_API uint32_t srslte_dci_ul_info(srslte_dci_ul_t* dci_ul, + char* info_str, + uint32_t len); -SRSLTE_API srslte_dci_format_t srslte_dci_format_from_string(char *str); +SRSLTE_API srslte_dci_format_t srslte_dci_format_from_string(char* str); SRSLTE_API char* srslte_dci_format_string(srslte_dci_format_t format); SRSLTE_API char* srslte_dci_format_string_short(srslte_dci_format_t format); -SRSLTE_API int srslte_dci_location_set(srslte_dci_location_t *c, - uint32_t L, +SRSLTE_API int srslte_dci_location_set(srslte_dci_location_t* c, + uint32_t L, uint32_t nCCE); -SRSLTE_API bool srslte_dci_location_isvalid(srslte_dci_location_t *c); - -SRSLTE_API int srslte_dci_msg_get_type(srslte_dci_msg_t *msg, - srslte_dci_msg_type_t *type, - uint32_t nof_prb, - uint16_t msg_rnti); - -SRSLTE_API void srslte_dci_msg_type_fprint(FILE *f, - srslte_dci_msg_type_t type); - -// For srslte_dci_msg_type_t = SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED -SRSLTE_API int srslte_dci_msg_pack_pusch(srslte_ra_ul_dci_t *data, - srslte_dci_msg_t *msg, - uint32_t nof_prb); - -SRSLTE_API int srslte_dci_msg_unpack_pusch(srslte_dci_msg_t *msg, - srslte_ra_ul_dci_t *data, - uint32_t nof_prb); - -// For srslte_dci_msg_type_t = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED -SRSLTE_API int srslte_dci_msg_pack_pdsch(srslte_ra_dl_dci_t *data, - srslte_dci_format_t format, - srslte_dci_msg_t *msg, - uint32_t nof_prb, - uint32_t nof_ports, - bool crc_is_crnti); - -SRSLTE_API int srslte_dci_msg_unpack_pdsch(srslte_dci_msg_t *msg, - srslte_ra_dl_dci_t *data, - uint32_t nof_prb, - uint32_t nof_ports, - bool crc_is_crnti); - -SRSLTE_API uint32_t srslte_dci_format_sizeof(srslte_dci_format_t format, - uint32_t nof_prb, - uint32_t nof_ports); - -SRSLTE_API uint32_t srslte_dci_dl_info(char *info_str, - uint32_t str_len, - srslte_ra_dl_dci_t *dci_msg, - srslte_dci_format_t format); - -SRSLTE_API uint32_t srslte_dci_ul_info(char *info_str, - uint32_t len, - srslte_ra_ul_dci_t *dci_msg); - -// This is for backwards compatibility only for tm1 formats -SRSLTE_API uint32_t srslte_dci_format_sizeof_lut(srslte_dci_format_t format, - uint32_t nof_prb); +SRSLTE_API bool srslte_dci_location_isvalid(srslte_dci_location_t* c); #endif // DCI_ diff --git a/lib/include/srslte/phy/phch/pbch.h b/lib/include/srslte/phy/phch/pbch.h index 1e0af67cd..f67983f1f 100644 --- a/lib/include/srslte/phy/phch/pbch.h +++ b/lib/include/srslte/phy/phch/pbch.h @@ -38,16 +38,17 @@ #define SRSLTE_PBCH_H #include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_dl.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/fec/convcoder.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/fec/viterbi.h" #include "srslte/phy/mimo/layermap.h" -#include "srslte/phy/modem/mod.h" +#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/modem/mod.h" #include "srslte/phy/scrambling/scrambling.h" -#include "srslte/phy/fec/rm_conv.h" -#include "srslte/phy/fec/convcoder.h" -#include "srslte/phy/fec/viterbi.h" -#include "srslte/phy/fec/crc.h" #define SRSLTE_BCH_PAYLOAD_LEN 24 #define SRSLTE_BCH_PAYLOADCRC_LEN (SRSLTE_BCH_PAYLOAD_LEN+16) @@ -92,27 +93,22 @@ SRSLTE_API void srslte_pbch_free(srslte_pbch_t *q); SRSLTE_API int srslte_pbch_set_cell(srslte_pbch_t *q, srslte_cell_t cell); -SRSLTE_API int srslte_pbch_decode(srslte_pbch_t *q, - cf_t *slot1_symbols, - cf_t *ce_slot1[SRSLTE_MAX_PORTS], - float noise_estimate, - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], - uint32_t *nof_tx_ports, - int *sfn_offset); +SRSLTE_API int srslte_pbch_decode(srslte_pbch_t* q, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], + uint32_t* nof_tx_ports, + int* sfn_offset); -SRSLTE_API int srslte_pbch_encode(srslte_pbch_t *q, - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], - cf_t *slot1_symbols[SRSLTE_MAX_PORTS], - uint32_t frame_idx); +SRSLTE_API int srslte_pbch_encode(srslte_pbch_t* q, + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + uint32_t frame_idx); SRSLTE_API void srslte_pbch_decode_reset(srslte_pbch_t *q); -SRSLTE_API void srslte_pbch_mib_unpack(uint8_t *msg, - srslte_cell_t *cell, - uint32_t *sfn); +SRSLTE_API void srslte_pbch_mib_unpack(uint8_t* msg, srslte_cell_t* cell, uint32_t* sfn); -SRSLTE_API void srslte_pbch_mib_pack(srslte_cell_t *cell, - uint32_t sfn, - uint8_t *msg); +SRSLTE_API void srslte_pbch_mib_pack(srslte_cell_t* cell, uint32_t sfn, uint8_t* msg); #endif // SRSLTE_PBCH_H diff --git a/lib/include/srslte/phy/phch/pcfich.h b/lib/include/srslte/phy/phch/pcfich.h index 554a150a7..96415add4 100644 --- a/lib/include/srslte/phy/phch/pcfich.h +++ b/lib/include/srslte/phy/phch/pcfich.h @@ -36,13 +36,14 @@ #define SRSLTE_PCFICH_H #include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_dl.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/layermap.h" -#include "srslte/phy/modem/mod.h" +#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/modem/demod_soft.h" -#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/modem/mod.h" #include "srslte/phy/phch/regs.h" +#include "srslte/phy/scrambling/scrambling.h" #define PCFICH_CFI_LEN 32 #define PCFICH_RE PCFICH_CFI_LEN/2 @@ -73,9 +74,9 @@ typedef struct SRSLTE_API { float data_f[PCFICH_CFI_LEN]; /* tx & rx objects */ - srslte_modem_table_t mod; - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; - + srslte_modem_table_t mod; + srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME]; + } srslte_pcfich_t; SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q, @@ -87,25 +88,12 @@ SRSLTE_API int srslte_pcfich_set_cell(srslte_pcfich_t *q, SRSLTE_API void srslte_pcfich_free(srslte_pcfich_t *q); -SRSLTE_API int srslte_pcfich_decode(srslte_pcfich_t *q, - cf_t *sf_symbols, - cf_t *ce[SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t subframe, - uint32_t *cfi, - float *corr_result); - -SRSLTE_API int srslte_pcfich_decode_multi(srslte_pcfich_t *q, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t subframe, - uint32_t *cfi, - float *corr_result); - -SRSLTE_API int srslte_pcfich_encode(srslte_pcfich_t *q, - uint32_t cfi, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], - uint32_t subframe); +SRSLTE_API int srslte_pcfich_decode(srslte_pcfich_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + float* corr_result); + +SRSLTE_API int srslte_pcfich_encode(srslte_pcfich_t* q, srslte_dl_sf_cfg_t* sf, cf_t* sf_symbols[SRSLTE_MAX_PORTS]); #endif // SRSLTE_PCFICH_H diff --git a/lib/include/srslte/phy/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h index 14f7b07ab..14a464cf2 100644 --- a/lib/include/srslte/phy/phch/pdcch.h +++ b/lib/include/srslte/phy/phch/pdcch.h @@ -36,21 +36,19 @@ #define SRSLTE_PDCCH_H #include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_dl.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/mimo/precoding.h" -#include "srslte/phy/mimo/layermap.h" -#include "srslte/phy/modem/mod.h" -#include "srslte/phy/modem/demod_soft.h" -#include "srslte/phy/scrambling/scrambling.h" -#include "srslte/phy/fec/rm_conv.h" #include "srslte/phy/fec/convcoder.h" -#include "srslte/phy/fec/viterbi.h" #include "srslte/phy/fec/crc.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/fec/viterbi.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/modem/mod.h" #include "srslte/phy/phch/dci.h" #include "srslte/phy/phch/regs.h" - - - +#include "srslte/phy/scrambling/scrambling.h" typedef enum SRSLTE_API { SEARCH_UE, SEARCH_COMMON @@ -79,10 +77,10 @@ typedef struct SRSLTE_API { /* tx & rx objects */ srslte_modem_table_t mod; - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME]; srslte_viterbi_t decoder; - srslte_crc_t crc; - + srslte_crc_t crc; + } srslte_pdcch_t; SRSLTE_API int srslte_pdcch_init_ue(srslte_pdcch_t *q, @@ -96,50 +94,38 @@ SRSLTE_API int srslte_pdcch_set_cell(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell); -SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q); +SRSLTE_API void srslte_pdcch_set_regs(srslte_pdcch_t* q, srslte_regs_t* regs); +SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t* q); SRSLTE_API float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l); /* Encoding function */ -SRSLTE_API int srslte_pdcch_encode(srslte_pdcch_t *q, - srslte_dci_msg_t *msg, - srslte_dci_location_t location, - uint16_t rnti, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], - uint32_t nsubframe, - uint32_t cfi); +SRSLTE_API int srslte_pdcch_encode(srslte_pdcch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_dci_msg_t* msg, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]); /* Decoding functions: Extract the LLRs and save them in the srslte_pdcch_t object */ -SRSLTE_API int srslte_pdcch_extract_llr(srslte_pdcch_t *q, - cf_t *sf_symbols, - cf_t *ce[SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t nsubframe, - uint32_t cfi); - -SRSLTE_API int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t nsubframe, - uint32_t cfi); + +SRSLTE_API int srslte_pdcch_extract_llr(srslte_pdcch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]); /* Decoding functions: Try to decode a DCI message after calling srslte_pdcch_extract_llr */ -SRSLTE_API int srslte_pdcch_decode_msg(srslte_pdcch_t *q, - srslte_dci_msg_t *msg, - srslte_dci_location_t *location, - srslte_dci_format_t format, - uint32_t cfi, - uint16_t *crc_rem); - -SRSLTE_API int srslte_pdcch_dci_decode(srslte_pdcch_t *q, - float *e, - uint8_t *data, - uint32_t E, - uint32_t nof_bits, - uint16_t *crc); +SRSLTE_API int srslte_pdcch_decode_msg(srslte_pdcch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_dci_cfg_t* dci_cfg, + srslte_dci_msg_t* msg); + +SRSLTE_API int srslte_pdcch_dci_decode(srslte_pdcch_t* q, + float* e, + uint8_t* data, + uint32_t E, + uint32_t nof_bits, + uint16_t* crc); SRSLTE_API int srslte_pdcch_dci_encode(srslte_pdcch_t *q, uint8_t *data, @@ -155,35 +141,33 @@ SRSLTE_API void srslte_pdcch_dci_encode_conv(srslte_pdcch_t *q, uint16_t rnti); /* Function for generation of UE-specific search space DCI locations */ -SRSLTE_API uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t *q, - srslte_dci_location_t *locations, +SRSLTE_API uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_dci_location_t* locations, uint32_t max_locations, - uint32_t nsubframe, - uint32_t cfi, uint16_t rnti); -SRSLTE_API uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, - srslte_dci_location_t *c, - uint32_t max_candidates, - uint32_t nsubframe, +SRSLTE_API uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, + srslte_dci_location_t* c, + uint32_t max_candidates, + uint32_t sf_idx, uint16_t rnti); SRSLTE_API uint32_t srslte_pdcch_ue_locations_ncce_L(uint32_t nof_cce, - srslte_dci_location_t *c, + srslte_dci_location_t* c, uint32_t max_candidates, - uint32_t nsubframe, + uint32_t sf_idx, uint16_t rnti, int L); /* Function for generation of common search space DCI locations */ -SRSLTE_API uint32_t srslte_pdcch_common_locations(srslte_pdcch_t *q, - srslte_dci_location_t *locations, - uint32_t max_locations, - uint32_t cfi); - -SRSLTE_API uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, - srslte_dci_location_t *c, - uint32_t max_candidates); - +SRSLTE_API uint32_t srslte_pdcch_common_locations(srslte_pdcch_t* q, + srslte_dci_location_t* locations, + uint32_t max_locations, + uint32_t cfi); + +SRSLTE_API uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, + srslte_dci_location_t* c, + uint32_t max_candidates); #endif // SRSLTE_PDCCH_H diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 787853d0a..ad721d9a3 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -36,19 +36,20 @@ #define SRSLTE_PDSCH_H #include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_dl.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/layermap.h" -#include "srslte/phy/modem/mod.h" +#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/modem/demod_soft.h" -#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/modem/mod.h" #include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/pdsch_cfg.h" #include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/sch.h" -#include "srslte/phy/phch/pdsch_cfg.h" +#include "srslte/phy/scrambling/scrambling.h" typedef struct { - srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NOF_SF_X_FRAME]; uint32_t cell_id; bool sequence_generated; } srslte_pdsch_user_t; @@ -58,8 +59,6 @@ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t nof_rx_antennas; - uint32_t last_nof_iterations[SRSLTE_MAX_CODEWORDS]; - uint32_t max_re; uint16_t ue_rnti; @@ -67,9 +66,6 @@ typedef struct SRSLTE_API { bool llr_is_8bit; - /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ - float rho_a; - /* buffers */ // void buffers are shared for tx and rx cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ @@ -78,7 +74,6 @@ typedef struct SRSLTE_API { cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */ void *e[SRSLTE_MAX_CODEWORDS]; - bool csi_enabled; float *csi[SRSLTE_MAX_CODEWORDS]; /* Channel Strengh Indicator */ /* tx & rx objects */ @@ -95,6 +90,11 @@ typedef struct SRSLTE_API { } srslte_pdsch_t; +typedef struct { + uint8_t* payload; + bool crc; + float avg_iterations_block; +} srslte_pdsch_res_t; SRSLTE_API int srslte_pdsch_init_ue(srslte_pdsch_t *q, uint32_t max_prb, @@ -105,75 +105,48 @@ SRSLTE_API int srslte_pdsch_init_enb(srslte_pdsch_t *q, SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q); -SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t *q, - srslte_cell_t cell); +/* These functions modify the state of the object and may take some time */ +SRSLTE_API int srslte_pdsch_enable_coworker(srslte_pdsch_t* q); + +SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t* q, srslte_cell_t cell); SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti); -SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, - float rho_a); - -SRSLTE_API int srslte_pdsch_enable_csi(srslte_pdsch_t *q, - bool enable); - -SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, - uint16_t rnti); - -SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, - srslte_cell_t cell, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx, - int rvidx); - -SRSLTE_API int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, - srslte_cell_t cell, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx, - int rvidx[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t mimo_type, - uint32_t pmi); - -SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, - cf_t *sf_symbols[SRSLTE_MAX_PORTS]); - -SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - cf_t *sf_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint16_t rnti, - uint8_t *data[SRSLTE_MAX_CODEWORDS], - bool acks[SRSLTE_MAX_CODEWORDS]); - -SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t nof_ce, - uint32_t pmi[SRSLTE_MAX_LAYERS], - float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]); - -SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q, - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - uint32_t nof_ce, - float *cn); - -SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, - uint32_t max_iter); - -SRSLTE_API float srslte_pdsch_last_noi(srslte_pdsch_t *q); - -SRSLTE_API int srslte_pdsch_enable_coworker(srslte_pdsch_t *q); - -SRSLTE_API uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, - uint32_t cw_idx); +SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti); + +/* These functions do not modify the state and run in real-time */ +SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* cfg, + uint8_t* data[SRSLTE_MAX_CODEWORDS], + cf_t* sf_symbols[SRSLTE_MAX_PORTS]); + +SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* cfg, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + srslte_pdsch_res_t data[SRSLTE_MAX_CODEWORDS]); + +SRSLTE_API int srslte_pdsch_select_pmi(srslte_pdsch_t* q, + srslte_chest_dl_res_t* channel, + uint32_t nof_layers, + uint32_t* best_pmi, + float sinr[SRSLTE_MAX_CODEBOOKS]); + +SRSLTE_API int srslte_pdsch_compute_cn(srslte_pdsch_t* q, srslte_chest_dl_res_t* channel, float* cn); + +SRSLTE_API uint32_t srslte_pdsch_grant_rx_info(srslte_pdsch_grant_t* grant, + srslte_pdsch_res_t res[SRSLTE_MAX_CODEWORDS], + char* str, + uint32_t str_len); + +SRSLTE_API uint32_t srslte_pdsch_rx_info(srslte_pdsch_cfg_t* cfg, + srslte_pdsch_res_t res[SRSLTE_MAX_CODEWORDS], + char* str, + uint32_t str_len); + +SRSLTE_API uint32_t srslte_pdsch_tx_info(srslte_pdsch_cfg_t* cfg, char* str, uint32_t str_len); #endif // SRSLTE_PDSCH_H diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index 3e4849014..6657c2268 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -39,24 +39,41 @@ #include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/fec/cbsegm.h" -/* 3GPP 36.213 Table 5.2-1: The cell-specific ratio rho_B / rho_A for 1, 2, or 4 cell specific antenna ports */ -static const float pdsch_cfg_cell_specific_ratio_table[2][4] = - { /* One antenna port */ {1.0f / 1.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f}, - /* Two or more antenna port */ {5.0f / 4.0f, 1.0f / 1.0f, 3.0f / 4.0f, 1.0f / 2.0f} - }; +typedef struct SRSLTE_API { + srslte_tx_scheme_t tx_scheme; + uint32_t pmi; + bool prb_idx[2][SRSLTE_MAX_PRB]; + uint32_t nof_prb; + uint32_t nof_re; + uint32_t nof_symb_slot[2]; + srslte_ra_tb_t tb[SRSLTE_MAX_CODEWORDS]; + int last_tbs[SRSLTE_MAX_CODEWORDS]; + uint32_t nof_tb; + uint32_t nof_layers; +} srslte_pdsch_grant_t; typedef struct SRSLTE_API { - srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS]; - srslte_ra_dl_grant_t grant; - srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]; - uint32_t rv[SRSLTE_MAX_CODEWORDS]; - uint32_t sf_idx; - uint32_t nof_layers; - uint32_t codebook_idx; - srslte_mimo_type_t mimo_type; - bool tb_cw_swap; + + srslte_pdsch_grant_t grant; + + uint16_t rnti; + uint32_t max_nof_iterations; + srslte_mimo_decoder_t decoder_type; + float p_a; + uint32_t p_b; + float rs_power; + bool power_scale; + bool csi_enable; + + union { + srslte_softbuffer_tx_t* tx[SRSLTE_MAX_CODEWORDS]; + srslte_softbuffer_rx_t* rx[SRSLTE_MAX_CODEWORDS]; + } softbuffers; + + bool meas_time_en; + uint32_t meas_time_value; + } srslte_pdsch_cfg_t; #endif // SRSLTE_PDSCH_CFG_H - diff --git a/lib/include/srslte/phy/phch/phich.h b/lib/include/srslte/phy/phch/phich.h index d131dc637..0a8f24044 100644 --- a/lib/include/srslte/phy/phch/phich.h +++ b/lib/include/srslte/phy/phch/phich.h @@ -35,16 +35,15 @@ #ifndef SRSLTE_PHICH_H #define SRSLTE_PHICH_H +#include "regs.h" #include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_dl.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/layermap.h" -#include "srslte/phy/modem/mod.h" +#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/modem/mod.h" #include "srslte/phy/scrambling/scrambling.h" -#include "regs.h" - - #define SRSLTE_PHICH_NORM_NSEQUENCES 8 #define SRSLTE_PHICH_EXT_NSEQUENCES 4 @@ -61,11 +60,11 @@ /* phich object */ typedef struct SRSLTE_API { srslte_cell_t cell; - - uint32_t nof_rx_antennas; - + + uint32_t nof_rx_antennas; + /* handler to REGs resource mapper */ - srslte_regs_t *regs; + srslte_regs_t* regs; /* buffers */ cf_t ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS][SRSLTE_PHICH_MAX_NSYMB]; @@ -81,12 +80,27 @@ typedef struct SRSLTE_API { /* tx & rx objects */ srslte_modem_table_t mod; - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; - + srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME]; + } srslte_phich_t; -SRSLTE_API int srslte_phich_init(srslte_phich_t *q, - uint32_t nof_rx_antennas); +typedef struct SRSLTE_API { + uint32_t ngroup; + uint32_t nseq; +} srslte_phich_resource_t; + +typedef struct SRSLTE_API { + uint32_t n_prb_lowest; + uint32_t n_dmrs; + uint32_t I_phich; +} srslte_phich_grant_t; + +typedef struct SRSLTE_API { + bool ack_value; + float distance; +} srslte_phich_res_t; + +SRSLTE_API int srslte_phich_init(srslte_phich_t* q, uint32_t nof_rx_antennas); SRSLTE_API void srslte_phich_free(srslte_phich_t *q); @@ -94,34 +108,27 @@ SRSLTE_API int srslte_phich_set_cell(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell); -SRSLTE_API void srslte_phich_calc(srslte_phich_t *q, - uint32_t n_prb_lowest, - uint32_t n_dmrs, - uint32_t *ngroup, - uint32_t *nseq); - -SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, - cf_t *slot_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t ngroup, - uint32_t nseq, - uint32_t nsubframe, - uint8_t *ack, - float *distance); - -SRSLTE_API int srslte_phich_encode(srslte_phich_t *q, - uint8_t ack, - uint32_t ngroup, - uint32_t nseq, - uint32_t nsubframe, - cf_t *slot_symbols[SRSLTE_MAX_PORTS]); - -SRSLTE_API void srslte_phich_reset(srslte_phich_t *q, - cf_t *slot_symbols[SRSLTE_MAX_PORTS]); - -SRSLTE_API uint32_t srslte_phich_ngroups(srslte_phich_t *q); - -SRSLTE_API uint32_t srslte_phich_nsf(srslte_phich_t *q); +SRSLTE_API void srslte_phich_set_regs(srslte_phich_t* q, srslte_regs_t* regs); + +SRSLTE_API void srslte_phich_calc(srslte_phich_t* q, srslte_phich_grant_t* grant, srslte_phich_resource_t* n_phich); + +SRSLTE_API int srslte_phich_decode(srslte_phich_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_res_t* channel, + srslte_phich_resource_t n_phich, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + srslte_phich_res_t* result); + +SRSLTE_API int srslte_phich_encode(srslte_phich_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_phich_resource_t n_phich, + uint8_t ack, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]); + +SRSLTE_API void srslte_phich_reset(srslte_phich_t* q, cf_t* slot_symbols[SRSLTE_MAX_PORTS]); + +SRSLTE_API uint32_t srslte_phich_ngroups(srslte_phich_t* q); + +SRSLTE_API uint32_t srslte_phich_nsf(srslte_phich_t* q); #endif // SRSLTE_PHICH_H diff --git a/lib/include/srslte/phy/phch/pmch.h b/lib/include/srslte/phy/phch/pmch.h index 22f1458a4..7e52ce814 100644 --- a/lib/include/srslte/phy/phch/pmch.h +++ b/lib/include/srslte/phy/phch/pmch.h @@ -37,25 +37,24 @@ #include "srslte/config.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/common/sequence.h" #include "srslte/phy/mimo/layermap.h" -#include "srslte/phy/modem/mod.h" +#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/modem/demod_soft.h" -#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/modem/mod.h" #include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/sch.h" -#include "srslte/phy/common/sequence.h" - +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/phch/ra_dl.h" typedef struct { - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME]; } srslte_pmch_seq_t; typedef struct SRSLTE_API { - srslte_cbsegm_t cb_segm; - srslte_ra_dl_grant_t grant; - srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]; - uint32_t sf_idx; + srslte_pdsch_cfg_t pdsch_cfg; + uint16_t area_id; } srslte_pmch_cfg_t; /* PMCH object */ @@ -84,69 +83,29 @@ typedef struct SRSLTE_API { } srslte_pmch_t; +SRSLTE_API int srslte_pmch_init(srslte_pmch_t* q, uint32_t max_prb, uint32_t nof_rx_antennas); -SRSLTE_API int srslte_pmch_init(srslte_pmch_t *q, - uint32_t max_prb); - -SRSLTE_API int srslte_pmch_init_multi(srslte_pmch_t *q, - uint32_t max_prb, - uint32_t nof_rx_antennas); - -SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q); - -SRSLTE_API int srslte_pmch_set_cell(srslte_pmch_t *q, srslte_cell_t cell); - -SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id); - -SRSLTE_API void srslte_pmch_free_area_id(srslte_pmch_t *q, uint16_t area_id); - - - -SRSLTE_API int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart); - -SRSLTE_API int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart); - -SRSLTE_API int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put); - - - -SRSLTE_API float srslte_pmch_coderate(uint32_t tbs, - uint32_t nof_re); - +SRSLTE_API void srslte_pmch_free(srslte_pmch_t* q); -SRSLTE_API int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, - srslte_cell_t cell, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx); +SRSLTE_API int srslte_pmch_set_cell(srslte_pmch_t* q, srslte_cell_t cell); -SRSLTE_API int srslte_pmch_encode(srslte_pmch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint16_t area_id, - cf_t *sf_symbols[SRSLTE_MAX_PORTS]); +SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t* q, uint16_t area_id); -SRSLTE_API int srslte_pmch_decode(srslte_pmch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce[SRSLTE_MAX_PORTS], - float noise_estimate, - uint16_t area_id, - uint8_t *data); +SRSLTE_API void srslte_pmch_free_area_id(srslte_pmch_t* q, uint16_t area_id); -SRSLTE_API int srslte_pmch_decode_multi(srslte_pmch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint16_t area_id, - uint8_t *data); +SRSLTE_API void srslte_configure_pmch(srslte_pmch_cfg_t* pmch_cfg, srslte_cell_t* cell, srslte_mbsfn_cfg_t* mbsfn_cfg); -SRSLTE_API float srslte_pmch_average_noi(srslte_pmch_t *q); +SRSLTE_API int srslte_pmch_encode(srslte_pmch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pmch_cfg_t* cfg, + uint8_t* data, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]); -SRSLTE_API uint32_t srslte_pmch_last_noi(srslte_pmch_t *q); +SRSLTE_API int srslte_pmch_decode(srslte_pmch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pmch_cfg_t* cfg, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + srslte_pdsch_res_t* data); #endif // SRSLTE_PMCH_H diff --git a/lib/include/srslte/phy/phch/prach.h b/lib/include/srslte/phy/phch/prach.h index 27c59d394..e1623644b 100644 --- a/lib/include/srslte/phy/phch/prach.h +++ b/lib/include/srslte/phy/phch/prach.h @@ -99,7 +99,10 @@ typedef struct SRSLTE_API { uint32_t deadzone; float peak_values[65]; uint32_t peak_offsets[65]; - + + srslte_tdd_config_t tdd_config; + uint32_t current_prach_idx; + } srslte_prach_t; typedef struct SRSLTE_API { @@ -117,9 +120,21 @@ typedef struct { uint32_t root_seq_idx; uint32_t zero_corr_zone; uint32_t freq_offset; - bool hs_flag; -} srslte_prach_cfg_t; + bool hs_flag; + srslte_tdd_config_t tdd_config; +} srslte_prach_cfg_t; +typedef struct SRSLTE_API { + uint32_t f; + uint32_t t0; + uint32_t t1; + uint32_t t2; +} srslte_prach_tdd_loc_t; + +typedef struct SRSLTE_API { + uint32_t nof_elems; + srslte_prach_tdd_loc_t elems[6]; +} srslte_prach_tdd_loc_table_t; SRSLTE_API uint32_t srslte_prach_get_preamble_format(uint32_t config_idx); @@ -129,38 +144,55 @@ SRSLTE_API bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe); -SRSLTE_API bool srslte_prach_tti_opportunity_config(uint32_t config_idx, - uint32_t current_tti, - int allowed_subframe); +SRSLTE_API bool srslte_prach_tti_opportunity_config_fdd(uint32_t config_idx, + uint32_t current_tti, + int allowed_subframe); + +SRSLTE_API bool srslte_prach_tti_opportunity_config_tdd(uint32_t config_idx, + uint32_t tdd_ul_dl_config, + uint32_t current_tti, + uint32_t* prach_idx); + +SRSLTE_API uint32_t srslte_prach_f_ra_tdd(uint32_t config_idx, + uint32_t tdd_ul_dl_config, + uint32_t current_tti, + uint32_t prach_idx, + uint32_t prach_offset, + uint32_t n_rb_ul); + +SRSLTE_API uint32_t srslte_prach_f_id_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config, uint32_t prach_idx); + +SRSLTE_API uint32_t srslte_prach_nof_f_idx_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config); + +SRSLTE_API void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t* sf_config); -SRSLTE_API void srslte_prach_sf_config(uint32_t config_idx, - srslte_prach_sf_config_t *sf_config); +SRSLTE_API int srslte_prach_init(srslte_prach_t* p, uint32_t max_N_ifft_ul); -SRSLTE_API int srslte_prach_init(srslte_prach_t *p, - uint32_t max_N_ifft_ul); +SRSLTE_API int srslte_prach_set_cell_fdd(srslte_prach_t* p, + uint32_t N_ifft_ul, + uint32_t config_idx, + uint32_t root_seq_index, + bool high_speed_flag, + uint32_t zero_corr_zone_config); -SRSLTE_API int srslte_prach_set_cell(srslte_prach_t *p, - uint32_t N_ifft_ul, - uint32_t config_idx, - uint32_t root_seq_index, - bool high_speed_flag, - uint32_t zero_corr_zone_config); +SRSLTE_API int srslte_prach_set_cell_tdd(srslte_prach_t* p, + uint32_t N_ifft_ul, + uint32_t config_idx, + uint32_t root_seq_index, + bool high_speed_flag, + uint32_t zero_corr_zone_config, + srslte_tdd_config_t* tdd_config); -SRSLTE_API int srslte_prach_init_cfg(srslte_prach_t* p, - srslte_prach_cfg_t* cfg, - uint32_t nof_prb); +SRSLTE_API int srslte_prach_set_cfg(srslte_prach_t* p, srslte_prach_cfg_t* cfg, uint32_t nof_prb); -SRSLTE_API int srslte_prach_gen(srslte_prach_t *p, - uint32_t seq_index, - uint32_t freq_offset, - cf_t *signal); +SRSLTE_API int srslte_prach_gen(srslte_prach_t* p, uint32_t seq_index, uint32_t freq_offset, cf_t* signal); -SRSLTE_API int srslte_prach_detect(srslte_prach_t *p, +SRSLTE_API int srslte_prach_detect(srslte_prach_t* p, uint32_t freq_offset, - cf_t *signal, + cf_t* signal, uint32_t sig_len, - uint32_t *indices, - uint32_t *ind_len); + uint32_t* indices, + uint32_t* ind_len); SRSLTE_API int srslte_prach_detect_offset(srslte_prach_t *p, uint32_t freq_offset, @@ -171,8 +203,7 @@ SRSLTE_API int srslte_prach_detect_offset(srslte_prach_t *p, float *peak_to_avg, uint32_t *ind_len); -SRSLTE_API void srslte_prach_set_detect_factor(srslte_prach_t *p, - float factor); +SRSLTE_API void srslte_prach_set_detect_factor(srslte_prach_t *p, float factor); SRSLTE_API int srslte_prach_free(srslte_prach_t *p); diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index 20b1b2ed4..b2c88dd42 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -36,88 +36,55 @@ #define SRSLTE_PUCCH_H #include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/sequence.h" #include "srslte/phy/modem/mod.h" #include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/pucch_cfg.h" #include "srslte/phy/phch/uci.h" -#define SRSLTE_PUCCH_N_SEQ 12 -#define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B -#define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS +#define SRSLTE_PUCCH_N_SEQ 12 +#define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B +#define SRSLTE_PUCCH3_NOF_BITS (4 * SRSLTE_NRE) +#define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS #define SRSLTE_PUCCH_MAX_SYMBOLS 128 -typedef enum SRSLTE_API { - SRSLTE_PUCCH_FORMAT_1 = 0, - SRSLTE_PUCCH_FORMAT_1A, - SRSLTE_PUCCH_FORMAT_1B, - SRSLTE_PUCCH_FORMAT_2, - SRSLTE_PUCCH_FORMAT_2A, - SRSLTE_PUCCH_FORMAT_2B, - SRSLTE_PUCCH_FORMAT_ERROR, -} srslte_pucch_format_t; +typedef struct { + srslte_sequence_t seq_f2[SRSLTE_NOF_SF_X_FRAME]; + uint32_t cell_id; + bool sequence_generated; +} srslte_pucch_user_t; +/* PUCCH object */ typedef struct SRSLTE_API { - bool sps_enabled; - uint32_t tpc_for_pucch; - uint32_t N_pucch_1; - uint32_t n_pucch_1[4]; // 4 n_pucch resources specified by RRC - uint32_t n_pucch_2; - uint32_t n_pucch_sr; -}srslte_pucch_sched_t; + srslte_cell_t cell; + srslte_modem_table_t mod; -typedef struct SRSLTE_API { - // Common configuration - uint32_t delta_pucch_shift; - uint32_t n_rb_2; - uint32_t N_cs; - uint32_t n1_pucch_an; - - // SRS configuration - bool srs_configured; - uint32_t srs_cs_subf_cfg; - bool srs_simul_ack; -} srslte_pucch_cfg_t; - -typedef struct { - srslte_sequence_t seq_f2[SRSLTE_NSUBFRAMES_X_FRAME]; - uint32_t cell_id; - bool sequence_generated; -} srslte_pucch_user_t; + srslte_uci_cqi_pucch_t cqi; -/* PUCCH object */ -typedef struct SRSLTE_API { - srslte_cell_t cell; - srslte_pucch_cfg_t pucch_cfg; - srslte_modem_table_t mod; - - srslte_uci_cqi_pucch_t cqi; - - srslte_pucch_user_t **users; - - uint8_t bits_scram[SRSLTE_PUCCH_MAX_BITS]; - cf_t d[SRSLTE_PUCCH_MAX_BITS/2]; - uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]; + srslte_pucch_user_t** users; + srslte_sequence_t tmp_seq; + uint16_t ue_rnti; + bool is_ue; + + uint8_t bits_scram[SRSLTE_PUCCH_MAX_BITS]; + cf_t d[SRSLTE_PUCCH_MAX_BITS / 2]; + uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]; uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME]; - float tmp_arg[SRSLTE_PUCCH_N_SEQ]; - + float tmp_arg[SRSLTE_PUCCH_N_SEQ]; + cf_t *z; cf_t *z_tmp; cf_t *ce; - - bool shortened; - bool group_hopping_en; - float threshold_format1; - float last_corr; - uint32_t last_n_prb; - uint32_t last_n_pucch; - - srslte_sequence_t tmp_seq; - uint16_t ue_rnti; - bool is_ue; -}srslte_pucch_t; +} srslte_pucch_t; +typedef struct SRSLTE_API { + srslte_uci_value_t uci_data; + float correlation; + bool detected; +} srslte_pucch_res_t; SRSLTE_API int srslte_pucch_init_ue(srslte_pucch_t *q); @@ -125,96 +92,67 @@ SRSLTE_API int srslte_pucch_init_enb(srslte_pucch_t *q); SRSLTE_API void srslte_pucch_free(srslte_pucch_t *q); -SRSLTE_API int srslte_pucch_set_cell(srslte_pucch_t *q, - srslte_cell_t cell); - -SRSLTE_API bool srslte_pucch_set_cfg(srslte_pucch_t* q, - srslte_pucch_cfg_t* cfg, - bool group_hopping_en); - -SRSLTE_API void srslte_pucch_set_threshold(srslte_pucch_t *q, - float format1_threshold); - -SRSLTE_API int srslte_pucch_set_crnti(srslte_pucch_t *q, - uint16_t c_rnti); - -SRSLTE_API void srslte_pucch_clear_rnti(srslte_pucch_t *q, - uint16_t rnti); - -SRSLTE_API uint32_t srslte_pucch_nof_symbols(srslte_pucch_cfg_t *cfg, - srslte_pucch_format_t format, - bool shortened); - -SRSLTE_API float srslte_pucch_get_last_corr(srslte_pucch_t* q); - -SRSLTE_API int srslte_pucch_encode(srslte_pucch_t *q, - srslte_pucch_format_t format, - uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format - uint32_t sf_idx, - uint16_t rnti, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS], - cf_t *sf_symbols); - -SRSLTE_API int srslte_pucch_decode(srslte_pucch_t *q, - srslte_pucch_format_t format, - uint32_t n_pucch, // n_pucch_1 or n_pucch_2 depending on format - uint32_t sf_idx, - uint16_t rnti, - cf_t *sf_symbols, - cf_t *ce, - float noise_estimate, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS], - uint32_t nof_bits); - -SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], - srslte_pucch_cfg_t *cfg, - uint32_t n_pucch, - srslte_cp_t cp, - bool is_dmrs, - uint32_t ns, - uint32_t l, - uint32_t *n_oc, - uint32_t *n_prime_ns); - -SRSLTE_API float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], - srslte_pucch_cfg_t *cfg, - uint32_t n_pucch, - uint32_t ns, - uint32_t l); - -SRSLTE_API uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, - srslte_pucch_format_t format, - uint32_t n_pucch, - srslte_cp_t cp); - -SRSLTE_API srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, - srslte_cp_t cp); - -SRSLTE_API uint32_t srslte_pucch_get_npucch(uint32_t n_cce, - srslte_pucch_format_t format, - bool has_scheduling_request, - srslte_pucch_sched_t *pucch_sched); - -SRSLTE_API uint32_t srslte_pucch_n_prb(srslte_pucch_cfg_t *cfg, - srslte_pucch_format_t format, - uint32_t n_pucch, - uint32_t nof_prb, - srslte_cp_t cp, - uint32_t ns); - -SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell, - uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]); - -SRSLTE_API int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, - uint8_t bits[2], - cf_t *d_10); - -SRSLTE_API bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t *cfg, - uint32_t nof_prb); - -SRSLTE_API bool srslte_n_pucch_isvalid(srslte_pucch_t *q, - uint32_t n_pucch); - -SRSLTE_API void srslte_pucch_cfg_default(srslte_pucch_cfg_t *cfg); +/* These functions modify the state of the object and may take some time */ +SRSLTE_API int srslte_pucch_set_cell(srslte_pucch_t* q, srslte_cell_t cell); + +SRSLTE_API int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti); + +SRSLTE_API void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti); + +/* These functions do not modify the state and run in real-time */ +SRSLTE_API void srslte_pucch_uci_gen_cfg(srslte_pucch_t* q, srslte_pucch_cfg_t* cfg, srslte_uci_data_t* uci_data); + +SRSLTE_API int srslte_pucch_encode(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + srslte_uci_value_t* uci_data, + cf_t* sf_symbols); + +SRSLTE_API int srslte_pucch_decode(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + srslte_chest_ul_res_t* channel, + cf_t* sf_symbols, + srslte_pucch_res_t* data); + +/* Other utilities. These functions do not modify the state and run in real-time */ +SRSLTE_API float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], + srslte_pucch_cfg_t* cfg, + srslte_cp_t cp, + bool is_dmrs, + uint32_t ns, + uint32_t l, + uint32_t* n_oc, + uint32_t* n_prime_ns); + +SRSLTE_API float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], + srslte_pucch_cfg_t* cfg, + uint32_t ns, + uint32_t l); + +SRSLTE_API int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uint8_t bits[2], cf_t* d_10); + +SRSLTE_API uint32_t srslte_pucch_m(srslte_pucch_cfg_t* cfg, srslte_cp_t cp); + +SRSLTE_API uint32_t srslte_pucch_n_prb(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns); + +SRSLTE_API int srslte_pucch_n_cs_cell(srslte_cell_t cell, + uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]); + +SRSLTE_API char* srslte_pucch_format_text(srslte_pucch_format_t format); + +SRSLTE_API char* srslte_pucch_format_text_short(srslte_pucch_format_t format); + +SRSLTE_API void srslte_pucch_tx_info(srslte_pucch_cfg_t* cfg, + srslte_uci_value_t* uci_data, + char* str, + uint32_t str_len); + +SRSLTE_API void srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, + srslte_uci_value_t* uci_data, + char* str, + uint32_t str_len); + +SRSLTE_API bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t* cfg, uint32_t nof_prb); #endif // SRSLTE_PUCCH_H diff --git a/lib/include/srslte/phy/phch/pucch_cfg.h b/lib/include/srslte/phy/phch/pucch_cfg.h new file mode 100644 index 000000000..b69e9282b --- /dev/null +++ b/lib/include/srslte/phy/phch/pucch_cfg.h @@ -0,0 +1,86 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSLTE_PUCCH_CFG_H +#define SRSLTE_PUCCH_CFG_H + +#include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/uci_cfg.h" + +#define SRSLTE_PUCCH_SIZE_AN_CS 4 +#define SRSLTE_PUCCH_NOF_AN_CS 2 +#define SRSLTE_PUCCH2_MAX_DMRS_BITS 16 + +typedef enum SRSLTE_API { + SRSLTE_PUCCH_FORMAT_1 = 0, + SRSLTE_PUCCH_FORMAT_1A, + SRSLTE_PUCCH_FORMAT_1B, + SRSLTE_PUCCH_FORMAT_2, + SRSLTE_PUCCH_FORMAT_2A, + SRSLTE_PUCCH_FORMAT_2B, + SRSLTE_PUCCH_FORMAT_3, + SRSLTE_PUCCH_FORMAT_ERROR, +} srslte_pucch_format_t; + +typedef struct SRSLTE_API { + // Input configuration for this subframe + uint16_t rnti; + + // UCI configuration + srslte_uci_cfg_t uci_cfg; + + // Common configuration + uint32_t delta_pucch_shift; + uint32_t n_rb_2; + uint32_t N_cs; + uint32_t N_pucch_1; + bool group_hopping_en; // common pusch config + + // Dedicated PUCCH configuration + uint32_t I_sr; + bool sr_configured; + uint32_t n_pucch_1[4]; // 4 n_pucch resources specified by RRC + uint32_t n_pucch_2; + uint32_t n_pucch_sr; + bool simul_cqi_ack; + bool tdd_ack_bundle; // if false, multiplex + bool sps_enabled; + uint32_t tpc_for_pucch; + + // Release 10 CA specific + srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode; + uint32_t n1_pucch_an_cs[SRSLTE_PUCCH_SIZE_AN_CS][SRSLTE_PUCCH_NOF_AN_CS]; + uint32_t n3_pucch_an_list[SRSLTE_PUCCH_SIZE_AN_CS]; + + // Other configuration + float threshold_format1; + float threshold_data_valid_format1a; + float threshold_data_valid_format2; + + // PUCCH configuration generated during a call to encode/decode + srslte_pucch_format_t format; + uint32_t n_pucch; + uint8_t pucch2_drs_bits[SRSLTE_PUCCH2_MAX_DMRS_BITS]; + +} srslte_pucch_cfg_t; + +#endif // SRSLTE_PUCCH_CFG_H diff --git a/lib/include/srslte/phy/phch/pusch.h b/lib/include/srslte/phy/phch/pusch.h index 027fc02b2..8280fa5ab 100644 --- a/lib/include/srslte/phy/phch/pusch.h +++ b/lib/include/srslte/phy/phch/pusch.h @@ -49,28 +49,17 @@ #include "srslte/phy/dft/dft_precoding.h" #include "srslte/phy/ch_estimation/refsignal_ul.h" -#define SRSLTE_PUSCH_MAX_TDEC_ITERS 5 - -typedef struct { - enum { - SRSLTE_PUSCH_HOP_MODE_INTER_SF = 1, - SRSLTE_PUSCH_HOP_MODE_INTRA_SF = 0 - } hop_mode; - uint32_t hopping_offset; - uint32_t n_sb; -} srslte_pusch_hopping_cfg_t; - typedef struct { - srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; - uint32_t cell_id; - bool sequence_generated; + srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME]; + uint32_t cell_id; + bool sequence_generated; } srslte_pusch_user_t; /* PUSCH object */ typedef struct SRSLTE_API { srslte_cell_t cell; - bool is_ue; + bool is_ue; uint16_t ue_rnti; uint32_t max_re; @@ -89,17 +78,25 @@ typedef struct SRSLTE_API { /* tx & rx objects */ srslte_modem_table_t mod[4]; - srslte_sequence_t seq_type2_fo; - + srslte_sch_t ul_sch; + // This is to generate the scrambling seq for multiple CRNTIs srslte_pusch_user_t **users; srslte_sequence_t tmp_seq; - srslte_sch_t ul_sch; - bool shortened; - -}srslte_pusch_t; +} srslte_pusch_t; +typedef struct SRSLTE_API { + uint8_t* ptr; + srslte_uci_value_t uci; +} srslte_pusch_data_t; + +typedef struct SRSLTE_API { + uint8_t* data; + srslte_uci_value_t uci; + bool crc; + float avg_iterations_block; +} srslte_pusch_res_t; SRSLTE_API int srslte_pusch_init_ue(srslte_pusch_t *q, uint32_t max_prb); @@ -109,46 +106,40 @@ SRSLTE_API int srslte_pusch_init_enb(srslte_pusch_t *q, SRSLTE_API void srslte_pusch_free(srslte_pusch_t *q); +/* These functions modify the state of the object and may take some time */ SRSLTE_API int srslte_pusch_set_cell(srslte_pusch_t *q, srslte_cell_t cell); -SRSLTE_API int srslte_pusch_cfg(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_ra_ul_grant_t *grant, - srslte_uci_cfg_t *uci_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t tti, - uint32_t rv_idx, - uint32_t current_tx_nb); - -SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t *q, - uint16_t rnti); +SRSLTE_API int srslte_pusch_set_rnti(srslte_pusch_t* q, uint16_t rnti); SRSLTE_API void srslte_pusch_free_rnti(srslte_pusch_t *q, uint16_t rnti); -SRSLTE_API int srslte_pusch_encode(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - srslte_uci_data_t uci_data, - uint16_t rnti, - cf_t *sf_symbols); - -SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce, - float noise_estimate, - uint16_t rnti, - uint8_t *data, - srslte_cqi_value_t *cqi_value, - srslte_uci_data_t *uci_data); - -SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q); - -SRSLTE_API uint32_t srslte_pusch_last_noi(srslte_pusch_t *q); +/* These functions do not modify the state and run in real-time */ +SRSLTE_API int srslte_pusch_encode(srslte_pusch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_cfg_t* cfg, + srslte_pusch_data_t* data, + cf_t* sf_symbols); + +SRSLTE_API int srslte_pusch_decode(srslte_pusch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_cfg_t* cfg, + srslte_chest_ul_res_t* channel, + cf_t* sf_symbols, + srslte_pusch_res_t* data); + +SRSLTE_API uint32_t srslte_pusch_grant_tx_info(srslte_pusch_grant_t* grant, + srslte_uci_cfg_t* uci_cfg, + srslte_uci_value_t* uci_data, + char* str, + uint32_t str_len); + +SRSLTE_API uint32_t srslte_pusch_tx_info(srslte_pusch_cfg_t* cfg, + srslte_uci_value_t* uci_data, + char* str, + uint32_t str_len); + +SRSLTE_API uint32_t srslte_pusch_rx_info(srslte_pusch_cfg_t* cfg, srslte_pusch_res_t* res, char* str, uint32_t str_len); #endif // SRSLTE_PUSCH_H diff --git a/lib/include/srslte/phy/phch/pusch_cfg.h b/lib/include/srslte/phy/phch/pusch_cfg.h index ed3239cab..179ff1bff 100644 --- a/lib/include/srslte/phy/phch/pusch_cfg.h +++ b/lib/include/srslte/phy/phch/pusch_cfg.h @@ -24,38 +24,66 @@ * */ -/****************************************************************************** - * File: pdsch_cfg.h - * - * Description: Physical downlink shared channel configuration - * - * Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6.4 - *****************************************************************************/ - #ifndef SRSLTE_PUSCH_CFG_H #define SRSLTE_PUSCH_CFG_H -#include "srslte/phy/phch/ra.h" #include "srslte/phy/fec/softbuffer.h" -#include "srslte/phy/fec/cbsegm.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/uci_cfg.h" typedef struct SRSLTE_API { uint32_t I_offset_cqi; uint32_t I_offset_ri; uint32_t I_offset_ack; -} srslte_uci_cfg_t; +} srslte_uci_offset_cfg_t; + +typedef struct { + enum { SRSLTE_PUSCH_HOP_MODE_INTER_SF = 1, SRSLTE_PUSCH_HOP_MODE_INTRA_SF = 0 } hop_mode; + uint32_t hopping_offset; + uint32_t n_sb; + uint32_t n_rb_ho; + uint32_t current_tx_nb; + bool hopping_enabled; +} srslte_pusch_hopping_cfg_t; typedef struct SRSLTE_API { - srslte_cbsegm_t cb_segm; - srslte_ra_ul_grant_t grant; - srslte_ra_nbits_t nbits; - srslte_uci_cfg_t uci_cfg; - uint32_t rv; - uint32_t sf_idx; - uint32_t tti; - srslte_cp_t cp; + + bool is_from_rar; + uint32_t L_prb; + uint32_t n_prb[2]; // rb_start after frequency hopping + uint32_t n_prb_tilde[2]; // rb_start after frequency hopping per retx + uint32_t freq_hopping; + uint32_t nof_re; + uint32_t nof_symb; + srslte_ra_tb_t tb; + srslte_ra_tb_t last_tb; + uint32_t n_dmrs; + +} srslte_pusch_grant_t; + +typedef struct SRSLTE_API { + + uint16_t rnti; + + srslte_uci_cfg_t uci_cfg; + srslte_uci_offset_cfg_t uci_offset; + srslte_pusch_grant_t grant; + + uint32_t max_nof_iterations; uint32_t last_O_cqi; + uint32_t K_segm; + uint32_t current_tx_nb; + bool csi_enable; + bool enable_64qam; + + union { + srslte_softbuffer_tx_t* tx; + srslte_softbuffer_rx_t* rx; + } softbuffers; + + bool meas_time_en; + uint32_t meas_time_value; + } srslte_pusch_cfg_t; #endif // SRSLTE_PUSCH_CFG_H - diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 38c709f2f..db5b33605 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -27,8 +27,7 @@ /****************************************************************************** * File: ra.h * - * Description: Structures and utility functions for DL/UL resource allocation. - * Convert an UL/DL unpacket DCI message to a resource allocation + * Description: Implements Resource allocation Procedures common in for DL and UL * * Reference: 3GPP TS 36.213 version 10.0.1 Release 10 *****************************************************************************/ @@ -43,27 +42,24 @@ #include "srslte/phy/common/phy_common.h" /************************************************** - * Common structures used for Resource Allocation + * Common structures used for Resource Allocation **************************************************/ typedef struct SRSLTE_API { srslte_mod_t mod; - int tbs; - uint32_t idx; -} srslte_ra_mcs_t; + int tbs; + int rv; + uint32_t nof_bits; + uint32_t cw_idx; + bool enabled; - -/* Structure that gives the number of encoded bits and RE for a UL/DL grant */ -typedef struct { - uint32_t lstart; - uint32_t nof_symb; - uint32_t nof_bits; - uint32_t nof_re; -} srslte_ra_nbits_t; + // this is for debugging and metrics purposes + uint32_t mcs_idx; +} srslte_ra_tb_t; typedef enum SRSLTE_API { - SRSLTE_RA_ALLOC_TYPE0 = 0, - SRSLTE_RA_ALLOC_TYPE1 = 1, + SRSLTE_RA_ALLOC_TYPE0 = 0, + SRSLTE_RA_ALLOC_TYPE1 = 1, SRSLTE_RA_ALLOC_TYPE2 = 2 } srslte_ra_type_t; @@ -74,13 +70,11 @@ typedef struct SRSLTE_API { typedef struct SRSLTE_API { uint32_t vrb_bitmask; uint32_t rbg_subset; - bool shift; + bool shift; } srslte_ra_type1_t; typedef struct SRSLTE_API { uint32_t riv; // if L_crb==0, DCI message packer will take this value directly - uint32_t L_crb; - uint32_t RB_start; enum { SRSLTE_RA_TYPE2_NPRB1A_2 = 0, SRSLTE_RA_TYPE2_NPRB1A_3 = 1 } n_prb1a; @@ -92,218 +86,34 @@ typedef struct SRSLTE_API { } mode; } srslte_ra_type2_t; - - - -/************************************************** - * Structures used for Downlink Resource Allocation - **************************************************/ - -typedef struct SRSLTE_API { - bool prb_idx[2][SRSLTE_MAX_PRB]; - uint32_t nof_prb; - uint32_t Qm[SRSLTE_MAX_CODEWORDS]; - srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; - srslte_sf_t sf_type; - bool tb_en[SRSLTE_MAX_CODEWORDS]; - uint32_t pinfo; - bool tb_cw_swap; -} srslte_ra_dl_grant_t; - -#define SRSLTE_RA_DL_GRANT_NOF_TB(G) ((((G)->tb_en[0])?1:0)+(((G)->tb_en[1])?1:0)) - -/** Unpacked DCI message for DL grant */ -typedef struct SRSLTE_API { - - srslte_ra_type_t alloc_type; - union { - srslte_ra_type0_t type0_alloc; - srslte_ra_type1_t type1_alloc; - srslte_ra_type2_t type2_alloc; - }; - - uint32_t harq_process; - uint32_t mcs_idx; - int rv_idx; - bool ndi; - uint32_t mcs_idx_1; - int rv_idx_1; - bool ndi_1; - - bool tb_cw_swap; - bool sram_id; - uint8_t pinfo; - bool pconf; - bool power_offset; - - uint8_t tpc_pucch; - - bool tb_en[2]; - - bool is_ra_order; - uint32_t ra_preamble; - uint32_t ra_mask_idx; - - bool dci_is_1a; - bool dci_is_1c; -} srslte_ra_dl_dci_t; - - - - - -/************************************************** - * Structures used for Uplink Resource Allocation - **************************************************/ - -typedef struct SRSLTE_API { - uint32_t n_prb[2]; - uint32_t n_prb_tilde[2]; - uint32_t L_prb; - uint32_t freq_hopping; - uint32_t M_sc; - uint32_t M_sc_init; - uint32_t Qm; - srslte_ra_mcs_t mcs; - uint32_t ncs_dmrs; -} srslte_ra_ul_grant_t; - -/** Unpacked DCI Format0 message */ -typedef struct SRSLTE_API { - /* 36.213 Table 8.4-2: SRSLTE_RA_PUSCH_HOP_HALF is 0 for < 10 Mhz and 10 for > 10 Mhz. - * SRSLTE_RA_PUSCH_HOP_QUART is 00 for > 10 Mhz and SRSLTE_RA_PUSCH_HOP_QUART_NEG is 01 for > 10 Mhz. - */ - enum { - SRSLTE_RA_PUSCH_HOP_DISABLED = -1, - SRSLTE_RA_PUSCH_HOP_QUART = 0, - SRSLTE_RA_PUSCH_HOP_QUART_NEG = 1, - SRSLTE_RA_PUSCH_HOP_HALF = 2, - SRSLTE_RA_PUSCH_HOP_TYPE2 = 3 - } freq_hop_fl; - - srslte_ra_ul_grant_t prb_alloc; - - srslte_ra_type2_t type2_alloc; - uint32_t mcs_idx; - uint32_t rv_idx; - uint32_t n_dmrs; - bool ndi; - bool cqi_request; - uint8_t tpc_pusch; - -} srslte_ra_ul_dci_t; - -typedef union { - srslte_ra_ul_grant_t ul; - srslte_ra_dl_grant_t dl; -} srslte_phy_grant_t; - -#define SRSLTE_PHY_GRANT_LEN sizeof(srslte_phy_grant_t) - - -/************************************************** - * Functions - **************************************************/ - -SRSLTE_API int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, - uint32_t nof_prb, - uint16_t rnti, - srslte_ra_dl_grant_t *grant); - -SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, - uint32_t cfi, - srslte_cell_t cell, - uint32_t sf_idx, - srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]); - -SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, - uint32_t nof_prb, - uint32_t nof_ctrl_symbols); - -SRSLTE_API uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, - srslte_cell_t cell, - uint32_t sf_idx, - uint32_t nof_ctrl_symbols); - -SRSLTE_API int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, - uint32_t nof_prb, - uint32_t n_rb_ho, - srslte_ra_ul_grant_t *grant); - -SRSLTE_API void srslte_ra_ul_grant_to_nbits(srslte_ra_ul_grant_t *grant, - srslte_cp_t cp, - uint32_t N_srs, - srslte_ra_nbits_t *nbits); - -SRSLTE_API int srslte_ra_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, - srslte_ra_ul_grant_t *grant, - uint32_t n_rb_ho, - uint32_t nof_prb); - -SRSLTE_API int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, - srslte_ra_dl_grant_t *grant, - uint32_t nof_prb); - -SRSLTE_API int srslte_ra_dl_tbs_idx_from_mcs(uint32_t mcs); - -SRSLTE_API int srslte_ra_ul_tbs_idx_from_mcs(uint32_t mcs); - -SRSLTE_API srslte_mod_t srslte_ra_dl_mod_from_mcs(uint32_t mcs); - -SRSLTE_API srslte_mod_t srslte_ra_ul_mod_from_mcs(uint32_t mcs); - -SRSLTE_API int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx); - -SRSLTE_API int srslte_ra_ul_mcs_from_tbs_idx(uint32_t tbs_idx); - -SRSLTE_API int srslte_ra_tbs_from_idx(uint32_t tbs_idx, - uint32_t n_prb); - -SRSLTE_API int srslte_ra_tbs_to_table_idx(uint32_t tbs, - uint32_t n_prb); - SRSLTE_API uint32_t srslte_ra_type0_P(uint32_t nof_prb); -SRSLTE_API uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, - uint32_t RB_start, - uint32_t nof_prb); - -SRSLTE_API void srslte_ra_type2_from_riv(uint32_t riv, - uint32_t *L_crb, - uint32_t *RB_start, - uint32_t nof_prb, - uint32_t nof_vrb); - -SRSLTE_API uint32_t srslte_ra_type2_n_vrb_dl(uint32_t nof_prb, - bool ngap_is_1); +SRSLTE_API uint32_t srslte_ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1); SRSLTE_API uint32_t srslte_ra_type2_n_rb_step(uint32_t nof_prb); -SRSLTE_API uint32_t srslte_ra_type2_ngap(uint32_t nof_prb, - bool ngap_is_1); +SRSLTE_API uint32_t srslte_ra_type2_ngap(uint32_t nof_prb, bool ngap_is_1); SRSLTE_API uint32_t srslte_ra_type1_N_rb(uint32_t nof_prb); -SRSLTE_API void srslte_ra_pdsch_fprint(FILE *f, - srslte_ra_dl_dci_t *ra, - uint32_t nof_prb); +SRSLTE_API uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb); -SRSLTE_API void srslte_ra_dl_grant_fprint(FILE *f, - srslte_ra_dl_grant_t *grant); +SRSLTE_API void srslte_ra_type2_from_riv(uint32_t riv, + uint32_t* L_crb, + uint32_t* RB_start, + uint32_t nof_prb, + uint32_t nof_vrb); -SRSLTE_API void srslte_ra_prb_fprint(FILE *f, - srslte_ra_dl_grant_t *grant); +SRSLTE_API int srslte_ra_tbs_idx_from_mcs(uint32_t mcs, bool is_ul); -SRSLTE_API void srslte_ra_pusch_fprint(FILE *f, - srslte_ra_ul_dci_t *ra, - uint32_t nof_prb); +SRSLTE_API srslte_mod_t srslte_ra_dl_mod_from_mcs(uint32_t mcs); -SRSLTE_API void srslte_ra_ul_grant_fprint(FILE *f, - srslte_ra_ul_grant_t *grant); +SRSLTE_API srslte_mod_t srslte_ra_ul_mod_from_mcs(uint32_t mcs); -SRSLTE_API int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb); +SRSLTE_API int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx, bool is_ul); -SRSLTE_API int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb); +SRSLTE_API int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb); +SRSLTE_API int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb); -#endif // SRSLTE_RA_H \ No newline at end of file +#endif // SRSLTE_RA_H diff --git a/lib/include/srslte/phy/phch/ra_dl.h b/lib/include/srslte/phy/phch/ra_dl.h new file mode 100644 index 000000000..fb311505e --- /dev/null +++ b/lib/include/srslte/phy/phch/ra_dl.h @@ -0,0 +1,69 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +/****************************************************************************** + * File: ra_dl.h + * + * Description: Implements Resource allocation Procedures for DL defined in Section 7 + * + * Reference: 3GPP TS 36.213 version 10.0.1 Release 10 + *****************************************************************************/ + +#ifndef SRSLTE_RA_DL_H +#define SRSLTE_RA_DL_H + +#include +#include + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/pdsch_cfg.h" +#include "srslte/phy/phch/ra.h" + +/************************************************** + * Structures used for Downlink Resource Allocation + **************************************************/ + +/** Functions to generate a grant from a received DCI */ +SRSLTE_API int srslte_ra_dl_dci_to_grant(srslte_cell_t* cell, + srslte_dl_sf_cfg_t* sf, + srslte_tm_t tm, + srslte_dci_dl_t* dci, + srslte_pdsch_grant_t* grant); + +SRSLTE_API int srslte_ra_dl_grant_to_grant_prb_allocation(srslte_dci_dl_t* dci, + srslte_pdsch_grant_t* grant, + uint32_t nof_prb); + +/** Functions used by the eNodeB scheduler */ +SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t* cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols); + +SRSLTE_API uint32_t srslte_ra_dl_grant_nof_re(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_pdsch_grant_t* grant); + +/** Others */ +SRSLTE_API int srslte_dl_fill_ra_mcs(srslte_ra_tb_t* tb, int last_tbs, uint32_t nprb); + +SRSLTE_API void srslte_ra_dl_compute_nof_re(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_pdsch_grant_t* grant); + +SRSLTE_API uint32_t srslte_ra_dl_info(srslte_pdsch_grant_t* grant, char* info_str, uint32_t len); + +#endif // SRSLTE_RA_DL_H diff --git a/lib/include/srslte/phy/phch/ra_ul.h b/lib/include/srslte/phy/phch/ra_ul.h new file mode 100644 index 000000000..5ff0eaca3 --- /dev/null +++ b/lib/include/srslte/phy/phch/ra_ul.h @@ -0,0 +1,67 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +/****************************************************************************** + * File: ra_ul.h + * + * Description: Implements Resource allocation Procedures for UL defined in Sections 8 + * + * Reference: 3GPP TS 36.213 version 10.0.1 Release 10 + *****************************************************************************/ + +#ifndef SRSLTE_RA_UL_H +#define SRSLTE_RA_UL_H + +#include +#include + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/pusch_cfg.h" + +// Structure for PUSCH frequency hopping procedure +typedef struct SRSLTE_API { + bool initialized; + srslte_cell_t cell; + srslte_sequence_t seq_type2_fo; +} srslte_ra_ul_pusch_hopping_t; + +SRSLTE_API int srslte_ra_ul_pusch_hopping_init(srslte_ra_ul_pusch_hopping_t* q, srslte_cell_t cell); + +SRSLTE_API void srslte_ra_ul_pusch_hopping_free(srslte_ra_ul_pusch_hopping_t* q); + +SRSLTE_API void srslte_ra_ul_pusch_hopping(srslte_ra_ul_pusch_hopping_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_hopping_cfg_t* hopping_cfg, + srslte_pusch_grant_t* grant); + +/** Functions to generate a grant from a received DCI */ +SRSLTE_API int srslte_ra_ul_dci_to_grant(srslte_cell_t* cell, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_hopping_cfg_t* hopping_cfg, + srslte_dci_ul_t* dci, + srslte_pusch_grant_t* grant); + +/** Others */ +SRSLTE_API uint32_t srslte_ra_ul_info(srslte_pusch_grant_t* grant, char* info_str, uint32_t len); + +#endif // SRSLTE_RA_UL_H diff --git a/lib/include/srslte/phy/phch/regs.h b/lib/include/srslte/phy/phch/regs.h index 91e6f3338..db043758e 100644 --- a/lib/include/srslte/phy/phch/regs.h +++ b/lib/include/srslte/phy/phch/regs.h @@ -64,15 +64,16 @@ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t max_ctrl_symbols; uint32_t ngroups_phich; - - srslte_phich_resources_t phich_res; + + srslte_phich_r_t phich_res; srslte_phich_length_t phich_len; srslte_regs_ch_t pcfich; srslte_regs_ch_t *phich; // there are several phich srslte_regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for the three possible CFI value */ - + + uint32_t phich_mi; uint32_t nof_regs; srslte_regs_reg_t *regs; }srslte_regs_t; @@ -80,8 +81,9 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_regs_init(srslte_regs_t *h, srslte_cell_t cell); -SRSLTE_API void srslte_regs_free(srslte_regs_t *h); +SRSLTE_API int srslte_regs_init_opts(srslte_regs_t* h, srslte_cell_t cell, uint32_t phich_mi, bool mbsfn_or_sf1_6_tdd); +SRSLTE_API void srslte_regs_free(srslte_regs_t* h); SRSLTE_API int srslte_regs_pdcch_nregs(srslte_regs_t *h, uint32_t cfi); @@ -98,6 +100,7 @@ SRSLTE_API int srslte_regs_pcfich_get(srslte_regs_t *h, cf_t symbols[REGS_PCFICH_NSYM]); SRSLTE_API uint32_t srslte_regs_phich_nregs(srslte_regs_t *h); + SRSLTE_API int srslte_regs_phich_add(srslte_regs_t *h, cf_t symbols[REGS_PHICH_NSYM], uint32_t ngroup, diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 50077f417..331d2bbcf 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -57,7 +57,7 @@ typedef struct SRSLTE_API { uint32_t max_iterations; - uint32_t nof_iterations; + float avg_iterations; bool llr_is_8bit; @@ -67,9 +67,8 @@ typedef struct SRSLTE_API { void *e; uint8_t *temp_g_bits; uint32_t *ul_interleaver; - srslte_uci_bit_t ack_ri_bits[12*288]; - uint32_t nof_ri_ack_bits; - + srslte_uci_bit_t ack_ri_bits[57600]; // 4*M_sc*Qm_max for RI and ACK + srslte_tcod_t encoder; srslte_tdec_t decoder; srslte_crc_t crc_tb; @@ -78,87 +77,54 @@ typedef struct SRSLTE_API { srslte_uci_cqi_pusch_t uci_cqi; } srslte_sch_t; -#include "srslte/phy/phch/pmch.h" SRSLTE_API int srslte_sch_init(srslte_sch_t *q); SRSLTE_API void srslte_sch_free(srslte_sch_t *q); +SRSLTE_API void srslte_sch_set_max_noi(srslte_sch_t* q, uint32_t max_iterations); + +SRSLTE_API float srslte_sch_last_noi(srslte_sch_t* q); + +SRSLTE_API int srslte_dlsch_encode(srslte_sch_t* q, srslte_pdsch_cfg_t* cfg, uint8_t* data, uint8_t* e_bits); + +SRSLTE_API int srslte_dlsch_encode2(srslte_sch_t* q, + srslte_pdsch_cfg_t* cfg, + uint8_t* data, + uint8_t* e_bits, + int codeword_idx, + uint32_t nof_layers); + +SRSLTE_API int srslte_dlsch_decode(srslte_sch_t* q, srslte_pdsch_cfg_t* cfg, int16_t* e_bits, uint8_t* data); + +SRSLTE_API int srslte_dlsch_decode2(srslte_sch_t* q, + srslte_pdsch_cfg_t* cfg, + int16_t* e_bits, + uint8_t* data, + int codeword_idx, + uint32_t nof_layers); + +SRSLTE_API int srslte_ulsch_encode(srslte_sch_t* q, + srslte_pusch_cfg_t* cfg, + uint8_t* data, + srslte_uci_value_t* uci_data, + uint8_t* g_bits, + uint8_t* q_bits); + +SRSLTE_API int srslte_ulsch_decode(srslte_sch_t* q, + srslte_pusch_cfg_t* cfg, + int16_t* q_bits, + int16_t* g_bits, + uint8_t* c_seq, + uint8_t* data, + srslte_uci_value_t* uci_data); + +SRSLTE_API float srslte_sch_beta_cqi(uint32_t I_cqi); + +SRSLTE_API uint32_t srslte_sch_find_Ioffset_ack(float beta); + +SRSLTE_API uint32_t srslte_sch_find_Ioffset_cqi(float beta); -SRSLTE_API void srslte_sch_set_max_noi(srslte_sch_t *q, - uint32_t max_iterations); - -SRSLTE_API uint32_t srslte_sch_last_noi(srslte_sch_t *q); - -SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint8_t *e_bits); - -SRSLTE_API int srslte_dlsch_encode2(srslte_sch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint8_t *e_bits, - int codeword_idx); - -SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, - uint8_t *data); - -SRSLTE_API int srslte_dlsch_decode2(srslte_sch_t *q, - srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, - uint8_t *data, - int codeword_idx); - -SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - uint8_t *g_bits, - uint8_t *q_bits); - -SRSLTE_API int srslte_ulsch_uci_encode(srslte_sch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, - srslte_uci_data_t uci_data, - uint8_t *g_bits, - uint8_t *q_bits); - -SRSLTE_API int srslte_ulsch_decode(srslte_sch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - int16_t *q_bits, - int16_t *g_bits, - uint8_t *data); - -SRSLTE_API int srslte_ulsch_uci_decode(srslte_sch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - int16_t *q_bits, - int16_t *g_bits, - uint8_t *data, - srslte_uci_data_t *uci_data); - -SRSLTE_API int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_softbuffer_rx_t *softbuffer, - int16_t *q_bits, - uint8_t *c_seq, - srslte_uci_data_t *uci_data); - -SRSLTE_API float srslte_sch_beta_cqi(uint32_t I_cqi); - -SRSLTE_API uint32_t srslte_sch_find_Ioffset_ack(float beta); - -SRSLTE_API uint32_t srslte_sch_find_Ioffset_cqi(float beta); - -SRSLTE_API uint32_t srslte_sch_find_Ioffset_ri(float beta); +SRSLTE_API uint32_t srslte_sch_find_Ioffset_ri(float beta); #endif // SRSLTE_SCH_H diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index 4f211ff1a..3fc417a70 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -37,14 +37,15 @@ #include "srslte/config.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/phch/pusch_cfg.h" #include "srslte/phy/fec/crc.h" #include "srslte/phy/fec/viterbi.h" -#include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/pusch_cfg.h" +#include "srslte/phy/phch/uci_cfg.h" #define SRSLTE_UCI_MAX_CQI_LEN_PUSCH 512 #define SRSLTE_UCI_MAX_CQI_LEN_PUCCH 13 #define SRSLTE_UCI_CQI_CODED_PUCCH_B 20 +#define SRSLTE_UCI_STR_MAX_CHAR 32 typedef struct SRSLTE_API { srslte_crc_t crc; @@ -61,29 +62,6 @@ typedef struct SRSLTE_API { int16_t **cqi_table_s; } srslte_uci_cqi_pucch_t; -typedef struct SRSLTE_API { - uint8_t uci_cqi[SRSLTE_CQI_MAX_BITS]; - uint32_t uci_cqi_len; - uint8_t uci_ri; // Only 1-bit supported for RI - uint32_t uci_ri_len; - uint8_t uci_ack; // 1st codeword bit for HARQ-ACK - uint8_t uci_ack_2; // 2st codeword bit for HARQ-ACK - uint32_t uci_ack_len; - bool ri_periodic_report; - bool scheduling_request; - bool channel_selection; - bool cqi_ack; -} srslte_uci_data_t; - -typedef enum { - UCI_BIT_1 = 0, UCI_BIT_0, UCI_BIT_REPETITION, UCI_BIT_PLACEHOLDER -} srslte_uci_bit_type_t; - -typedef struct { - uint32_t position; - srslte_uci_bit_type_t type; -} srslte_uci_bit_t; - SRSLTE_API void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q); SRSLTE_API void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q); @@ -97,13 +75,14 @@ SRSLTE_API int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]); -SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, - int16_t b_bits[32], // aligned for simd - uint8_t *cqi_data, - uint32_t cqi_len); +SRSLTE_API int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t* q, + int16_t b_bits[SRSLTE_CQI_MAX_BITS], // aligned for simd + uint8_t* cqi_data, + uint32_t cqi_len); +SRSLTE_API void srslte_uci_encode_ack_sr_pucch3(uint8_t* data, uint32_t nof_bits, uint8_t output[32]); -SRSLTE_API int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t *q); +SRSLTE_API int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t* q); SRSLTE_API void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q); @@ -122,35 +101,40 @@ SRSLTE_API int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, uint32_t Q_prime_ri, uint32_t cqi_len, uint8_t *cqi_data, - bool *cqi_ack); - -SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, - uint8_t acks[2], - uint32_t nof_acks, - uint32_t O_cqi, - float beta, - uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits); - -SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, - uint8_t *data, - uint32_t data_len, - uint32_t O_cqi, - float beta, - uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits, - bool is_ri); - -SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - uint8_t *c_seq, - float beta, - uint32_t H_prime_total, - uint32_t O_cqi, - srslte_uci_bit_t *ack_ri_bits, - uint8_t data[2], - uint32_t nof_bits, - bool is_ri); - + bool *cqi_ack); + +SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t* cfg, + uint8_t acks[2], + uint32_t nof_acks, + uint32_t O_cqi, + float beta, + uint32_t H_prime_total, + srslte_uci_bit_t* ri_bits); + +SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t* cfg, + uint8_t* data, + uint32_t O_ack, + uint32_t O_cqi, + float beta, + uint32_t H_prime_total, + bool input_is_ri, + uint32_t N_bundle, + srslte_uci_bit_t* ri_bits); + +SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg, + int16_t* q_bits, + uint8_t* c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t* ack_ri_bits, + uint8_t data[2], + uint32_t nof_bits, + bool is_ri); + +SRSLTE_API int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg, + srslte_uci_value_t* uci_data, + char* str, + uint32_t maxlen); #endif // SRSLTE_UCI_H diff --git a/lib/include/srslte/phy/phch/uci_cfg.h b/lib/include/srslte/phy/phch/uci_cfg.h new file mode 100644 index 000000000..83b7cf2dd --- /dev/null +++ b/lib/include/srslte/phy/phch/uci_cfg.h @@ -0,0 +1,71 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSLTE_UCI_CFG_H +#define SRSLTE_UCI_CFG_H + +#include "srslte/phy/phch/cqi.h" + +#define SRSLTE_UCI_MAX_ACK_BITS 10 +#define SRSLTE_UCI_MAX_M 9 + +typedef struct SRSLTE_API { + uint8_t ack_value[SRSLTE_UCI_MAX_ACK_BITS]; + bool valid; +} srslte_uci_value_ack_t; + +typedef struct SRSLTE_API { + bool pending_tb[SRSLTE_MAX_CODEWORDS]; + uint32_t nof_acks; + uint32_t ncce[SRSLTE_UCI_MAX_M]; + uint32_t N_bundle; + uint32_t tdd_ack_M; + uint32_t tdd_ack_m; + bool tdd_is_bundling; + bool has_scell_ack; +} srslte_uci_cfg_ack_t; + +typedef struct SRSLTE_API { + srslte_uci_cfg_ack_t ack; + srslte_cqi_cfg_t cqi; + bool is_scheduling_request_tti; +} srslte_uci_cfg_t; + +typedef struct SRSLTE_API { + bool scheduling_request; + srslte_cqi_value_t cqi; + srslte_uci_value_ack_t ack; + uint8_t ri; // Only 1-bit supported for RI +} srslte_uci_value_t; + +typedef struct SRSLTE_API { + srslte_uci_cfg_t cfg; + srslte_uci_value_t value; +} srslte_uci_data_t; + +typedef enum { UCI_BIT_0 = 0, UCI_BIT_1 = 1, UCI_BIT_REPETITION = 2, UCI_BIT_PLACEHOLDER = 3 } srslte_uci_bit_type_t; + +typedef struct { + uint32_t position; + srslte_uci_bit_type_t type; +} srslte_uci_bit_t; + +#endif // SRSLTE_UCI_CFG_H diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 2f3845471..f15bef61f 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -129,8 +129,7 @@ SRSLTE_API void srslte_rf_suppress_stdout(srslte_rf_t *h); SRSLTE_API void srslte_rf_register_error_handler(srslte_rf_t *h, srslte_rf_error_handler_t error_handler); -SRSLTE_API double srslte_rf_set_rx_freq(srslte_rf_t *h, - double freq); +SRSLTE_API double srslte_rf_set_rx_freq(srslte_rf_t* h, uint32_t ch, double freq); SRSLTE_API int srslte_rf_recv(srslte_rf_t *h, void *data, @@ -157,12 +156,11 @@ SRSLTE_API double srslte_rf_set_tx_srate(srslte_rf_t *h, SRSLTE_API double srslte_rf_set_tx_gain(srslte_rf_t *h, double gain); -SRSLTE_API double srslte_rf_set_tx_freq(srslte_rf_t *h, - double freq); +SRSLTE_API double srslte_rf_set_tx_freq(srslte_rf_t* h, uint32_t ch, double freq); -SRSLTE_API void srslte_rf_get_time(srslte_rf_t *h, - time_t *secs, - double *frac_secs); +SRSLTE_API void srslte_rf_get_time(srslte_rf_t* h, time_t* secs, double* frac_secs); + +SRSLTE_API int srslte_rf_sync(srslte_rf_t* rf); SRSLTE_API int srslte_rf_send(srslte_rf_t *h, void *data, diff --git a/lib/include/srslte/phy/rf/rf_utils.h b/lib/include/srslte/phy/rf/rf_utils.h index 4cfe16461..8c0c0cb03 100644 --- a/lib/include/srslte/phy/rf/rf_utils.h +++ b/lib/include/srslte/phy/rf/rf_utils.h @@ -34,7 +34,8 @@ typedef struct SRSLTE_API { uint32_t max_frames_pbch; // timeout in number of 5ms frames for MIB decoding uint32_t max_frames_pss; // timeout in number of 5ms frames for synchronization uint32_t nof_valid_pss_frames; // number of required synchronized frames - float init_agc; // 0 or negative to disable AGC + float init_agc; // 0 or negative to disable AGC + bool force_tdd; } cell_search_cfg_t; SRSLTE_API int rf_rssi_scan(srslte_rf_t *rf, diff --git a/lib/include/srslte/phy/sync/sss.h b/lib/include/srslte/phy/sync/sss.h index a0062d63b..c2c8d876b 100644 --- a/lib/include/srslte/phy/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -104,8 +104,9 @@ SRSLTE_API void srslte_sss_put_slot(float *sss, uint32_t nof_prb, srslte_cp_t cp); -SRSLTE_API int srslte_sss_set_N_id_2(srslte_sss_t *q, - uint32_t N_id_2); +SRSLTE_API void srslte_sss_put_symbol(float* sss, cf_t* symbol, uint32_t nof_prb); + +SRSLTE_API int srslte_sss_set_N_id_2(srslte_sss_t* q, uint32_t N_id_2); SRSLTE_API int srslte_sss_m0m1_partial(srslte_sss_t *q, const cf_t *input, diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index f99bfc17a..02c5e3f00 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -91,6 +91,8 @@ typedef struct SRSLTE_API { uint32_t max_frame_size; + srslte_frame_type_t frame_type; + bool detect_frame_type; // variables for various CFO estimation methods bool cfo_cp_enable; @@ -118,6 +120,13 @@ typedef struct SRSLTE_API { cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX]; cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX]; + bool sss_generated; + bool sss_detected; + bool sss_available; + srslte_dft_plan_t idftp_sss; + cf_t sss_recv[SRSLTE_SYMBOL_SZ_MAX]; + cf_t sss_signal[2][SRSLTE_SYMBOL_SZ_MAX]; + }srslte_sync_t; typedef enum { @@ -182,6 +191,8 @@ SRSLTE_API void srslte_sync_set_em_alpha(srslte_sync_t *q, SRSLTE_API int srslte_sync_set_N_id_2(srslte_sync_t *q, uint32_t N_id_2); +SRSLTE_API int srslte_sync_set_N_id_1(srslte_sync_t* q, uint32_t N_id_1); + /* Gets the Physical CellId from the last call to synch_run() */ SRSLTE_API int srslte_sync_get_cell_id(srslte_sync_t *q); @@ -216,10 +227,10 @@ SRSLTE_API void srslte_sync_set_cfo_pss_enable(srslte_sync_t *q, SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q, float tol); -/* Sets the exponential moving average coefficient for CFO averaging */ -SRSLTE_API void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, - float alpha); +SRSLTE_API void srslte_sync_set_frame_type(srslte_sync_t* q, srslte_frame_type_t frame_type); +/* Sets the exponential moving average coefficient for CFO averaging */ +SRSLTE_API void srslte_sync_set_cfo_ema_alpha(srslte_sync_t* q, float alpha); /* Gets the CP length estimation from the last call to synch_run() */ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); @@ -236,9 +247,10 @@ SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); +SRSLTE_API bool srslte_sync_sss_available(srslte_sync_t* q); + /* Enables/Disables CP detection */ -SRSLTE_API void srslte_sync_cp_en(srslte_sync_t *q, - bool enabled); +SRSLTE_API void srslte_sync_cp_en(srslte_sync_t* q, bool enabled); #endif // SRSLTE_SYNC_H diff --git a/lib/include/srslte/phy/ue/ue_cell_search.h b/lib/include/srslte/phy/ue/ue_cell_search.h index e99e916d4..0f30a841d 100644 --- a/lib/include/srslte/phy/ue/ue_cell_search.h +++ b/lib/include/srslte/phy/ue/ue_cell_search.h @@ -58,7 +58,8 @@ typedef struct SRSLTE_API { uint32_t cell_id; - srslte_cp_t cp; + srslte_cp_t cp; + srslte_frame_type_t frame_type; float peak; float mode; float psr; @@ -70,8 +71,8 @@ typedef struct SRSLTE_API { srslte_ue_sync_t ue_sync; cf_t *sf_buffer[SRSLTE_MAX_PORTS]; - uint32_t nof_rx_antennas; - + uint32_t nof_rx_antennas; + uint32_t max_frames; uint32_t nof_valid_frames; // number of 5 ms frames to scan diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 197a650b1..ae6c7f3fb 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -64,194 +64,184 @@ #define MAX_CANDIDATES_UE 16 // From 36.213 Table 9.1.1-1 #define MAX_CANDIDATES_COM 6 // From 36.213 Table 9.1.1-1 -#define MAX_CANDIDATES (MAX_CANDIDATES_UE + MAX_CANDIDATES_COM) +#define MAX_CANDIDATES (MAX_CANDIDATES_UE + MAX_CANDIDATES_COM) +#define MI_NOF_REGS ((q->cell.frame_type == SRSLTE_FDD) ? 1 : 6) +#define MI_MAX_REGS 6 -typedef struct { +#define SRSLTE_MAX_DCI_MSG SRSLTE_MAX_CARRIERS + +typedef struct SRSLTE_API { srslte_dci_format_t format; srslte_dci_location_t loc[MAX_CANDIDATES]; - uint32_t nof_locations; -} dci_blind_search_t; + uint32_t nof_locations; +} dci_blind_search_t; typedef struct SRSLTE_API { - srslte_pcfich_t pcfich; - srslte_pdcch_t pdcch; - srslte_pdsch_t pdsch; - srslte_pmch_t pmch; - srslte_phich_t phich; - srslte_regs_t regs; - srslte_ofdm_t fft[SRSLTE_MAX_PORTS]; - srslte_ofdm_t fft_mbsfn; - srslte_chest_dl_t chest; - - srslte_pdsch_cfg_t pdsch_cfg; - srslte_pdsch_cfg_t pmch_cfg; - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; - srslte_ra_dl_dci_t dl_dci; + // Cell configuration srslte_cell_t cell; + uint32_t nof_rx_antennas; + uint16_t current_mbsfn_area_id; + uint16_t pregen_rnti; - uint32_t nof_rx_antennas; - - cf_t *sf_symbols; // this is for backwards compatibility - cf_t *sf_symbols_m[SRSLTE_MAX_PORTS]; - cf_t *ce[SRSLTE_MAX_PORTS]; // compatibility - cf_t *ce_m[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - - /* RI, PMI and SINR for MIMO statistics */ - float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]; - uint32_t pmi[SRSLTE_MAX_LAYERS]; - uint32_t ri; - - /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ - float rho_b; - - srslte_dci_format_t dci_format; - uint64_t pkt_errors; - uint64_t pkts_total; - uint64_t pdsch_pkt_errors; - uint64_t pdsch_pkts_total; - uint64_t pmch_pkt_errors; - uint64_t pmch_pkts_total; - uint64_t nof_detected; - - uint16_t current_rnti; - uint16_t current_mbsfn_area_id; - dci_blind_search_t current_ss_ue[3][10]; - dci_blind_search_t current_ss_common[3]; - srslte_dci_location_t last_location; - srslte_dci_location_t last_location_ul; - - srslte_dci_msg_t pending_ul_dci_msg; - uint16_t pending_ul_dci_rnti; - - float last_phich_corr; -}srslte_ue_dl_t; - -/* This function shall be called just after the initial synchronization */ -SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t max_prb, - uint32_t nof_rx_antennas); - -SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q); - -SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, - srslte_cell_t cell); - -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi); - -SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi, - srslte_sf_t sf_type); - -SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, - cf_t *input[SRSLTE_MAX_PORTS], - uint32_t sf_idx, - uint32_t *cfi); - -SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi); - -SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t *cfi, - srslte_sf_t sf_type); - -SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, - srslte_ra_dl_grant_t *grant, - uint32_t cfi, - uint32_t sf_idx, - int rvidx[SRSLTE_MAX_CODEWORDS], - srslte_mimo_type_t mimo_type); - -SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, - uint32_t cfi, - uint32_t sf_idx, - uint16_t rnti, - srslte_dci_msg_t *dci_msg); - -SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, - uint32_t tm, - uint32_t cfi, - uint32_t sf_idx, - uint16_t rnti, - srslte_dci_msg_t *dci_msg); - -SRSLTE_API int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, - uint32_t tm, - uint32_t cfi, - uint32_t sf_idx, - uint16_t rnti, - srslte_rnti_type_t rnti_type, - srslte_dci_msg_t *dci_msg); - -SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q); - -SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, - uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tm, - uint32_t tti, - bool acks[SRSLTE_MAX_CODEWORDS]); - -SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, - uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tm, - uint32_t tti, - uint16_t rnti, - bool acks[SRSLTE_MAX_CODEWORDS]); - -/* Used by example applications - full PMCH decode for a given MBSFN area ID - * srslte_ue_dl_decode_fft_estimate_multi, - * srslte_chest_dl_get_noise_estimate, - * srslte_ue_dl_cfg_grant, - * srslte_pmch_decode_multi - */ -SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - uint8_t *data, - uint32_t tti); + // Objects for all DL Physical Channels + srslte_pcfich_t pcfich; + srslte_pdcch_t pdcch; + srslte_pdsch_t pdsch; + srslte_pmch_t pmch; + srslte_phich_t phich; + + // Control region + srslte_regs_t regs[MI_MAX_REGS]; + uint32_t mi_manual_index; + bool mi_auto; + + // Channel estimation and OFDM demodulation + srslte_chest_dl_t chest; + srslte_chest_dl_res_t chest_res; + srslte_ofdm_t fft[SRSLTE_MAX_PORTS]; + srslte_ofdm_t fft_mbsfn; + + // Buffers to store channel symbols after demodulation + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + + // Variables for blind DCI search + dci_blind_search_t current_ss_ue[MI_MAX_REGS][3][10]; + dci_blind_search_t current_ss_common[MI_MAX_REGS][3]; + srslte_dci_msg_t pending_ul_dci_msg[SRSLTE_MAX_DCI_MSG]; + uint32_t pending_ul_dci_count; + +} srslte_ue_dl_t; + +// Downlink config (includes common and dedicated variables) +typedef struct SRSLTE_API { + srslte_cqi_report_cfg_t cqi_report; + srslte_pdsch_cfg_t pdsch; + srslte_tm_t tm; +} srslte_dl_cfg_t; +typedef struct SRSLTE_API { + srslte_dl_cfg_t cfg; + srslte_chest_dl_cfg_t chest_cfg; + srslte_dci_cfg_t dci_cfg; + uint32_t last_ri; + float snr_to_cqi_offset; +} srslte_ue_dl_cfg_t; -SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, - uint8_t *ri, - uint8_t *pmi, - float *current_sinr); +typedef struct { + uint32_t v_dai_dl; + uint32_t n_cce; +} srslte_pdsch_ack_resource_t; -SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, - uint8_t *ri, - float *cn); +typedef struct { + srslte_pdsch_ack_resource_t resource; + uint32_t k; + uint8_t value[SRSLTE_MAX_CODEWORDS]; // 0/1 or 2 for DTX + bool present; +} srslte_pdsch_ack_m_t; -SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, - uint32_t sf_idx, - uint32_t n_prb_lowest, - uint32_t n_dmrs); +typedef struct { + uint32_t M; + srslte_pdsch_ack_m_t m[SRSLTE_UCI_MAX_M]; +} srslte_pdsch_ack_cc_t; -SRSLTE_API void srslte_ue_dl_reset(srslte_ue_dl_t *q); +typedef struct { + srslte_pdsch_ack_cc_t cc[SRSLTE_MAX_CARRIERS]; + uint32_t nof_cc; + uint32_t V_dai_ul; + srslte_tm_t transmission_mode; + srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode; + bool is_grant_available; + bool is_pusch_available; + bool tdd_ack_bundle; + bool simul_cqi_ack; +} srslte_pdsch_ack_t; -SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, - uint16_t rnti); +SRSLTE_API int +srslte_ue_dl_init(srslte_ue_dl_t* q, cf_t* input[SRSLTE_MAX_PORTS], uint32_t max_prb, uint32_t nof_rx_antennas); -/* Generate signals if required, store in q->current_mbsfn_area_id */ -SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, - uint16_t mbsfn_area_id); +SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t* q); -SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, - uint8_t non_mbsfn_region_length); +SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t* q, srslte_cell_t cell); -SRSLTE_API void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q, - float rho_a, - float rho_b); +SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t* q, uint16_t rnti); +SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t* q, uint16_t mbsfn_area_id); -SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, - srslte_softbuffer_rx_t *softbuffer, - uint32_t tti, - uint32_t rv_idx, - uint16_t rnti, - uint32_t cfi); +SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, + uint8_t non_mbsfn_region_length); +SRSLTE_API void srslte_ue_dl_set_mi_manual(srslte_ue_dl_t* q, uint32_t mi_idx); + +SRSLTE_API void srslte_ue_dl_set_mi_auto(srslte_ue_dl_t* q); + +/* Perform signal demodulation and channel estimation and store signals in the object */ +SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t* q, srslte_dl_sf_cfg_t* sf, srslte_ue_dl_cfg_t* cfg); + +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + cf_t* input[SRSLTE_MAX_PORTS]); + +/* Finds UL/DL DCI in the signal processed in a previous call to decode_fft_estimate() */ +SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + uint16_t rnti, + srslte_dci_ul_t dci_msg[SRSLTE_MAX_DCI_MSG]); + +SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + uint16_t rnti, + srslte_dci_dl_t dci_msg[SRSLTE_MAX_DCI_MSG]); + +SRSLTE_API int srslte_ue_dl_dci_to_pdsch_grant(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + srslte_dci_dl_t* dci, + srslte_pdsch_grant_t* grant); + +/* Decodes PDSCH and PHICH in the signal processed in a previous call to decode_fft_estimate() */ +SRSLTE_API int srslte_ue_dl_decode_pdsch(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* pdsch_cfg, + srslte_pdsch_res_t data[SRSLTE_MAX_CODEWORDS]); + +SRSLTE_API int srslte_ue_dl_decode_pmch(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pmch_cfg_t* pmch_cfg, + srslte_pdsch_res_t* data); + +SRSLTE_API int srslte_ue_dl_decode_phich(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + srslte_phich_grant_t* grant, + srslte_phich_res_t* result); + +SRSLTE_API int srslte_ue_dl_select_ri(srslte_ue_dl_t* q, uint32_t* ri, float* cn); + +SRSLTE_API void srslte_ue_dl_gen_cqi_periodic( + srslte_ue_dl_t* q, srslte_ue_dl_cfg_t* cfg, uint32_t wideband_value, uint32_t tti, srslte_uci_data_t* uci_data); + +SRSLTE_API void srslte_ue_dl_gen_cqi_aperiodic(srslte_ue_dl_t* q, + srslte_ue_dl_cfg_t* cfg, + uint32_t wideband_value, + srslte_uci_data_t* uci_data); + +SRSLTE_API void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_ack_t* ack_info, + srslte_uci_data_t* uci_data); + +/* Functions used for testing purposes */ +SRSLTE_API int srslte_ue_dl_find_and_decode(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + srslte_pdsch_cfg_t* pdsch_cfg, + uint8_t* data[SRSLTE_MAX_CODEWORDS], + bool acks[SRSLTE_MAX_CODEWORDS]); + +SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t* q, srslte_dl_sf_cfg_t* sf, srslte_pdsch_cfg_t* pdsch_cfg); #endif // SRSLTE_UE_DL_H diff --git a/lib/include/srslte/phy/ue/ue_mib.h b/lib/include/srslte/phy/ue/ue_mib.h index 38f27d024..ff9a4b3e7 100644 --- a/lib/include/srslte/phy/ue/ue_mib.h +++ b/lib/include/srslte/phy/ue/ue_mib.h @@ -63,15 +63,16 @@ typedef struct SRSLTE_API { srslte_sync_t sfind; - - cf_t *sf_symbols; - cf_t *ce[SRSLTE_MAX_PORTS]; - + + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + srslte_ofdm_t fft; - srslte_chest_dl_t chest; srslte_pbch_t pbch; - - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + srslte_chest_dl_t chest; + srslte_chest_dl_res_t chest_res; + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; uint32_t nof_tx_ports; uint32_t sfn_offset; @@ -114,9 +115,7 @@ SRSLTE_API int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, SRSLTE_API void srslte_ue_mib_sync_free(srslte_ue_mib_sync_t *q); -SRSLTE_API int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp); +SRSLTE_API int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t* q, srslte_cell_t cell); SRSLTE_API void srslte_ue_mib_sync_reset(srslte_ue_mib_sync_t * q); diff --git a/lib/include/srslte/phy/ue/ue_phy.h b/lib/include/srslte/phy/ue/ue_phy.h index 0a8217594..6f056ab9d 100644 --- a/lib/include/srslte/phy/ue/ue_phy.h +++ b/lib/include/srslte/phy/ue/ue_phy.h @@ -59,18 +59,18 @@ public: PDCCH_UL_SEARCH_TEMPORAL, PDCCH_UL_SEARCH_TPC_PUSCH, PDCCH_UL_SEARCH_TPC_PUCCH - } pdcch_ul_search_t; + } 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_TEMPORAL, PDCCH_DL_SEARCH_SPS - } pdcch_dl_search_t; - - /* Uplink/Downlink scheduling grant generated by a successfully decoded PDCCH */ + } pdcch_dl_search_t; + + /* Uplink/Downlink scheduling dci generated by a successfully decoded PDCCH */ class sched_grant { public: uint16_t get_rnti(); @@ -81,8 +81,8 @@ public: uint32_t get_harq_process(); private: union { - srslte_ra_ul_dci_t ul_grant; - srslte_ra_dl_dci_t dl_grant; + srslte_ra_ul_grant_t ul_grant; + srslte_ra_dl_grant_t dl_grant; }; direction_t dir; }; diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index 45aabfbc3..ae60c99e7 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -76,7 +76,9 @@ typedef enum SRSLTE_API { SF_FIND, SF_TRACK} srslte_ue_sync_state_t; -//#define MEASURE_EXEC_TIME +//#define MEASURE_EXEC_TIME + +typedef int(ue_sync_recv_callback_t)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*); typedef struct SRSLTE_API { srslte_sync_t sfind; @@ -122,8 +124,6 @@ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t sf_idx; - bool decode_sss_on_track; - bool cfo_is_copied; bool cfo_correct_enable_track; bool cfo_correct_enable_find; @@ -157,12 +157,13 @@ SRSLTE_API int srslte_ue_sync_init(srslte_ue_sync_t *q, int (recv_callback)(void*, void*, uint32_t, srslte_timestamp_t*), void *stream_handler); -SRSLTE_API int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, - uint32_t max_prb, - bool search_cell, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler); +SRSLTE_API int +srslte_ue_sync_init_multi(srslte_ue_sync_t* q, + uint32_t max_prb, + bool search_cell, + int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler); SRSLTE_API int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, uint32_t max_prb, @@ -197,8 +198,14 @@ SRSLTE_API void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q); SRSLTE_API void srslte_ue_sync_reset(srslte_ue_sync_t *q); -SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, - double (set_gain_callback)(void*, double), +SRSLTE_API void srslte_ue_sync_set_frame_type(srslte_ue_sync_t* q, srslte_frame_type_t frame_type); + +SRSLTE_API void srslte_ue_sync_set_nof_find_frames(srslte_ue_sync_t* q, uint32_t nof_frames); + +SRSLTE_API srslte_frame_type_t srslte_ue_sync_get_frame_type(srslte_ue_sync_t* q); + +SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t* q, + double(set_gain_callback)(void*, double), double min_gain, double max_gain, double init_gain_value); @@ -209,14 +216,9 @@ SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period); /* CAUTION: input_buffer MUST have space for 2 subframes */ -SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, - cf_t *input_buffer); - -SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, - cf_t *input_buffer[SRSLTE_MAX_PORTS]); +SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]); -SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, - float tol); +SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t* q, float tol); SRSLTE_API void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, srslte_ue_sync_t *src_obj); @@ -240,9 +242,6 @@ SRSLTE_API void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q, SRSLTE_API void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2); -SRSLTE_API void srslte_ue_sync_decode_sss_on_track(srslte_ue_sync_t *q, - bool enabled); - SRSLTE_API uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q); SRSLTE_API float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q); diff --git a/lib/include/srslte/phy/ue/ue_ul.h b/lib/include/srslte/phy/ue/ue_ul.h index c6eb96a17..7b3635ab4 100644 --- a/lib/include/srslte/phy/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -62,156 +62,95 @@ typedef struct { // Dedicated configuration float p0_ue_pusch; - bool delta_mcs_based; - bool acc_enabled; + bool delta_mcs_based; + bool acc_enabled; float p0_ue_pucch; float p_srs_offset; } srslte_ue_ul_powerctrl_t; typedef struct SRSLTE_API { - srslte_ofdm_t fft; - srslte_cfo_t cfo; - srslte_cell_t cell; - - bool normalize_en; - bool cfo_en; - - float current_cfo_tol; - float current_cfo; - srslte_pucch_format_t last_pucch_format; - - srslte_pusch_cfg_t pusch_cfg; - srslte_refsignal_ul_t signals; - srslte_refsignal_ul_dmrs_pregen_t pregen_drms; - srslte_refsignal_srs_pregen_t pregen_srs; - - srslte_softbuffer_tx_t softbuffer; - - srslte_pusch_t pusch; - srslte_pucch_t pucch; - - srslte_pucch_sched_t pucch_sched; - srslte_refsignal_srs_cfg_t srs_cfg; - srslte_uci_cfg_t uci_cfg; - srslte_pusch_hopping_cfg_t hopping_cfg; + // Uplink config (includes common and dedicated variables) + srslte_pucch_cfg_t pucch; + srslte_pusch_cfg_t pusch; + srslte_pusch_hopping_cfg_t hopping; srslte_ue_ul_powerctrl_t power_ctrl; - - cf_t *refsignal; - cf_t *srs_signal; - cf_t *sf_symbols; - - float last_amplitude; + srslte_refsignal_dmrs_pusch_cfg_t dmrs; + srslte_refsignal_srs_cfg_t srs; +} srslte_ul_cfg_t; - uint16_t current_rnti; - bool signals_pregenerated; -}srslte_ue_ul_t; - - - -/* This function shall be called just after the initial synchronization */ -SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t *q, - cf_t *out_buffer, - uint32_t max_prb); - -SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t *q); - -SRSLTE_API int srslte_ue_ul_set_cell(srslte_ue_ul_t *q, - srslte_cell_t cell); - -SRSLTE_API void srslte_ue_ul_set_cfo_tol(srslte_ue_ul_t *q, - float tol); +typedef struct SRSLTE_API { -SRSLTE_API void srslte_ue_ul_set_cfo(srslte_ue_ul_t *q, - float cur_cfo); + srslte_ul_cfg_t ul_cfg; + bool grant_available; + uint32_t cc_idx; -SRSLTE_API void srslte_ue_ul_set_cfo_enable(srslte_ue_ul_t *q, - bool enabled); + bool normalize_en; + bool cfo_en; + float cfo_tol; + float cfo_value; -SRSLTE_API void srslte_ue_ul_set_normalization(srslte_ue_ul_t *q, - bool enabled); +} srslte_ue_ul_cfg_t; -SRSLTE_API float srslte_ue_ul_get_last_amplitude(srslte_ue_ul_t *q); +typedef struct SRSLTE_API { + srslte_cell_t cell; -SRSLTE_API void srslte_ue_ul_set_cfg(srslte_ue_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *dmrs_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg, - srslte_pucch_cfg_t *pucch_cfg, - srslte_pucch_sched_t *pucch_sched, - srslte_uci_cfg_t *uci_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_ue_ul_powerctrl_t *power_ctrl); + uint16_t current_rnti; + bool signals_pregenerated; -SRSLTE_API int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, - srslte_ra_ul_grant_t *grant, - uint32_t tti, - uint32_t rvidx, - uint32_t current_tx_nb); + srslte_ofdm_t fft; + srslte_cfo_t cfo; -SRSLTE_API int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, - srslte_uci_data_t uci_data, - uint32_t pdcch_n_cce, /* Ncce of the last PDCCH message received */ - uint32_t tti, - cf_t *output_signal); + srslte_refsignal_ul_t signals; + srslte_refsignal_ul_dmrs_pregen_t pregen_dmrs; + srslte_refsignal_srs_pregen_t pregen_srs; -SRSLTE_API int srslte_ue_ul_pusch_encode(srslte_ue_ul_t *q, - uint8_t *data, - cf_t *output_signal); + srslte_pusch_t pusch; + srslte_pucch_t pucch; -SRSLTE_API int srslte_ue_ul_pusch_encode_rnti(srslte_ue_ul_t *q, - uint8_t *data, - uint16_t rnti, - cf_t *output_signal); + srslte_ra_ul_pusch_hopping_t hopping; -SRSLTE_API int srslte_ue_ul_pusch_uci_encode(srslte_ue_ul_t *q, - uint8_t *data, - srslte_uci_data_t uci_data, - cf_t *output_signal); + cf_t* out_buffer; + cf_t* refsignal; + cf_t* srs_signal; + cf_t* sf_symbols; -SRSLTE_API int srslte_ue_ul_pusch_uci_encode_rnti(srslte_ue_ul_t *q, - uint8_t *data, - srslte_uci_data_t uci_data, - uint16_t rnti, - cf_t *output_signal); +} srslte_ue_ul_t; -SRSLTE_API int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, - uint8_t *data, - srslte_uci_data_t uci_data, - srslte_softbuffer_tx_t *softbuffer, - uint16_t rnti, - cf_t *output_signal); +SRSLTE_API int srslte_ue_ul_init(srslte_ue_ul_t* q, cf_t* out_buffer, uint32_t max_prb); -SRSLTE_API int srslte_ue_ul_srs_encode(srslte_ue_ul_t *q, - uint32_t tti, - cf_t *output_signal); +SRSLTE_API void srslte_ue_ul_free(srslte_ue_ul_t* q); -SRSLTE_API void srslte_ue_ul_reset(srslte_ue_ul_t *q); +SRSLTE_API int srslte_ue_ul_set_cell(srslte_ue_ul_t* q, srslte_cell_t cell); -SRSLTE_API int srslte_ue_ul_pregen_signals(srslte_ue_ul_t *q); +SRSLTE_API void srslte_ue_ul_set_rnti(srslte_ue_ul_t* q, uint16_t rnti); -SRSLTE_API void srslte_ue_ul_set_rnti(srslte_ue_ul_t *q, - uint16_t rnti); +SRSLTE_API int srslte_ue_ul_pregen_signals(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg); -/* Power control procedure */ -SRSLTE_API float srslte_ue_ul_pusch_power(srslte_ue_ul_t *q, - float PL, - float p0_preamble); +SRSLTE_API int srslte_ue_ul_dci_to_pusch_grant(srslte_ue_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_ue_ul_cfg_t* cfg, + srslte_dci_ul_t* dci, + srslte_pusch_grant_t* grant); -SRSLTE_API float srslte_ue_ul_pucch_power(srslte_ue_ul_t *q, - float PL, - srslte_pucch_format_t format, - uint32_t n_cqi, - uint32_t n_harq); +SRSLTE_API void srslte_ue_ul_pusch_hopping(srslte_ue_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_ue_ul_cfg_t* cfg, + srslte_pusch_grant_t* grant); -SRSLTE_API float srslte_ue_ul_srs_power(srslte_ue_ul_t *q, - float PL); +SRSLTE_API int +srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, srslte_pusch_data_t* data); -/* Other static functions for UL PHY procedures defined in 36.213 */ +SRSLTE_API int srslte_ue_ul_sr_send_tti(srslte_pucch_cfg_t* cfg, uint32_t current_tti); -SRSLTE_API int srslte_ue_ul_sr_send_tti(uint32_t I_sr, - uint32_t current_tti); +SRSLTE_API bool +srslte_ue_ul_gen_sr(srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, srslte_uci_data_t* uci_data, bool sr_request); -SRSLTE_API bool srslte_ue_ul_srs_tx_enabled(srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t tti); +SRSLTE_API void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell, + srslte_pucch_cfg_t* cfg, + srslte_uci_cfg_t* uci_cfg, + srslte_uci_value_t* uci_data); +SRSLTE_API bool srslte_ue_ul_info( + srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, srslte_uci_value_t* uci_data, char* str, uint32_t str_len); #endif // SRSLTE_UE_UL_H diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index 7fe532eb4..72e575dd1 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -35,9 +35,9 @@ #ifndef SRSLTE_DEBUG_H #define SRSLTE_DEBUG_H -#include +#include "phy_logger.h" #include "srslte/config.h" -#include "srslte/phy/common/phy_logger.h" +#include #define SRSLTE_VERBOSE_DEBUG 2 #define SRSLTE_VERBOSE_INFO 1 @@ -59,19 +59,34 @@ SRSLTE_API extern int handler_registered; #define PRINT_INFO srslte_verbose=SRSLTE_VERBOSE_INFO #define PRINT_NONE srslte_verbose=SRSLTE_VERBOSE_NONE -#define DEBUG(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered)\ - { fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__); }\ - else{ srslte_phy_log_print(LOG_LEVEL_DEBUG, _fmt, ##__VA_ARGS__); } +#define DEBUG(_fmt, ...) \ + do { \ + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG && !handler_registered) { \ + fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__); \ + } else { \ + srslte_phy_log_print(LOG_LEVEL_DEBUG_S, _fmt, ##__VA_ARGS__); \ + } \ + } while (0) -#define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) \ - { fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__); }\ - else{ srslte_phy_log_print(LOG_LEVEL_INFO, _fmt, ##__VA_ARGS__); } +#define INFO(_fmt, ...) \ + do { \ + if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { \ + fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__); \ + } else { \ + srslte_phy_log_print(LOG_LEVEL_INFO_S, _fmt, ##__VA_ARGS__); \ + } \ + } while (0) #if CMAKE_BUILD_TYPE==Debug /* In debug mode, it prints out the */ -#define ERROR(_fmt, ...) if (!handler_registered)\ - { fprintf(stderr, "\e[31m%s.%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__);}\ - else {srslte_phy_log_print(LOG_LEVEL_ERROR, _fmt, ##__VA_ARGS__);} // +#define ERROR(_fmt, ...) \ + do { \ + if (!handler_registered) { \ + fprintf(stderr, "\e[31m%s.%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + } else { \ + srslte_phy_log_print(LOG_LEVEL_ERROR_S, _fmt, ##__VA_ARGS__); \ + } \ + } while (0) #else #define ERROR(_fmt, ...) if (!handler_registered)\ { fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__);}\ diff --git a/lib/include/srslte/phy/common/phy_logger.h b/lib/include/srslte/phy/utils/phy_logger.h similarity index 64% rename from lib/include/srslte/phy/common/phy_logger.h rename to lib/include/srslte/phy/utils/phy_logger.h index 2f0805df8..9e5ca621d 100644 --- a/lib/include/srslte/phy/common/phy_logger.h +++ b/lib/include/srslte/phy/utils/phy_logger.h @@ -1,19 +1,14 @@ -/** +/* + * Copyright 2013-2019 Software Radio Systems Limited * - * \section COPYRIGHT + * This file is part of srsLTE. * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify + * 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. * - * srsUE is distributed in the hope that it will be useful, + * 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. @@ -39,18 +34,17 @@ #include #include #include -#include #ifdef __cplusplus extern "C" { #endif // __cplusplus -typedef enum {LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR} phy_logger_level_t; + typedef enum { LOG_LEVEL_INFO_S, LOG_LEVEL_DEBUG_S, LOG_LEVEL_ERROR_S } phy_logger_level_t; -typedef void (*phy_log_handler_t)(phy_logger_level_t log_level, void *ctx, char *str); + typedef void (*phy_log_handler_t)(phy_logger_level_t log_level, void* ctx, char* str); -void srslte_phy_log_register_handler(void *ctx, phy_log_handler_t handler); + void srslte_phy_log_register_handler(void* ctx, phy_log_handler_t handler); - void srslte_phy_log_print(phy_logger_level_t log_level, const char *format, ...); + void srslte_phy_log_print(phy_logger_level_t log_level, const char* format, ...); #ifdef __cplusplus } diff --git a/lib/include/srslte/phy/utils/ringbuffer.h b/lib/include/srslte/phy/utils/ringbuffer.h index b7a852155..a65e07a15 100644 --- a/lib/include/srslte/phy/utils/ringbuffer.h +++ b/lib/include/srslte/phy/utils/ringbuffer.h @@ -1,3 +1,23 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ #ifndef SRSLTE_RINGBUFFER_H #define SRSLTE_RINGBUFFER_H diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index ebeabf10e..afef8028c 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -26,13 +26,26 @@ #include -#include "srslte/srslte.h" -#include "srslte/phy/rf/rf.h" +#include "srslte/common/log_filter.h" #include "srslte/common/trace.h" +#include "srslte/phy/rf/rf.h" +#include "srslte/radio/radio_sync.h" +#include "srslte/srslte.h" #ifndef SRSLTE_RADIO_H #define SRSLTE_RADIO_H +typedef struct { + float tx_corr_dc_gain; + float tx_corr_dc_phase; + float tx_corr_iq_i; + float tx_corr_iq_q; + float rx_corr_dc_gain; + float rx_corr_dc_phase; + float rx_corr_iq_i; + float rx_corr_iq_q; +} rf_cal_t; + namespace srslte { /* Interface to the RF frontend. @@ -46,6 +59,9 @@ class radio { zeros = (cf_t*)srslte_vec_malloc(burst_preamble_max_samples * sizeof(cf_t)); bzero(zeros, burst_preamble_max_samples * sizeof(cf_t)); + sync = NULL; + log_h = NULL; + burst_preamble_sec = 0; is_start_of_burst = false; burst_preamble_samples = 0; @@ -70,13 +86,18 @@ class radio { { if (zeros) { free(zeros); + zeros = NULL; } } - bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1); + bool init(log_filter* _log_h, + char* args = NULL, + char* devname = NULL, + uint32_t nof_channels = 1, + bool enable_synch = false); void stop(); void reset(); - bool start_agc(bool tx_gain_same_rx); + bool start_agc(bool tx_gain_same_rx = false); void set_burst_preamble(double preamble_us); void set_tx_adv(int nsamples); @@ -86,11 +107,13 @@ class radio { void set_continuous_tx(bool enable); void get_time(srslte_timestamp_t *now); - bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); + int synch_wait(); + void synch_issue(); + bool tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + bool tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); void tx_end(); - bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); - bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); + bool rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time); + bool rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); void set_tx_gain(float gain); void set_rx_gain(float gain); @@ -98,8 +121,8 @@ class radio { double set_rx_gain_th(float gain); void set_freq_offset(double freq); - void set_tx_freq(double freq); - void set_rx_freq(double freq); + void set_tx_freq(uint32_t chan, double freq); + void set_rx_freq(uint32_t chan, double freq); double get_freq_offset(); double get_tx_freq(); @@ -118,9 +141,6 @@ class radio { float get_rssi(); bool has_rssi(); - void start_trace(); - void write_trace(std::string filename); - void set_tti(uint32_t tti); bool is_first_of_burst(); @@ -131,9 +151,9 @@ class radio { protected: - void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time); - srslte_rf_t rf_device; + radio_sync* sync; + log_filter* log_h; const static uint32_t burst_preamble_max_samples = 13824; double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time) diff --git a/lib/include/srslte/radio/radio_multi.h b/lib/include/srslte/radio/radio_multi.h index 097fe55e2..712a95072 100644 --- a/lib/include/srslte/radio/radio_multi.h +++ b/lib/include/srslte/radio/radio_multi.h @@ -39,17 +39,93 @@ extern "C" { namespace srslte { - + /* Interface to the RF frontend. */ - class radio_multi : public radio - { - public: - radio_multi() {} - ~radio_multi() {} - bool init_multi(uint32_t nof_rx_antennas, char *args = NULL, char *devname = NULL); - bool rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); - }; +class radio_multi +{ +private: + /* Temporal buffer size for flushing the radios */ + static const size_t TEMP_BUFFER_SIZE = 307200; + + /* Maximum sample offset that can be compensated without isssuing PPS synchronism */ + static const size_t MAX_NOF_ALIGN_SAMPLES = TEMP_BUFFER_SIZE * 10; + + log_filter* log_h; + bool initiated; + double rx_srate; + std::vector radios; + srslte_timestamp_t ts_rx[SRSLTE_MAX_RADIOS]; + cf_t* temp_buffers[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS]; + bool align_radio_ts(); + bool synch_wait(); + void synch_issue(); + pthread_mutex_t mutex; + bool locked; + uint32_t nof_ports; + +public: + radio_multi(); + bool init(log_filter* _log_h, + char* args[SRSLTE_MAX_RADIOS] = NULL, + char* devname = NULL, + uint32_t nof_radios = 1, + uint32_t nof_rf_ports = 1); + void stop(); + void reset(); + + bool start_agc(bool tx_gain_same_rx = false); + + void set_burst_preamble(double preamble_us); + void set_tx_adv(int nsamples); + void set_tx_adv_neg(bool tx_adv_is_neg); + + void set_manual_calibration(rf_cal_t* calibration); + + bool is_continuous_tx(); + void set_continuous_tx(bool enable); + + bool tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + bool tx(cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); + void tx_end(); + bool rx_now(cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time); + + void set_tx_gain(float gain, uint32_t radio_idx = UINT32_MAX); + void set_rx_gain(float gain, uint32_t radio_idx = UINT32_MAX); + void set_tx_rx_gain_offset(float offset); + double set_rx_gain_th(float gain); + + float get_tx_gain(uint32_t radio_idx = 0); + float get_rx_gain(uint32_t radio_idx = 0); + + void set_freq_offset(double freq); + void set_tx_freq(double freq, uint32_t radio_idx = UINT32_MAX); + void set_rx_freq(double freq, uint32_t radio_idx = UINT32_MAX); + + double get_freq_offset(); + double get_tx_freq(uint32_t radio_idx = 0); + double get_rx_freq(uint32_t radio_idx = 0); + srslte_rf_info_t* get_info(uint32_t radio_idx = 0); + + void set_master_clock_rate(double rate); + void set_tx_srate(double srate); + void set_rx_srate(double srate); + + float get_max_tx_power(); + float set_tx_power(float power); + float get_rssi(); + bool has_rssi(); + radio* get_radio_ptr(uint32_t idx); + + void start_trace(); + void write_trace(std::string filename); + + void set_tti(uint32_t tti); + + bool is_init(); + + void register_error_handler(srslte_rf_error_handler_t h); +}; } #endif // SRSLTE_RADIO_MULTI_H diff --git a/lib/include/srslte/radio/radio_sync.h b/lib/include/srslte/radio/radio_sync.h new file mode 100644 index 000000000..5d06d13d9 --- /dev/null +++ b/lib/include/srslte/radio/radio_sync.h @@ -0,0 +1,54 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +extern "C" { +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/timestamp.h" +#include "srslte/phy/rf/rf.h" +} + +#ifndef SRSLTE_RADIO_SYNC_H +#define SRSLTE_RADIO_SYNC_H + +namespace srslte { + +/* Interface to the RF frontend. + */ +class radio_sync +{ +private: + void* thread_args; + +public: + radio_sync(); + bool init(srslte_rf_t* dev); + void issue_sync(); + void issue_rx(cf_t* data[SRSLTE_MAX_PORTS], + uint32_t nsamples, + srslte_timestamp_t* timestamp, + bool start_streaming = false); + int wait(); + ~radio_sync(); +}; + +} // namespace srslte + +#endif // SRSLTE_RADIO_SYNC_H diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index 01e8cf4bc..75c541bd2 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -47,10 +47,10 @@ extern "C" { #include "srslte/phy/utils/cexptab.h" #include "srslte/phy/utils/vector.h" -#include "srslte/phy/common/timestamp.h" -#include "srslte/phy/common/sequence.h" #include "srslte/phy/common/phy_common.h" -#include "srslte/phy/common/phy_logger.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/common/timestamp.h" +#include "srslte/phy/utils/phy_logger.h" #include "srslte/phy/ch_estimation/chest_ul.h" #include "srslte/phy/ch_estimation/chest_dl.h" @@ -91,18 +91,20 @@ extern "C" { #include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/phch/cqi.h" #include "srslte/phy/phch/dci.h" -#include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/phch/pbch.h" #include "srslte/phy/phch/pcfich.h" #include "srslte/phy/phch/pdcch.h" #include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/phich.h" -#include "srslte/phy/phch/pusch.h" -#include "srslte/phy/phch/pucch.h" #include "srslte/phy/phch/prach.h" +#include "srslte/phy/phch/pucch.h" +#include "srslte/phy/phch/pusch.h" #include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/ra_dl.h" +#include "srslte/phy/phch/ra_ul.h" #include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/sch.h" #include "srslte/phy/phch/uci.h" diff --git a/lib/include/srslte/upper/rlc_interface.h b/lib/include/srslte/upper/rlc_interface.h index 9549cdd38..b70ba1a85 100644 --- a/lib/include/srslte/upper/rlc_interface.h +++ b/lib/include/srslte/upper/rlc_interface.h @@ -150,7 +150,7 @@ public: cfg.um.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS; cfg.um.tx_mod = 32; cfg.um.is_mrb = true; - cfg.tx_queue_length = 512; + cfg.tx_queue_length = 1024; return cfg; } }; diff --git a/lib/src/common/arch_select.cc b/lib/src/common/arch_select.cc index ebfa33ab6..a78f80a2e 100644 --- a/lib/src/common/arch_select.cc +++ b/lib/src/common/arch_select.cc @@ -113,4 +113,4 @@ int main(int argc, char *argv[]) fprintf(stderr, "%s: %s\n", cmd, strerror(errno)); exit(errno); } -} \ No newline at end of file +} diff --git a/lib/src/common/log_filter.cc b/lib/src/common/log_filter.cc index 6f30cab5d..12239f0ff 100644 --- a/lib/src/common/log_filter.cc +++ b/lib/src/common/log_filter.cc @@ -145,6 +145,7 @@ void log_filter::console(const char * message, ...) { va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) printf("%s",args_msg); // Print directly to stdout + fflush(stdout); va_end(args); free(args_msg); } diff --git a/lib/src/common/pdu.cc b/lib/src/common/pdu.cc index d36b67f9f..c07afcc65 100644 --- a/lib/src/common/pdu.cc +++ b/lib/src/common/pdu.cc @@ -63,7 +63,7 @@ void sch_pdu::parse_packet(uint8_t *ptr) if (n_sub >= 0) { subheaders[nof_subheaders-1].set_payload_size(n_sub); } else { - fprintf(stderr,"Reading MAC PDU: negative payload for last subheader\n"); + ERROR("Reading MAC PDU: negative payload for last subheader\n"); } } } @@ -129,8 +129,11 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h) header_sz += onetwo_padding; } if (ce_payload_sz + header_sz >= sdu_offset_start) { - fprintf(stderr, "Writing PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n", - header_sz + ce_payload_sz, sdu_offset_start, pdu_len, total_sdu_len); + ERROR("Writing PDU: header sz + ce_payload_sz >= sdu_offset_start (%d>=%d). pdu_len=%d, total_sdu_len=%d\n", + header_sz + ce_payload_sz, + sdu_offset_start, + pdu_len, + total_sdu_len); return NULL; } @@ -184,31 +187,49 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h) pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len, init_rem_len); } - + if (rem_len + header_sz + ce_payload_sz + total_sdu_len != pdu_len) { - printf("\n------------------------------\n"); - for (int i=0;ierror("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, multi=%d, init_rem_len=%d\n", - pdu_len, header_sz+ce_payload_sz, header_sz, ce_payload_sz, - nof_subheaders, last_sdu_idx, total_sdu_len, onetwo_padding, rem_len, init_rem_len); - + log_h->console("\n------------------------------\n"); + for (int i = 0; i < nof_subheaders; i++) { + log_h->console("SUBH %d is_sdu=%d, payload=%d\n", i, subheaders[i].is_sdu(), subheaders[i].get_payload_size()); + } + log_h->console("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, " + "onepad=%d, multi=%d, init_rem_len=%d\n", + pdu_len, + header_sz + ce_payload_sz, + header_sz, + ce_payload_sz, + nof_subheaders, + last_sdu_idx, + total_sdu_len, + onetwo_padding, + rem_len, + init_rem_len); + ERROR("Expected PDU len %d bytes but wrote %d\n", pdu_len, rem_len + header_sz + ce_payload_sz + total_sdu_len); + log_h->console("------------------------------\n"); + + log_h->error("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, sdu_len=%d, onepad=%d, " + "multi=%d, init_rem_len=%d\n", + pdu_len, + header_sz + ce_payload_sz, + header_sz, + ce_payload_sz, + nof_subheaders, + last_sdu_idx, + total_sdu_len, + onetwo_padding, + rem_len, + init_rem_len); } return NULL; } if ((int)(header_sz + ce_payload_sz) != (int) (ptr - pdu_start_ptr)) { - fprintf(stderr, "Expected a header and CE payload of %d bytes but wrote %d\n", - header_sz+ce_payload_sz,(int) (ptr - pdu_start_ptr)); + ERROR("Expected a header and CE payload of %d bytes but wrote %d\n", + header_sz + ce_payload_sz, + (int)(ptr - pdu_start_ptr)); return NULL; } @@ -352,6 +373,8 @@ uint32_t sch_subh::sizeof_ce(uint32_t lcid, bool is_ul) return 0; case PADDING: return 0; + case SCELL_ACTIVATION: + return 1; } } } @@ -438,10 +461,10 @@ bool sch_subh::get_next_mch_sched_info(uint8_t *lcid_, uint16_t *mtch_stop) { if(payload) { nof_mch_sched_ce = nof_bytes/2; - if(cur_mch_sched_ce < nof_mch_sched_ce) { - *lcid_ = (payload[cur_mch_sched_ce*2]&0xF8) >> 3; - *mtch_stop = ((uint16_t)(payload[cur_mch_sched_ce*2]&0x07)) << 8; - *mtch_stop += payload[cur_mch_sched_ce*2+1]; + if (cur_mch_sched_ce < nof_mch_sched_ce) { + *lcid_ = (payload[cur_mch_sched_ce * 2] & 0xF8) >> 3; + *mtch_stop = ((uint16_t)(payload[cur_mch_sched_ce * 2] & 0x07)) << 8; + *mtch_stop += payload[cur_mch_sched_ce * 2 + 1]; cur_mch_sched_ce++; return true; } @@ -458,6 +481,16 @@ uint8_t sch_subh::get_ta_cmd() } } +uint8_t sch_subh::get_activation_deactivation_cmd() +{ + /* 3GPP 36.321 section 6.1.3.8 Activation/Deactivation MAC Control Element */ + if (payload) { + return payload[0]; + } else { + return 0; + } +} + uint32_t sch_subh::get_sdu_lcid() { return lcid; diff --git a/lib/src/common/pdu_queue.cc b/lib/src/common/pdu_queue.cc index 87e6c84e9..621365f58 100644 --- a/lib/src/common/pdu_queue.cc +++ b/lib/src/common/pdu_queue.cc @@ -45,7 +45,7 @@ void pdu_queue::init(process_callback *callback_, log* log_h_) uint8_t* pdu_queue::request(uint32_t len) { if (len > MAX_PDU_LEN) { - fprintf(stderr, "Error request buffer of invalid size %d. Max bytes %d\n", len, MAX_PDU_LEN); + ERROR("Error request buffer of invalid size %d. Max bytes %d\n", len, MAX_PDU_LEN); return NULL; } pdu_t* pdu = pool.allocate("pdu_queue::request", true); @@ -53,10 +53,10 @@ uint8_t* pdu_queue::request(uint32_t len) if (log_h) { log_h->error("Not enough buffers for MAC PDU\n"); } - fprintf(stderr, "Not enough buffers for MAC PDU\n"); + ERROR("Not enough buffers for MAC PDU\n"); } if ((void*) pdu->ptr != (void*) pdu) { - fprintf(stderr, "Fatal error in memory alignment in struct pdu_queue::pdu_t\n"); + ERROR("Fatal error in memory alignment in struct pdu_queue::pdu_t\n"); exit(-1); } @@ -70,16 +70,15 @@ void pdu_queue::deallocate(uint8_t* pdu) } } -/* Demultiplexing of logical channels and dissassemble of MAC CE - * This function enqueues the packet and returns quicly because ACK - * deadline is important here. - */ -void pdu_queue::push(uint8_t *ptr, uint32_t len, channel_t channel, uint32_t tstamp) +/* Demultiplexing of logical channels and dissassemble of MAC CE + * This function enqueues the packet and returns quicly because ACK + * deadline is important here. + */ +void pdu_queue::push(uint8_t* ptr, uint32_t len, channel_t channel) { if (ptr) { pdu_t *pdu = (pdu_t*) ptr; pdu->len = len; - pdu->tstamp = tstamp; pdu->channel = channel; pdu_q.push(pdu); } else { @@ -94,7 +93,7 @@ bool pdu_queue::process_pdus() pdu_t *pdu; while(pdu_q.try_pop(&pdu)) { if (callback) { - callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->tstamp); + callback->process_pdu(pdu->ptr, pdu->len, pdu->channel); } cnt++; have_data = true; diff --git a/lib/src/common/threads.c b/lib/src/common/threads.c index 1d35d91aa..b54dc7029 100644 --- a/lib/src/common/threads.c +++ b/lib/src/common/threads.c @@ -65,7 +65,7 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void } if (pthread_attr_setschedparam(&attr, ¶m)) { perror("pthread_attr_setschedparam"); - fprintf(stderr, "Error not enough privileges to set Scheduling priority\n"); + ERROR("Error not enough privileges to set Scheduling priority\n"); } attr_enable = true; } else if (prio_offset == -1) { @@ -79,7 +79,7 @@ bool threads_new_rt_cpu(pthread_t *thread, void *(*start_routine) (void*), void } if (pthread_attr_setschedparam(&attr, ¶m)) { perror("pthread_attr_setschedparam"); - fprintf(stderr, "Error not enough privileges to set Scheduling priority\n"); + ERROR("Error not enough privileges to set Scheduling priority\n"); } attr_enable = true; } else if (prio_offset == -2) { diff --git a/lib/src/phy/CMakeLists.txt b/lib/src/phy/CMakeLists.txt index b52af7b1d..43f242669 100644 --- a/lib/src/phy/CMakeLists.txt +++ b/lib/src/phy/CMakeLists.txt @@ -34,25 +34,45 @@ add_subdirectory(modem) add_subdirectory(resampling) add_subdirectory(scrambling) add_subdirectory(ue) -add_subdirectory(enb) +if(ENABLE_SRSENB) + add_subdirectory(enb) + set(srslte_srcs $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) +else(ENABLE_SRSENB) + set(srslte_srcs $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + ) + +endif(ENABLE_SRSENB) -set(srslte_srcs $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ -) add_library(srslte_phy STATIC ${srslte_srcs}) target_link_libraries(srslte_phy ${FFT_LIBRARIES}) diff --git a/lib/src/phy/agc/agc.c b/lib/src/phy/agc/agc.c index 38b8271e0..9554d78e6 100644 --- a/lib/src/phy/agc/agc.c +++ b/lib/src/phy/agc/agc.c @@ -157,8 +157,8 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { t = (float*) signal; y = t[srslte_vec_max_fi(t, 2*len)];// take only positive max to avoid abs() (should be similar) break; - default: - fprintf(stderr, "Unsupported AGC mode\n"); + default: + ERROR("Unsupported AGC mode\n"); return; } @@ -173,8 +173,8 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { case SRSLTE_AGC_MODE_PEAK_AMPLITUDE: y = q->y_tmp[srslte_vec_max_fi(q->y_tmp, q->nof_frames)]; break; - default: - fprintf(stderr, "Unsupported AGC mode\n"); + default: + ERROR("Unsupported AGC mode\n"); return; } } diff --git a/lib/src/phy/ch_estimation/chest_common.c b/lib/src/phy/ch_estimation/chest_common.c index 2ef80130d..d465ec280 100644 --- a/lib/src/phy/ch_estimation/chest_common.c +++ b/lib/src/phy/ch_estimation/chest_common.c @@ -37,7 +37,7 @@ #include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/convolution.h" -void srslte_chest_set_triangle_filter(float *fil, int filter_len) +uint32_t srslte_chest_set_triangle_filter(float* fil, int filter_len) { for (int i=0;i +#include #include #include -#include #include -#include -#include -#include -#include +#include #include "srslte/config.h" @@ -74,26 +71,25 @@ static void set_default_filter(srslte_chest_dl_t *q, int filter_len) { * * This object depends on the srslte_refsignal_t object for creating the LTE CSR signal. */ -int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) +int srslte_chest_dl_init(srslte_chest_dl_t* q, uint32_t max_prb, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL) { bzero(q, sizeof(srslte_chest_dl_t)); - ret = srslte_refsignal_cs_init(&q->csr_refs, max_prb); if (ret != SRSLTE_SUCCESS) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); goto clean_exit; } - - q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t)); + + q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t*)); if (!q->mbsfn_refs) { - fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret); + ERROR("Calloc error initializing mbsfn_refs (%d)\n", ret); goto clean_exit; } - + int pilot_vec_size; if(SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb)>SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)) { pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb); @@ -132,35 +128,28 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) } if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, SRSLTE_NRE*max_prb)) { - fprintf(stderr, "Error initializing vector interpolator\n"); - goto clean_exit; + ERROR("Error initializing vector interpolator\n"); + goto clean_exit; } if (srslte_interp_linear_init(&q->srslte_interp_lin, 2*max_prb, SRSLTE_NRE/2)) { - fprintf(stderr, "Error initializing interpolator\n"); - goto clean_exit; + ERROR("Error initializing interpolator\n"); + goto clean_exit; } if (srslte_interp_linear_init(&q->srslte_interp_lin_3, 4*max_prb, SRSLTE_NRE/4)) { - fprintf(stderr, "Error initializing interpolator\n"); + ERROR("Error initializing interpolator\n"); goto clean_exit; } if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) { - fprintf(stderr, "Error initializing interpolator\n"); + ERROR("Error initializing interpolator\n"); goto clean_exit; } - - q->noise_alg = SRSLTE_NOISE_ALG_REFS; - q->rsrp_neighbour = false; - q->average_subframe = false; - q->smooth_filter_auto = false; - q->smooth_filter_len = 3; - srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); - + q->nof_rx_antennas = nof_rx_antennas; } - + ret = SRSLTE_SUCCESS; clean_exit: @@ -207,10 +196,60 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q) bzero(q, sizeof(srslte_chest_dl_t)); } +int srslte_chest_dl_res_init(srslte_chest_dl_res_t* q, uint32_t max_prb) +{ + bzero(q, sizeof(srslte_chest_dl_res_t)); + q->nof_re = SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM); + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (uint32_t j = 0; j < SRSLTE_MAX_PORTS; j++) { + q->ce[i][j] = srslte_vec_malloc(q->nof_re * sizeof(cf_t)); + if (!q->ce[i][j]) { + perror("malloc"); + return -1; + } + bzero(q->ce[i][j], SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); + } + } + return 0; +} -int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){ +void srslte_chest_dl_res_set_identity(srslte_chest_dl_res_t* q) +{ + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (uint32_t j = 0; j < SRSLTE_MAX_PORTS; j++) { + for (uint32_t k = 0; k < q->nof_re; k++) { + q->ce[i][j][k] = (i == j) ? 1.0f : 0.0f; + } + } + } +} + +void srslte_chest_dl_res_set_ones(srslte_chest_dl_res_t* q) +{ + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (uint32_t j = 0; j < SRSLTE_MAX_PORTS; j++) { + for (uint32_t k = 0; k < q->nof_re; k++) { + q->ce[i][j][k] = 1.0f; + } + } + } +} + +void srslte_chest_dl_res_free(srslte_chest_dl_res_t* q) +{ + for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (uint32_t j = 0; j < SRSLTE_MAX_PORTS; j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } + } + } +} + +int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t* q, uint16_t mbsfn_area_id) +{ if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) { - if(!q->mbsfn_refs[mbsfn_area_id]) { + if (!q->mbsfn_refs[mbsfn_area_id]) { q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t)); if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell.nof_prb)) { return SRSLTE_ERROR; @@ -233,31 +272,31 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) srslte_cell_isvalid(&cell)) { if (q->cell.id != cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; ret = srslte_refsignal_cs_set_cell(&q->csr_refs, cell); if (ret != SRSLTE_SUCCESS) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); return SRSLTE_ERROR; } - if (srslte_pss_generate(q->pss_signal, cell.id%3)) { - fprintf(stderr, "Error initializing PSS signal for noise estimation\n"); + if (srslte_pss_generate(q->pss_signal, cell.id % 3)) { + ERROR("Error initializing PSS signal for noise estimation\n"); return SRSLTE_ERROR; } - if (srslte_interp_linear_vector_resize(&q->srslte_interp_linvec, SRSLTE_NRE*q->cell.nof_prb)) { - fprintf(stderr, "Error initializing vector interpolator\n"); + if (srslte_interp_linear_vector_resize(&q->srslte_interp_linvec, SRSLTE_NRE * q->cell.nof_prb)) { + ERROR("Error initializing vector interpolator\n"); return SRSLTE_ERROR; } if (srslte_interp_linear_resize(&q->srslte_interp_lin, 2*q->cell.nof_prb, SRSLTE_NRE/2)) { - fprintf(stderr, "Error initializing interpolator\n"); + ERROR("Error initializing interpolator\n"); return SRSLTE_ERROR; } if (srslte_interp_linear_resize(&q->srslte_interp_lin_3, 4 * q->cell.nof_prb, SRSLTE_NRE / 4)) { - fprintf(stderr, "Error initializing interpolator\n"); + ERROR("Error initializing interpolator\n"); return SRSLTE_ERROR; } - if (srslte_interp_linear_resize(&q->srslte_interp_lin_mbsfn, 6*q->cell.nof_prb, SRSLTE_NRE/6)) { + if (srslte_interp_linear_resize(&q->srslte_interp_lin_mbsfn, 6 * q->cell.nof_prb, SRSLTE_NRE / 6)) { fprintf(stderr, "Error initializing interpolator\n"); return SRSLTE_ERROR; } @@ -269,19 +308,33 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) } /* Uses the difference between the averaged and non-averaged pilot estimates */ -static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslte_sf_t ch_mode) +static float estimate_noise_pilots(srslte_chest_dl_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id) { - const float weight = 1.0f; + srslte_sf_t ch_mode = sf->sf_type; + const float weight = 1.0f; float sum_power = 0.0f; - uint32_t count = 0; - uint32_t npilots = (ch_mode == SRSLTE_SF_MBSFN)?SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id):SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); - uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id); + uint32_t count = 0; + uint32_t npilots = (ch_mode == SRSLTE_SF_MBSFN) ? SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id) + : srslte_refsignal_cs_nof_re(&q->csr_refs, sf, port_id); + uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() + : srslte_refsignal_cs_nof_symbols(&q->csr_refs, sf, port_id); uint32_t nref = npilots / nsymbols; uint32_t fidx = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_fidx(1):srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0); cf_t *input2d[nsymbols + 2]; cf_t *tmp_noise = q->tmp_noise; + // Special case for 1 symbol + if (nsymbols == 1) { + srslte_vec_sc_prod_cfc(q->pilot_estimates + 1, weight, tmp_noise, nref - 2); + srslte_vec_sum_ccc(q->pilot_estimates + 0, tmp_noise, tmp_noise, nref - 2); + srslte_vec_sum_ccc(q->pilot_estimates + 2, tmp_noise, tmp_noise, nref - 2); + srslte_vec_sc_prod_cfc(tmp_noise, 1.0f / (weight + 2.0f), tmp_noise, nref - 2); + srslte_vec_sub_ccc(q->pilot_estimates + 1, tmp_noise, tmp_noise, nref - 2); + sum_power = srslte_vec_avg_power_cf(tmp_noise, nref - 2); + return sum_power; + } + for (int i = 0; i < nsymbols; i++) { input2d[i + 1] = &q->pilot_estimates[i * nref]; } @@ -366,21 +419,28 @@ static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) { #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] -static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id, srslte_sf_t ch_mode) +static void interpolate_pilots(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* pilot_estimates, + cf_t* ce, + uint32_t port_id) { /* interpolate the symbols with references in the freq domain */ - uint32_t l; - uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nsymbols = (sf->sf_type == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() + 1 + : srslte_refsignal_cs_nof_symbols(&q->csr_refs, sf, port_id); uint32_t fidx_offset = 0; + /* Interpolate in the frequency domain */ - if (q->average_subframe) { - nsymbols = 1; + uint32_t freq_nsymbols = nsymbols; + if (!cfg->interpolate_subframe) { + freq_nsymbols = 1; } - // we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation - for (l=0;lsf_type == SRSLTE_SF_MBSFN) { if (l == 0) { fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], @@ -394,7 +454,7 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t } } else { - if (q->average_subframe) { + if (!cfg->interpolate_subframe && nsymbols > 1) { fidx_offset = q->cell.id % 3; srslte_interp_linear_offset(&q->srslte_interp_lin_3, pilot_estimates, @@ -409,33 +469,40 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t } } } - + /* Now interpolate in the time domain between symbols */ - if (q->average_subframe) { + if (sf->sf_type == SRSLTE_SF_NORM && (!cfg->interpolate_subframe || nsymbols < 3)) { // If we average per subframe, just copy the estimates in the time domain - for (l=1;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) { + for (uint32_t l = 1; l < 2 * SRSLTE_CP_NSYMB(q->cell.cp); l++) { memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb); } } else { - if (ch_mode == SRSLTE_SF_MBSFN) { + if (sf->sf_type == SRSLTE_SF_MBSFN) { srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); } else { if (SRSLTE_CP_ISNORM(q->cell.cp)) { - if (nsymbols == 4) { + if (port_id <= 2) { srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); + srslte_interp_linear_vector2( + &q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + } else { + srslte_interp_linear_vector2( + &q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(7), &cesymb(8), 3, 6); + } } else { srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); } } else { - if (nsymbols == 4) { + if (port_id <= 2) { + // TODO: TDD and extended cyclic prefix srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); @@ -450,148 +517,76 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t } } - -void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { - if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) { - if (filter) { - memcpy(q->smooth_filter, filter, filter_len*sizeof(float)); - q->smooth_filter_len = filter_len; - } else { - q->smooth_filter_len = 0; - } - } else { - fprintf(stderr, "Error setting smoothing filter: filter len exceeds maximum (%d>%d)\n", - filter_len, SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN); - } -} - -void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, srslte_chest_dl_noise_alg_t noise_estimation_alg) { - q->noise_alg = noise_estimation_alg; -} - -void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w) -{ - q->smooth_filter_len = 3; - q->smooth_filter[0] = w; - q->smooth_filter[2] = w; - q->smooth_filter[1] = 1-2*w; -} - -void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, uint32_t order, float std_dev) +static void average_pilots(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* input, + cf_t* output, + uint32_t port_id, + float* filter, + uint32_t filter_len) { - const uint32_t filterlen = order + 1; - const int center = (filterlen - 1) / 2; - float *filter = q->smooth_filter; - float norm_p = 0.0f; - - if (filterlen) { - - for (int i = 0; i < filterlen; i++) { - filter[i] = expf(-powf(i - center, 2) / (2.0f * powf(std_dev, 2))); - norm_p += powf(filter[i], 2); - } - - const float norm = srslte_vec_acc_ff(filter, filterlen); - - srslte_vec_sc_prod_fff(filter, 1.0f / norm, filter, filterlen); - q->smooth_filter_len = filterlen; - } -} - -void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t *q, bool enable) { - q->smooth_filter_auto = enable; -} - -uint32_t srslte_chest_dl_interleave_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *tmp, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) { - uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); - uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; - uint32_t fidx = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_fidx(1):srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0); - - if (fidx < 3) { - srslte_vec_interleave(input, &input[nref], tmp, nref); - for (int l = 2; l < nsymbols - 1; l += 2) { - srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], tmp, nref); - } - } else { - srslte_vec_interleave(&input[nref], input, tmp, nref); - for (int l = 2; l < nsymbols - 1; l += 2) { - srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], tmp, nref); - } - } - - nref *= 2; - srslte_vec_sc_prod_cfc(tmp, 2.0f / nsymbols, output, nref); - - return nref; -} - -static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) { - uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); - uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; + uint32_t nsymbols = (sf->sf_type == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols(port_id) + : srslte_refsignal_cs_nof_symbols(&q->csr_refs, sf, port_id); + uint32_t nref = (sf->sf_type == SRSLTE_SF_MBSFN) ? 6 * q->cell.nof_prb : 2 * q->cell.nof_prb; // Average in the time domain if enabled - if (q->average_subframe) { - if (ch_mode == SRSLTE_SF_MBSFN) { - for (int l = 1; l < nsymbols; l++) { - srslte_vec_sum_ccc(&input[l * nref], input, input, nref); + if (!cfg->interpolate_subframe && nsymbols > 1) { + cf_t* temp = output; // Use output as temporal buffer + + if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) { + srslte_vec_interleave(input, &input[nref], temp, nref); + for (int l = 2; l < nsymbols - 1; l += 2) { + srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], temp, nref); } - srslte_vec_sc_prod_cfc(input, 1.0f / ((float) nsymbols), input, nref); - nsymbols = 1; } else { - cf_t *temp = output; // Use ouput as temporal buffer - - if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) { - srslte_vec_interleave(input, &input[nref], temp, nref); - for (int l = 2; l < nsymbols - 1; l += 2) { - srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], temp, nref); - } - } else { - srslte_vec_interleave(&input[nref], input, temp, nref); - for (int l = 2; l < nsymbols - 1; l += 2) { - srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], temp, nref); - } + srslte_vec_interleave(&input[nref], input, temp, nref); + for (int l = 2; l < nsymbols - 1; l += 2) { + srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], temp, nref); } - nref *= 2; - srslte_vec_sc_prod_cfc(temp, 2.0f / (float) nsymbols, input, nref); - - nsymbols = 1; } - } + nref *= 2; + srslte_vec_sc_prod_cfc(temp, 2.0f / (float)nsymbols, input, nref); + nsymbols = 1; + } - uint32_t skip = (ch_mode == SRSLTE_SF_MBSFN)?2*q->cell.nof_prb:0; - - if(ch_mode == SRSLTE_SF_MBSFN){ + uint32_t skip = (sf->sf_type == SRSLTE_SF_MBSFN) ? 2 * q->cell.nof_prb : 0; + if (sf->sf_type == SRSLTE_SF_MBSFN) { memcpy(&output[0],&input[0],skip*sizeof(cf_t)); } // Average in the frequency domain for (int l=0;lsmooth_filter, &output[l*nref + skip], nref, q->smooth_filter_len); + srslte_conv_same_cf(&input[l * nref + skip], filter, &output[l * nref + skip], nref, filter_len); } } -float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) { +static float chest_dl_rssi(srslte_chest_dl_t* q, srslte_dl_sf_cfg_t* sf, cf_t* input, uint32_t port_id) +{ uint32_t l; float rssi = 0; - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(&q->csr_refs, sf, port_id); for (l=0;lcell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE]; rssi += srslte_vec_dot_prod_conj_ccc(tmp, tmp, q->cell.nof_prb * SRSLTE_NRE); - } - return rssi/nsymbols; + } + return rssi / nsymbols; } // CFO estimation algorithm taken from "Carrier Frequency Synchronization in the // Downlink of 3GPP LTE", Qi Wang, C. Mehlfuhrer, M. Rupp -float chest_estimate_cfo(srslte_chest_dl_t *q) +static float chest_estimate_cfo(srslte_chest_dl_t* q) { - float n = (float) srslte_symbol_sz(q->cell.nof_prb); - float ns = (float) SRSLTE_CP_NSYMB(q->cell.cp); - float ng = (float) SRSLTE_CP_LEN_NORM(1, n); + float n = (float)srslte_symbol_sz(q->cell.nof_prb); + float ns = (float)SRSLTE_CP_NSYMB(q->cell.cp); + float ng = (float)SRSLTE_CP_LEN_NORM(1, n); - uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 0); + srslte_dl_sf_cfg_t sf_cfg; + ZERO_OBJECT(sf_cfg); + + uint32_t npilots = srslte_refsignal_cs_nof_re(&q->csr_refs, &sf_cfg, 0); // Compute angles between slots for (int i=0;i<2;i++) { @@ -604,205 +599,189 @@ float chest_estimate_cfo(srslte_chest_dl_t *q) cf_t sum = srslte_vec_acc_cc(q->tmp_cfo_estimate, npilots/2); // Compute CFO - return -cargf(sum)*n/(ns*(n+ng))/2/M_PI; + return -cargf(sum) * n / (ns * (n + ng)) / 2 / M_PI; } -void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){ - if (q->cfo_estimate_enable && ((1<cfo_estimate_sf_mask) && ch_mode != SRSLTE_SF_MBSFN ) { +static void chest_interpolate_noise_est(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* input, + cf_t* ce, + uint32_t port_id, + uint32_t rxant_id) +{ + + float filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN]; + uint32_t filter_len = 0; + uint32_t sf_idx = sf->tti % 10; + srslte_sf_t ch_mode = sf->sf_type; + + if (cfg->cfo_estimate_enable && ((1 << sf_idx) & cfg->cfo_estimate_sf_mask) && ch_mode != SRSLTE_SF_MBSFN) { q->cfo = chest_estimate_cfo(q); } /* Estimate noise */ - if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && ch_mode != SRSLTE_SF_MBSFN ) { - q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode); + if (cfg->noise_alg == SRSLTE_NOISE_ALG_REFS) { + if (ch_mode == SRSLTE_SF_MBSFN) { + ERROR("Warning: REFS noise estimation algorithm not supported in MBSFN subframes\n"); + } + + q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, sf, port_id); } if (ce != NULL) { - if (q->smooth_filter_auto) { - srslte_chest_dl_set_smooth_filter_gauss(q, 4, q->noise_estimate[rxant_id][port_id] * 200.0f); + + switch (cfg->filter_type) { + case SRSLTE_CHEST_FILTER_GAUSS: + if (ch_mode == SRSLTE_SF_MBSFN) { + ERROR("Warning: Gauss filter not supported in MBSFN subframes\n"); + } + if (cfg->filter_coef[0] <= 0) { + filter_len = srslte_chest_set_smooth_filter_gauss(filter, 4, q->noise_estimate[rxant_id][port_id] * 200.0f); + } else { + filter_len = srslte_chest_set_smooth_filter_gauss(filter, (uint32_t)cfg->filter_coef[0], cfg->filter_coef[1]); + } + break; + case SRSLTE_CHEST_FILTER_TRIANGLE: + filter_len = srslte_chest_set_smooth_filter3_coeff(filter, cfg->filter_coef[0]); + break; + default: + break; + } + + if (!cfg->interpolate_subframe && ch_mode == SRSLTE_SF_MBSFN) { + ERROR("Warning: Subframe interpolation must be enabled in MBSFN subframes\n"); } /* Smooth estimates (if applicable) and interpolate */ - if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { - interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode); + if (cfg->filter_type == SRSLTE_CHEST_FILTER_NONE) { + interpolate_pilots(q, sf, cfg, q->pilot_estimates, ce, port_id); } else { - average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id, ch_mode); - interpolate_pilots(q, q->pilot_estimates_average, ce, port_id, ch_mode); + average_pilots(q, sf, cfg, q->pilot_estimates, q->pilot_estimates_average, port_id, filter, filter_len); + interpolate_pilots(q, sf, cfg, q->pilot_estimates_average, ce, port_id); + } + + /* Estimate noise for PSS and EMPTY algorithms */ + switch (cfg->noise_alg) { + case SRSLTE_NOISE_ALG_PSS: + if (sf_idx == 0 || sf_idx == 5) { + q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); + } + break; + case SRSLTE_NOISE_ALG_EMPTY: + if (sf_idx == 0 || sf_idx == 5) { + q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); + } + break; + default: + break; } - - /* Estimate noise power */ - if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) { - if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); - } - } else if (q->noise_alg != SRSLTE_NOISE_ALG_REFS) { - if (sf_idx == 0 || sf_idx == 5) { - q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); - } - } } } -int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) +static int estimate_port(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* input, + cf_t* ce, + uint32_t port_id, + uint32_t rxant_id) { - uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + uint32_t npilots = srslte_refsignal_cs_nof_re(&q->csr_refs, sf, port_id); /* Get references from the input signal */ - srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); - + srslte_refsignal_cs_get_sf(&q->csr_refs, sf, port_id, input, q->pilot_recv_signal); + /* Use the known CSR signal to compute Least-squares estimates */ - srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], - q->pilot_estimates, npilots); + srslte_vec_prod_conj_ccc( + q->pilot_recv_signal, q->csr_refs.pilots[port_id / 2][sf->tti % 10], q->pilot_estimates, npilots); /* Compute RSRP for the channel estimates in this port */ - if (q->rsrp_neighbour) { + if (cfg->rsrp_neighbour) { double energy = cabs(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots); - q->rsrp_corr[rxant_id][port_id] = energy*energy; + q->rsrp_corr[rxant_id][port_id] = energy * energy; } q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, npilots); - q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); + q->rssi[rxant_id][port_id] = chest_dl_rssi(q, sf, input, port_id); - chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM); + chest_interpolate_noise_est(q, sf, cfg, input, ce, port_id, rxant_id); return 0; } -int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id) +static int estimate_port_mbsfn(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* input, + cf_t* ce, + uint32_t port_id, + uint32_t rxant_id) { + uint32_t sf_idx = sf->tti % 10; + uint16_t mbsfn_area_id = cfg->mbsfn_area_id; + + if (!q->mbsfn_refs[mbsfn_area_id]) { + ERROR("Error in chest_dl: MBSFN area id=%d not initialized\n", cfg->mbsfn_area_id); + } /* Use the known CSR signal to compute Least-squares estimates */ srslte_refsignal_mbsfn_get_sf(q->cell, port_id, input, q->pilot_recv_signal); // estimate for non-mbsfn section of subframe - srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], - q->pilot_estimates, (2*q->cell.nof_prb)); - + srslte_vec_prod_conj_ccc( + q->pilot_recv_signal, q->csr_refs.pilots[port_id / 2][sf_idx], q->pilot_estimates, (2 * q->cell.nof_prb)); + srslte_vec_prod_conj_ccc(&q->pilot_recv_signal[(2*q->cell.nof_prb)], q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx], &q->pilot_estimates[(2*q->cell.nof_prb)], SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb)); - - chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN); - - return 0; -} + chest_interpolate_noise_est(q, sf, cfg, input, ce, port_id, rxant_id); -int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) -{ - for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { - if (srslte_chest_dl_estimate_port(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id)) { - return SRSLTE_ERROR; - } - } - } - q->last_nof_antennas = nof_rx_antennas; - return SRSLTE_SUCCESS; -} - -int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *input, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx) -{ - uint32_t port_id; - - for (port_id=0;port_idcell.nof_ports;port_id++) { - if (srslte_chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id, 0)) { - return SRSLTE_ERROR; - } - } - q->last_nof_antennas = 1; - return SRSLTE_SUCCESS; -} - -int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas, uint16_t mbsfn_area_id) -{ - for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { - if (srslte_chest_dl_estimate_port_mbsfn(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id, mbsfn_area_id)) { - return SRSLTE_ERROR; - } - } - } - q->last_nof_antennas = nof_rx_antennas; - return SRSLTE_SUCCESS; -} - -void srslte_chest_dl_set_rsrp_neighbour(srslte_chest_dl_t *q, bool rsrp_for_neighbour) { - q->rsrp_neighbour = rsrp_for_neighbour; -} - -void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable) -{ - q->average_subframe = enable; + return 0; } -void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask) +static float get_noise(srslte_chest_dl_t* q) { - q->cfo_estimate_enable = enable; - q->cfo_estimate_sf_mask = mask; -} - -float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q) { - return q->cfo; -} - -float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { - float n = 0; - for (int i=0;ilast_nof_antennas;i++) { + float n = 0; + for (int i = 0; i < q->nof_rx_antennas; i++) { n += srslte_vec_acc_ff(q->noise_estimate[i], q->cell.nof_ports)/q->cell.nof_ports; } - if (q->last_nof_antennas) { - n /= q->last_nof_antennas; + if (q->nof_rx_antennas) { + n /= q->nof_rx_antennas; } return n; } -float srslte_chest_dl_get_snr(srslte_chest_dl_t *q) { -#ifdef FREQ_SEL_SNR - int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 0); - return srslte_vec_acc_ff(q->snr_vector, nref)/nref; -#else - float rsrp = 0; - for (int i=0;ilast_nof_antennas;i++) { - for (int j=0;jcell.nof_ports;j++) { - rsrp += q->rsrp[i][j]/q->cell.nof_ports; - } +static float get_rssi(srslte_chest_dl_t* q) +{ + float n = 0; + for (int i = 0; i < q->nof_rx_antennas; i++) { + n += 4 * q->rssi[i][0] / q->cell.nof_prb / SRSLTE_NRE; } - return rsrp/srslte_chest_dl_get_noise_estimate(q); -#endif -} - - -float srslte_chest_dl_get_snr_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx, uint32_t port_idx) { - return srslte_chest_dl_get_rsrp_ant_port(q, ant_idx, port_idx)/srslte_chest_dl_get_noise_estimate(q); + return n / q->nof_rx_antennas; } -float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q) { - float n = 0; - for (int i=0;ilast_nof_antennas;i++) { - n += 4*q->rssi[i][0]/q->cell.nof_prb/SRSLTE_NRE; - } - return n/q->last_nof_antennas; -} - -/* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB - * q->rsrp[0] is the average power of RE containing references only (for port 0). -*/ -float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) { - float n = 0; - for (int i=0;ilast_nof_antennas;i++) { +/* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb + * is the average power per PRB q->rsrp[0] is the average power of RE containing references only (for port 0). + */ +static float get_rsrq(srslte_chest_dl_t* q) +{ + float n = 0; + for (int i = 0; i < q->nof_rx_antennas; i++) { n += q->cell.nof_prb*q->rsrp[i][0] / q->rssi[i][0]; } - return n/q->last_nof_antennas; - + return n / q->nof_rx_antennas; } float srslte_chest_dl_get_rsrq_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx, uint32_t port_idx) { return q->cell.nof_prb*q->rsrp[ant_idx][port_idx] / q->rssi[ant_idx][port_idx]; } -float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t *q, uint32_t ant_idx, uint32_t port) { +float srslte_chest_dl_get_rsrp_ant_port(srslte_chest_dl_t* q, uint32_t ant_idx, uint32_t port) +{ return q->rsrp[ant_idx][port]; } -float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) { +static float get_rsrp_port(srslte_chest_dl_t* q, uint32_t port) +{ float sum = 0.0f; for (int j = 0; j < q->cell.nof_ports; ++j) { sum +=q->rsrp[port][j]; @@ -815,7 +794,8 @@ float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) { return sum; } -float srslte_chest_dl_get_rsrp_neighbour_port(srslte_chest_dl_t *q, uint32_t port) { +static float get_rsrp_neigbhour_port(srslte_chest_dl_t* q, uint32_t port) +{ float sum = 0.0f; for (int j = 0; j < q->cell.nof_ports; ++j) { sum +=q->rsrp_corr[port][j]; @@ -828,10 +808,11 @@ float srslte_chest_dl_get_rsrp_neighbour_port(srslte_chest_dl_t *q, uint32_t por return sum; } -float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { +static float get_rsrp(srslte_chest_dl_t* q) +{ float max = -1e9; - for (int i = 0; i < q->last_nof_antennas; ++i) { - float v = srslte_chest_dl_get_rsrp_port(q, i); + for (int i = 0; i < q->nof_rx_antennas; ++i) { + float v = get_rsrp_port(q, i); if (v > max) { max = v; } @@ -839,13 +820,82 @@ float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { return max; } -float srslte_chest_dl_get_rsrp_neighbour(srslte_chest_dl_t *q) { +static float get_snr(srslte_chest_dl_t* q) +{ +#ifdef FREQ_SEL_SNR + int nref = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 0); + return srslte_vec_acc_ff(q->snr_vector, nref) / nref; +#else + return get_rsrp(q) / get_noise(q); +#endif +} + +static float get_rsrp_neighbour(srslte_chest_dl_t* q) +{ float max = -1e9; - for (int i = 0; i < q->last_nof_antennas; ++i) { - float v = srslte_chest_dl_get_rsrp_neighbour_port(q, i); + for (int i = 0; i < q->nof_rx_antennas; ++i) { + float v = get_rsrp_neigbhour_port(q, i); if (v > max) { max = v; } } return max; } + +#define dbm(a) (10 * log10(a) + 30) +#define db(a) (10 * log10(a)) + +static void fill_res(srslte_chest_dl_t* q, srslte_chest_dl_res_t* res) +{ + res->noise_estimate = get_noise(q); + res->noise_estimate_dbm = dbm(res->noise_estimate); + res->cfo = q->cfo; + res->rsrp = get_rsrp(q); + res->rsrp_dbm = dbm(res->rsrp); + res->rsrp_neigh_dbm = dbm(get_rsrp_neighbour(q)); + res->rsrq = get_rsrq(q); + res->rsrq_db = db(res->rsrq); + res->snr_db = db(get_snr(q)); + res->rssi_dbm = dbm(get_rssi(q)); + + for (uint32_t port_id = 0; port_id < q->cell.nof_ports; port_id++) { + res->rsrp_port_dbm[port_id] = dbm(get_rsrp_port(q, port_id)); + } +} + +int srslte_chest_dl_estimate(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + cf_t* input[SRSLTE_MAX_PORTS], + srslte_chest_dl_res_t* res) +{ + srslte_chest_dl_cfg_t cfg; + ZERO_OBJECT(cfg); + + return srslte_chest_dl_estimate_cfg(q, sf, &cfg, input, res); +} + +int srslte_chest_dl_estimate_cfg(srslte_chest_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_cfg_t* cfg, + cf_t* input[SRSLTE_MAX_PORTS], + srslte_chest_dl_res_t* res) +{ + + for (uint32_t rxant_id = 0; rxant_id < q->nof_rx_antennas; rxant_id++) { + for (uint32_t port_id = 0; port_id < q->cell.nof_ports; port_id++) { + if (sf->sf_type == SRSLTE_SF_MBSFN) { + if (estimate_port_mbsfn(q, sf, cfg, input[rxant_id], res->ce[port_id][rxant_id], port_id, rxant_id)) { + return SRSLTE_ERROR; + } + } else { + if (estimate_port(q, sf, cfg, input[rxant_id], res->ce[port_id][rxant_id], port_id, rxant_id)) { + return SRSLTE_ERROR; + } + } + } + } + + fill_res(q, res); + + return SRSLTE_SUCCESS; +} diff --git a/lib/src/phy/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c index d7e6f3be0..2861a2990 100644 --- a/lib/src/phy/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -32,15 +32,13 @@ #include #include #include -#include -#include #include "srslte/config.h" - -#include "srslte/phy/dft/dft_precoding.h" #include "srslte/phy/ch_estimation/chest_ul.h" -#include "srslte/phy/utils/vector.h" +#include "srslte/phy/dft/dft_precoding.h" #include "srslte/phy/utils/convolution.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" #define NOF_REFS_SYM (q->cell.nof_prb*SRSLTE_NRE) #define NOF_REFS_SF (NOF_REFS_SYM*2) // 2 reference symbols per subframe @@ -66,7 +64,7 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, uint32_t max_prb) ret = srslte_refsignal_ul_init(&q->dmrs_signal, max_prb); if (ret != SRSLTE_SUCCESS) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); goto clean_exit; } @@ -100,17 +98,17 @@ int srslte_chest_ul_init(srslte_chest_ul_t *q, uint32_t max_prb) } if (srslte_interp_linear_vector_init(&q->srslte_interp_linvec, MAX_REFS_SYM)) { - fprintf(stderr, "Error initializing vector interpolator\n"); + ERROR("Error initializing vector interpolator\n"); goto clean_exit; } - q->smooth_filter_len = 3; - srslte_chest_ul_set_smooth_filter3_coeff(q, 0.3333); - + q->smooth_filter_len = 3; + srslte_chest_set_smooth_filter3_coeff(q->smooth_filter, 0.3333); + q->dmrs_signal_configured = false; - if (srslte_refsignal_dmrs_pusch_pregen_init(&q->dmrs_signal, &q->dmrs_pregen, max_prb)) { - fprintf(stderr, "Error allocating memory for pregenerated signals\n"); + if (srslte_refsignal_dmrs_pusch_pregen_init(&q->dmrs_pregen, max_prb)) { + ERROR("Error allocating memory for pregenerated signals\n"); goto clean_exit; } @@ -152,22 +150,48 @@ void srslte_chest_ul_free(srslte_chest_ul_t *q) bzero(q, sizeof(srslte_chest_ul_t)); } -int srslte_chest_ul_set_cell(srslte_chest_ul_t *q, srslte_cell_t cell) +int srslte_chest_ul_res_init(srslte_chest_ul_res_t* q, uint32_t max_prb) +{ + bzero(q, sizeof(srslte_chest_ul_res_t)); + q->nof_re = SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM); + q->ce = srslte_vec_malloc(q->nof_re * sizeof(cf_t)); + if (!q->ce) { + perror("malloc"); + return -1; + } + return 0; +} + +void srslte_chest_ul_res_set_identity(srslte_chest_ul_res_t* q) +{ + for (uint32_t i = 0; i < q->nof_re; i++) { + q->ce[i] = 1.0; + } +} + +void srslte_chest_ul_res_free(srslte_chest_ul_res_t* q) +{ + if (q->ce) { + free(q->ce); + } +} + +int srslte_chest_ul_set_cell(srslte_chest_ul_t* q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && srslte_cell_isvalid(&cell)) { if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - ret = srslte_refsignal_ul_set_cell(&q->dmrs_signal, cell); + q->cell = cell; + ret = srslte_refsignal_ul_set_cell(&q->dmrs_signal, cell); if (ret != SRSLTE_SUCCESS) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); return SRSLTE_ERROR; } if (srslte_interp_linear_vector_resize(&q->srslte_interp_linvec, NOF_REFS_SYM)) { - fprintf(stderr, "Error initializing vector interpolator\n"); + ERROR("Error initializing vector interpolator\n"); return SRSLTE_ERROR; } } @@ -176,14 +200,10 @@ int srslte_chest_ul_set_cell(srslte_chest_ul_t *q, srslte_cell_t cell) return ret; } -void srslte_chest_ul_set_cfg(srslte_chest_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pucch_cfg_t *pucch_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg) +void srslte_chest_ul_pregen(srslte_chest_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* cfg) { - srslte_refsignal_ul_set_cfg(&q->dmrs_signal, pusch_cfg, pucch_cfg, srs_cfg); - srslte_refsignal_dmrs_pusch_pregen(&q->dmrs_signal, &q->dmrs_pregen); - q->dmrs_signal_configured = true; + srslte_refsignal_dmrs_pusch_pregen(&q->dmrs_signal, &q->dmrs_pregen, cfg); + q->dmrs_signal_configured = true; } /* Uses the difference between the averaged and non-averaged pilot estimates */ @@ -214,8 +234,9 @@ static float estimate_noise_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nref #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,n_prb[0]*SRSLTE_NRE)] static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { +#ifdef DO_LINEAR_INTERPOLATION uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp); - uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp); + uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp); uint32_t NL = 2*SRSLTE_CP_NSYMB(q->cell.cp); /* Interpolate in the time domain between symbols */ @@ -225,27 +246,16 @@ static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, u &cesymb(L1), &cesymb(L2), NULL, &cesymb(L1+1), (L2-L1), (L2-L1)-1, true, nrefs); srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L2), &cesymb(L2+1), (L2-L1), (NL-L2)-1, true, nrefs); - -} - -void srslte_chest_ul_set_smooth_filter(srslte_chest_ul_t *q, float *filter, uint32_t filter_len) { - if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) { - if (filter) { - memcpy(q->smooth_filter, filter, filter_len*sizeof(float)); - q->smooth_filter_len = filter_len; - } else { - q->smooth_filter_len = 0; +#else + // Instead of a linear interpolation, we just copy the estimates to all symbols in that subframe + for (int s = 0; s < 2; s++) { + for (int i = 0; i < SRSLTE_CP_NSYMB(q->cell.cp); i++) { + memcpy(&ce[((i + s * SRSLTE_CP_NSYMB(q->cell.cp)) * q->cell.nof_prb + n_prb[s]) * SRSLTE_NRE], + &ce[(SRSLTE_REFSIGNAL_UL_L(s, q->cell.cp) * q->cell.nof_prb + n_prb[s]) * SRSLTE_NRE], + nrefs * sizeof(cf_t)); } - } else { - fprintf(stderr, "Error setting smoothing filter: filter len exceeds maximum (%d>%d)\n", - filter_len, SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN); } -} - -void srslte_chest_ul_set_smooth_filter3_coeff(srslte_chest_ul_t* q, float w) -{ - srslte_chest_set_smooth_filter3_coeff(q->smooth_filter, w); - q->smooth_filter_len = 3; +#endif } static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { @@ -256,115 +266,126 @@ static void average_pilots(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, uint32_t } } -int srslte_chest_ul_estimate(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, - uint32_t nof_prb, uint32_t sf_idx, uint32_t cyclic_shift_for_dmrs, uint32_t n_prb[2]) +int srslte_chest_ul_estimate_pusch( + srslte_chest_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_pusch_cfg_t* cfg, cf_t* input, srslte_chest_ul_res_t* res) { if (!q->dmrs_signal_configured) { - fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); - return SRSLTE_ERROR; + ERROR("Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); + return SRSLTE_ERROR; } - + + uint32_t nof_prb = cfg->grant.L_prb; + if (!srslte_dft_precoding_valid_prb(nof_prb)) { - fprintf(stderr, "Error invalid nof_prb=%d\n", nof_prb); + ERROR("Error invalid nof_prb=%d\n", nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } - - int nrefs_sym = nof_prb*SRSLTE_NRE; - int nrefs_sf = nrefs_sym*2; - + + int nrefs_sym = nof_prb * SRSLTE_NRE; + int nrefs_sf = nrefs_sym * 2; + /* Get references from the input signal */ - srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, input, nof_prb, n_prb, q->pilot_recv_signal); - + srslte_refsignal_dmrs_pusch_get(&q->dmrs_signal, cfg, input, q->pilot_recv_signal); + /* Use the known DMRS signal to compute Least-squares estimates */ - srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->dmrs_pregen.r[cyclic_shift_for_dmrs][sf_idx][nof_prb], - q->pilot_estimates, nrefs_sf); - - if (n_prb[0] != n_prb[1]) { + srslte_vec_prod_conj_ccc( + q->pilot_recv_signal, q->dmrs_pregen.r[cfg->grant.n_dmrs][sf->tti % 10][nof_prb], q->pilot_estimates, nrefs_sf); + + if (cfg->grant.n_prb[0] != cfg->grant.n_prb[1]) { printf("ERROR: intra-subframe frequency hopping not supported in the estimator!!\n"); } - - if (ce != NULL) { + + if (res->ce != NULL) { if (q->smooth_filter_len > 0) { - average_pilots(q, q->pilot_estimates, ce, nrefs_sym, n_prb); - interpolate_pilots(q, ce, nrefs_sym, n_prb); + average_pilots(q, q->pilot_estimates, res->ce, nrefs_sym, cfg->grant.n_prb); + interpolate_pilots(q, res->ce, nrefs_sym, cfg->grant.n_prb); /* If averaging, compute noise from difference between received and averaged estimates */ - q->noise_estimate = estimate_noise_pilots(q, ce, nrefs_sym, n_prb); + res->noise_estimate = estimate_noise_pilots(q, res->ce, nrefs_sym, cfg->grant.n_prb); } else { // Copy estimates to CE vector without averaging for (int i=0;i<2;i++) { - memcpy(&ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp)*q->cell.nof_prb*SRSLTE_NRE+n_prb[i]*SRSLTE_NRE], - &q->pilot_estimates[i*nrefs_sym], - nrefs_sym*sizeof(cf_t)); + memcpy(&res->ce[SRSLTE_REFSIGNAL_UL_L(i, q->cell.cp) * q->cell.nof_prb * SRSLTE_NRE + + cfg->grant.n_prb[i] * SRSLTE_NRE], + &q->pilot_estimates[i * nrefs_sym], + nrefs_sym * sizeof(cf_t)); } - interpolate_pilots(q, ce, nrefs_sym, n_prb); - q->noise_estimate = 0; + interpolate_pilots(q, res->ce, nrefs_sym, cfg->grant.n_prb); + res->noise_estimate = 0; } } // Estimate received pilot power - q->pilot_power = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf); + if (res->noise_estimate) { + res->snr = srslte_vec_avg_power_cf(q->pilot_recv_signal, nrefs_sf) / res->noise_estimate; + } else { + res->snr = NAN; + } + + res->snr_db = 10 * log10(res->snr); + res->noise_estimate_dbm = 10 * log10(res->noise_estimate) + 30; + return 0; } -int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, - srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx, - uint8_t *pucch2_ack_bits) +int srslte_chest_ul_estimate_pucch( + srslte_chest_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, cf_t* input, srslte_chest_ul_res_t* res) { if (!q->dmrs_signal_configured) { - fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); - return SRSLTE_ERROR; + ERROR("Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); + return SRSLTE_ERROR; } - - int n_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp); + + int n_rs = srslte_refsignal_dmrs_N_rs(cfg->format, q->cell.cp); if (!n_rs) { - fprintf(stderr, "Error computing N_rs\n"); - return SRSLTE_ERROR; + ERROR("Error computing N_rs\n"); + return SRSLTE_ERROR; } - int nrefs_sf = SRSLTE_NRE*n_rs*2; - + int nrefs_sf = SRSLTE_NRE * n_rs * 2; + /* Get references from the input signal */ - srslte_refsignal_dmrs_pucch_get(&q->dmrs_signal, format, n_pucch, input, q->pilot_recv_signal); - + srslte_refsignal_dmrs_pucch_get(&q->dmrs_signal, cfg, input, q->pilot_recv_signal); + /* Generate known pilots */ - uint8_t pucch2_bits[2] = {0, 0}; - if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { + if (cfg->format == SRSLTE_PUCCH_FORMAT_2A || cfg->format == SRSLTE_PUCCH_FORMAT_2B) { float max = -1e9; - int i_max = 0; - - int m = 0; - if (format == SRSLTE_PUCCH_FORMAT_2A) { - m = 2; + int i_max = 0; + + int m = 0; + if (cfg->format == SRSLTE_PUCCH_FORMAT_2A) { + m = 2; } else { m = 4; } for (int i=0;idmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal); + cfg->pucch2_drs_bits[0] = i % 2; + cfg->pucch2_drs_bits[1] = i / 2; + srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, sf, cfg, q->pilot_known_signal); srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates_tmp[i], nrefs_sf); float x = cabsf(srslte_vec_acc_cc(q->pilot_estimates_tmp[i], nrefs_sf)); if (x >= max) { - max = x; - i_max = i; - } + max = x; + i_max = i; + } } memcpy(q->pilot_estimates, q->pilot_estimates_tmp[i_max], nrefs_sf*sizeof(cf_t)); - pucch2_ack_bits[0] = i_max%2; - pucch2_ack_bits[1] = i_max/2; + cfg->pucch2_drs_bits[0] = i_max % 2; + cfg->pucch2_drs_bits[1] = i_max / 2; + } else { - srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal); + srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, sf, cfg, q->pilot_known_signal); /* Use the known DMRS signal to compute Least-squares estimates */ srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf); } - - if (ce != NULL) { + + if (res->ce != NULL) { /* FIXME: Currently averaging entire slot, performance good enough? */ - for (int ns=0;ns<2;ns++) { + for (int ns = 0; ns < 2; ns++) { // Average all slot for (int i=1;ipilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_estimates[(i+ns*n_rs)*SRSLTE_NRE], - &q->pilot_estimates[ns*n_rs*SRSLTE_NRE], + srslte_vec_sum_ccc(&q->pilot_estimates[ns * n_rs * SRSLTE_NRE], + &q->pilot_estimates[(i + ns * n_rs) * SRSLTE_NRE], + &q->pilot_estimates[ns * n_rs * SRSLTE_NRE], SRSLTE_NRE); } srslte_vec_sc_prod_ccc(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], (float) 1.0/n_rs, @@ -376,25 +397,17 @@ int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, q->smooth_filter, SRSLTE_NRE, 1, q->smooth_filter_len); // Determine n_prb - uint32_t n_prb = srslte_pucch_n_prb(&q->dmrs_signal.pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); + uint32_t n_prb = srslte_pucch_n_prb(&q->cell, cfg, ns); // copy estimates to slot for (int i=0;icell.cp);i++) { - memcpy(&ce[SRSLTE_RE_IDX(q->cell.nof_prb, i+ns*SRSLTE_CP_NSYMB(q->cell.cp), n_prb*SRSLTE_NRE)], - &q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE], sizeof(cf_t)*SRSLTE_NRE); + memcpy(&res->ce[SRSLTE_RE_IDX(q->cell.nof_prb, i + ns * SRSLTE_CP_NSYMB(q->cell.cp), n_prb * SRSLTE_NRE)], + &q->pilot_recv_signal[ns * n_rs * SRSLTE_NRE], + sizeof(cf_t) * SRSLTE_NRE); } } } - - return 0; -} - -float srslte_chest_ul_get_noise_estimate(srslte_chest_ul_t *q) { - return q->noise_estimate; -} - -float srslte_chest_ul_get_snr(srslte_chest_ul_t *q) { - return q->pilot_power/srslte_chest_ul_get_noise_estimate(q); + return 0; } diff --git a/lib/src/phy/ch_estimation/refsignal_dl.c b/lib/src/phy/ch_estimation/refsignal_dl.c index 1c949f7a0..a9e0846a8 100644 --- a/lib/src/phy/ch_estimation/refsignal_dl.c +++ b/lib/src/phy/ch_estimation/refsignal_dl.c @@ -24,12 +24,12 @@ * */ - +#include "srslte/srslte.h" +#include #include +#include #include #include -#include -#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/ch_estimation/refsignal_dl.h" @@ -37,6 +37,105 @@ #include "srslte/phy/utils/debug.h" #include "srslte/phy/common/sequence.h" +/** Allocates memory for the 20 slots in a subframe + */ +int srslte_refsignal_cs_init(srslte_refsignal_t* q, uint32_t max_prb) +{ + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = SRSLTE_ERROR; + bzero(q, sizeof(srslte_refsignal_t)); + for (int p = 0; p < 2; p++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { + q->pilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)); + if (!q->pilots[p][i]) { + perror("malloc"); + goto free_and_exit; + } + } + } + ret = SRSLTE_SUCCESS; + } +free_and_exit: + if (ret == SRSLTE_ERROR) { + srslte_refsignal_free(q); + } + return ret; +} + +/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for + * the 20 slots in a subframe + */ +int srslte_refsignal_cs_set_cell(srslte_refsignal_t* q, srslte_cell_t cell) +{ + + uint32_t c_init; + uint32_t N_cp, mp; + srslte_sequence_t seq; + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && srslte_cell_isvalid(&cell)) { + if (cell.id != q->cell.id || q->cell.nof_prb == 0) { + q->cell = cell; + + bzero(&seq, sizeof(srslte_sequence_t)); + if (srslte_sequence_init(&seq, 2 * 2 * SRSLTE_MAX_PRB)) { + return SRSLTE_ERROR; + } + + if (SRSLTE_CP_ISNORM(cell.cp)) { + N_cp = 1; + } else { + N_cp = 0; + } + + srslte_dl_sf_cfg_t sf_cfg; + ZERO_OBJECT(sf_cfg); + + for (uint32_t ns = 0; ns < SRSLTE_NSLOTS_X_FRAME; ns++) { + for (uint32_t p = 0; p < 2; p++) { + sf_cfg.tti = ns / 2; + uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(q, &sf_cfg, 2 * p) / 2; + for (uint32_t l = 0; l < nsymbols; l++) { + /* Compute sequence init value */ + uint32_t lp = srslte_refsignal_cs_nsymbol(l, cell.cp, 2 * p); + c_init = 1024 * (7 * (ns + 1) + lp + 1) * (2 * cell.id + 1) + 2 * cell.id + N_cp; + + /* generate sequence for this symbol and slot */ + srslte_sequence_set_LTE_pr(&seq, 2 * 2 * SRSLTE_MAX_PRB, c_init); + + /* Compute signal */ + for (uint32_t i = 0; i < 2 * q->cell.nof_prb; i++) { + mp = i + SRSLTE_MAX_PRB - cell.nof_prb; + /* save signal */ + q->pilots[p][ns / 2][SRSLTE_REFSIGNAL_PILOT_IDX(i, (ns % 2) * nsymbols + l, q->cell)] = + (1 - 2 * (float)seq.c[2 * mp]) / sqrt(2) + _Complex_I * (1 - 2 * (float)seq.c[2 * mp + 1]) / sqrt(2); + } + } + } + } + srslte_sequence_free(&seq); + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + +/** Deallocates a srslte_refsignal_cs_t object allocated with srslte_refsignal_cs_init */ +void srslte_refsignal_free(srslte_refsignal_t* q) +{ + for (int p = 0; p < 2; p++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { + if (q->pilots[p][i]) { + free(q->pilots[p][i]); + } + } + } + bzero(q, sizeof(srslte_refsignal_t)); +} + uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx) { uint32_t v = 0; @@ -73,43 +172,76 @@ uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx) return v; } -uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id) +inline uint32_t srslte_refsignal_cs_nof_symbols(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id) { - uint32_t ret; - if (port_id < 2) { - ret = 4; + if (q->cell.frame_type == SRSLTE_FDD || !sf->tdd_config.configured || + srslte_sfidx_tdd_type(sf->tdd_config, sf->tti % 10) == SRSLTE_TDD_SF_D) { + if (port_id < 2) { + return 4; + } else { + return 2; + } } else { - ret = 2; + uint32_t nof_dw_symbols = srslte_sfidx_tdd_nof_dw(sf->tdd_config); + if (q->cell.cp == SRSLTE_CP_NORM) { + if (nof_dw_symbols >= 12) { + if (port_id < 2) { + return 4; + } else { + return 2; + } + } else if (nof_dw_symbols >= 9) { + if (port_id < 2) { + return 3; + } else { + return 2; + } + } else if (nof_dw_symbols >= 5) { + if (port_id < 2) { + return 2; + } else { + return 1; + } + } else { + return 1; + } + } else { + if (nof_dw_symbols >= 10) { + if (port_id < 2) { + return 4; + } else { + return 2; + } + } else if (nof_dw_symbols >= 8) { + if (port_id < 2) { + return 3; + } else { + return 2; + } + } else if (nof_dw_symbols >= 4) { + if (port_id < 2) { + return 2; + } else { + return 1; + } + } else { + return 1; + } + } } - return ret; } -uint32_t srslte_refsignal_mbsfn_nof_symbols() +inline uint32_t srslte_refsignal_cs_nof_re(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id) { - return 3; + return srslte_refsignal_cs_nof_symbols(q, sf, port_id) * q->cell.nof_prb * 2; // 2 RE per PRB } - inline uint32_t srslte_refsignal_cs_fidx(srslte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m) { return 6*m + ((srslte_refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6); } -inline uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l) +inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id) { - - uint32_t ret = 0; - if(l == 0){ - ret = 0; - }else if (l == 1){ - ret = 1; - }else if(l == 2){ - ret = 0; - } - - return ret; -} - -inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id) { if (port_id < 2) { if (l % 2) { return (l/2+1)*SRSLTE_CP_NSYMB(cp) - 3; @@ -121,59 +253,156 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t } } +/* Maps a reference signal initialized with srslte_refsignal_cs_init() into an array of subframe symbols */ +int srslte_refsignal_cs_put_sf(srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id, cf_t* sf_symbols) +{ + uint32_t i, l; + uint32_t fidx; + + if (q != NULL && port_id < SRSLTE_MAX_PORTS && sf_symbols != NULL) { + cf_t* pilots = q->pilots[port_id / 2][sf->tti % 10]; + for (l = 0; l < srslte_refsignal_cs_nof_symbols(q, sf, port_id); l++) { + uint32_t nsymbol = srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id); + /* Compute offset frequency index */ + fidx = ((srslte_refsignal_cs_v(port_id, l) + (q->cell.id % 6)) % 6); + for (i = 0; i < 2 * q->cell.nof_prb; i++) { + sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, nsymbol, fidx)] = pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i, l, q->cell)]; + fidx += SRSLTE_NRE / 2; // 1 reference every 6 RE + } + } + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + +/** Copies the RE containing references from an array of subframe symbols to the pilots array. */ +int srslte_refsignal_cs_get_sf( + srslte_refsignal_t* q, srslte_dl_sf_cfg_t* sf, uint32_t port_id, cf_t* sf_symbols, cf_t* pilots) +{ + uint32_t i, l; + uint32_t fidx; + + if (q != NULL && pilots != NULL && sf_symbols != NULL) { + for (l = 0; l < srslte_refsignal_cs_nof_symbols(q, sf, port_id); l++) { + uint32_t nsymbol = srslte_refsignal_cs_nsymbol(l, q->cell.cp, port_id); + /* Compute offset frequency index */ + fidx = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); + for (i = 0; i < 2 * q->cell.nof_prb; i++) { + pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i, l, q->cell)] = sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, nsymbol, fidx)]; + fidx += SRSLTE_NRE / 2; // 2 references per PRB + } + } + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + +SRSLTE_API int srslte_refsignal_mbsfn_put_sf( + srslte_cell_t cell, uint32_t port_id, cf_t* cs_pilots, cf_t* mbsfn_pilots, cf_t* sf_symbols) +{ + uint32_t i, l; + uint32_t fidx; + + if (srslte_cell_isvalid(&cell) && srslte_portid_isvalid(port_id) && cs_pilots != NULL && mbsfn_pilots != NULL && + sf_symbols != NULL) { + // adding CS refs for the non-mbsfn section of the sub-frame + fidx = ((srslte_refsignal_cs_v(port_id, 0) + (cell.id % 6)) % 6); + for (i = 0; i < 2 * cell.nof_prb; i++) { + sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, 0, fidx)] = cs_pilots[SRSLTE_REFSIGNAL_PILOT_IDX(i, 0, cell)]; + fidx += SRSLTE_NRE / 2; // 1 reference every 6 RE + } + + for (l = 0; l < srslte_refsignal_mbsfn_nof_symbols(); l++) { + uint32_t nsymbol = srslte_refsignal_mbsfn_nsymbol(l); + fidx = srslte_refsignal_mbsfn_fidx(l); + for (i = 0; i < 6 * cell.nof_prb; i++) { + sf_symbols[SRSLTE_RE_IDX(cell.nof_prb, nsymbol, fidx)] = + mbsfn_pilots[SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i, l, cell)]; + fidx += SRSLTE_NRE / 6; + } + } + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + +uint32_t srslte_refsignal_mbsfn_nof_symbols() +{ + return 3; +} + +inline uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l) +{ + + uint32_t ret = 0; + if (l == 0) { + ret = 0; + } else if (l == 1) { + ret = 1; + } else if (l == 2) { + ret = 0; + } + + return ret; +} inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l) { uint32_t ret = 0; - if(l == 0){ - ret = 2; - } else if (l == 1) { - ret = 6; - } else if (l == 2){ - ret = 10; - } - - return ret; + if (l == 0) { + ret = 2; + } else if (l == 1) { + ret = 6; + } else if (l == 2) { + ret = 10; + } + + return ret; } -int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, srslte_cell_t cell, uint32_t N_mbsfn_id) +int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t* q, srslte_cell_t cell, uint32_t N_mbsfn_id) { uint32_t c_init; uint32_t i, ns, l, p; uint32_t mp; - int ret = SRSLTE_ERROR; + int ret = SRSLTE_ERROR; srslte_sequence_t seq_mbsfn; bzero(&seq_mbsfn, sizeof(srslte_sequence_t)); - if (srslte_sequence_init(&seq_mbsfn, 20* SRSLTE_MAX_PRB)) { + if (srslte_sequence_init(&seq_mbsfn, 20 * SRSLTE_MAX_PRB)) { goto free_and_exit; } - for(ns=0; nscell.nof_prb;i++) { - mp = i + 3*(SRSLTE_MAX_PRB - cell.nof_prb); - q->pilots[p][ns][ SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i, l ,q->cell)] = (1 - 2 * (float) seq_mbsfn.c[2 * mp]) / sqrt(2) +_Complex_I * (1 - 2 * (float) seq_mbsfn.c[2 * mp + 1]) / sqrt(2); + uint32_t slot = (l) ? (ns * 2 + 1) : (ns * 2); + c_init = 512 * (7 * (slot + 1) + lp + 1) * (2 * N_mbsfn_id + 1) + N_mbsfn_id; + srslte_sequence_set_LTE_pr(&seq_mbsfn, SRSLTE_MAX_PRB * 20, c_init); + for (i = 0; i < 6 * q->cell.nof_prb; i++) { + mp = i + 3 * (SRSLTE_MAX_PRB - cell.nof_prb); + q->pilots[p][ns][SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i, l, q->cell)] = + (1 - 2 * (float)seq_mbsfn.c[2 * mp]) / sqrt(2) + + _Complex_I * (1 - 2 * (float)seq_mbsfn.c[2 * mp + 1]) / sqrt(2); } } } } - + srslte_sequence_free(&seq_mbsfn); ret = SRSLTE_SUCCESS; - + free_and_exit: if (ret == SRSLTE_ERROR) { srslte_sequence_free(&seq_mbsfn); srslte_refsignal_free(q); } return ret; - } @@ -185,12 +414,11 @@ int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, uint32_t max_prb) { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_refsignal_t)); - + q->type = SRSLTE_SF_MBSFN; - for (p=0;p<2;p++) { - for (i=0;ipilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * max_prb * 18); if (!q->pilots[p][i]) { perror("malloc"); @@ -199,7 +427,6 @@ int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, uint32_t max_prb) } } - ret = SRSLTE_SUCCESS; } @@ -211,47 +438,17 @@ free_and_exit: } int srslte_refsignal_mbsfn_set_cell(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id){ - + int ret = SRSLTE_ERROR_INVALID_INPUTS; q->cell = cell; q->mbsfn_area_id = mbsfn_area_id; - if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) { + if (srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) { goto free_and_exit; } - - ret = SRSLTE_SUCCESS; - - free_and_exit: - if (ret == SRSLTE_ERROR) { - srslte_refsignal_free(q); - } - return ret; -} + ret = SRSLTE_SUCCESS; -/** Allocates memory for the 20 slots in a subframe - */ -int srslte_refsignal_cs_init(srslte_refsignal_t * q, uint32_t max_prb) -{ - - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL) - { - ret = SRSLTE_ERROR; - bzero(q, sizeof(srslte_refsignal_t)); - for (int p=0;p<2;p++) { - for (int i=0;ipilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p)); - if (!q->pilots[p][i]) { - perror("malloc"); - goto free_and_exit; - } - } - } - ret = SRSLTE_SUCCESS; - } free_and_exit: if (ret == SRSLTE_ERROR) { srslte_refsignal_free(q); @@ -259,172 +456,6 @@ free_and_exit: return ret; } -/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for - * the 20 slots in a subframe - */ -int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, srslte_cell_t cell) -{ - - uint32_t c_init; - uint32_t i, ns, l, p; - uint32_t N_cp, mp; - srslte_sequence_t seq; - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - srslte_cell_isvalid(&cell)) - { - if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - - bzero(&seq, sizeof(srslte_sequence_t)); - if (srslte_sequence_init(&seq, 2*2*SRSLTE_MAX_PRB)) { - return SRSLTE_ERROR; - } - - if (SRSLTE_CP_ISNORM(cell.cp)) { - N_cp = 1; - } else { - N_cp = 0; - } - - for (ns=0;nscell.nof_prb; i++) { - mp = i + SRSLTE_MAX_PRB - cell.nof_prb; - /* save signal */ - q->pilots[p][ns/2][SRSLTE_REFSIGNAL_PILOT_IDX(i,(ns%2)*nsymbols+l,q->cell)] = - (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) + - _Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); - } - } - } - } - srslte_sequence_free(&seq); - } - ret = SRSLTE_SUCCESS; - } - return ret; -} - -/** Deallocates a srslte_refsignal_cs_t object allocated with srslte_refsignal_cs_init */ -void srslte_refsignal_free(srslte_refsignal_t * q) -{ - for (int p=0;p<2;p++) { - for (int i=0;ipilots[p][i]) { - free(q->pilots[p][i]); - } - } - } - bzero(q, sizeof(srslte_refsignal_t)); -} - - - - -/* Maps a reference signal initialized with srslte_refsignal_cs_init() into an array of subframe symbols */ -int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, cf_t *pilots, cf_t *sf_symbols) -{ - uint32_t i, l; - uint32_t fidx; - - if (srslte_cell_isvalid(&cell) && - srslte_portid_isvalid(port_id) && - pilots != NULL && - sf_symbols != NULL) - { - - for (l=0;l #include #include -#include -#include "srslte/phy/common/phy_common.h" #include "srslte/phy/ch_estimation/refsignal_ul.h" -#include "srslte/phy/utils/vector.h" -#include "srslte/phy/utils/debug.h" +#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/sequence.h" #include "srslte/phy/dft/dft_precoding.h" +#include "srslte/phy/phch/pucch.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #include "ul_rs_tables.h" @@ -216,9 +216,7 @@ int srslte_refsignal_ul_set_cell(srslte_refsignal_ul_t * q, srslte_cell_t cell) if (q != NULL && srslte_cell_isvalid(&cell)) { if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - - srslte_pucch_cfg_default(&q->pucch_cfg); + q->cell = cell; // Precompute n_prs if (generate_n_prs(q)) { @@ -244,27 +242,8 @@ int srslte_refsignal_ul_set_cell(srslte_refsignal_ul_t * q, srslte_cell_t cell) return ret; } -void srslte_refsignal_ul_set_cfg(srslte_refsignal_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pucch_cfg_t *pucch_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg) +static uint32_t largest_prime_lower_than(uint32_t x) { - if (pusch_cfg) { - memcpy(&q->pusch_cfg, pusch_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); - } - if (pucch_cfg) { - if (srslte_pucch_cfg_isvalid(pucch_cfg, q->cell.nof_prb)) { - memcpy(&q->pucch_cfg, pucch_cfg, sizeof(srslte_pucch_cfg_t)); - } else { - fprintf(stderr, "Invalid PUCCH configuration in refsignal_ul\n"); - } - } - if (srs_cfg) { - memcpy(&q->srs_cfg, srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - } -} - -uint32_t largest_prime_lower_than(uint32_t x) { /* get largest prime n_zc 0; i--) { if (prime_numbers[i] < x) { @@ -329,8 +308,8 @@ static float pusch_alpha(srslte_refsignal_ul_t *q, srslte_refsignal_dmrs_pusch_c } -bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q, srslte_refsignal_dmrs_pusch_cfg_t *cfg, - uint32_t nof_prb) { +static bool pusch_cfg_isvalid(srslte_refsignal_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* cfg, uint32_t nof_prb) +{ if (cfg->cyclic_shift < SRSLTE_NOF_CSHIFT && cfg->delta_ss < SRSLTE_NOF_DELTA_SS && nof_prb <= q->cell.nof_prb) { @@ -340,40 +319,55 @@ bool srslte_refsignal_dmrs_pusch_cfg_isvalid(srslte_refsignal_ul_t *q, srslte_re } } -void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t *q, cf_t *r_pusch, uint32_t nof_prb, uint32_t n_prb[2], cf_t *sf_symbols) +void srslte_refsignal_dmrs_pusch_put(srslte_refsignal_ul_t* q, + srslte_pusch_cfg_t* pusch_cfg, + cf_t* r_pusch, + cf_t* sf_symbols) { for (uint32_t ns_idx=0;ns_idx<2;ns_idx++) { - INFO("Putting DRMS to n_prb: %d, L: %d, ns_idx: %d\n", n_prb[ns_idx], nof_prb, ns_idx); + INFO("Putting DMRS to n_prb: %d, L: %d, ns_idx: %d\n", + pusch_cfg->grant.n_prb_tilde[ns_idx], + pusch_cfg->grant.L_prb, + ns_idx); uint32_t L = SRSLTE_REFSIGNAL_UL_L(ns_idx, q->cell.cp); - memcpy(&sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, L, n_prb[ns_idx]*SRSLTE_NRE)], - &r_pusch[ns_idx*SRSLTE_NRE*nof_prb], nof_prb*SRSLTE_NRE*sizeof(cf_t)); + memcpy(&sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, L, pusch_cfg->grant.n_prb_tilde[ns_idx] * SRSLTE_NRE)], + &r_pusch[ns_idx * SRSLTE_NRE * pusch_cfg->grant.L_prb], + pusch_cfg->grant.L_prb * SRSLTE_NRE * sizeof(cf_t)); } } -void srslte_refsignal_dmrs_pusch_get(srslte_refsignal_ul_t *q, cf_t *sf_symbols, uint32_t nof_prb, uint32_t n_prb[2], cf_t *r_pusch) +void srslte_refsignal_dmrs_pusch_get(srslte_refsignal_ul_t* q, + srslte_pusch_cfg_t* pusch_cfg, + cf_t* sf_symbols, + cf_t* r_pusch) { - for (uint32_t ns_idx=0;ns_idx<2;ns_idx++) { - INFO("Getting DRMS from n_prb: %d, L: %d, ns_idx: %d\n", n_prb[ns_idx], nof_prb, ns_idx); + for (uint32_t ns_idx = 0; ns_idx < 2; ns_idx++) { + INFO("Getting DMRS from n_prb: %d, L: %d, ns_idx: %d\n", + pusch_cfg->grant.n_prb_tilde[ns_idx], + pusch_cfg->grant.L_prb, + ns_idx); uint32_t L = SRSLTE_REFSIGNAL_UL_L(ns_idx, q->cell.cp); - memcpy(&r_pusch[ns_idx*SRSLTE_NRE*nof_prb], - &sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, L, n_prb[ns_idx]*SRSLTE_NRE)], - nof_prb*SRSLTE_NRE*sizeof(cf_t)); + memcpy(&r_pusch[ns_idx * SRSLTE_NRE * pusch_cfg->grant.L_prb], + &sf_symbols[SRSLTE_RE_IDX(q->cell.nof_prb, L, pusch_cfg->grant.n_prb_tilde[ns_idx] * SRSLTE_NRE)], + pusch_cfg->grant.L_prb * SRSLTE_NRE * sizeof(cf_t)); } } /* Computes r sequence */ -void compute_r(srslte_refsignal_ul_t *q, uint32_t nof_prb, uint32_t ns, uint32_t delta_ss) { - // Get group hopping number u - uint32_t f_gh=0; - if (q->pusch_cfg.group_hopping_en) { +static void compute_r( + srslte_refsignal_ul_t* q, srslte_refsignal_dmrs_pusch_cfg_t* cfg, uint32_t nof_prb, uint32_t ns, uint32_t delta_ss) +{ + // Get group hopping number u + uint32_t f_gh = 0; + if (cfg->group_hopping_en) { f_gh = q->f_gh[ns]; } uint32_t u = (f_gh + (q->cell.id%30)+delta_ss)%30; - // Get sequence hopping number v - uint32_t v = 0; - if (nof_prb >= 6 && q->pusch_cfg.sequence_hopping_en) { - v = q->v_pusch[ns][q->pusch_cfg.delta_ss]; + // Get sequence hopping number v + uint32_t v = 0; + if (nof_prb >= 6 && cfg->sequence_hopping_en) { + v = q->v_pusch[ns][cfg->delta_ss]; } // Compute signal argument @@ -381,10 +375,9 @@ void compute_r(srslte_refsignal_ul_t *q, uint32_t nof_prb, uint32_t ns, uint32_t } -int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_t *q, srslte_refsignal_ul_dmrs_pregen_t *pregen, - uint32_t max_prb) +int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_dmrs_pregen_t* pregen, uint32_t max_prb) { - for (uint32_t sf_idx=0;sf_idxr[cs][sf_idx] = (cf_t**) calloc(sizeof(cf_t*), max_prb + 1); if (pregen->r[cs][sf_idx]) { @@ -405,16 +398,17 @@ int srslte_refsignal_dmrs_pusch_pregen_init(srslte_refsignal_ul_t *q, srslte_ref return SRSLTE_SUCCESS; } - -int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t *q, srslte_refsignal_ul_dmrs_pregen_t *pregen) +int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t* q, + srslte_refsignal_ul_dmrs_pregen_t* pregen, + srslte_refsignal_dmrs_pusch_cfg_t* cfg) { - for (uint32_t sf_idx=0;sf_idxr[cs][sf_idx]) { for (uint32_t n=0;n<=q->cell.nof_prb;n++) { if (srslte_dft_precoding_valid_prb(n)) { if (pregen->r[cs][sf_idx][n]) { - if (srslte_refsignal_dmrs_pusch_gen(q, n, sf_idx, cs, pregen->r[cs][sf_idx][n])) { + if (srslte_refsignal_dmrs_pusch_gen(q, cfg, n, sf_idx, cs, pregen->r[cs][sf_idx][n])) { return SRSLTE_ERROR; } } else { @@ -432,7 +426,7 @@ int srslte_refsignal_dmrs_pusch_pregen(srslte_refsignal_ul_t *q, srslte_refsigna void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t *q, srslte_refsignal_ul_dmrs_pregen_t *pregen) { - for (uint32_t sf_idx=0;sf_idxr[cs][sf_idx]) { for (uint32_t n=0;n<=q->cell.nof_prb;n++) { @@ -442,47 +436,49 @@ void srslte_refsignal_dmrs_pusch_pregen_free(srslte_refsignal_ul_t *q, srslte_re } } } - free(pregen->r[cs][sf_idx]); + free(pregen->r[cs][sf_idx]); } } } } -int srslte_refsignal_dmrs_pusch_pregen_put(srslte_refsignal_ul_t *q, - srslte_refsignal_ul_dmrs_pregen_t *pregen, - uint32_t nof_prb, - uint32_t sf_idx, - uint32_t cyclic_shift_for_dmrs, - uint32_t n_prb[2], - cf_t *sf_symbols) +int srslte_refsignal_dmrs_pusch_pregen_put(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf_cfg, + srslte_refsignal_ul_dmrs_pregen_t* pregen, + srslte_pusch_cfg_t* pusch_cfg, + cf_t* sf_symbols) { - if (srslte_dft_precoding_valid_prb(nof_prb) && - sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && - cyclic_shift_for_dmrs < SRSLTE_NOF_CSHIFT) - { - srslte_refsignal_dmrs_pusch_put(q, pregen->r[cyclic_shift_for_dmrs][sf_idx][nof_prb], nof_prb, n_prb, sf_symbols); + uint32_t sf_idx = sf_cfg->tti % 10; + + if (srslte_dft_precoding_valid_prb(pusch_cfg->grant.L_prb) && sf_idx < SRSLTE_NOF_SF_X_FRAME && + pusch_cfg->grant.n_dmrs < SRSLTE_NOF_CSHIFT) { + srslte_refsignal_dmrs_pusch_put( + q, pusch_cfg, pregen->r[pusch_cfg->grant.n_dmrs][sf_idx][pusch_cfg->grant.L_prb], sf_symbols); return SRSLTE_SUCCESS; } else { return SRSLTE_ERROR_INVALID_INPUTS; } } - -/* Generate DRMS for PUSCH signal according to 5.5.2.1 of 36.211 */ -int srslte_refsignal_dmrs_pusch_gen(srslte_refsignal_ul_t *q, uint32_t nof_prb, uint32_t sf_idx, - uint32_t cyclic_shift_for_dmrs, cf_t *r_pusch) +/* Generate DMRS for PUSCH signal according to 5.5.2.1 of 36.211 */ +int srslte_refsignal_dmrs_pusch_gen(srslte_refsignal_ul_t* q, + srslte_refsignal_dmrs_pusch_cfg_t* cfg, + uint32_t nof_prb, + uint32_t sf_idx, + uint32_t cyclic_shift_for_dmrs, + cf_t* r_pusch) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (srslte_refsignal_dmrs_pusch_cfg_isvalid(q, &q->pusch_cfg, nof_prb)) { + if (pusch_cfg_isvalid(q, cfg, nof_prb)) { ret = SRSLTE_ERROR; for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - - compute_r(q, nof_prb, ns, q->pusch_cfg.delta_ss); - + + compute_r(q, cfg, nof_prb, ns, cfg->delta_ss); + // Add cyclic prefix alpha - float alpha = pusch_alpha(q, &q->pusch_cfg, cyclic_shift_for_dmrs, ns); + float alpha = pusch_alpha(q, cfg, cyclic_shift_for_dmrs, ns); // Do complex exponential and adjust amplitude for (int i=0;icell.cp); - - cf_t z_m_1 = 1.0; - if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { - srslte_pucch_format2ab_mod_bits(format, pucch_bits, &z_m_1); + + uint32_t N_rs = srslte_refsignal_dmrs_N_rs(cfg->format, q->cell.cp); + + uint32_t sf_idx = sf->tti % 10; + + cf_t z_m_1 = 1.0; + if (cfg->format == SRSLTE_PUCCH_FORMAT_2A || cfg->format == SRSLTE_PUCCH_FORMAT_2B) { + srslte_pucch_format2ab_mod_bits(cfg->format, cfg->pucch2_drs_bits, &z_m_1); } - - for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - // Get group hopping number u - uint32_t f_gh=0; - if (q->pusch_cfg.group_hopping_en) { + + for (uint32_t ns = 2 * sf_idx; ns < 2 * (sf_idx + 1); ns++) { + // Get group hopping number u + uint32_t f_gh = 0; + if (cfg->group_hopping_en) { f_gh = q->f_gh[ns]; } - uint32_t u = (f_gh + (q->cell.id%30))%30; - + uint32_t u = (f_gh + (q->cell.id % 30)) % 30; + srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u); for (uint32_t m=0;mcell.cp); + uint32_t n_oc = 0; + + uint32_t l = srslte_refsignal_dmrs_pucch_symbol(m, cfg->format, q->cell.cp); // Add cyclic prefix alpha - float alpha = 0.0; - if (format < SRSLTE_PUCCH_FORMAT_2) { - alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, NULL); + float alpha = 0.0; + if (cfg->format < SRSLTE_PUCCH_FORMAT_2) { + alpha = srslte_pucch_alpha_format1(q->n_cs_cell, cfg, q->cell.cp, true, ns, l, &n_oc, NULL); } else { - alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l); + alpha = srslte_pucch_alpha_format2(q->n_cs_cell, cfg, ns, l); } - // Choose number of symbols and orthogonal sequence from Tables 5.5.2.2.1-1 to -3 + // Choose number of symbols and orthogonal sequence from Tables 5.5.2.2.1-1 to -3 float *w=NULL; - switch (format) { + switch (cfg->format) { case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1A: case SRSLTE_PUCCH_FORMAT_1B: @@ -611,6 +613,7 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma } break; case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_3: if (SRSLTE_CP_ISNORM(q->cell.cp)) { w=w_arg_pucch_format2_cpnorm; } else { @@ -622,69 +625,71 @@ int srslte_refsignal_dmrs_pucch_gen(srslte_refsignal_ul_t *q, srslte_pucch_forma w=w_arg_pucch_format2_cpnorm; break; default: - fprintf(stderr, "Unsupported format %d\n", format); + ERROR("DMRS Generator: Unsupported format %d\n", cfg->format); return SRSLTE_ERROR; } - cf_t z_m = 1.0; + cf_t z_m = 1.0; if (m == 1) { z_m = z_m_1; } for (uint32_t n=0;ntmp_arg[n]+alpha*n)); + r_pucch[(ns % 2) * SRSLTE_NRE * N_rs + m * SRSLTE_NRE + n] = + z_m * cexpf(I * (w[m] + q->tmp_arg[n] + alpha * n)); } } } ret = SRSLTE_SUCCESS; } - return ret; + return ret; } -int srslte_refsignal_dmrs_pucch_cp(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *source, cf_t *dest, bool source_is_grid) +int srslte_refsignal_dmrs_pucch_cp( + srslte_refsignal_ul_t* q, srslte_pucch_cfg_t* cfg, cf_t* source, cf_t* dest, bool source_is_grid) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q && source && dest) { - ret = SRSLTE_ERROR; + uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB; - - uint32_t N_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp); + + uint32_t N_rs = srslte_refsignal_dmrs_N_rs(cfg->format, q->cell.cp); for (uint32_t ns=0;ns<2;ns++) { // Determine n_prb - uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); + uint32_t n_prb = srslte_pucch_n_prb(&q->cell, cfg, ns); for (uint32_t i=0;icell.cp); + uint32_t l = srslte_refsignal_dmrs_pucch_symbol(i, cfg->format, q->cell.cp); if (!source_is_grid) { memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], &source[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE], SRSLTE_NRE*sizeof(cf_t)); } else { - memcpy(&dest[ns*N_rs*SRSLTE_NRE+i*SRSLTE_NRE], - &source[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], - SRSLTE_NRE*sizeof(cf_t)); + memcpy(&dest[ns * N_rs * SRSLTE_NRE + i * SRSLTE_NRE], + &source[SRSLTE_RE_IDX(q->cell.nof_prb, l + ns * nsymbols, n_prb * SRSLTE_NRE)], + SRSLTE_NRE * sizeof(cf_t)); } } } - - ret = SRSLTE_SUCCESS; + + ret = SRSLTE_SUCCESS; } - return ret; + return ret; } /* Maps PUCCH DMRS to the physical resources as defined in 5.5.2.2.2 in 36.211 */ -int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *r_pucch, cf_t *output) +int srslte_refsignal_dmrs_pucch_put(srslte_refsignal_ul_t* q, srslte_pucch_cfg_t* cfg, cf_t* r_pucch, cf_t* output) { - return srslte_refsignal_dmrs_pucch_cp(q, format, n_pucch, r_pucch, output, false); + return srslte_refsignal_dmrs_pucch_cp(q, cfg, r_pucch, output, false); } /* Gets PUCCH DMRS from the physical resources as defined in 5.5.2.2.2 in 36.211 */ -int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *input, cf_t *r_pucch) +int srslte_refsignal_dmrs_pucch_get(srslte_refsignal_ul_t* q, srslte_pucch_cfg_t* cfg, cf_t* input, cf_t* r_pucch) { - return srslte_refsignal_dmrs_pucch_cp(q, format, n_pucch, input, r_pucch, true); + return srslte_refsignal_dmrs_pucch_cp(q, cfg, input, r_pucch, true); } - -uint32_t T_srs_table(uint32_t I_srs) { +static uint32_t T_srs_table(uint32_t I_srs) +{ uint32_t T_srs; /* This is Table 8.2-1 */ if (I_srs < 2) { @@ -730,22 +735,89 @@ int srslte_refsignal_srs_send_ue(uint32_t I_srs, uint32_t tti) { } else if (I_srs < 157) { Toffset = I_srs-77; } else if (I_srs < 317) { - Toffset = I_srs-157; + Toffset = I_srs - 157; } else if (I_srs < 637) { - Toffset = I_srs-317; + Toffset = I_srs - 317; } else { - return 0; + return 0; } - if (((tti-Toffset)%T_srs_table(I_srs)) == 0) { - return 1; + if (((tti - Toffset) % T_srs_table(I_srs)) == 0) { + return 1; } else { - return 0; + return 0; } } else { return SRSLTE_ERROR_INVALID_INPUTS; } } +// Shortened PUCCH happen in every cell-specific SRS subframes for Format 1/1a/1b +void srslte_refsignal_srs_pucch_shortened(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_refsignal_srs_cfg_t* srs_cfg, + srslte_pucch_cfg_t* pucch_cfg) +{ + bool shortened = false; + if (srs_cfg->configured && pucch_cfg->format < SRSLTE_PUCCH_FORMAT_2) { + shortened = false; + // If CQI is not transmitted, PUCCH will be normal unless ACK/NACK and SRS simultaneous transmission is enabled + if (srs_cfg->simul_ack) { + // If simultaneous ACK and SRS is enabled, PUCCH is shortened in cell-specific SRS subframes + if (srslte_refsignal_srs_send_cs(srs_cfg->subframe_config, sf->tti % 10) == 1) { + shortened = true; + } + } + } + sf->shortened = shortened; +} + +void srslte_refsignal_srs_pusch_shortened(srslte_refsignal_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_refsignal_srs_cfg_t* srs_cfg, + srslte_pusch_cfg_t* pusch_cfg) +{ + bool shortened = false; + + if (srs_cfg->configured) { + // If UE-specific SRS is configured, PUSCH is shortened every time UE transmits SRS even if overlaping in the same + // RB or not + if (srslte_refsignal_srs_send_cs(srs_cfg->subframe_config, sf->tti % 10) == 1 && + srslte_refsignal_srs_send_ue(srs_cfg->I_srs, sf->tti) == 1) { + shortened = true; + /* If RBs are contiguous, PUSCH is not shortened */ + uint32_t k0_srs = srslte_refsignal_srs_rb_start_cs(srs_cfg->bw_cfg, q->cell.nof_prb); + uint32_t nrb_srs = srslte_refsignal_srs_rb_L_cs(srs_cfg->bw_cfg, q->cell.nof_prb); + for (uint32_t ns = 0; ns < 2 && shortened; ns++) { + if (pusch_cfg->grant.n_prb_tilde[ns] == + k0_srs + nrb_srs || // If PUSCH is contiguous on the right-hand side of SRS + pusch_cfg->grant.n_prb_tilde[ns] + pusch_cfg->grant.L_prb == + k0_srs) // If SRS is contiguous on the left-hand side of PUSCH + { + shortened = false; + } + } + } + // If not coincides with UE transmission. PUSCH shall be shortened if cell-specific SRS transmission RB + // coincides with PUSCH allocated RB + if (!shortened) { + if (srslte_refsignal_srs_send_cs(srs_cfg->subframe_config, sf->tti % 10) == 1) { + uint32_t k0_srs = srslte_refsignal_srs_rb_start_cs(srs_cfg->bw_cfg, q->cell.nof_prb); + uint32_t nrb_srs = srslte_refsignal_srs_rb_L_cs(srs_cfg->bw_cfg, q->cell.nof_prb); + for (uint32_t ns = 0; ns < 2 && !shortened; ns++) { + if ((pusch_cfg->grant.n_prb_tilde[ns] >= k0_srs && pusch_cfg->grant.n_prb_tilde[ns] < k0_srs + nrb_srs) || + (pusch_cfg->grant.n_prb_tilde[ns] + pusch_cfg->grant.L_prb >= k0_srs && + pusch_cfg->grant.n_prb_tilde[ns] + pusch_cfg->grant.L_prb < k0_srs + nrb_srs) || + (pusch_cfg->grant.n_prb_tilde[ns] <= k0_srs && + pusch_cfg->grant.n_prb_tilde[ns] + pusch_cfg->grant.L_prb >= k0_srs + nrb_srs)) { + shortened = true; + } + } + } + } + } + sf->shortened = shortened; +} + /* Returns 1 if sf_idx is a valid subframe for SRS transmission according to subframe_config (cell-specific), * as defined in Section 5.5.3.3 of 36.211. Returns 0 if no SRS shall be transmitted or a negative * number if error. @@ -773,7 +845,7 @@ int srslte_refsignal_srs_send_cs(uint32_t subframe_config, uint32_t sf_idx) { } } else if (subframe_config < 13) { if ((sf_idx%tsfc)==Delta_sfc2[subframe_config-9]) { - return 1; + return 1; } else { return 0; } @@ -797,11 +869,12 @@ int srslte_refsignal_srs_send_cs(uint32_t subframe_config, uint32_t sf_idx) { } } -uint32_t srsbwtable_idx(uint32_t nof_prb) { +static uint32_t srsbwtable_idx(uint32_t nof_prb) +{ if (nof_prb <= 40) { return 0; } else if (nof_prb <= 60) { - return 1; + return 1; } else if (nof_prb <= 80) { return 2; } else { @@ -821,11 +894,12 @@ uint32_t srslte_refsignal_srs_rb_start_cs(uint32_t bw_cfg, uint32_t nof_prb) { uint32_t srslte_refsignal_srs_rb_L_cs(uint32_t bw_cfg, uint32_t nof_prb) { if (bw_cfg < 8) { return m_srs_b[srsbwtable_idx(nof_prb)][0][bw_cfg]; - } - return 0; + } + return 0; } -uint32_t srs_Fb(srslte_refsignal_srs_cfg_t *cfg, uint32_t b, uint32_t nof_prb, uint32_t tti) { +static uint32_t srs_Fb(srslte_refsignal_srs_cfg_t* cfg, uint32_t b, uint32_t nof_prb, uint32_t tti) +{ uint32_t Fb = 0; uint32_t T = T_srs_table(cfg->I_srs); if (T) { @@ -847,14 +921,15 @@ uint32_t srs_Fb(srslte_refsignal_srs_cfg_t *cfg, uint32_t b, uint32_t nof_prb, u } /* Returns k0: frequency-domain starting position for ue-specific SRS */ -uint32_t srs_k0_ue(srslte_refsignal_srs_cfg_t *cfg, uint32_t nof_prb, uint32_t tti) { - - if (cfg->bw_cfg < 8 && cfg->B < 4 && cfg->k_tc < 2) { - uint32_t k0p = srslte_refsignal_srs_rb_start_cs(cfg->bw_cfg, nof_prb)*SRSLTE_NRE + cfg->k_tc; - uint32_t k0 = k0p; +static uint32_t srs_k0_ue(srslte_refsignal_srs_cfg_t* cfg, uint32_t nof_prb, uint32_t tti) +{ + + if (cfg->bw_cfg < 8 && cfg->B < 4 && cfg->k_tc < 2) { + uint32_t k0p = srslte_refsignal_srs_rb_start_cs(cfg->bw_cfg, nof_prb) * SRSLTE_NRE + cfg->k_tc; + uint32_t k0 = k0p; uint32_t nb = 0; for (int b=0;b<=cfg->B;b++) { - uint32_t m_srs = m_srs_b[srsbwtable_idx(nof_prb)][b][cfg->bw_cfg]; + uint32_t m_srs = m_srs_b[srsbwtable_idx(nof_prb)][b][cfg->bw_cfg]; uint32_t m_sc = m_srs*SRSLTE_NRE/2; if (b <= cfg->b_hop) { nb = (4*cfg->n_rrc/m_srs)%Nb[srsbwtable_idx(nof_prb)][b][cfg->bw_cfg]; @@ -870,18 +945,22 @@ uint32_t srs_k0_ue(srslte_refsignal_srs_cfg_t *cfg, uint32_t nof_prb, uint32_t t return 0; } -uint32_t srslte_refsignal_srs_M_sc(srslte_refsignal_ul_t *q) { - return m_srs_b[srsbwtable_idx(q->cell.nof_prb)][q->srs_cfg.B][q->srs_cfg.bw_cfg]*SRSLTE_NRE/2; +uint32_t srslte_refsignal_srs_M_sc(srslte_refsignal_ul_t* q, srslte_refsignal_srs_cfg_t* cfg) +{ + return m_srs_b[srsbwtable_idx(q->cell.nof_prb)][cfg->B][cfg->bw_cfg] * SRSLTE_NRE / 2; } -int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t *q, srslte_refsignal_srs_pregen_t *pregen) -{ - uint32_t M_sc = srslte_refsignal_srs_M_sc(q); - for (uint32_t sf_idx=0;sf_idxr[sf_idx] = srslte_vec_malloc(2*M_sc*sizeof(cf_t)); if (pregen->r[sf_idx]) { - if (srslte_refsignal_srs_gen(q, sf_idx, pregen->r[sf_idx])) { - return SRSLTE_ERROR; + if (srslte_refsignal_srs_gen(q, cfg, dmrs, sf_idx, pregen->r[sf_idx])) { + return SRSLTE_ERROR; } } else { return SRSLTE_ERROR; @@ -892,32 +971,39 @@ int srslte_refsignal_srs_pregen(srslte_refsignal_ul_t *q, srslte_refsignal_srs_p void srslte_refsignal_srs_pregen_free(srslte_refsignal_ul_t *q, srslte_refsignal_srs_pregen_t *pregen) { - for (uint32_t sf_idx=0;sf_idxr[sf_idx]) { free(pregen->r[sf_idx]); } } } -int srslte_refsignal_srs_pregen_put(srslte_refsignal_ul_t *q, srslte_refsignal_srs_pregen_t *pregen, - uint32_t tti, cf_t *sf_symbols) +int srslte_refsignal_srs_pregen_put(srslte_refsignal_ul_t* q, + srslte_refsignal_srs_pregen_t* pregen, + srslte_refsignal_srs_cfg_t* cfg, + uint32_t tti, + cf_t* sf_symbols) { - return srslte_refsignal_srs_put(q, tti, pregen->r[tti%SRSLTE_NSUBFRAMES_X_FRAME], sf_symbols); + return srslte_refsignal_srs_put(q, cfg, tti, pregen->r[tti % SRSLTE_NOF_SF_X_FRAME], sf_symbols); } /* Genearte SRS signal as defined in Section 5.5.3.1 */ -int srslte_refsignal_srs_gen(srslte_refsignal_ul_t *q, uint32_t sf_idx, cf_t *r_srs) +int srslte_refsignal_srs_gen(srslte_refsignal_ul_t* q, + srslte_refsignal_srs_cfg_t* cfg, + srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg, + uint32_t sf_idx, + cf_t* r_srs) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (r_srs && q) { + if (r_srs && q && cfg && pusch_cfg) { ret = SRSLTE_ERROR; - - uint32_t M_sc = srslte_refsignal_srs_M_sc(q); + + uint32_t M_sc = srslte_refsignal_srs_M_sc(q, cfg); for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - - compute_r(q, M_sc/SRSLTE_NRE, ns, 0); - float alpha = 2*M_PI*q->srs_cfg.n_srs/8; + + compute_r(q, pusch_cfg, M_sc / SRSLTE_NRE, ns, 0); + float alpha = 2 * M_PI * cfg->n_srs / 8; // Do complex exponential and adjust amplitude for (int i=0;isrs_cfg, q->cell.nof_prb, tti); + uint32_t M_sc = srslte_refsignal_srs_M_sc(q, cfg); + uint32_t k0 = srs_k0_ue(cfg, q->cell.nof_prb, tti); for (int i=0;icell.nof_prb, 2*SRSLTE_CP_NSYMB(q->cell.cp)-1, k0 + 2*i)] = r_srs[i]; } diff --git a/lib/src/phy/ch_estimation/test/chest_test_dl.c b/lib/src/phy/ch_estimation/test/chest_test_dl.c index 65cc8ced5..df6376692 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_dl.c +++ b/lib/src/phy/ch_estimation/test/chest_test_dl.c @@ -29,18 +29,16 @@ #include #include #include -#include #include "srslte/srslte.h" -srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1000, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_NORM, - SRSLTE_PHICH_R_1_6 -}; +srslte_cell_t cell = {6, // nof_prb + 1, // nof_ports + 1000, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, + SRSLTE_PHICH_R_1_6, + SRSLTE_FDD}; char *output_matlab = NULL; @@ -86,9 +84,9 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { srslte_chest_dl_t est; cf_t *input = NULL, *ce = NULL, *h = NULL, *output = NULL; - int i, j, n_port=0, sf_idx=0, cid=0, num_re; + int i, j, num_re; int ret = -1; - int max_cid; + int max_cid; FILE *fmatlab = NULL; parse_args(argc,argv); @@ -124,103 +122,114 @@ int main(int argc, char **argv) { goto do_exit; } + uint32_t cid = 0; if (cell.id == 1000) { - cid = 0; + cid = 0; max_cid = 504; } else { cid = cell.id; max_cid = cell.id; } - if (srslte_chest_dl_init(&est, cell.nof_prb)) { - fprintf(stderr, "Error initializing equalizer\n"); + if (srslte_chest_dl_init(&est, cell.nof_prb, 1)) { + ERROR("Error initializing equalizer\n"); goto do_exit; } while(cid <= max_cid) { cell.id = cid; if (srslte_chest_dl_set_cell(&est, cell)) { - fprintf(stderr, "Error initializing equalizer\n"); + ERROR("Error initializing equalizer\n"); goto do_exit; } - for (sf_idx=0;sf_idx<1;sf_idx++) { - for (n_port=0;n_port 2.0) { - goto do_exit; - } - - if (fmatlab) { - fprintf(fmatlab, "input="); - srslte_vec_fprint_c(fmatlab, input, num_re); - fprintf(fmatlab, ";\n"); - fprintf(fmatlab, "h="); - srslte_vec_fprint_c(fmatlab, h, num_re); - fprintf(fmatlab, ";\n"); - fprintf(fmatlab, "ce="); - srslte_vec_fprint_c(fmatlab, ce, num_re); - fprintf(fmatlab, ";\n"); - } + struct timeval t[3]; + gettimeofday(&t[1], NULL); + for (int j = 0; j < 100; j++) { + srslte_chest_dl_estimate(&est, &sf_cfg, input_m, &res); + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + printf("CHEST: %f us\n", (float)t[0].tv_usec / 100); + + gettimeofday(&t[1], NULL); + for (int j = 0; j < 100; j++) { + srslte_predecoding_single(input, ce, output, NULL, num_re, 1.0f, 0); + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + printf("CHEQ-ZF: %f us\n", (float)t[0].tv_usec / 100); + + float mse = 0; + for (i = 0; i < num_re; i++) { + mse += cabsf(input[i] - output[i]); + } + mse /= num_re; + printf("MSE: %f\n", mse); + + gettimeofday(&t[1], NULL); + for (int j = 0; j < 100; j++) { + srslte_predecoding_single(input, ce, output, NULL, num_re, 1.0f, res.noise_estimate); + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + printf("CHEQ-MMSE: %f us\n", (float)t[0].tv_usec / 100); + + mse = 0; + for (i = 0; i < num_re; i++) { + mse += cabsf(input[i] - output[i]); + } + mse /= num_re; + printf("MSE: %f\n", mse); + + if (mse > 2.0) { + goto do_exit; + } + + if (fmatlab) { + fprintf(fmatlab, "input="); + srslte_vec_fprint_c(fmatlab, input, num_re); + fprintf(fmatlab, ";\n"); + fprintf(fmatlab, "h="); + srslte_vec_fprint_c(fmatlab, h, num_re); + fprintf(fmatlab, ";\n"); + fprintf(fmatlab, "ce="); + srslte_vec_fprint_c(fmatlab, ce, num_re); + fprintf(fmatlab, ";\n"); } } - cid+=10; + cid += 10; INFO("cid=%d\n", cid); } srslte_chest_dl_free(&est); @@ -246,7 +255,7 @@ do_exit: if (!ret) { printf("OK\n"); } else { - printf("Error at cid=%d, slot=%d, port=%d\n",cid, sf_idx, n_port); + printf("Error at cid=%d\n", cid); } exit(ret); diff --git a/lib/src/phy/ch_estimation/test/chest_test_dl_mex.c b/lib/src/phy/ch_estimation/test/chest_test_dl_mex.c deleted file mode 100644 index 0465ba6fe..000000000 --- a/lib/src/phy/ch_estimation/test/chest_test_dl_mex.c +++ /dev/null @@ -1,159 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define INPUT prhs[1] -#define NOF_INPUTS 2 - -void help() -{ - mexErrMsgTxt - ("[estChannel, noiseEst, eq_output] = srslte_chest_dl(enb, inputSignal, [w_coeff])\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - int i; - srslte_cell_t cell; - srslte_chest_dl_t chest; - - cf_t *input_signal = NULL, *output_signal = NULL, *tmp_x[SRSLTE_MAX_LAYERS]; - cf_t *ce[SRSLTE_MAX_PORTS]; - - for (int i=0;i NOF_INPUTS) { - float w = (float) mxGetScalar(prhs[NOF_INPUTS]); - srslte_chest_dl_set_smooth_filter3_coeff(&chest, w); - } else { - srslte_chest_dl_set_smooth_filter(&chest, NULL, 0); - } - - // Perform channel estimation - if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) { - mexErrMsgTxt("Error running channel estimator\n"); - return; - } - - // Get noise power estimation - float noise_power = srslte_chest_dl_get_noise_estimate(&chest); - - // Perform channel equalization - if (cell.nof_ports == 1) { - srslte_predecoding_single(input_signal, ce[0], output_signal, nof_re, noise_power); - } else { - srslte_predecoding_diversity(input_signal, ce, tmp_x, cell.nof_ports, nof_re); - srslte_layerdemap_diversity(tmp_x, output_signal, cell.nof_ports, nof_re/cell.nof_ports); - } - - /* Write output values */ - if (nlhs >= 1) { - mexutils_write_cf(ce[0], &plhs[0], mxGetM(INPUT), mxGetN(INPUT)); - } - if (nlhs >= 2) { - plhs[1] = mxCreateLogicalScalar(noise_power); - } - if (nlhs >= 3) { - mexutils_write_cf(output_signal, &plhs[2], mxGetM(INPUT), mxGetN(INPUT)); - } - - // Free all memory - srslte_chest_dl_free(&chest); - - for (i=0;iFW@tO@WYQMW&Xk5sX$=Vp{rDr$mS$4gx*3v6d~{N08eCdX-`m?~ zug(&~^pEn7R-=3Se(z)V-rnur?Y;Zky4uTJE=I-8KFyGuscG5`4ae3{JqVQw9ejcEumTpw;TjBazVci2LvJ(UPr(PVI0U$l8w9boR`|ED z^-xTMlk&kou=YCE-F6%6=<3|qqOI|*@m=p6i~_tH?noRGm-xN@vvP*_@ul!@f-%K{ zqzsOGZ(&@97>+jr#V+ z%ky%hgvEzNO38%3}!LWqO zaZ|_Ms#JGZythnY>iDEpkqLsbI(E475O+6w$X#DntFYYV<#6<@Y=#>05tL`Aa!@XR z7hFVK$RFeUH1c=}WG6ZQ2J$#G+5Mb9i98NT_DRm4Kpux8yNC0yAdf?k9p(J5kjKzx zhdBQN@)+{$cFrF}9z&h&;rx%0#}H?mIlm8iyu`8%oc}iR80xG7ygE^_7XWpl>1#mx z)T?IH^eJ_0rg~>t{~-v_?=G?fG~J(@!t)3Hdu;u?CH?1T+-mv-_4zk8sIFt`%QGo% zeBsmF_!VoqUris$okaW5rqy7_Qdg>DOkyq=-Ut0J0~mbej`e461qYs$qo|+#4Ake$_h56N zych-~Gx|QXa|jXtt^Te4K7a2P^?|oux{$HX^gC+$*JJOxt)*i*m*qKtt}>J0D*GcC zT6OpO%-Q#HxrZkAq&kq<3Z5WnE^D2-`@YJ|AGj>FiZeHoYz1n*1|qI0e8$jcKlgc` zH&bovR;N5*>doYA<*JlW-hj#twsK{r29&2g-iB#U%}?sz0Jq@&J+PQoJ*!xHT;&jW ziK3T--`{5!^_`P2PVV&M%^*KI-U>&&czJt|+U-?)9-s6)GnpRm0%6z0ceexSo`}^c zTxlODO?>J_9+A&Oy)#{2*9kXH_qw-If94vyB#k?{#u0Vmxl!<|K-C<)d#&v=Rdg5^mi8!aO^tnuUuFr2mPcv6wpT9t1ZA1_0!`$0z z|IXzOV!&I|r_)C>i@9i_3e}CgdZcsrhRjh=>P#OMC$t()2-`agCsa4(+4lN0bh7TW zgvO@IJ=@+!c-7zJuIJDXbp7Y*1BdalzQcc~zu$kCUxQm4=Raw>y8{;MmPjCx&}02d zlOh&>{sd7U)MGI%8d{}96GJI$OLPz(XRcbbNZG7gDI;Mj0VU2K8NG2uB!(eFtG zVv3bitcWffk>1Xz72&d=-J$}GN5O|~D&eG|=z(BFF?2JTGJ@dDezE~SvMZm`TiAEh z`aGOQq;42R;HIT9a8#>_TByRLl|{h;qL{X{Q22m z?R~hcW$}V;a0EC$Z-?Mt26Fz)OY)va-H(({RD5y4*h2ST%WP%PE0t0NN)aeUpcH{p z1WFMoMW7UcQUpp7C`F(Yfl>rM$_UVYJ?+m^UvP^BOPQz;?{)AOJNS<~c>H#Nh4!ZD zyB_UH9~Xj)ZME6&w3i4T-?gzUw+W-~3iy7Gh2;NyKbJ)QjA)Pc=4WuD01EBN*TOy) z7TQA(3w`>AP-~0lz6B@>M}!$`6#BHkKzsVjgx!;(A;PCbN2s5ZLXYwhOvd z(6FF81btZ0uL$}*L7x%yh@h_uO5c|{T3T*Y>iY`i;s=WFz>xn}jc6lYgoWdn@) zVEf7n3;?wZn?|UXNLspYFp=^Nq@uCVHPH~`TqIydm@hPv085)%hAr8l8zz2+sllPw#3;MTEH*@ zBen(A?+$_*cn`#*LFh>m9KylJTd_S3m?rZDlX3j`=^Uf~g~$6AuYJ01o%s;B|0b7m znSr_w{^#J@C40J`iPj5!x~|1A&w6Qu8s5ufPxm{~DRIMKyQo9`zf*$l&%AELw3Y}*yhkfz2Cb6KqyXqC;u|&;P_Gd`$ZnY{ts#YD%j$+NA|RSQ9hU=28QBB?bCJe z7f1V)*Km9#2%yy4WcEn*L|+Gq+<&Ghwyq$fHaB}DJECucM7F2(Z&a~ONRJ#i`LiHE zjLv_TXn&VtTR8QxExF79gII$MLY?fL*B{vv#T)}_TXyjS#pYb3D1;7{w@vqsY=5TS z=C+H81)m?+z@N^C<{!L23$@?#N!$K*hjVB9wpQVz8+u3Up{#*9I<&s!<8DUlRz6JqI+L%zfYJJqk1u4jF685tv-5sFejcNFJRhH*uZMCs&hQjq$-oV715*X@ z#f;`jNge!DGn)VManEeNWIpa?G+*W8HM8#*`S_CA_lkV{0!H&kKE4$4Llqg~bvL_^ z(fuw9-RvSZdml>zH(Lg&k&1-aRTy=+Ukc&$mNaLA*I#*oygXbsTx@>-(L-5*_~UaI z;$FuBd-*C)=Gu0rF;15(TOC<^yThYEo^$F~M> z7kssLURTQj$G9C6<3hQdE4lvsetv@E^RG8Q_cQ-K?EpN#hjvecfKyx4cch6T`29uj zhl}8k0ItZ6Mg5ya^!EW?DF5^+u0KEj6mvuh_5Zg;@DqR+>d)Vc=)YS8uYmQTke`)+ z7wXTIMeruTFDnoq7Bno=N5Qu3ZD`}WoAT`Y34R9!?TYAX1cHIqYz;gj5%)^b^ZYHqw42-8x3u+Yz5b0|ZO{yVyZ)ebWGQjD za0W1?5J#c8yd>wmTx87E&Cf?Jk|->)lM5v`+wI$l#!_N3?>&ueUMe;BRW!F*%S)$j JZkAJt{|hd+x{Lq- diff --git a/lib/src/phy/ch_estimation/test/chest_test_ul.c b/lib/src/phy/ch_estimation/test/chest_test_ul.c index 9d5a7f4f4..7f3e0f443 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_ul.c +++ b/lib/src/phy/ch_estimation/test/chest_test_ul.c @@ -33,12 +33,14 @@ #include "srslte/srslte.h" srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 0, - 1000, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_NORM + 6, // nof_prb + 1, // nof_ports + 1000, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, + SRSLTE_PHICH_R_1, // PHICH length + SRSLTE_FDD, + }; char *output_matlab = NULL; @@ -128,13 +130,13 @@ int main(int argc, char **argv) { } printf("max_cid=%d, cid=%d, cell.id=%d\n", max_cid, cid, cell.id); if (srslte_chest_ul_init(&est, cell.nof_prb)) { - fprintf(stderr, "Error initializing equalizer\n"); + ERROR("Error initializing equalizer\n"); goto do_exit; } while(cid <= max_cid) { cell.id = cid; if (srslte_chest_ul_set_cell(&est, cell)) { - fprintf(stderr, "Error initializing equalizer\n"); + ERROR("Error initializing equalizer\n"); goto do_exit; } @@ -165,8 +167,8 @@ int main(int argc, char **argv) { } pusch_cfg.group_hopping_en = group_hopping_en; pusch_cfg.sequence_hopping_en = sequence_hopping_en; - srslte_chest_ul_set_cfg(&est, &pusch_cfg, NULL, NULL); - + srslte_chest_ul_pregen(&est, &pusch_cfg); + // Loop through subframe idx and cyclic shifts for (int sf_idx=0;sf_idx<10;sf_idx+=3) { @@ -195,11 +197,25 @@ int main(int argc, char **argv) { input[i*cell.nof_prb * SRSLTE_NRE+j] *= h[i*cell.nof_prb * SRSLTE_NRE+j]; } } - + + // Configure estimator + srslte_chest_ul_res_t res; + srslte_pusch_cfg_t cfg; + + ZERO_OBJECT(cfg); + res.ce = ce; + cfg.grant.L_prb = n; + cfg.grant.n_prb_tilde[0] = 0; + cfg.grant.n_prb_tilde[1] = 0; + cfg.grant.n_dmrs = cshift_dmrs; + + srslte_ul_sf_cfg_t ul_sf; + ZERO_OBJECT(ul_sf); + ul_sf.tti = sf_idx; + // Estimate channel - uint32_t prb_idx[2]= {0, 0}; - srslte_chest_ul_estimate(&est, input, ce, n, sf_idx, cshift_dmrs, prb_idx); - + srslte_chest_ul_estimate_pusch(&est, &ul_sf, &cfg, input, &res); + // Compute MSE float mse = 0; for (i=0;i -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PUSCHCFG prhs[1] -#define INPUT prhs[2] -#define NOF_INPUTS 3 - -void help() -{ - mexErrMsgTxt - ("[estChannel, noiseEst, eq_output] = srslte_chest_ul(ue_cfg, pusch_cfg, inputSignal, [w_coeff])\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - srslte_cell_t cell; - srslte_chest_ul_t chest; - - cf_t *input_signal = NULL, *output_signal = NULL; - cf_t *ce = NULL; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - cell.cp = SRSLTE_CP_NORM; - cell.nof_ports = 1; - - uint32_t sf_idx=0; - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) { - help(); - return; - } - - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - pusch_cfg.group_hopping_en = false; - pusch_cfg.sequence_hopping_en = false; - char *tmp = mexutils_get_char_struct(UECFG, "Hopping"); - if (tmp) { - if (!strcmp(tmp, "Group")) { - pusch_cfg.group_hopping_en = true; - } else if (!strcmp(tmp, "Sequence")) { - pusch_cfg.sequence_hopping_en = true; - } - mxFree(tmp); - } - - - if (mexutils_read_uint32_struct(UECFG, "SeqGroup", &pusch_cfg.delta_ss)) { - pusch_cfg.delta_ss = 0; - } - if (mexutils_read_uint32_struct(UECFG, "CyclicShift", &pusch_cfg.cyclic_shift)) { - pusch_cfg.cyclic_shift = 0; - } - float *prbset; - mxArray *p; - p = mxGetField(PUSCHCFG, 0, "PRBSet"); - if (!p) { - mexErrMsgTxt("Error field PRBSet not found in PUSCH config\n"); - return; - } - uint32_t nof_prb = mexutils_read_f(p, &prbset); - uint32_t n_prb[2]; - n_prb[0] = prbset[0]; - n_prb[1] = prbset[0]; - - - uint32_t cyclic_shift_for_dmrs = 0; - if (mexutils_read_uint32_struct(PUSCHCFG, "DynCyclicShift", &cyclic_shift_for_dmrs)) { - cyclic_shift_for_dmrs = 0; - } - - if (srslte_chest_ul_init(&chest, cell)) { - mexErrMsgTxt("Error initiating channel estimator\n"); - return; - } - - srslte_chest_ul_set_cfg(&chest, &pusch_cfg, NULL, NULL); - - /** Allocate input buffers */ - int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE; - ce = srslte_vec_malloc(nof_re * sizeof(cf_t)); - output_signal = srslte_vec_malloc(nof_re * sizeof(cf_t)); - - // Read input signal - int insignal_len = mexutils_read_cf(INPUT, &input_signal); - if (insignal_len < 0) { - mexErrMsgTxt("Error reading input signal\n"); - return; - } - - // Read optional value smooth filter coefficient - if (nrhs > NOF_INPUTS) { - float w = (float) mxGetScalar(prhs[NOF_INPUTS]); - srslte_chest_ul_set_smooth_filter3_coeff(&chest, w); - } else { - srslte_chest_ul_set_smooth_filter(&chest, NULL, 0); - } - - // Perform channel estimation - if (srslte_chest_ul_estimate(&chest, input_signal, ce, nof_prb, sf_idx, cyclic_shift_for_dmrs, n_prb)) { - mexErrMsgTxt("Error running channel estimator\n"); - return; - } - - // Get noise power estimation - float noise_power = srslte_chest_ul_get_noise_estimate(&chest); - - // Perform channel equalization - srslte_predecoding_single(input_signal, ce, output_signal, nof_re, noise_power); - - /* Write output values */ - if (nlhs >= 1) { - mexutils_write_cf(ce, &plhs[0], mxGetM(INPUT), mxGetN(INPUT)); - } - if (nlhs >= 2) { - plhs[1] = mxCreateDoubleScalar(noise_power); - } - if (nlhs >= 3) { - mexutils_write_cf(output_signal, &plhs[2], mxGetM(INPUT), mxGetN(INPUT)); - } - - // Free all memory - srslte_chest_ul_free(&chest); - - if (ce) { - free(ce); - } - if (input_signal) { - free(input_signal); - } - if (output_signal) { - free(output_signal); - } - - return; -} - diff --git a/lib/src/phy/ch_estimation/test/refsignal_pusch_mex.c b/lib/src/phy/ch_estimation/test/refsignal_pusch_mex.c deleted file mode 100644 index 2564d1fcb..000000000 --- a/lib/src/phy/ch_estimation/test/refsignal_pusch_mex.c +++ /dev/null @@ -1,151 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PUSCHCFG prhs[1] -#define NOF_INPUTS 2 - -void help() -{ - mexErrMsgTxt - ("[seq] = srslte_refsignal_pusch(ueConfig, puschConfig)\n\n"); -} - -extern int indices[2048]; - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - srslte_cell_t cell; - srslte_refsignal_ul_t refs; - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - uint32_t sf_idx; - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - cell.cp = SRSLTE_CP_NORM; - cell.nof_ports = 1; - - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - - bzero(&pusch_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); - - - pusch_cfg.group_hopping_en = false; - pusch_cfg.sequence_hopping_en = false; - char *tmp = mexutils_get_char_struct(UECFG, "Hopping"); - if (tmp) { - if (!strcmp(tmp, "Group")) { - pusch_cfg.group_hopping_en = true; - } else if (!strcmp(tmp, "Sequence")) { - pusch_cfg.sequence_hopping_en = true; - } - mxFree(tmp); - } - - - if (mexutils_read_uint32_struct(UECFG, "SeqGroup", &pusch_cfg.delta_ss)) { - pusch_cfg.delta_ss = 0; - } - if (mexutils_read_uint32_struct(UECFG, "CyclicShift", &pusch_cfg.cyclic_shift)) { - pusch_cfg.cyclic_shift = 0; - } - float *prbset; - mxArray *p; - p = mxGetField(PUSCHCFG, 0, "PRBSet"); - if (!p) { - mexErrMsgTxt("Error field PRBSet not found in PUSCH config\n"); - return; - } - uint32_t nof_prb = mexutils_read_f(p, &prbset); - - uint32_t cyclic_shift_for_dmrs = 0; - if (mexutils_read_uint32_struct(PUSCHCFG, "DynCyclicShift", &cyclic_shift_for_dmrs)) { - cyclic_shift_for_dmrs = 0; - } - - if (srslte_refsignal_ul_init(&refs, cell)) { - mexErrMsgTxt("Error initiating srslte_refsignal_ul\n"); - return; - } - - mexPrintf("nof_prb: %d, ",nof_prb); - mexPrintf("cyclic_shift: %d, ",pusch_cfg.cyclic_shift); - mexPrintf("cyclic_shift_for_dmrs: %d, ", cyclic_shift_for_dmrs); - mexPrintf("delta_ss: %d, ",pusch_cfg.delta_ss); - - cf_t *signal = srslte_vec_malloc(2*SRSLTE_NRE*nof_prb*sizeof(cf_t)); - if (!signal) { - perror("malloc"); - return; - } - cf_t *sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)*sizeof(cf_t)); - if (!sf_symbols) { - perror("malloc"); - return; - } - bzero(sf_symbols, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)*sizeof(cf_t)); - - srslte_refsignal_ul_set_cfg(&refs, &pusch_cfg, NULL, NULL); - - //mexPrintf("Generating DRMS for ns=%d, nof_prb=%d\n", 2*sf_idx+i,pusch_cfg.nof_prb); - srslte_refsignal_dmrs_pusch_gen(&refs, nof_prb, sf_idx, cyclic_shift_for_dmrs, signal); - uint32_t n_prb[2]; - n_prb[0] = prbset[0]; - n_prb[1] = prbset[0]; - srslte_refsignal_dmrs_pusch_put(&refs, signal, nof_prb, n_prb, sf_symbols); - if (nlhs >= 1) { - mexutils_write_cf(sf_symbols, &plhs[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); - } - - srslte_refsignal_ul_free(&refs); - free(signal); - free(prbset); - - return; -} - diff --git a/lib/src/phy/ch_estimation/test/refsignal_srs_mex.c b/lib/src/phy/ch_estimation/test/refsignal_srs_mex.c deleted file mode 100644 index 29e93b912..000000000 --- a/lib/src/phy/ch_estimation/test/refsignal_srs_mex.c +++ /dev/null @@ -1,165 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define SRSCFG prhs[1] -#define NOF_INPUTS 2 - -void help() -{ - mexErrMsgTxt - ("[sym, subframe]=srslte_refsignal_srs(ue, chs)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - - srslte_cell_t cell; - bzero(&cell, sizeof(srslte_cell_t)); - cell.nof_ports = 1; - cell.cp = SRSLTE_CP_NORM; - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - - uint32_t sf_idx = 0; - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - uint32_t nf = 0; - if (mexutils_read_uint32_struct(UECFG, "NFrame", &nf)) { - mexErrMsgTxt("Field NFrame not found in UE config\n"); - return; - } - uint32_t tti = nf*10+sf_idx; - - srslte_refsignal_srs_cfg_t srs_cfg; - bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - - if (mexutils_read_uint32_struct(SRSCFG, "BWConfig", &srs_cfg.bw_cfg)) { - mexErrMsgTxt("Field BWConfig not found in SRSCFG\n"); - return; - } - if (mexutils_read_uint32_struct(SRSCFG, "BW", &srs_cfg.B)) { - mexErrMsgTxt("Field BW not found in SRSCFG\n"); - return; - } - if (mexutils_read_uint32_struct(SRSCFG, "ConfigIdx", &srs_cfg.I_srs)) { - mexErrMsgTxt("Field ConfigIdx not found in SRSCFG\n"); - return; - } - if (mexutils_read_uint32_struct(SRSCFG, "FreqPosition", &srs_cfg.n_rrc)) { - mexErrMsgTxt("Field FreqPosition not found in SRSCFG\n"); - return; - } - if (mexutils_read_uint32_struct(SRSCFG, "HoppingBW", &srs_cfg.b_hop)) { - mexErrMsgTxt("Field HoppingBW not found in SRSCFG\n"); - return; - } - if (mexutils_read_uint32_struct(SRSCFG, "TxComb", &srs_cfg.k_tc)) { - mexErrMsgTxt("Field TxComb not found in SRSCFG\n"); - return; - } - if (mexutils_read_uint32_struct(SRSCFG, "CyclicShift", &srs_cfg.n_srs)) { - mexErrMsgTxt("Field CyclicShift not found in SRSCFG\n"); - return; - } - bool group_hopping_en = false; - char *hop = mexutils_get_char_struct(UECFG, "Hopping"); - if (hop) { - if (!strcmp(hop, "Group")) { - group_hopping_en = true; - } - mxFree(hop); - } - - cf_t *r_srs = srslte_vec_malloc(sizeof(cf_t) * cell.nof_prb * 12); - if (!r_srs) { - return; - } - bzero(r_srs, cell.nof_prb * 12 * sizeof(cf_t)); - - cf_t *sf_symbols = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); - if (!sf_symbols) { - return; - } - bzero(sf_symbols, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - - srslte_refsignal_ul_t refsignal; - if (srslte_refsignal_ul_init(&refsignal, cell)) { - mexErrMsgTxt("Error initiating UL refsignal\n"); - return; - } - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - pusch_cfg.group_hopping_en = group_hopping_en; - pusch_cfg.sequence_hopping_en = false; - srslte_refsignal_ul_set_cfg(&refsignal, &pusch_cfg, NULL, &srs_cfg); - - if (srslte_refsignal_srs_gen(&refsignal, sf_idx, r_srs)) { - mexErrMsgTxt("Error generating SRS\n"); - return; - } - - if (srslte_refsignal_srs_put(&refsignal, tti, r_srs, sf_symbols)) { - mexErrMsgTxt("Error allocating SRS\n"); - return; - } - - if (nlhs >= 1) { - uint32_t M_sc = srslte_refsignal_srs_M_sc(&refsignal); ; - mexutils_write_cf(r_srs, &plhs[0], M_sc, 1); - } - - if (nlhs >= 2) { - mexutils_write_cf(sf_symbols, &plhs[1], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); - } - - srslte_refsignal_ul_free(&refsignal); - free(sf_symbols); - free(r_srs); - - return; -} - diff --git a/lib/src/phy/ch_estimation/test/refsignal_ul_test.c b/lib/src/phy/ch_estimation/test/refsignal_ul_test.c index 5ca18cdda..4fbca4447 100644 --- a/lib/src/phy/ch_estimation/test/refsignal_ul_test.c +++ b/lib/src/phy/ch_estimation/test/refsignal_ul_test.c @@ -24,21 +24,24 @@ * */ +#include "srslte/srslte.h" +#include #include #include #include #include -#include #include "srslte/srslte.h" srslte_cell_t cell = { - 100, // nof_prb - SRSLTE_MAX_PORTS, // nof_ports - 1, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_NORM, - SRSLTE_PHICH_R_1_6 + 100, // nof_prb + SRSLTE_MAX_PORTS, // nof_ports + 1, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, + SRSLTE_PHICH_R_1_6, // PHICH length + SRSLTE_FDD, + }; void usage(char *prog) { @@ -84,12 +87,12 @@ int main(int argc, char **argv) { parse_args(argc,argv); if (srslte_refsignal_ul_init(&refs, cell.nof_prb)) { - fprintf(stderr, "Error initializing UL reference signal\n"); + ERROR("Error initializing UL reference signal\n"); goto do_exit; } if (srslte_refsignal_ul_set_cell(&refs, cell)) { - fprintf(stderr, "Error initializing UL reference signal\n"); + ERROR("Error initializing UL reference signal\n"); goto do_exit; } @@ -134,14 +137,17 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); pusch_cfg.group_hopping_en = group_hopping_en; pusch_cfg.sequence_hopping_en = sequence_hopping_en; - srslte_refsignal_ul_set_cfg(&refs, &pusch_cfg, NULL, NULL); - srslte_refsignal_dmrs_pusch_gen(&refs, nof_prb, sf_idx, cshift_dmrs, signal); + + srslte_refsignal_dmrs_pusch_gen(&refs, &pusch_cfg, nof_prb, sf_idx, cshift_dmrs, signal); gettimeofday(&t[2], NULL); get_time_interval(t); printf("DMRS ExecTime: %ld us\n", t[0].tv_usec); + srslte_refsignal_srs_cfg_t srs_cfg; + ZERO_OBJECT(srs_cfg); + gettimeofday(&t[1], NULL); - srslte_refsignal_srs_gen(&refs, sf_idx, signal); + srslte_refsignal_srs_gen(&refs, &srs_cfg, &pusch_cfg, sf_idx, signal); gettimeofday(&t[2], NULL); get_time_interval(t); printf("SRS ExecTime: %ld us\n", t[0].tv_usec); diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index c9835f427..6b9e31e2e 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -24,18 +24,17 @@ * */ - - - +#include #include #include #include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/sequence.h" +#include "srslte/phy/utils/debug.h" #ifdef FORCE_STANDARD_RATE -static bool use_standard_rates = true; +static bool use_standard_rates = true; #else static bool use_standard_rates = false; #endif @@ -66,6 +65,7 @@ bool srslte_cell_isvalid(srslte_cell_t *cell) { } void srslte_cell_fprint(FILE *stream, srslte_cell_t *cell, uint32_t sfn) { + fprintf(stream, " - Type: %s\n", cell->frame_type == SRSLTE_FDD ? "FDD" : "TDD"); fprintf(stream, " - PCI: %d\n", cell->id); fprintf(stream, " - Nof ports: %d\n", cell->nof_ports); fprintf(stream, " - CP: %s\n", srslte_cp_string(cell->cp)); @@ -92,19 +92,96 @@ void srslte_cell_fprint(FILE *stream, srslte_cell_t *cell, uint32_t sfn) { } -bool srslte_sfidx_isvalid(uint32_t sf_idx) { - if (sf_idx <= SRSLTE_NSUBFRAMES_X_FRAME) { - return true; +// Internal type for srslte_tdd_sf_t +typedef enum { D = 0, U = 1, S = 2 } tdd_sf_t; + +static srslte_tdd_sf_t tdd_sf[7][10] = {{D, S, U, U, U, D, S, U, U, U}, + {D, S, U, U, D, D, S, U, U, D}, + {D, S, U, D, D, D, S, U, D, D}, + {D, S, U, U, U, D, D, D, D, D}, + {D, S, U, U, D, D, D, D, D, D}, + {D, S, U, D, D, D, D, D, D, D}, + {D, S, U, U, U, D, S, U, U, D}}; + +static uint32_t tdd_nof_sf_symbols[10][3] = { + {3, 10, 1}, {9, 4, 1}, {10, 3, 1}, {11, 2, 1}, {12, 1, 1}, {3, 9, 2}, {9, 3, 2}, {10, 2, 2}, {11, 1, 1}, {6, 6, 2}}; + +srslte_tdd_sf_t srslte_sfidx_tdd_type(srslte_tdd_config_t tdd_config, uint32_t sf_idx) +{ + if (tdd_config.sf_config < 7 && sf_idx < 10 && tdd_config.configured) { + return tdd_sf[tdd_config.sf_config][sf_idx]; + } else { + return SRSLTE_TDD_SF_D; + } +} + +uint32_t srslte_sfidx_tdd_nof_dw_slot(srslte_tdd_config_t tdd_config, uint32_t slot, srslte_cp_t cp) +{ + uint32_t n = srslte_sfidx_tdd_nof_dw(tdd_config); + if (n < SRSLTE_CP_NSYMB(cp)) { + if (slot == 1) { + return 0; + } else { + return n; + } } else { - return false; + if (slot == 1) { + return n - SRSLTE_CP_NSYMB(cp); + } else { + return SRSLTE_CP_NSYMB(cp); + } } } -bool srslte_portid_isvalid(uint32_t port_id) { +uint32_t srslte_sfidx_tdd_nof_dw(srslte_tdd_config_t tdd_config) +{ + if (tdd_config.ss_config < 10) { + return tdd_nof_sf_symbols[tdd_config.ss_config][0]; + } else { + return 0; + } +} + +uint32_t srslte_sfidx_tdd_nof_gp(srslte_tdd_config_t tdd_config) +{ + if (tdd_config.ss_config < 10) { + return tdd_nof_sf_symbols[tdd_config.ss_config][1]; + } else { + return 0; + } +} + +const static uint32_t tdd_nof_harq[7] = {7, 4, 2, 3, 2, 1, 6}; + +uint32_t srslte_tdd_nof_harq(srslte_tdd_config_t tdd_config) +{ + return tdd_nof_harq[tdd_config.sf_config]; +} + +uint32_t srslte_sfidx_tdd_nof_up(srslte_tdd_config_t tdd_config) +{ + if (tdd_config.ss_config < 10) { + return tdd_nof_sf_symbols[tdd_config.ss_config][2]; + } else { + return 0; + } +} + +bool srslte_sfidx_isvalid(uint32_t sf_idx) +{ + if (sf_idx <= SRSLTE_NOF_SF_X_FRAME) { + return true; + } else { + return false; + } +} + +bool srslte_portid_isvalid(uint32_t port_id) +{ if (port_id <= SRSLTE_MAX_PORTS) { - return true; + return true; } else { - return false; + return false; } } @@ -210,7 +287,6 @@ uint32_t srslte_N_ta_new_rar(uint32_t ta) { return ta*16; } - void srslte_use_standard_symbol_size(bool enabled) { use_standard_rates = enabled; } @@ -430,7 +506,27 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = { {30, 2350, 9770, 27660, 45, SRSLTE_BAND_GEO_AREA_NAR}, {31, 462.5, 9870, 27760, 10, SRSLTE_BAND_GEO_AREA_CALA}, {32, 1452, 9920, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, - {64, 0, 10359, 27809, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {33, 1900, 36000, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, + {34, 2010, 36200, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, + {35, 1850, 36350, 0, 0, SRSLTE_BAND_GEO_AREA_NAR}, + {36, 1930, 36950, 0, 0, SRSLTE_BAND_GEO_AREA_NAR}, + {37, 1910, 37550, 0, 0, SRSLTE_BAND_GEO_AREA_NAR}, + {38, 2570, 37750, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, + {39, 1880, 38250, 0, 0, SRSLTE_BAND_GEO_AREA_APAC}, + {40, 2300, 38650, 0, 0, SRSLTE_BAND_GEO_AREA_APAC}, + {41, 2496, 39650, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {42, 3400, 41590, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {43, 3600, 43590, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {44, 703, 45590, 0, 0, SRSLTE_BAND_GEO_AREA_APAC}, + {45, 1447, 46590, 0, 0, SRSLTE_BAND_GEO_AREA_APAC}, + {46, 5150, 46790, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {47, 5855, 54540, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {48, 3550, 55240, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {49, 3550, 56740, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {50, 1432, 58240, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {51, 1427, 59090, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {52, 3300, 59140, 0, 0, SRSLTE_BAND_GEO_AREA_ALL}, + {64, 0, 60139, 27809, 0, SRSLTE_BAND_GEO_AREA_ALL}, {65, 2110, 65536, 131072, 90, SRSLTE_BAND_GEO_AREA_ALL}, {66, 2110, 66436, 131972, 90, SRSLTE_BAND_GEO_AREA_NAR}, {67, 738, 67336, 0, 0, SRSLTE_BAND_GEO_AREA_EMEA}, @@ -440,45 +536,45 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = { {71, 0, 68586, 133122, 0, SRSLTE_BAND_GEO_AREA_NAR} // dummy band to bound band 70 earfcn }; - -int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { +int srslte_str2mimotype(char* mimo_type_str, srslte_tx_scheme_t* type) +{ int i = 0; /* Low case */ while (mimo_type_str[i] |= ' ', mimo_type_str[++i]); - if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "port0")) { - *type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "txdiversity")) { - *type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "spatialmux")) { - *type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (!strcmp(mimo_type_str, "cdd")) { - *type = SRSLTE_MIMO_TYPE_CDD; - } else { - return SRSLTE_ERROR; - } - return SRSLTE_SUCCESS; + srslte_tx_scheme_t t = SRSLTE_TXSCHEME_PORT0; + do { + if (!strcmp(mimo_type_str, srslte_mimotype2str(t))) { + *type = t; + return SRSLTE_SUCCESS; + } + t++; + } while (t <= SRSLTE_TXSCHEME_CDD); + + return SRSLTE_ERROR; } -char *srslte_mimotype2str(srslte_mimo_type_t mimo_type) { +char* srslte_mimotype2str(srslte_tx_scheme_t mimo_type) +{ switch (mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - return "Single"; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - return "Diversity"; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - return "Multiplex"; - case SRSLTE_MIMO_TYPE_CDD: - return "CDD"; + case SRSLTE_TXSCHEME_PORT0: + return "p0"; + case SRSLTE_TXSCHEME_DIVERSITY: + return "div"; + case SRSLTE_TXSCHEME_SPATIALMUX: + return "mux"; + case SRSLTE_TXSCHEME_CDD: + return "cdd"; default: return "N/A"; } } -float get_fd(struct lte_band *band, uint32_t dl_earfcn) { +float get_fd(struct lte_band* band, uint32_t dl_earfcn) +{ if (dl_earfcn >= band->dl_earfcn_offset) { - return band->fd_low_mhz + 0.1*(dl_earfcn - band->dl_earfcn_offset); + return band->fd_low_mhz + 0.1 * (dl_earfcn - band->dl_earfcn_offset); } else { return 0.0; } @@ -492,22 +588,37 @@ float get_fu(struct lte_band *band, uint32_t ul_earfcn) { } } -int srslte_band_get_band(uint32_t dl_earfcn) { - uint32_t i = SRSLTE_NOF_LTE_BANDS-1; +bool srslte_band_is_tdd(uint32_t band) +{ + uint32_t i = 0; + while (i < SRSLTE_NOF_LTE_BANDS && lte_bands[i].band != band) { + i++; + } + if (i == SRSLTE_NOF_LTE_BANDS) { + ERROR("Invalid Band %d\n", band); + return false; + } + return lte_bands[i].ul_earfcn_offset == 0; +} + +int srslte_band_get_band(uint32_t dl_earfcn) +{ + uint32_t i = SRSLTE_NOF_LTE_BANDS - 1; if (dl_earfcn > lte_bands[i].dl_earfcn_offset) { - fprintf(stderr, "Invalid DL_EARFCN=%d\n", dl_earfcn); + ERROR("Invalid DL_EARFCN=%d\n", dl_earfcn); } i--; - while(i > 0 && lte_bands[i].dl_earfcn_offset>dl_earfcn) { + while (i > 0 && lte_bands[i].dl_earfcn_offset > dl_earfcn) { i--; } return lte_bands[i].band; } -float srslte_band_fd(uint32_t dl_earfcn) { +float srslte_band_fd(uint32_t dl_earfcn) +{ uint32_t i = SRSLTE_NOF_LTE_BANDS-1; if (dl_earfcn > lte_bands[i].dl_earfcn_offset) { - fprintf(stderr, "Invalid DL_EARFCN=%d\n", dl_earfcn); + ERROR("Invalid DL_EARFCN=%d\n", dl_earfcn); } i--; while(i > 0 && lte_bands[i].dl_earfcn_offset>dl_earfcn) { @@ -520,7 +631,7 @@ float srslte_band_fd(uint32_t dl_earfcn) { float srslte_band_fu(uint32_t ul_earfcn) { uint32_t i = SRSLTE_NOF_LTE_BANDS-1; if (ul_earfcn > lte_bands[i].ul_earfcn_offset) { - fprintf(stderr, "Invalid UL_EARFCN=%d\n", ul_earfcn); + ERROR("Invalid UL_EARFCN=%d\n", ul_earfcn); } i--; while(i > 0 && (lte_bands[i].ul_earfcn_offset>ul_earfcn || lte_bands[i].ul_earfcn_offset == 0)) { @@ -532,7 +643,7 @@ float srslte_band_fu(uint32_t ul_earfcn) { uint32_t srslte_band_ul_earfcn(uint32_t dl_earfcn) { uint32_t i = SRSLTE_NOF_LTE_BANDS-1; if (dl_earfcn > lte_bands[i].dl_earfcn_offset) { - fprintf(stderr, "Invalid DL_EARFCN=%d\n", dl_earfcn); + ERROR("Invalid DL_EARFCN=%d\n", dl_earfcn); } i--; while(i > 0 && lte_bands[i].dl_earfcn_offset>dl_earfcn) { @@ -545,7 +656,9 @@ int srslte_band_get_fd_band_all(uint32_t band, srslte_earfcn_t *earfcn, uint32_t return srslte_band_get_fd_band(band, earfcn, -1, -1, max_elems); } -int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, uint32_t max_elems) { +int srslte_band_get_fd_band( + uint32_t band, srslte_earfcn_t* earfcn, int start_earfcn, int end_earfcn, uint32_t max_elems) +{ uint32_t i, j; uint32_t nof_earfcn; i=0; @@ -553,14 +666,14 @@ int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, int start_ea i++; } if (i >= SRSLTE_NOF_LTE_BANDS - 1) { - fprintf(stderr, "Error: Invalid band %d\n", band); + ERROR("Error: Invalid band %d\n", band); return SRSLTE_ERROR; } if (end_earfcn == -1) { end_earfcn = lte_bands[i+1].dl_earfcn_offset-1; } else { if (end_earfcn > lte_bands[i+1].dl_earfcn_offset-1) { - fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i+1].dl_earfcn_offset-1); + ERROR("Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i + 1].dl_earfcn_offset - 1); return SRSLTE_ERROR; } } @@ -568,7 +681,7 @@ int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, int start_ea start_earfcn = lte_bands[i].dl_earfcn_offset; } else { if (start_earfcn < lte_bands[i].dl_earfcn_offset) { - fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].dl_earfcn_offset); + ERROR("Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].dl_earfcn_offset); return SRSLTE_ERROR; } } @@ -581,7 +694,7 @@ int srslte_band_get_fd_band(uint32_t band, srslte_earfcn_t *earfcn, int start_ea earfcn[j].id = j + start_earfcn; earfcn[j].fd = get_fd(<e_bands[i], earfcn[j].id); } - return (int) j; + return (int)j; } int srslte_band_get_fd_region(enum band_geographical_area region, srslte_earfcn_t *earfcn, uint32_t max_elems) { @@ -612,4 +725,16 @@ uint32_t srslte_tti_interval(uint32_t tti1, uint32_t tti2) { } } - +uint32_t srslte_print_check(char* s, size_t max_len, uint32_t cur_len, const char* format, ...) +{ + if (cur_len < max_len - 1) { + va_list args; + va_start(args, format); + cur_len += vsnprintf(&s[cur_len], max_len - cur_len, format, args); + va_end(args); + } else { + ERROR("Buffer full when printing string\n"); + exit(-1); + } + return cur_len; +} diff --git a/lib/src/phy/common/sequence.c b/lib/src/phy/common/sequence.c index 52497f5de..5219ce695 100644 --- a/lib/src/phy/common/sequence.c +++ b/lib/src/phy/common/sequence.c @@ -28,11 +28,11 @@ #include #include #include -#include #include "srslte/phy/common/sequence.h" -#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #define Nc 1600 @@ -54,14 +54,12 @@ int srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed int n; if (len > q->max_len) { - fprintf(stderr, "Error generating pseudo-random sequence: len %d exceeds maximum len %d\n", - len, MAX_SEQ_LEN); + ERROR("Error generating pseudo-random sequence: len %d exceeds maximum len %d\n", len, MAX_SEQ_LEN); return -1; } if (len > q->max_len) { - fprintf(stderr, "Error generating pseudo-random sequence: len %d is greater than allocated len %d\n", - len, q->max_len); + ERROR("Error generating pseudo-random sequence: len %d is greater than allocated len %d\n", len, q->max_len); return -1; } pthread_mutex_lock(&mutex); @@ -90,8 +88,7 @@ int srslte_sequence_set_LTE_pr(srslte_sequence_t *q, uint32_t len, uint32_t seed uint32_t *x1, *x2; if (len > q->max_len) { - fprintf(stderr, "Error generating pseudo-random sequence: len %d is greater than allocated len %d\n", - len, q->max_len); + ERROR("Error generating pseudo-random sequence: len %d is greater than allocated len %d\n", len, q->max_len); return -1; } diff --git a/lib/src/phy/dft/dft_fftw.c b/lib/src/phy/dft/dft_fftw.c index 151156a96..79d8a4560 100644 --- a/lib/src/phy/dft/dft_fftw.c +++ b/lib/src/phy/dft/dft_fftw.c @@ -24,12 +24,11 @@ * */ - -#include +#include "srslte/srslte.h" #include #include +#include #include -#include #include "srslte/phy/dft/dft.h" #include "srslte/phy/utils/vector.h" @@ -81,8 +80,10 @@ int srslte_dft_replan(srslte_dft_plan_t *plan, const int new_dft_points) { return srslte_dft_replan_r(plan,new_dft_points); } } else { - fprintf(stderr, "DFT: Error calling replan: new_dft_points (%d) must be lower or equal " - "dft_size passed initially (%d)\n", new_dft_points, plan->init_size); + ERROR("DFT: Error calling replan: new_dft_points (%d) must be lower or equal " + "dft_size passed initially (%d)\n", + new_dft_points, + plan->init_size); return -1; } } @@ -312,7 +313,7 @@ void srslte_dft_run_guru_c(srslte_dft_plan_t *plan) { if (plan->is_guru == true) { fftwf_execute(plan->p); } else { - fprintf(stderr, "srslte_dft_run_guru_c: the selected plan is not guru!\n"); + ERROR("srslte_dft_run_guru_c: the selected plan is not guru!\n"); } } diff --git a/lib/src/phy/dft/dft_precoding.c b/lib/src/phy/dft/dft_precoding.c index a43d79406..781ce9360 100644 --- a/lib/src/phy/dft/dft_precoding.c +++ b/lib/src/phy/dft/dft_precoding.c @@ -52,7 +52,7 @@ int srslte_dft_precoding_init(srslte_dft_precoding_t *q, uint32_t max_prb, bool if(srslte_dft_precoding_valid_prb(i)) { DEBUG("Initiating DFT precoding plan for %d PRBs\n", i); if (srslte_dft_plan_c(&q->dft_plan[i], i*SRSLTE_NRE, is_tx?SRSLTE_DFT_FORWARD:SRSLTE_DFT_BACKWARD)) { - fprintf(stderr, "Error: Creating DFT plan %d\n",i); + ERROR("Error: Creating DFT plan %d\n", i); goto clean_exit; } srslte_dft_plan_set_norm(&q->dft_plan[i], true); @@ -106,7 +106,7 @@ int srslte_dft_precoding(srslte_dft_precoding_t *q, cf_t *input, cf_t *output, { if (!srslte_dft_precoding_valid_prb(nof_prb) && nof_prb <= q->max_prb) { - fprintf(stderr, "Error invalid number of PRB (%d)\n", nof_prb); + ERROR("Error invalid number of PRB (%d)\n", nof_prb); return SRSLTE_ERROR; } diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 06da6b41a..12746c680 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -24,12 +24,12 @@ * */ -#include -#include -#include +#include "srslte/srslte.h" #include #include -#include +#include +#include +#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/dft/dft.h" @@ -60,7 +60,7 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, c q->out_buffer= out_buffer; if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) { - fprintf(stderr, "Error: Creating DFT plan\n"); + ERROR("Error: Creating DFT plan\n"); return -1; } @@ -96,7 +96,7 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, c in_buffer + cp1 + q->slot_sz * slot, q->tmp + q->nof_symbols * q->symbol_sz * slot, 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz + cp2, symbol_sz)) { - fprintf(stderr, "Error: Creating DFT plan (1)\n"); + ERROR("Error: Creating DFT plan (1)\n"); return -1; } } else { @@ -104,7 +104,7 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, c q->tmp + q->nof_symbols * q->symbol_sz * slot, out_buffer + cp1 + q->slot_sz * slot, 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz, symbol_sz + cp2)) { - fprintf(stderr, "Error: Creating DFT plan (1)\n"); + ERROR("Error: Creating DFT plan (1)\n"); return -1; } } @@ -143,7 +143,7 @@ void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, uint8_t non_mbsfn_region int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb) { if (srslte_dft_replan_c(&q->fft_plan, symbol_sz)) { - fprintf(stderr, "Error: Creating DFT plan\n"); + ERROR("Error: Creating DFT plan\n"); return -1; } @@ -190,7 +190,7 @@ int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof in_buffer + cp1 + q->slot_sz * slot, q->tmp + q->nof_symbols * q->symbol_sz * slot, 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz + cp2, symbol_sz)) { - fprintf(stderr, "Error: Creating DFT plan (1)\n"); + ERROR("Error: Creating DFT plan (1)\n"); return -1; } } else { @@ -198,7 +198,7 @@ int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof q->tmp + q->nof_symbols * q->symbol_sz * slot, out_buffer + cp1 + q->slot_sz * slot, 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz, symbol_sz + cp2)) { - fprintf(stderr, "Error: Creating DFT plan (1)\n"); + ERROR("Error: Creating DFT plan (1)\n"); return -1; } } @@ -240,7 +240,7 @@ void srslte_ofdm_free_(srslte_ofdm_t *q) { int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t *out_buffer, uint32_t max_prb) { int symbol_sz = srslte_symbol_sz(max_prb); if (symbol_sz < 0) { - fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb); + ERROR("Error: Invalid nof_prb=%d\n", max_prb); return -1; } q->max_prb = max_prb; @@ -251,7 +251,7 @@ int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, { int symbol_sz = srslte_symbol_sz(max_prb); if (symbol_sz < 0) { - fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb); + ERROR("Error: Invalid nof_prb=%d\n", max_prb); return -1; } q->max_prb = max_prb; @@ -265,7 +265,7 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, cf_t int symbol_sz = srslte_symbol_sz(max_prb); if (symbol_sz < 0) { - fprintf(stderr, "Error: Invalid nof_prb=%d\n", max_prb); + ERROR("Error: Invalid nof_prb=%d\n", max_prb); return -1; } q->max_prb = max_prb; @@ -290,8 +290,8 @@ int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, int ret; int symbol_sz = srslte_symbol_sz(nof_prb); - if (symbol_sz < 0) { - fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + if (symbol_sz < 0) { + ERROR("Error: Invalid nof_prb=%d\n", nof_prb); return -1; } q->max_prb = nof_prb; @@ -313,13 +313,14 @@ int srslte_ofdm_rx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { if (nof_prb <= q->max_prb) { int symbol_sz = srslte_symbol_sz(nof_prb); if (symbol_sz < 0) { - fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + ERROR("Error: Invalid nof_prb=%d\n", nof_prb); return -1; } return srslte_ofdm_replan_(q, cp, symbol_sz, nof_prb); } else { - fprintf(stderr, "OFDM (Rx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", - nof_prb, q->max_prb); + ERROR("OFDM (Rx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", + nof_prb, + q->max_prb); return -1; } } @@ -331,7 +332,7 @@ int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { if (nof_prb <= q->max_prb) { int symbol_sz = srslte_symbol_sz(nof_prb); if (symbol_sz < 0) { - fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + ERROR("Error: Invalid nof_prb=%d\n", nof_prb); return -1; } @@ -346,8 +347,9 @@ int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { } return ret; } else { - fprintf(stderr, "OFDM (Tx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", - nof_prb, q->max_prb); + ERROR("OFDM (Tx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", + nof_prb, + q->max_prb); return -1; } } @@ -550,7 +552,7 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, int slot_in_sf) { for (int i = 0; i < q->slot_sz; i++) { float error = cabsf(output1[i] - output2[i])/cabsf(output2[i]); cf_t k = output1[i]/output2[i]; - if (error > 0.1) printf("%d/%05d error=%f output=%+f%+fi gold=%+f%+fi k=%+f%+fi\n", slot_in_sf, i, error, + if (error > 0.1) printf("%d/%05d error=%f output=%+f%+fi gold=%+f%+fi k=%+f%+fi\n", slot_in_sf, i, ERROR( __real__ output1[i], __imag__ output1[i], __real__ output2[i], __imag__ output2[i], __real__ k, __imag__ k); diff --git a/lib/src/phy/dft/test/ofdm_test.c b/lib/src/phy/dft/test/ofdm_test.c index c40be4d0a..a44af5701 100644 --- a/lib/src/phy/dft/test/ofdm_test.c +++ b/lib/src/phy/dft/test/ofdm_test.c @@ -115,13 +115,13 @@ int main(int argc, char **argv) { bzero(outifft, sizeof(cf_t) * SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * 2); if (srslte_ofdm_rx_init(&fft, cp, outifft, outfft, n_prb)) { - fprintf(stderr, "Error initializing FFT\n"); + ERROR("Error initializing FFT\n"); exit(-1); } srslte_ofdm_set_normalize(&fft, true); if (srslte_ofdm_tx_init(&ifft, cp, input, outifft, n_prb)) { - fprintf(stderr, "Error initializing iFFT\n"); + ERROR("Error initializing iFFT\n"); exit(-1); } srslte_ofdm_set_normalize(&ifft, true); diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 32703febb..cf0ad1e29 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -26,18 +26,16 @@ #include "srslte/phy/enb/enb_dl.h" +#include "srslte/srslte.h" #include #include #include -#include -#include - #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) #define CURRENT_SFLEN SRSLTE_SF_LEN(CURRENT_FFTSIZE) #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SRSLTE_NOF_RE(q->cell) #define SRSLTE_ENB_RF_AMP 0.1 @@ -50,9 +48,6 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_enb_dl_t)); - - q->cfi = 3; - q->tx_amp = SRSLTE_ENB_RF_AMP; for (int i=0;isf_symbols[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); @@ -60,65 +55,62 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, cf_t *out_buffer[SRSLTE_MAX_PORTS], u perror("malloc"); goto clean_exit; } - q->slot1_symbols[i] = &q->sf_symbols[i][SRSLTE_SLOT_LEN_RE(max_prb, SRSLTE_CP_NORM)]; } for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { if (srslte_ofdm_tx_init(&q->ifft[i], SRSLTE_CP_NORM, q->sf_symbols[i], out_buffer[i], max_prb)) { - fprintf(stderr, "Error initiating FFT (%d)\n", i); + ERROR("Error initiating FFT (%d)\n", i); goto clean_exit; } } if (srslte_ofdm_tx_init_mbsfn(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->sf_symbols[0], out_buffer[0], max_prb)) { - fprintf(stderr, "Error initiating FFT \n"); + ERROR("Error initiating FFT \n"); goto clean_exit; } if (srslte_pbch_init(&q->pbch)) { - fprintf(stderr, "Error creating PBCH object\n"); + ERROR("Error creating PBCH object\n"); goto clean_exit; } if (srslte_pcfich_init(&q->pcfich, 0)) { - fprintf(stderr, "Error creating PCFICH object\n"); + ERROR("Error creating PCFICH object\n"); goto clean_exit; } if (srslte_phich_init(&q->phich, 0)) { - fprintf(stderr, "Error creating PHICH object\n"); + ERROR("Error creating PHICH object\n"); goto clean_exit; } int mbsfn_area_id = 1; - - - if (srslte_pmch_init(&q->pmch, max_prb)) { - fprintf(stderr, "Error creating PMCH object\n"); + + if (srslte_pmch_init(&q->pmch, max_prb, 1)) { + ERROR("Error creating PMCH object\n"); } srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id); - if (srslte_pdcch_init_enb(&q->pdcch, max_prb)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); goto clean_exit; } if (srslte_pdsch_init_enb(&q->pdsch, max_prb)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); goto clean_exit; } - + if (srslte_refsignal_cs_init(&q->csr_signal, max_prb)) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); goto clean_exit; } if (srslte_refsignal_mbsfn_init(&q->mbsfnr_signal, max_prb)) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); goto clean_exit; - } + } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters\n"); + ERROR("Invalid parameters\n"); } clean_exit: @@ -160,70 +152,64 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell) if (q != NULL && srslte_cell_isvalid(&cell)) { - q->tx_amp = SRSLTE_ENB_RF_AMP; - if (q->cell.id != cell.id || q->cell.nof_prb == 0) { if (q->cell.nof_prb != 0) { srslte_regs_free(&q->regs); } - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; if (srslte_regs_init(&q->regs, q->cell)) { - fprintf(stderr, "Error resizing REGs\n"); + ERROR("Error resizing REGs\n"); return SRSLTE_ERROR; } for (int i = 0; i < q->cell.nof_ports; i++) { - - q->slot1_symbols[i] = &q->sf_symbols[i][SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, SRSLTE_CP_NORM)]; - if (srslte_ofdm_tx_set_prb(&q->ifft[i], q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error re-planning iFFT (%d)\n", i); + ERROR("Error re-planning iFFT (%d)\n", i); return SRSLTE_ERROR; } } if (srslte_ofdm_tx_set_prb(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->cell.nof_prb)) { - fprintf(stderr, "Error re-planning ifft_mbsfn\n"); + ERROR("Error re-planning ifft_mbsfn\n"); return SRSLTE_ERROR; } - + srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, 2); - //srslte_ofdm_set_normalize(&q->ifft_mbsfn, true); - + if (srslte_pbch_set_cell(&q->pbch, q->cell)) { - fprintf(stderr, "Error creating PBCH object\n"); + ERROR("Error creating PBCH object\n"); return SRSLTE_ERROR; } if (srslte_pcfich_set_cell(&q->pcfich, &q->regs, q->cell)) { - fprintf(stderr, "Error creating PCFICH object\n"); + ERROR("Error creating PCFICH object\n"); return SRSLTE_ERROR; } if (srslte_phich_set_cell(&q->phich, &q->regs, q->cell)) { - fprintf(stderr, "Error creating PHICH object\n"); + ERROR("Error creating PHICH object\n"); return SRSLTE_ERROR; } if (srslte_pdcch_set_cell(&q->pdcch, &q->regs, q->cell)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); return SRSLTE_ERROR; } if (srslte_pdsch_set_cell(&q->pdsch, q->cell)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); return SRSLTE_ERROR; } - + if (srslte_pmch_set_cell(&q->pmch, q->cell)) { - fprintf(stderr, "Error creating PMCH object\n"); + ERROR("Error creating PMCH object\n"); return SRSLTE_ERROR; } if (srslte_refsignal_cs_set_cell(&q->csr_signal, q->cell)) { - fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); + ERROR("Error initializing CSR signal (%d)\n", ret); return SRSLTE_ERROR; } int mbsfn_area_id = 1; if (srslte_refsignal_mbsfn_set_cell(&q->mbsfnr_signal, q->cell, mbsfn_area_id)) { - fprintf(stderr, "Error initializing MBSFNR signal (%d)\n",ret); + ERROR("Error initializing MBSFNR signal (%d)\n", ret); return SRSLTE_ERROR; } /* Generate PSS/SSS signals */ @@ -233,37 +219,22 @@ int srslte_enb_dl_set_cell(srslte_enb_dl_t *q, srslte_cell_t cell) ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + ERROR("Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; } - - -void srslte_enb_dl_set_non_mbsfn_region(srslte_enb_dl_t *q, uint8_t non_mbsfn_region) -{ - srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, non_mbsfn_region); -} - -void srslte_enb_dl_set_amp(srslte_enb_dl_t *q, float amp) -{ - q->tx_amp = amp; -} - -void srslte_enb_dl_set_cfi(srslte_enb_dl_t *q, uint32_t cfi) +int srslte_enb_dl_add_rnti(srslte_enb_dl_t* q, uint16_t rnti) { - q->cfi = cfi; + return srslte_pdsch_set_rnti(&q->pdsch, rnti); } -void srslte_enb_dl_set_power_allocation(srslte_enb_dl_t *q, float rho_a, float rho_b) +void srslte_enb_dl_rem_rnti(srslte_enb_dl_t* q, uint16_t rnti) { - if (q) { - q->rho_b = rho_b; - srslte_pdsch_set_power_allocation(&q->pdsch, rho_a); - } + srslte_pdsch_free_rnti(&q->pdsch, rnti); } +#ifdef resolve void srslte_enb_dl_apply_power_allocation(srslte_enb_dl_t *q) { uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp); @@ -320,15 +291,19 @@ void srslte_enb_dl_prepare_power_allocation(srslte_enb_dl_t *q) } } -void srslte_enb_dl_clear_sf(srslte_enb_dl_t *q) +#endif + +static void clear_sf(srslte_enb_dl_t* q) { - for (int i=0;icell.nof_ports;i++) { - bzero(q->sf_symbols[i], CURRENT_SFLEN_RE * sizeof(cf_t)); + for (int i = 0; i < q->cell.nof_ports; i++) { + bzero(q->sf_symbols[i], CURRENT_SFLEN_RE * sizeof(cf_t)); } } -void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, uint32_t sf_idx) +static void put_sync(srslte_enb_dl_t* q) { + uint32_t sf_idx = q->dl_sf.tti % 10; + if (sf_idx == 0 || sf_idx == 5) { for (int p = 0; p < q->cell.nof_ports; p++) { srslte_pss_put_slot(q->pss_signal, q->sf_symbols[p], q->cell.nof_prb, q->cell.cp); @@ -338,196 +313,163 @@ void srslte_enb_dl_put_sync(srslte_enb_dl_t *q, uint32_t sf_idx) } } -void srslte_enb_dl_put_refs(srslte_enb_dl_t *q, uint32_t sf_idx) +static void put_refs(srslte_enb_dl_t* q) { - for (int p = 0; p < q->cell.nof_ports; p++) { - srslte_refsignal_cs_put_sf(q->cell, (uint32_t) p, q->csr_signal.pilots[p / 2][sf_idx], q->sf_symbols[p]); + uint32_t sf_idx = q->dl_sf.tti % 10; + if (q->dl_sf.sf_type == SRSLTE_SF_MBSFN) { + srslte_refsignal_mbsfn_put_sf( + q->cell, 0, q->csr_signal.pilots[0][sf_idx], q->mbsfnr_signal.pilots[0][sf_idx], q->sf_symbols[0]); + } else { + for (int p = 0; p < q->cell.nof_ports; p++) { + srslte_refsignal_cs_put_sf(&q->csr_signal, &q->dl_sf, (uint32_t)p, q->sf_symbols[p]); + } } } -void srslte_enb_dl_put_mib(srslte_enb_dl_t *q, uint32_t tti) +static void put_mib(srslte_enb_dl_t* q) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - if ((tti%10) == 0) { - srslte_pbch_mib_pack(&q->cell, tti/10, bch_payload); - srslte_pbch_encode(&q->pbch, bch_payload, q->slot1_symbols, ((tti/10)%4)); - } -} - -void srslte_enb_dl_put_pcfich(srslte_enb_dl_t *q, uint32_t sf_idx) -{ - srslte_pcfich_encode(&q->pcfich, q->cfi, q->sf_symbols, sf_idx); -} - -void srslte_enb_dl_put_phich(srslte_enb_dl_t *q, uint8_t ack, uint32_t n_prb_lowest, - uint32_t n_dmrs, uint32_t sf_idx) -{ - uint32_t ngroup, nseq; - srslte_phich_calc(&q->phich, n_prb_lowest, n_dmrs, &ngroup, &nseq); - srslte_phich_encode(&q->phich, ack, ngroup, nseq, sf_idx, q->sf_symbols); -} - -void srslte_enb_dl_put_base(srslte_enb_dl_t *q, uint32_t tti) -{ - uint32_t sf_idx = tti%10; - - srslte_enb_dl_put_sync(q, sf_idx); - srslte_enb_dl_put_refs(q, sf_idx); - srslte_enb_dl_put_mib(q, tti); - srslte_enb_dl_put_pcfich(q, sf_idx); - -} - -void srslte_enb_dl_put_mbsfn_base(srslte_enb_dl_t *q, uint32_t tti) -{ - uint32_t sf_idx1 = tti%10; - srslte_enb_dl_put_pcfich(q, sf_idx1); - srslte_refsignal_mbsfn_put_sf(q->cell, 0,q->csr_signal.pilots[0][sf_idx1], q->mbsfnr_signal.pilots[0][sf_idx1], q->sf_symbols[0]); -} + uint32_t sf_idx = q->dl_sf.tti % 10; + uint32_t sfn = q->dl_sf.tti / 10; -void srslte_enb_dl_gen_signal(srslte_enb_dl_t *q) -{ - // TODO: PAPR control - float norm_factor = 0.05f / sqrt(q->cell.nof_prb); - for (int i = 0; i < q->cell.nof_ports; i++) { - srslte_ofdm_tx_sf(&q->ifft[i]); - srslte_vec_sc_prod_cfc(q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + if (sf_idx == 0) { + srslte_pbch_mib_pack(&q->cell, sfn, bch_payload); + srslte_pbch_encode(&q->pbch, bch_payload, q->sf_symbols, sfn % 4); } } -void srslte_enb_dl_gen_signal_mbsfn(srslte_enb_dl_t *q) +static void put_pcfich(srslte_enb_dl_t* q) { - float norm_factor = 0.05f / sqrt(q->cell.nof_prb); - srslte_ofdm_tx_sf(&q->ifft_mbsfn); - srslte_vec_sc_prod_cfc(q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t) SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + srslte_pcfich_encode(&q->pcfich, &q->dl_sf, q->sf_symbols); } -int srslte_enb_dl_add_rnti(srslte_enb_dl_t *q, uint16_t rnti) +void srslte_enb_dl_put_base(srslte_enb_dl_t* q, srslte_dl_sf_cfg_t* dl_sf) { - return srslte_pdsch_set_rnti(&q->pdsch, rnti); + srslte_ofdm_set_non_mbsfn_region(&q->ifft_mbsfn, dl_sf->non_mbsfn_region); + q->dl_sf = *dl_sf; + clear_sf(q); + put_sync(q); + put_refs(q); + put_mib(q); + put_pcfich(q); } -void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q, uint16_t rnti) +void srslte_enb_dl_put_phich(srslte_enb_dl_t* q, srslte_phich_grant_t* grant, bool ack) { - srslte_pdsch_free_rnti(&q->pdsch, rnti); + srslte_phich_resource_t resource; + srslte_phich_calc(&q->phich, grant, &resource); + srslte_phich_encode(&q->phich, &q->dl_sf, resource, ack, q->sf_symbols); } -int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q, srslte_ra_dl_dci_t *grant, - srslte_dci_format_t format, srslte_dci_location_t location, - uint16_t rnti, uint32_t sf_idx) +int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t* q, srslte_dci_cfg_t* dci_cfg, srslte_dci_dl_t* dci_dl) { srslte_dci_msg_t dci_msg; - bzero(&dci_msg, sizeof(dci_msg)); - - bool rnti_is_user = true; - if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || (rnti >= SRSLTE_RARNTI_START && rnti <= SRSLTE_RARNTI_END)) { - rnti_is_user = false; - } + ZERO_OBJECT(dci_msg); - if (srslte_dci_msg_pack_pdsch(grant, format, &dci_msg, q->cell.nof_prb, q->cell.nof_ports, rnti_is_user)) { - fprintf(stderr, "Error packing DCI grant\n"); + if (srslte_dci_msg_pack_pdsch(&q->cell, &q->dl_sf, dci_cfg, dci_dl, &dci_msg)) { + ERROR("Error packing DL DCI\n"); } - if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { - fprintf(stderr, "Error encoding DCI message\n"); + if (srslte_pdcch_encode(&q->pdcch, &q->dl_sf, &dci_msg, q->sf_symbols)) { + ERROR("Error encoding DL DCI message\n"); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } -int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant, - srslte_dci_location_t location, - uint16_t rnti, uint32_t sf_idx) +int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t* q, srslte_dci_cfg_t* dci_cfg, srslte_dci_ul_t* dci_ul) { srslte_dci_msg_t dci_msg; - bzero(&dci_msg, sizeof(dci_msg)); + ZERO_OBJECT(dci_msg); - srslte_dci_msg_pack_pusch(grant, &dci_msg, q->cell.nof_prb); - if (srslte_pdcch_encode(&q->pdcch, &dci_msg, location, rnti, q->sf_symbols, sf_idx, q->cfi)) { - fprintf(stderr, "Error encoding DCI message\n"); + if (srslte_dci_msg_pack_pusch(&q->cell, &q->dl_sf, dci_cfg, dci_ul, &dci_msg)) { + ERROR("Error packing UL DCI\n"); + } + if (srslte_pdcch_encode(&q->pdcch, &q->dl_sf, &dci_msg, q->sf_symbols)) { + ERROR("Error encoding UL DCI message\n"); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } -int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, int rv_idx[SRSLTE_MAX_CODEWORDS], uint32_t sf_idx, - uint8_t *data[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) -{ - uint32_t pmi = 0; - uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); - - /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ - if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - switch(nof_tb) { - case 1: - if (grant->pinfo == 0) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (grant->pinfo > 0 && grant->pinfo < 5) { - pmi = grant->pinfo - 1; - } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); - return SRSLTE_ERROR; - } - break; - case 2: - if (grant->pinfo < 2) { - pmi = grant->pinfo; - } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); - return SRSLTE_ERROR; - } - break; - default: - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); - return SRSLTE_ERROR; +int srslte_enb_dl_put_pdsch(srslte_enb_dl_t* q, srslte_pdsch_cfg_t* pdsch, uint8_t* data[SRSLTE_MAX_CODEWORDS]) +{ + return srslte_pdsch_encode(&q->pdsch, &q->dl_sf, pdsch, data, q->sf_symbols); +} + +int srslte_enb_dl_put_pmch(srslte_enb_dl_t* q, srslte_pmch_cfg_t* pmch_cfg, uint8_t* data) +{ + return srslte_pmch_encode(&q->pmch, &q->dl_sf, pmch_cfg, data, q->sf_symbols); +} + +void srslte_enb_dl_gen_signal(srslte_enb_dl_t* q) +{ + // TODO: PAPR control + float norm_factor = 0.05f / sqrt(q->cell.nof_prb); + + if (q->dl_sf.sf_type == SRSLTE_SF_MBSFN) { + srslte_ofdm_tx_sf(&q->ifft_mbsfn); + srslte_vec_sc_prod_cfc( + q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t)SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + } else { + for (int i = 0; i < q->cell.nof_ports; i++) { + srslte_ofdm_tx_sf(&q->ifft[i]); + srslte_vec_sc_prod_cfc( + q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t)SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); } } +} - /* Configure pdsch_cfg parameters */ - if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) { - ERROR("Error configuring PDSCH (rnti=0x%04x)", rnti); - return SRSLTE_ERROR; +bool srslte_enb_dl_gen_cqi_periodic( + srslte_cell_t* cell, srslte_dl_cfg_t* dl_cfg, uint32_t tti, uint32_t ri, srslte_cqi_cfg_t* cqi_cfg) +{ + bool cqi_enabled = false; + if (srslte_cqi_periodic_ri_send(&dl_cfg->cqi_report, tti, cell->frame_type)) { + cqi_cfg->ri_len = 1; /* Asumes only 1 bit for RI */ + cqi_enabled = true; + } else if (srslte_cqi_periodic_send(&dl_cfg->cqi_report, tti, cell->frame_type)) { + cqi_cfg->type = SRSLTE_CQI_TYPE_WIDEBAND; + if (dl_cfg->tm == SRSLTE_TM4) { + cqi_cfg->pmi_present = true; + cqi_cfg->rank_is_not_one = ri > 0; + } + cqi_enabled = true; + cqi_cfg->data_enable = cqi_enabled; } - - /* Encode PDSCH */ - if (srslte_pdsch_encode(&q->pdsch, &q->pdsch_cfg, softbuffer, data, rnti, q->sf_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); - return SRSLTE_ERROR; - } - return SRSLTE_SUCCESS; + return cqi_enabled; } -int srslte_enb_dl_put_pmch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer, uint32_t sf_idx, uint8_t *data_mbms) +bool srslte_enb_dl_gen_cqi_aperiodic(srslte_cell_t* cell, + srslte_dl_cfg_t* dl_cfg, + uint32_t ri, + srslte_cqi_cfg_t* cqi_cfg) { - /* Encode PMCH */ - - int mbsfn_area_id = 1; - if (srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, q->cfi, sf_idx)) { - fprintf(stderr, "Error configuring PMCH\n"); - return SRSLTE_ERROR; - } - /* Encode PMCH */ - if (srslte_pmch_encode(&q->pmch, &q->pmch_cfg, softbuffer, data_mbms, mbsfn_area_id, q->sf_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); - return SRSLTE_ERROR; + bool cqi_enabled = false; + srslte_cqi_report_cfg_t* cqi_report_cfg = &dl_cfg->cqi_report; + + cqi_cfg->type = SRSLTE_CQI_TYPE_SUBBAND_HL; + if (dl_cfg->tm == SRSLTE_TM3 || dl_cfg->tm == SRSLTE_TM4) { + cqi_cfg->ri_present = true; } - - return SRSLTE_SUCCESS; + cqi_cfg->N = (cell->nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell->nof_prb) : 0; + cqi_cfg->four_antenna_ports = (cell->nof_ports == 4); + cqi_cfg->pmi_present = (cqi_report_cfg->pmi_idx != 0); + cqi_cfg->rank_is_not_one = ri > 0; + cqi_cfg->data_enable = true; + + return cqi_enabled; } -void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) +void srslte_enb_dl_save_signal(srslte_enb_dl_t* q) { char tmpstr[64]; - snprintf(tmpstr,64,"output/sf_symbols_%d",tti); - srslte_vec_save_file(tmpstr, q->sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + uint32_t tti = q->dl_sf.tti; - snprintf(tmpstr,64,"output/e_%d",tti); - srslte_bit_unpack_vector(q->pdsch.e[0], q->tmp, q->pdsch_cfg.nbits[0].nof_bits); - srslte_vec_save_file(tmpstr, q->tmp, q->pdsch_cfg.nbits[0].nof_bits*sizeof(uint8_t)); + snprintf(tmpstr, 64, "sf_symbols_%d", tti); + srslte_vec_save_file(tmpstr, q->sf_symbols[0], SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); /* int cb_len = q->pdsch_cfg.cb_segm[0].K1; @@ -537,11 +479,6 @@ void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, srslte_softbuffer_tx_t *softb srslte_vec_save_file(tmpstr, q->tmp, (3*cb_len+12)*sizeof(uint8_t)); }*/ - snprintf(tmpstr,64,"output/data_%d",tti); - srslte_bit_unpack_vector(data, q->tmp, q->pdsch_cfg.grant.mcs[0].tbs); - srslte_vec_save_file(tmpstr, q->tmp, q->pdsch_cfg.grant.mcs[0].tbs*sizeof(uint8_t)); - - //printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, - // q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti); + // printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, + // q->dci.mcs[0].idx, q->dci.mcs[0].tbs, rv_idx, rnti); } - diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 155b67598..210812220 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -26,36 +26,27 @@ #include "srslte/phy/enb/enb_ul.h" +#include "srslte/srslte.h" #include #include #include - #define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) #define CURRENT_SFLEN SRSLTE_SF_LEN(CURRENT_FFTSIZE) #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) - -#define MAX_CANDIDATES 16 +#define CURRENT_SFLEN_RE SRSLTE_NOF_RE(q->cell) int srslte_enb_ul_init(srslte_enb_ul_t *q, cf_t *in_buffer, uint32_t max_prb) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL) - { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { ret = SRSLTE_ERROR; - + bzero(q, sizeof(srslte_enb_ul_t)); - - q->users = calloc(sizeof(srslte_enb_ul_user_t*), (1+SRSLTE_SIRNTI)); - if (!q->users) { - perror("malloc"); - goto clean_exit; - } q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); if (!q->sf_symbols) { @@ -63,43 +54,41 @@ int srslte_enb_ul_init(srslte_enb_ul_t *q, goto clean_exit; } - q->ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->ce) { + q->chest_res.ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); + if (!q->chest_res.ce) { perror("malloc"); goto clean_exit; } if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer, q->sf_symbols, max_prb)) { - fprintf(stderr, "Error initiating FFT\n"); + ERROR("Error initiating FFT\n"); goto clean_exit; } srslte_ofdm_set_normalize(&q->fft, false); srslte_ofdm_set_freq_shift(&q->fft, -0.5); if (srslte_pucch_init_enb(&q->pucch)) { - fprintf(stderr, "Error creating PUCCH object\n"); + ERROR("Error creating PUCCH object\n"); goto clean_exit; } if (srslte_pusch_init_enb(&q->pusch, max_prb)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); goto clean_exit; } - srslte_pucch_set_threshold(&q->pucch, 0.8); - if (srslte_chest_ul_init(&q->chest, max_prb)) { - fprintf(stderr, "Error initiating channel estimator\n"); - goto clean_exit; + ERROR("Error initiating channel estimator\n"); + goto clean_exit; } ret = SRSLTE_SUCCESS; - + } else { - fprintf(stderr, "Invalid parameters\n"); + ERROR("Invalid parameters\n"); } -clean_exit: +clean_exit: if (ret == SRSLTE_ERROR) { srslte_enb_ul_free(q); } @@ -109,148 +98,78 @@ clean_exit: void srslte_enb_ul_free(srslte_enb_ul_t *q) { if (q) { - - if (q->users) { - for (int i=0;i<=SRSLTE_SIRNTI;i++) { - if (q->users[i]) { - free(q->users[i]); - } - } - free(q->users); - } - - srslte_prach_free(&q->prach); + srslte_ofdm_rx_free(&q->fft); srslte_pucch_free(&q->pucch); srslte_pusch_free(&q->pusch); srslte_chest_ul_free(&q->chest); + if (q->sf_symbols) { free(q->sf_symbols); } - if (q->ce) { - free(q->ce); + if (q->chest_res.ce) { + free(q->chest_res.ce); } bzero(q, sizeof(srslte_enb_ul_t)); - } + } } -int srslte_enb_ul_set_cell(srslte_enb_ul_t *q, srslte_cell_t cell, - srslte_prach_cfg_t *prach_cfg, - srslte_refsignal_dmrs_pusch_cfg_t *pusch_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_pucch_cfg_t *pucch_cfg) +int srslte_enb_ul_set_cell(srslte_enb_ul_t* q, srslte_cell_t cell, srslte_refsignal_dmrs_pusch_cfg_t* pusch_cfg) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) - { + if (q != NULL && srslte_cell_isvalid(&cell)) { if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - - if (hopping_cfg) { - memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); - } + q->cell = cell; if (srslte_ofdm_rx_set_prb(&q->fft, q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating FFT\n"); + ERROR("Error initiating FFT\n"); return SRSLTE_ERROR; } if (srslte_pucch_set_cell(&q->pucch, q->cell)) { - fprintf(stderr, "Error creating PUCCH object\n"); + ERROR("Error creating PUCCH object\n"); return SRSLTE_ERROR; } if (srslte_pusch_set_cell(&q->pusch, q->cell)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); return SRSLTE_ERROR; } - if (prach_cfg) { - if (srslte_prach_init_cfg(&q->prach, prach_cfg, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating PRACH\n"); - return SRSLTE_ERROR; - } - srslte_prach_set_detect_factor(&q->prach, 60); - } - if (srslte_chest_ul_set_cell(&q->chest, cell)) { - fprintf(stderr, "Error initiating channel estimator\n"); + ERROR("Error initiating channel estimator\n"); return SRSLTE_ERROR; } - // Configure common PUCCH configuration - srslte_pucch_set_cfg(&q->pucch, pucch_cfg, pusch_cfg->group_hopping_en); - // SRS is a dedicated configuration - srslte_chest_ul_set_cfg(&q->chest, pusch_cfg, pucch_cfg, NULL); + srslte_chest_ul_pregen(&q->chest, pusch_cfg); ret = SRSLTE_SUCCESS; } } else { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + ERROR("Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; } - int srslte_enb_ul_add_rnti(srslte_enb_ul_t *q, uint16_t rnti) { - if (!q->users[rnti]) { - q->users[rnti] = calloc(1, sizeof(srslte_enb_ul_user_t)); - - if (srslte_pucch_set_crnti(&q->pucch, rnti)) { - fprintf(stderr, "Error setting PUCCH rnti\n"); - return -1; - } - if (srslte_pusch_set_rnti(&q->pusch, rnti)) { - fprintf(stderr, "Error setting PUSCH rnti\n"); - return -1; - } - return 0; - } else { - fprintf(stderr, "Error adding rnti=0x%x, already exists\n", rnti); - return -1; + if (srslte_pucch_set_rnti(&q->pucch, rnti)) { + ERROR("Error setting PUCCH rnti\n"); + return -1; } -} - -void srslte_enb_ul_rem_rnti(srslte_enb_ul_t *q, uint16_t rnti) -{ - if (q->users[rnti]) { - free(q->users[rnti]); - q->users[rnti] = NULL; - srslte_pusch_free_rnti(&q->pusch, rnti); + if (srslte_pusch_set_rnti(&q->pusch, rnti)) { + ERROR("Error setting PUSCH rnti\n"); + return -1; } + return 0; } -int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti, - srslte_uci_cfg_t *uci_cfg, - srslte_pucch_sched_t *pucch_sched, - srslte_refsignal_srs_cfg_t *srs_cfg) +void srslte_enb_ul_rem_rnti(srslte_enb_ul_t* q, uint16_t rnti) { - if (q->users[rnti]) { - if (uci_cfg) { - memcpy(&q->users[rnti]->uci_cfg, uci_cfg, sizeof(srslte_uci_cfg_t)); - q->users[rnti]->uci_cfg_en = true; - } else { - q->users[rnti]->uci_cfg_en = false; - } - if (pucch_sched) { - memcpy(&q->users[rnti]->pucch_sched, pucch_sched, sizeof(srslte_pucch_sched_t)); - } - if (srs_cfg) { - memcpy(&q->users[rnti]->srs_cfg, srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - q->users[rnti]->srs_cfg_en = true; - } else { - q->users[rnti]->srs_cfg_en = false; - } - return SRSLTE_SUCCESS; - } else { - fprintf(stderr, "Error configuring UE: rnti=0x%x not found\n", rnti); - return SRSLTE_ERROR; - } + srslte_pucch_free_rnti(&q->pucch, rnti); + srslte_pusch_free_rnti(&q->pusch, rnti); } void srslte_enb_ul_fft(srslte_enb_ul_t *q) @@ -258,158 +177,67 @@ void srslte_enb_ul_fft(srslte_enb_ul_t *q) srslte_ofdm_rx_sf(&q->fft); } -int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, - uint32_t pdcch_n_cce, uint32_t sf_rx, - srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits) +static int get_pucch(srslte_enb_ul_t* q, srslte_ul_sf_cfg_t* ul_sf, srslte_pucch_cfg_t* cfg, srslte_pucch_res_t* res) { - float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); - - srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp); - if (format == SRSLTE_PUCCH_FORMAT_ERROR) { - fprintf(stderr,"Error getting format\n"); - return SRSLTE_ERROR; - } - - uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched); - - if (srslte_chest_ul_estimate_pucch(&q->chest, q->sf_symbols, q->ce, format, n_pucch, sf_rx, &bits[20])) { - fprintf(stderr,"Error estimating PUCCH DMRS\n"); + + srslte_ue_ul_pucch_resource_selection(&q->cell, cfg, &cfg->uci_cfg, NULL); + + // Prepare configuration + if (srslte_chest_ul_estimate_pucch(&q->chest, ul_sf, cfg, q->sf_symbols, &q->chest_res)) { + ERROR("Error estimating PUCCH DMRS\n"); return SRSLTE_ERROR; } - - int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits, nof_bits); + + int ret_val = srslte_pucch_decode(&q->pucch, ul_sf, cfg, &q->chest_res, q->sf_symbols, res); if (ret_val < 0) { - fprintf(stderr,"Error decoding PUCCH\n"); - return SRSLTE_ERROR; + ERROR("Error decoding PUCCH\n"); + return SRSLTE_ERROR; } return ret_val; } -int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti, - uint32_t pdcch_n_cce, uint32_t sf_rx, - srslte_uci_data_t *uci_data) +uint32_t srslte_enb_ul_get_pucch_prb_idx(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns) { - uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; - - if (q->users[rnti]) { - uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len); - int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); - - // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. - // try again to decode ACK only - if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { - uci_data->scheduling_request = false; - ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits); - } - - // update schedulign request - if (uci_data->scheduling_request) { - uci_data->scheduling_request = (ret_val==1); - } - - // Save ACK bits - if (uci_data->uci_ack_len > 0) { - uci_data->uci_ack = pucch_bits[0]; - } + // compute Format and n_pucch + srslte_ue_ul_pucch_resource_selection(cell, cfg, &cfg->uci_cfg, NULL); - if (uci_data->uci_ack_len > 1) { - uci_data->uci_ack_2 = pucch_bits[1]; - } - - // PUCCH2 CQI bits are decoded inside srslte_pucch_decode() - if (uci_data->uci_cqi_len) { - memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); - } + // compute prb_idx + return srslte_pucch_n_prb(cell, cfg, ns); +} - if (uci_data->uci_ri_len) { - uci_data->uci_ri = pucch_bits[0]; /* Assume only one bit of RI */ - } +int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q, + srslte_ul_sf_cfg_t* ul_sf, + srslte_pucch_cfg_t* cfg, + srslte_pucch_res_t* res) +{ - if (uci_data->uci_cqi_len || uci_data->uci_ri_len) { - if (uci_data->uci_ack_len >= 1) { - uci_data->uci_ack = pucch_bits[20]; - } - if (uci_data->uci_ack_len == 2) { - uci_data->uci_ack_2 = pucch_bits[21]; - } - } + if (!srslte_pucch_cfg_isvalid(cfg, q->cell.nof_prb)) { + ERROR("Invalid PUCCH configuration\n"); + return -1; + } - return SRSLTE_SUCCESS; - } else { - fprintf(stderr, "Error getting PUCCH: rnti=0x%x not found\n", rnti); - return SRSLTE_ERROR; + if (get_pucch(q, ul_sf, cfg, res)) { + return -1; } -} -int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer, - uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb, - uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti) -{ - if (q->users[rnti]) { - if (srslte_pusch_cfg(&q->pusch, - &q->pusch_cfg, - grant, - q->users[rnti]->uci_cfg_en?&q->users[rnti]->uci_cfg:NULL, - &q->hopping_cfg, - q->users[rnti]->srs_cfg_en?&q->users[rnti]->srs_cfg:NULL, - tti, rv_idx, current_tx_nb)) { - fprintf(stderr, "Error configuring PDSCH\n"); - return SRSLTE_ERROR; - } - } else { - if (srslte_pusch_cfg(&q->pusch, - &q->pusch_cfg, - grant, - NULL, - &q->hopping_cfg, - NULL, - tti, rv_idx, current_tx_nb)) { - fprintf(stderr, "Error configuring PDSCH\n"); - return SRSLTE_ERROR; + // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. + // try again to decode ACK only + if (cfg->uci_cfg.is_scheduling_request_tti && cfg->uci_cfg.ack.nof_acks && !res->detected) { + cfg->uci_cfg.is_scheduling_request_tti = false; + if (get_pucch(q, ul_sf, cfg, res)) { + return -1; } } - - uint32_t cyclic_shift_for_dmrs = 0; - - srslte_chest_ul_estimate(&q->chest, q->sf_symbols, q->ce, grant->L_prb, tti%10, cyclic_shift_for_dmrs, grant->n_prb); - - float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest); - - return srslte_pusch_decode(&q->pusch, &q->pusch_cfg, - softbuffer, q->sf_symbols, - q->ce, noise_power, - rnti, data, - cqi_value, - uci_data); -} - -int srslte_enb_ul_detect_prach(srslte_enb_ul_t *q, uint32_t tti, - uint32_t freq_offset, cf_t *signal, - uint32_t *indices, float *offsets, float *peak2avg) -{ - uint32_t nof_detected_prach = 0; - // consider the number of subframes the transmission must be anticipated - if (srslte_prach_tti_opportunity(&q->prach, tti, -1)) - { - - if (srslte_prach_detect_offset(&q->prach, - freq_offset, - &signal[q->prach.N_cp], - SRSLTE_SF_LEN_PRB(q->cell.nof_prb), - indices, - offsets, - peak2avg, - &nof_detected_prach)) - { - fprintf(stderr, "Error detecting PRACH\n"); - return SRSLTE_ERROR; - } - } - return (int) nof_detected_prach; + return SRSLTE_SUCCESS; } +int srslte_enb_ul_get_pusch(srslte_enb_ul_t* q, + srslte_ul_sf_cfg_t* ul_sf, + srslte_pusch_cfg_t* cfg, + srslte_pusch_res_t* res) +{ + srslte_chest_ul_estimate_pusch(&q->chest, ul_sf, cfg, q->sf_symbols, &q->chest_res); - - - + return srslte_pusch_decode(&q->pusch, ul_sf, cfg, &q->chest_res, q->sf_symbols, res); +} diff --git a/lib/src/phy/fec/crc.c b/lib/src/phy/fec/crc.c index c97bdd6f9..cb819e62f 100644 --- a/lib/src/phy/fec/crc.c +++ b/lib/src/phy/fec/crc.c @@ -28,8 +28,9 @@ #include #include -#include "srslte/phy/utils/bit.h" #include "srslte/phy/fec/crc.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" void gen_crc_table(srslte_crc_t *h) { @@ -65,7 +66,7 @@ int srslte_crc_set_init(srslte_crc_t *crc_par, uint64_t crc_init_value) { crc_par->crcinit = crc_init_value; if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) { - printf("ERROR, invalid crcinit in crc_set_init().\n"); + printf("ERROR(invalid crcinit in crc_set_init().\n"); return -1; } return 0; @@ -84,13 +85,12 @@ int srslte_crc_init(srslte_crc_t *h, uint32_t crc_poly, int crc_order) { // check parameters if (h->order % 8 != 0) { - fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n", - h->order); + ERROR("ERROR(invalid order=%d, it must be 8, 16, 24 or 32.\n", h->order); return -1; } if (srslte_crc_set_init(h, h->crcinit)) { - fprintf(stderr, "Error setting CRC init word\n"); + ERROR("Error setting CRC init word\n"); return -1; } diff --git a/lib/src/phy/fec/rm_conv.c b/lib/src/phy/fec/rm_conv.c index 9c02d97e3..af24fc03d 100644 --- a/lib/src/phy/fec/rm_conv.c +++ b/lib/src/phy/fec/rm_conv.c @@ -29,6 +29,7 @@ #include #include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/utils/debug.h" #define NCOLS 32 #define NROWS_MAX NCOLS @@ -54,8 +55,7 @@ int srslte_rm_conv_tx(uint8_t *input, uint32_t in_len, uint8_t *output, uint32_t nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { - fprintf(stderr, "Input too large. Max input length is %d\n", - 3 * NCOLS * NROWS_MAX); + ERROR("Input too large. Max input length is %d\n", 3 * NCOLS * NROWS_MAX); return -1; } K_p = nrows * NCOLS; @@ -106,8 +106,7 @@ int srslte_rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { - fprintf(stderr, "Output too large. Max output length is %d\n", - 3 * NCOLS * NROWS_MAX); + ERROR("Output too large. Max output length is %d\n", 3 * NCOLS * NROWS_MAX); return -1; } K_p = nrows * NCOLS; @@ -173,8 +172,7 @@ int srslte_rm_conv_rx_s(int16_t *input, uint32_t in_len, int16_t *output, uint32 nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { - fprintf(stderr, "Output too large. Max output length is %d\n", - 3 * NCOLS * NROWS_MAX); + ERROR("Output too large. Max output length is %d\n", 3 * NCOLS * NROWS_MAX); return -1; } K_p = nrows * NCOLS; diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index 0e83cda5b..5b1a6a897 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -31,10 +31,11 @@ #include #include +#include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/rm_turbo.h" #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" -#include "srslte/phy/fec/cbsegm.h" #ifdef DEBUG_MODE #warning FIXME: Disabling SSE/AVX turbo rate matching @@ -83,7 +84,7 @@ int deinter_table_idx_from_sb_len(uint32_t nof_subblocks) { } } if (nof_subblocks != 0) { - fprintf(stderr, "Error number of sub-blocks %d not supported in RM\n", nof_subblocks); + ERROR("Error number of sub-blocks %d not supported in RM\n", nof_subblocks); } return -1; } @@ -402,7 +403,7 @@ int srslte_rm_turbo_rx_lut_(int16_t *input, int16_t *output, uint32_t in_len, ui } else if (idx < NOF_DEINTER_TABLE_SB_IDX) { deinter = deinterleaver_sb[idx][cb_idx][rv_idx]; } else { - fprintf(stderr, "Sub-block size index %d not supported in srslte_rm_turbo_rx_lut()\n", idx); + ERROR("Sub-block size index %d not supported in srslte_rm_turbo_rx_lut()\n", idx); return -1; } #else @@ -442,7 +443,7 @@ int srslte_rm_turbo_rx_lut_8bit(int8_t *input, int8_t *output, uint32_t in_len, } else if (idx < NOF_DEINTER_TABLE_SB_IDX) { deinter = deinterleaver_sb[idx][cb_idx][rv_idx]; } else { - fprintf(stderr, "Sub-block size index %d not supported in srslte_rm_turbo_rx_lut()\n", idx); + ERROR("Sub-block size index %d not supported in srslte_rm_turbo_rx_lut()\n", idx); return -1; } #else @@ -1019,14 +1020,15 @@ int srslte_rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_ nrows = (uint16_t) (out_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; if (3 * K_p > w_buff_len) { - fprintf(stderr, - "Output too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n", - w_buff_len, nrows, out_len); + ERROR("Output too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n", + w_buff_len, + nrows, + out_len); return -1; } - + if (out_len < 3) { - fprintf(stderr, "Error minimum input length for rate matching is 3\n"); + ERROR("Error minimum input length for rate matching is 3\n"); return -1; } diff --git a/lib/src/phy/fec/tc_interl_lte.c b/lib/src/phy/fec/tc_interl_lte.c index 1b54b61eb..63a49f7e9 100644 --- a/lib/src/phy/fec/tc_interl_lte.c +++ b/lib/src/phy/fec/tc_interl_lte.c @@ -80,14 +80,13 @@ int srslte_tc_interl_LTE_gen_interl(srslte_tc_interl_t *h, uint32_t long_cb, uin uint64_t i, j; if (long_cb > h->max_long_cb) { - fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n", - h->max_long_cb); + ERROR("Interleaver initiated for max_long_cb=%d\n", h->max_long_cb); return -1; } cb_table_idx = srslte_cbsegm_cbindex(long_cb); if (cb_table_idx == -1) { - fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb); + ERROR("Can't find long_cb=%d in valid TC CB table\n", long_cb); return -1; } diff --git a/lib/src/phy/fec/tc_interl_umts.c b/lib/src/phy/fec/tc_interl_umts.c index 261b4d7d3..78014824b 100644 --- a/lib/src/phy/fec/tc_interl_umts.c +++ b/lib/src/phy/fec/tc_interl_umts.c @@ -30,6 +30,7 @@ #include #include "srslte/phy/fec/tc_interl.h" +#include "srslte/phy/utils/debug.h" #define TURBO_SRSLTE_TCOD_RATE 3 @@ -97,8 +98,7 @@ int srslte_tc_interl_UMTS_gen(srslte_tc_interl_t *h, uint32_t long_cb) { M_long = long_cb; if (long_cb > h->max_long_cb) { - fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n", - h->max_long_cb); + ERROR("Interleaver initiated for max_long_cb=%d\n", h->max_long_cb); return -1; } diff --git a/lib/src/phy/fec/test/crc_test.c b/lib/src/phy/fec/test/crc_test.c index 2d1577fd8..9d603ba95 100644 --- a/lib/src/phy/fec/test/crc_test.c +++ b/lib/src/phy/fec/test/crc_test.c @@ -107,7 +107,7 @@ int main(int argc, char **argv) { // check if generated word is as expected if (get_expected_word(num_bits, crc_length, crc_poly, seed, &expected_word)) { - fprintf(stderr, "Test parameters not defined in test_results.h\n"); + ERROR("Test parameters not defined in test_results.h\n"); exit(-1); } exit(expected_word != crc_word); diff --git a/lib/src/phy/fec/test/rm_turbo_rx_mex.c b/lib/src/phy/fec/test/rm_turbo_rx_mex.c deleted file mode 100644 index 3d5597e50..000000000 --- a/lib/src/phy/fec/test/rm_turbo_rx_mex.c +++ /dev/null @@ -1,99 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define INPUT prhs[0] -#define TRBLKLEN prhs[1] -#define RV prhs[2] -#define NOF_INPUTS 3 - - -void help() -{ - mexErrMsgTxt - ("[out] = srslte_rm_turbo_rx(in, trblkin, rv)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - float *input; - float *output; - uint32_t in_len, trblklen, cblen, rvidx; - float *w_buff_f; - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - - // Read input symbols - in_len = mexutils_read_f(INPUT, &input); - if (in_len < 0) { - mexErrMsgTxt("Error reading input bits\n"); - return; - } - - trblklen = (uint32_t) mxGetScalar(TRBLKLEN); - rvidx = (uint32_t) mxGetScalar(RV); - - srslte_cbsegm_t cbsegm; - srslte_cbsegm(&cbsegm, trblklen); - cblen = 3*cbsegm.K1+12; - - w_buff_f = calloc(1,sizeof(float) * cblen * 10); - if (!w_buff_f) { - perror("malloc"); - exit(-1); - } - - // allocate memory for output bits - output = srslte_vec_malloc(cblen * sizeof(float)); - - srslte_rm_turbo_rx(w_buff_f, cblen * 10, input, in_len, output, cblen, - rvidx,cbsegm.F); - - if (nlhs >= 1) { - mexutils_write_f(output, &plhs[0], cblen, 1); - } - if (nlhs >= 2) { - mexutils_write_f(input, &plhs[1], in_len, 1); - } - - free(input); - free(output); - free(w_buff_f); - - return; -} - diff --git a/lib/src/phy/fec/test/turbodecoder_test.c b/lib/src/phy/fec/test/turbodecoder_test.c index e80512518..217d61795 100644 --- a/lib/src/phy/fec/test/turbodecoder_test.c +++ b/lib/src/phy/fec/test/turbodecoder_test.c @@ -193,7 +193,7 @@ int main(int argc, char **argv) { } if (srslte_tcod_init(&tcod, frame_length)) { - fprintf(stderr, "Error initiating Turbo coder\n"); + ERROR("Error initiating Turbo coder\n"); exit(-1); } @@ -203,7 +203,7 @@ int main(int argc, char **argv) { // tdec_type = SRSLTE_TDEC_SSE_WINDOW; #endif if (srslte_tdec_init_manual(&tdec, frame_length, tdec_type)) { - fprintf(stderr, "Error initiating Turbo decoder\n"); + ERROR("Error initiating Turbo decoder\n"); exit(-1); } diff --git a/lib/src/phy/fec/test/turbodecoder_test_mex.c b/lib/src/phy/fec/test/turbodecoder_test_mex.c deleted file mode 100644 index f52e122e2..000000000 --- a/lib/src/phy/fec/test/turbodecoder_test_mex.c +++ /dev/null @@ -1,106 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define INPUT prhs[0] -#define NITERS prhs[1] -#define NOF_INPUTS 1 - - -void help() -{ - mexErrMsgTxt - ("[decoded_bits] = srslte_turbodecoder(input_llr, nof_iterations)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - srslte_tdec_gen_t tdec; - float *input_llr; - uint8_t *output_data; - uint32_t nof_bits; - uint32_t nof_iterations; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - // Read input symbols - uint32_t nof_symbols = mexutils_read_f(INPUT, &input_llr); - if (nof_symbols < 40) { - mexErrMsgTxt("Minimum block size is 40\n"); - return; - } - nof_bits = (nof_symbols-12)/3; - - if (!srslte_cbsegm_cbsize_isvalid(nof_bits)) { - mexErrMsgTxt("Invalid codeblock size\n"); - return; - } - - - // read number of iterations - if (nrhs > NOF_INPUTS) { - nof_iterations = (uint32_t) mxGetScalar(prhs[1]); - if (nof_iterations > 50) { - mexErrMsgTxt("Maximum number of iterations is 50\n"); - return; - } - } else { - nof_iterations = 5; // set the default nof iterations to 5 as in matlab - } - - // allocate memory for output bits - output_data = srslte_vec_malloc(nof_bits * sizeof(uint8_t)); - - if (srslte_tdec_gen_init(&tdec, nof_bits)) { - mexErrMsgTxt("Error initiating Turbo decoder\n"); - return; - } - - srslte_tdec_gen_run_all(&tdec, input_llr, output_data, nof_iterations, nof_bits); - - if (nlhs >= 1) { - mexutils_write_uint8(output_data, &plhs[0], nof_bits, 1); - } - - srslte_tdec_gen_free(&tdec); - - free(input_llr); - free(output_data); - - return; -} - diff --git a/lib/src/phy/fec/test/viterbi_test.c b/lib/src/phy/fec/test/viterbi_test.c index 8899f45de..6124d89fd 100644 --- a/lib/src/phy/fec/test/viterbi_test.c +++ b/lib/src/phy/fec/test/viterbi_test.c @@ -285,7 +285,7 @@ int main(int argc, char **argv) { if (snr_points == 1) { int expected_errors = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db); if (expected_errors == -1) { - fprintf(stderr, "Test parameters not defined in test_results.h\n"); + ERROR("Test parameters not defined in test_results.h\n"); exit(-1); } else { printf("errors =%d, expected =%d\n", errors, expected_errors); diff --git a/lib/src/phy/fec/test/viterbi_test_mex.c b/lib/src/phy/fec/test/viterbi_test_mex.c deleted file mode 100644 index 9d1862ae5..000000000 --- a/lib/src/phy/fec/test/viterbi_test_mex.c +++ /dev/null @@ -1,89 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define INPUT prhs[0] -#define NOF_INPUTS 1 - - -void help() -{ - mexErrMsgTxt - ("[decoded_bits] = srslte_viterbi(input_llr, type)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - srslte_viterbi_t viterbi; - float *input_llr; - uint8_t *output_data; - int nof_bits; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - // Read input symbols - nof_bits = mexutils_read_f(INPUT, &input_llr); - - output_data = srslte_vec_malloc(nof_bits * sizeof(uint8_t)); - - int poly[3] = { 0x6D, 0x4F, 0x57 }; - if (srslte_viterbi_init(&viterbi, SRSLTE_VITERBI_37, poly, nof_bits/3, true)) { - return; - } - - if (nrhs >= 2) { - float gain_quant = mxGetScalar(prhs[1]); - srslte_viterbi_set_gain_quant(&viterbi, gain_quant); - } - - srslte_viterbi_decode_f(&viterbi, input_llr, output_data, nof_bits/3); - - if (nlhs >= 1) { - mexutils_write_uint8(output_data, &plhs[0], nof_bits/3, 1); - } - if (nlhs >= 2) { - mexutils_write_uint8(viterbi.symbols_uc, &plhs[1], nof_bits/3, 1); - } - - srslte_viterbi_free(&viterbi); - - free(input_llr); - free(output_data); - - return; -} - diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index 0ede6b305..734fe8c84 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -29,11 +29,11 @@ #include #include #include -#include #include "srslte/phy/fec/cbsegm.h" #include "srslte/phy/fec/turbocoder.h" #include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" #define NOF_REGS 3 @@ -89,14 +89,13 @@ int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32 uint16_t *per; if (long_cb > h->max_long_cb) { - fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", - h->max_long_cb); + ERROR("Turbo coder initiated for max_long_cb=%d\n", h->max_long_cb); return -1; } int longcb_idx = srslte_cbsegm_cbindex(long_cb); if (longcb_idx < 0) { - fprintf(stderr, "Invalid CB size %d\n", long_cb); + ERROR("Invalid CB size %d\n", long_cb); return -1; } @@ -205,8 +204,8 @@ int srslte_tcod_encode_lut(srslte_tcod_t *h, uint32_t long_cb = (uint32_t) srslte_cbsegm_cbsize(cblen_idx); if (long_cb % 8) { - fprintf(stderr, "Turbo coder LUT implementation long_cb must be multiple of 8\n"); - return -1; + ERROR("Turbo coder LUT implementation long_cb must be multiple of 8\n"); + return -1; } /* Reset CRC */ @@ -381,14 +380,14 @@ void srslte_tcod_gentable() { srslte_tc_interl_t interl; if (srslte_tc_interl_init(&interl, 6144)) { - fprintf(stderr, "Error initiating interleave\n"); + ERROR("Error initiating interleave\n"); return; } for (uint32_t len=0;len<188;len++) { uint32_t long_cb = srslte_cbsegm_cbsize(len); if (srslte_tc_interl_LTE_gen(&interl, long_cb)) { - fprintf(stderr, "Error initiating TC interleaver for long_cb=%d\n", long_cb); + ERROR("Error initiating TC interleaver for long_cb=%d\n", long_cb); return; } // Save fw/bw permutation tables diff --git a/lib/src/phy/fec/turbodecoder.c b/lib/src/phy/fec/turbodecoder.c index 613b36889..2782f4992 100644 --- a/lib/src/phy/fec/turbodecoder.c +++ b/lib/src/phy/fec/turbodecoder.c @@ -28,10 +28,10 @@ #include #include #include -#include -#include "srslte/phy/utils/vector.h" #include "srslte/phy/fec/turbodecoder.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" #define debug_enabled 0 @@ -193,18 +193,18 @@ int srslte_tdec_init_manual(srslte_tdec_t * h, uint32_t max_long_cb, srslte_tdec h->dec8[0] = &sse8_win_impl; h->current_llr_type = SRSLTE_TDEC_8; break; -#endif +#endif /* LV_HAVE_SSE */ #ifdef HAVE_NEON case SRSLTE_TDEC_NEON_WINDOW: h->dec16[0] = &arm16_win_impl; h->current_llr_type = SRSLTE_TDEC_16; break; -#else +#else /* HAVE_NEON */ case SRSLTE_TDEC_GENERIC: h->dec16[0] = &gen_impl; h->current_llr_type = SRSLTE_TDEC_16; break; -#endif +#endif /* HAVE_NEON */ #ifdef LV_HAVE_AVX2 case SRSLTE_TDEC_AVX_WINDOW: h->dec16[0] = &avx16_win_impl; @@ -214,9 +214,9 @@ int srslte_tdec_init_manual(srslte_tdec_t * h, uint32_t max_long_cb, srslte_tdec h->dec8[0] = &avx8_win_impl; h->current_llr_type = SRSLTE_TDEC_8; break; -#endif +#endif /* LV_HAVE_AVX2 */ default: - fprintf(stderr, "Error decoder %d not supported\n", dec_type); + ERROR("Error decoder %d not supported\n", dec_type); goto clean_and_exit; } @@ -274,12 +274,12 @@ int srslte_tdec_init_manual(srslte_tdec_t * h, uint32_t max_long_cb, srslte_tdec #ifdef LV_HAVE_AVX2 h->dec16[AUTO_16_AVXWIN] = &avx16_win_impl; h->dec8[AUTO_8_AVXWIN] = &avx8_win_impl; -#endif -#else +#endif /* LV_HAVE_AVX2 */ +#else /* HAVE_NEON | LV_HAVE_SSE */ h->dec16[AUTO_16_SSE] = &gen_impl; h->dec16[AUTO_16_SSEWIN] = &gen_impl; -#endif /* HAVE_NEON */ - +#endif /* HAVE_NEON | LV_HAVE_SSE */ + for (int td=0;tddec16[td]) { if ((h->nof_blocks16[td] = h->dec16[td]->tdec_init(&h->dec16_hdlr[td], h->max_long_cb))<0) { @@ -420,7 +420,7 @@ static int tdec_sb_idx(uint32_t long_cb) { case 0: return AUTO_16_SSE; } - fprintf(stderr, "Error in tdec_sb_idx() invalid nof_sb=%d\n", nof_sb); + ERROR("Error in tdec_sb_idx() invalid nof_sb=%d\n", nof_sb); return 0; } @@ -452,7 +452,7 @@ static int tdec_sb_idx_8(uint32_t long_cb) { case 0: return 10+AUTO_16_SSE; } - fprintf(stderr, "Error in tdec_sb_idx_8() invalid nof_sb=%d\n", nof_sb); + ERROR("Error in tdec_sb_idx_8() invalid nof_sb=%d\n", nof_sb); return 0; } @@ -527,8 +527,7 @@ static void tdec_iteration_16(srslte_tdec_t * h, int16_t * input) int srslte_tdec_new_cb(srslte_tdec_t * h, uint32_t long_cb) { if (long_cb > h->max_long_cb) { - fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", - h->max_long_cb); + ERROR("TDEC was initialized for max_long_cb=%d\n", h->max_long_cb); return -1; } @@ -536,7 +535,7 @@ int srslte_tdec_new_cb(srslte_tdec_t * h, uint32_t long_cb) h->current_long_cb = long_cb; h->current_cbidx = srslte_cbsegm_cbindex(long_cb); if (h->current_cbidx < 0) { - fprintf(stderr, "Invalid CB length %d\n", long_cb); + ERROR("Invalid CB length %d\n", long_cb); return -1; } return 0; diff --git a/lib/src/phy/fec/turbodecoder_sse.c b/lib/src/phy/fec/turbodecoder_sse.c index e5724af45..773ce1144 100644 --- a/lib/src/phy/fec/turbodecoder_sse.c +++ b/lib/src/phy/fec/turbodecoder_sse.c @@ -38,7 +38,6 @@ #ifdef LV_HAVE_SSE #include -#include #endif diff --git a/lib/src/phy/fec/viterbi.c b/lib/src/phy/fec/viterbi.c index 15ed5574f..c15add0a0 100644 --- a/lib/src/phy/fec/viterbi.c +++ b/lib/src/phy/fec/viterbi.c @@ -31,9 +31,10 @@ #include #include -#include "srslte/phy/utils/vector.h" -#include "srslte/phy/fec/viterbi.h" #include "parity.h" +#include "srslte/phy/fec/viterbi.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #include "viterbi37.h" #define DEB 0 @@ -228,8 +229,7 @@ int decode37_neon(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_lengt uint32_t best_state; if (frame_length > q->framebits) { - fprintf(stderr, "Initialized decoder for max frame length %d bits\n", - q->framebits); + ERROR("Initialized decoder for max frame length %d bits\n", q->framebits); return -1; } @@ -304,7 +304,7 @@ int init37(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_bitin } if ((q->ptr = create_viterbi37_port(poly, TB_ITER*framebits)) == NULL) { - fprintf(stderr, "create_viterbi37 failed\n"); + ERROR("create_viterbi37 failed\n"); free37(q); return -1; } else { @@ -340,7 +340,7 @@ int init37_sse(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_b } if ((q->ptr = create_viterbi37_sse(poly, TB_ITER*framebits)) == NULL) { - fprintf(stderr, "create_viterbi37 failed\n"); + ERROR("create_viterbi37 failed\n"); free37(q); return -1; } else { @@ -377,7 +377,7 @@ int init37_neon(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_ } if ((q->ptr = create_viterbi37_neon(poly, TB_ITER*framebits)) == NULL) { - fprintf(stderr, "create_viterbi37 failed\n"); + ERROR("create_viterbi37 failed\n"); free37(q); return -1; } else { @@ -415,7 +415,7 @@ int init37_avx2(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool tail_ } if ((q->ptr = create_viterbi37_avx2(poly, TB_ITER*framebits)) == NULL) { - fprintf(stderr, "create_viterbi37 failed\n"); + ERROR("create_viterbi37 failed\n"); free37(q); return -1; } else { @@ -452,7 +452,7 @@ int init37_avx2_16bit(srslte_viterbi_t *q, int poly[3], uint32_t framebits, bool } //printf("pt0\n"); if ((q->ptr = create_viterbi37_avx2_16bit(poly, TB_ITER*framebits)) == NULL) { - fprintf(stderr, "create_viterbi37 failed\n"); + ERROR("create_viterbi37 failed\n"); free37(q); return -1; } else { @@ -493,7 +493,7 @@ int srslte_viterbi_init(srslte_viterbi_t *q, srslte_viterbi_type_t type, int pol #endif #endif default: - fprintf(stderr, "Decoder not implemented\n"); + ERROR("Decoder not implemented\n"); return -1; } } @@ -524,8 +524,7 @@ int srslte_viterbi_decode_f(srslte_viterbi_t *q, float *symbols, uint8_t *data, { uint32_t len; if (frame_length > q->framebits) { - fprintf(stderr, "Initialized decoder for max frame length %d bits\n", - q->framebits); + ERROR("Initialized decoder for max frame length %d bits\n", q->framebits); return -1; } if (q->tail_biting) { @@ -558,8 +557,7 @@ int srslte_viterbi_decode_s(srslte_viterbi_t *q, int16_t *symbols, uint8_t *data { uint32_t len; if (frame_length > q->framebits) { - fprintf(stderr, "Initialized decoder for max frame length %d bits\n", - q->framebits); + ERROR("Initialized decoder for max frame length %d bits\n", q->framebits); return -1; } if (q->tail_biting) { diff --git a/lib/src/phy/io/filesource.c b/lib/src/phy/io/filesource.c index 1324bf2b0..c3f7b819a 100644 --- a/lib/src/phy/io/filesource.c +++ b/lib/src/phy/io/filesource.c @@ -30,6 +30,7 @@ #include #include "srslte/phy/io/filesource.h" +#include "srslte/phy/utils/debug.h" int srslte_filesource_init(srslte_filesource_t *q, char *filename, srslte_datatype_t type) { bzero(q, sizeof(srslte_filesource_t)); @@ -128,7 +129,7 @@ int srslte_filesource_read_multi(srslte_filesource_t *q, void **buffer, int nsam case SRSLTE_COMPLEX_SHORT: case SRSLTE_FLOAT_BIN: case SRSLTE_COMPLEX_SHORT_BIN: - fprintf(stderr, "%s.%d:Read Mode not implemented\n", __FILE__, __LINE__); + ERROR("%s.%d:Read Mode not implemented\n", __FILE__, __LINE__); count = SRSLTE_ERROR; break; case SRSLTE_COMPLEX_FLOAT_BIN: diff --git a/lib/src/phy/mimo/layermap.c b/lib/src/phy/mimo/layermap.c index 6de30fca7..d707d3573 100644 --- a/lib/src/phy/mimo/layermap.c +++ b/lib/src/phy/mimo/layermap.c @@ -28,12 +28,11 @@ #include #include #include -#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/mimo/layermap.h" - - +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" int srslte_layermap_single(cf_t *d, cf_t *x, int nof_symbols) { memcpy(x, d, sizeof(cf_t) * nof_symbols); @@ -70,8 +69,7 @@ int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_ return nof_symbols[0] / n[0]; } else { - fprintf(stderr, "Number of symbols in codewords 0 and 1 is not consistent (%d, %d)\n", - nof_symbols[0], nof_symbols[1]); + ERROR("Number of symbols in codewords 0 and 1 is not consistent (%d, %d)\n", nof_symbols[0], nof_symbols[1]); return -1; } } @@ -82,48 +80,53 @@ int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_ * Based on 36.211 6.3.3 * Returns the number of symbols per layer (M_symb^layer in the specs) */ -int srslte_layermap_type(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_cw, int nof_layers, - int nof_symbols[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t type) { +int srslte_layermap_type(cf_t* d[SRSLTE_MAX_CODEWORDS], + cf_t* x[SRSLTE_MAX_LAYERS], + int nof_cw, + int nof_layers, + int nof_symbols[SRSLTE_MAX_CODEWORDS], + srslte_tx_scheme_t type) +{ if (nof_cw > SRSLTE_MAX_CODEWORDS) { - fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", SRSLTE_MAX_CODEWORDS, nof_cw); + ERROR("Maximum number of codewords is %d (nof_cw=%d)\n", SRSLTE_MAX_CODEWORDS, nof_cw); return -1; } if (nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", SRSLTE_MAX_LAYERS, nof_layers); + ERROR("Maximum number of layers is %d (nof_layers=%d)\n", SRSLTE_MAX_LAYERS, nof_layers); return -1; } if (nof_layers < nof_cw) { - fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n"); + ERROR("Number of codewords must be lower or equal than number of layers\n"); return -1; } switch(type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_cw == 1 && nof_layers == 1) { - return srslte_layermap_single(x[0], d[0], nof_symbols[0]); - } else { - fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_cw == 1) { - if (nof_layers == 2 || nof_layers == 4) { - return srslte_layermap_diversity(d[0], x, nof_layers, nof_symbols[0]); + case SRSLTE_TXSCHEME_PORT0: + if (nof_cw == 1 && nof_layers == 1) { + return srslte_layermap_single(x[0], d[0], nof_symbols[0]); } else { - fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n"); + ERROR("Number of codewords and layers must be 1 for transmission on single antenna ports\n"); return -1; } - } else { - fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - case SRSLTE_MIMO_TYPE_CDD: - return srslte_layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols); - break; + break; + case SRSLTE_TXSCHEME_DIVERSITY: + if (nof_cw == 1) { + if (nof_layers == 2 || nof_layers == 4) { + return srslte_layermap_diversity(d[0], x, nof_layers, nof_symbols[0]); + } else { + ERROR("Number of layers must be 2 or 4 for transmit diversity\n"); + return -1; + } + } else { + ERROR("Number of codewords must be 1 for transmit diversity\n"); + return -1; + } + break; + case SRSLTE_TXSCHEME_SPATIALMUX: + case SRSLTE_TXSCHEME_CDD: + return srslte_layermap_multiplex(d, x, nof_cw, nof_layers, nof_symbols); + break; } return 0; } @@ -172,50 +175,56 @@ int srslte_layerdemap_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *d[SRSLTE_MAX_C * Returns 0 on ok and saves the number of symbols per codeword (M_symb^(q) in the specs) in * nof_symbols. Returns -1 on error */ -int srslte_layerdemap_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *d[SRSLTE_MAX_CODEWORDS], int nof_layers, int nof_cw, - int nof_layer_symbols, int nof_symbols[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t type) { +int srslte_layerdemap_type(cf_t* x[SRSLTE_MAX_LAYERS], + cf_t* d[SRSLTE_MAX_CODEWORDS], + int nof_layers, + int nof_cw, + int nof_layer_symbols, + int nof_symbols[SRSLTE_MAX_CODEWORDS], + srslte_tx_scheme_t type) +{ if (nof_cw > SRSLTE_MAX_CODEWORDS) { - fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", SRSLTE_MAX_CODEWORDS, nof_cw); + ERROR("Maximum number of codewords is %d (nof_cw=%d)\n", SRSLTE_MAX_CODEWORDS, nof_cw); return -1; } if (nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", SRSLTE_MAX_LAYERS, nof_layers); + ERROR("Maximum number of layers is %d (nof_layers=%d)\n", SRSLTE_MAX_LAYERS, nof_layers); return -1; } if (nof_layers < nof_cw) { - fprintf(stderr, "Number of codewords must be lower or equal than number of layers\n"); + ERROR("Number of codewords must be lower or equal than number of layers\n"); return -1; } switch(type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_cw == 1 && nof_layers == 1) { - nof_symbols[0] = srslte_layerdemap_single(x[0], d[0], nof_layer_symbols); - nof_symbols[1] = 0; - } else { - fprintf(stderr, "Number of codewords and layers must be 1 for transmission on single antenna ports\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_cw == 1) { - if (nof_layers == 2 || nof_layers == 4) { - nof_symbols[0] = srslte_layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols); + case SRSLTE_TXSCHEME_PORT0: + if (nof_cw == 1 && nof_layers == 1) { + nof_symbols[0] = srslte_layerdemap_single(x[0], d[0], nof_layer_symbols); nof_symbols[1] = 0; } else { - fprintf(stderr, "Number of layers must be 2 or 4 for transmit diversity\n"); + ERROR("Number of codewords and layers must be 1 for transmission on single antenna ports\n"); return -1; } - } else { - fprintf(stderr, "Number of codewords must be 1 for transmit diversity\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - case SRSLTE_MIMO_TYPE_CDD: - return srslte_layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols); - break; + break; + case SRSLTE_TXSCHEME_DIVERSITY: + if (nof_cw == 1) { + if (nof_layers == 2 || nof_layers == 4) { + nof_symbols[0] = srslte_layerdemap_diversity(x, d[0], nof_layers, nof_layer_symbols); + nof_symbols[1] = 0; + } else { + ERROR("Number of layers must be 2 or 4 for transmit diversity\n"); + return -1; + } + } else { + ERROR("Number of codewords must be 1 for transmit diversity\n"); + return -1; + } + break; + case SRSLTE_TXSCHEME_SPATIALMUX: + case SRSLTE_TXSCHEME_CDD: + return srslte_layerdemap_multiplex(x, d, nof_layers, nof_cw, nof_layer_symbols, nof_symbols); + break; } return 0; } diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index dbf34ab90..da385b401 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -422,7 +422,7 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_ } return i; } else { - fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + ERROR("Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); return -1; } } @@ -662,7 +662,7 @@ int srslte_predecoding_diversity_csi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_M } return i; } else { - fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + ERROR("Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); return -1; } } @@ -706,8 +706,8 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t Gx[1][0] = conjf(G[0][1]); Gx[1][1] = conjf(G[1][1]); } else { - // MMSE equalizer: Gx = (G'G+I) - fprintf(stderr, "MMSE MIMO decoder not implemented\n"); + // MMSE equalizer: Gx = (G'G+I) + ERROR("MMSE MIMO decoder not implemented\n"); return -1; } @@ -909,13 +909,13 @@ static int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], return srslte_predecoding_ccd_2x2_zf(y, h, x, nof_symbols, scaling); } } else { - DEBUG("Error predecoding CCD: Invalid number of layers %d\n", nof_layers); + ERROR("Error predecoding CCD: Invalid number of layers %d\n", nof_layers); return -1; } } else if (nof_ports == 4) { - DEBUG("Error predecoding CCD: Only 2 ports supported\n"); + ERROR("Error predecoding CCD: Only 2 ports supported\n"); } else { - DEBUG("Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); + ERROR("Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } @@ -1107,13 +1107,13 @@ int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], return srslte_predecoding_ccd_2x2_mmse(y, h, x, nof_symbols, scaling, noise_estimate); } } else { - DEBUG("Error predecoding CCD: Invalid number of layers %d\n", nof_layers); + ERROR("Error predecoding CCD: Invalid number of layers %d\n", nof_layers); return -1; } } else if (nof_ports == 4) { - DEBUG("Error predecoding CCD: Only 2 ports supported\n"); + ERROR("Error predecoding CCD: Only 2 ports supported\n"); } else { - DEBUG("Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); + ERROR("Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } @@ -1137,7 +1137,7 @@ static int srslte_predecoding_multiplex_2x2_zf_csi(cf_t *y[SRSLTE_MAX_PORTS], norm = 2.0f / scaling; break; default: - DEBUG("Wrong codebook_idx=%d", codebook_idx); + ERROR("Wrong codebook_idx=%d", codebook_idx); return SRSLTE_ERROR; } @@ -1169,7 +1169,7 @@ static int srslte_predecoding_multiplex_2x2_zf_csi(cf_t *y[SRSLTE_MAX_PORTS], h11 = srslte_simd_cf_sub(h01i, srslte_simd_cf_mulj(h11i)); break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1211,7 +1211,7 @@ static int srslte_predecoding_multiplex_2x2_zf_csi(cf_t *y[SRSLTE_MAX_PORTS], h11 = h[0][1][i] - _Complex_I * h[1][1][i]; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1278,7 +1278,7 @@ static int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], h11 = srslte_simd_cf_sub(h01i, srslte_simd_cf_mulj(h11i)); break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1318,7 +1318,7 @@ static int srslte_predecoding_multiplex_2x2_zf(cf_t *y[SRSLTE_MAX_PORTS], h11 = h[0][1][i] - _Complex_I * h[1][1][i]; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1380,7 +1380,7 @@ static int srslte_predecoding_multiplex_2x2_mmse_csi(cf_t *y[SRSLTE_MAX_PORTS], h11 = srslte_simd_cf_sub(h01i, srslte_simd_cf_mulj(h11i)); break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1422,7 +1422,7 @@ static int srslte_predecoding_multiplex_2x2_mmse_csi(cf_t *y[SRSLTE_MAX_PORTS], h11 = h[0][1][i] - _Complex_I * h[1][1][i]; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1493,7 +1493,7 @@ static int srslte_predecoding_multiplex_2x2_mmse(cf_t *y[SRSLTE_MAX_PORTS], h11 = srslte_simd_cf_sub(h01i, srslte_simd_cf_mulj(h11i)); break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1532,7 +1532,7 @@ static int srslte_predecoding_multiplex_2x2_mmse(cf_t *y[SRSLTE_MAX_PORTS], h11 = h[0][1][i] - _Complex_I*h[1][1][i]; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1579,7 +1579,7 @@ static int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], hx = srslte_simd_cf_sub(h0xi, srslte_simd_cf_mulj(h1xi)); break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1614,7 +1614,7 @@ static int srslte_predecoding_multiplex_2x1_mrc(cf_t *y[SRSLTE_MAX_PORTS], h1 = h[0][1][i] - _Complex_I * h[1][1][i]; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1663,7 +1663,7 @@ static int srslte_predecoding_multiplex_2x1_mrc_csi(cf_t *y[SRSLTE_MAX_PORTS], hx = srslte_simd_cf_sub(h0xi, srslte_simd_cf_mulj(h1xi)); break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1699,7 +1699,7 @@ static int srslte_predecoding_multiplex_2x1_mrc_csi(cf_t *y[SRSLTE_MAX_PORTS], h1 = h[0][1][i] - _Complex_I * h[1][1][i]; break; default: - fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); + ERROR("Wrong codebook_idx=%d\n", codebook_idx); return SRSLTE_ERROR; } @@ -1756,9 +1756,9 @@ static int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], } } } else if (nof_ports == 4) { - DEBUG("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports); + ERROR("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports); } else { - DEBUG("Error predecoding multiplex: Invalid combination of ports %d and rx antennas %d\n", nof_ports, nof_rxant); + ERROR("Error predecoding multiplex: Invalid combination of ports %d and rx antennas %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } @@ -1768,63 +1768,67 @@ void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) { } /* 36.211 v10.3.0 Section 6.3.4 */ -int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - cf_t *x[SRSLTE_MAX_LAYERS], float *csi[SRSLTE_MAX_CODEWORDS], int nof_rxant, int nof_ports, int nof_layers, - int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float scaling, - float noise_estimate) { +int srslte_predecoding_type(cf_t* y[SRSLTE_MAX_PORTS], + cf_t* h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + cf_t* x[SRSLTE_MAX_LAYERS], + float* csi[SRSLTE_MAX_CODEWORDS], + int nof_rxant, + int nof_ports, + int nof_layers, + int codebook_idx, + int nof_symbols, + srslte_tx_scheme_t type, + float scaling, + float noise_estimate) +{ if (nof_ports > SRSLTE_MAX_PORTS) { - fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, - nof_ports); + ERROR("Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, nof_ports); return -1; } if (nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", - SRSLTE_MAX_LAYERS, nof_layers); + ERROR("Maximum number of layers is %d (nof_layers=%d)\n", SRSLTE_MAX_LAYERS, nof_layers); return -1; } switch (type) { - case SRSLTE_MIMO_TYPE_CDD: - if (nof_layers >= 2 && nof_layers <= 4) { - switch (mimo_decoder) { - case SRSLTE_MIMO_DECODER_ZF: - return srslte_predecoding_ccd_zf(y, h, x, csi, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling); - break; - case SRSLTE_MIMO_DECODER_MMSE: - return srslte_predecoding_ccd_mmse(y, h, x, csi, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling, noise_estimate); - break; + case SRSLTE_TXSCHEME_CDD: + if (nof_layers >= 2 && nof_layers <= 4) { + switch (mimo_decoder) { + case SRSLTE_MIMO_DECODER_ZF: + return srslte_predecoding_ccd_zf(y, h, x, csi, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling); + case SRSLTE_MIMO_DECODER_MMSE: + return srslte_predecoding_ccd_mmse( + y, h, x, csi, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling, noise_estimate); + } + } else { + ERROR("Invalid number of layers %d\n", nof_layers); + return -1; } - } else { - DEBUG("Invalid number of layers %d\n", nof_layers); - return -1; - } - return -1; - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_ports == 1 && nof_layers == 1) { - return srslte_predecoding_single_multi(y, h[0], x[0], csi, nof_rxant, nof_symbols, scaling, noise_estimate); - } else { - fprintf(stderr, - "Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers); return -1; - } - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_ports == nof_layers) { - return srslte_predecoding_diversity_multi(y, h, x, csi, nof_rxant, nof_ports, nof_symbols, scaling); - } else { - fprintf(stderr, - "Error number of layers must equal number of ports in transmit diversity\n"); - return -1; - } - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - return srslte_predecoding_multiplex(y, h, x, csi, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, - scaling, noise_estimate); + case SRSLTE_TXSCHEME_PORT0: + if (nof_ports == 1 && nof_layers == 1) { + return srslte_predecoding_single_multi(y, h[0], x[0], csi, nof_rxant, nof_symbols, scaling, noise_estimate); + } else { + ERROR("Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", + nof_ports, + nof_layers); + return -1; + } + case SRSLTE_TXSCHEME_DIVERSITY: + if (nof_ports == nof_layers) { + return srslte_predecoding_diversity_multi(y, h, x, csi, nof_rxant, nof_ports, nof_symbols, scaling); + } else { + ERROR("Error number of layers must equal number of ports in transmit diversity\n"); + return -1; + } + case SRSLTE_TXSCHEME_SPATIALMUX: + return srslte_predecoding_multiplex( + y, h, x, csi, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, scaling, noise_estimate); default: + ERROR("Invalid Txscheme=%d\n", type); return SRSLTE_ERROR; } - return SRSLTE_ERROR; } @@ -1888,7 +1892,7 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO } return 4 * i; } else { - fprintf(stderr, "Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + ERROR("Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); return -1; } } @@ -1961,7 +1965,7 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], { if (nof_ports == 2) { if (nof_layers != 2) { - DEBUG("Invalid number of layers %d for 2 ports\n", nof_layers); + ERROR("Invalid number of layers %d for 2 ports\n", nof_layers); return -1; } #ifdef LV_HAVE_AVX @@ -1974,10 +1978,10 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], #endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_AVX */ } else if (nof_ports == 4) { - DEBUG("Not implemented\n"); + ERROR("Not implemented\n"); return -1; } else { - DEBUG("Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); + ERROR("Number of ports must be 2 or 4 for transmit diversity (nof_ports=%d)\n", nof_ports); return -1; } } @@ -2007,8 +2011,10 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO srslte_vec_sc_prod_ccc(x[0], -_Complex_I * scaling, y[1], nof_symbols); break; default: - fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", - codebook_idx, nof_layers, nof_ports); + ERROR("Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", + codebook_idx, + nof_layers, + nof_ports); return SRSLTE_ERROR; } } else if (nof_layers == 2) { @@ -2086,8 +2092,10 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO break; case 3: default: - fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", - codebook_idx, nof_layers, nof_ports); + ERROR("Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", + codebook_idx, + nof_layers, + nof_ports); return SRSLTE_ERROR; } } else { @@ -2100,41 +2108,44 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO } /* 36.211 v10.3.0 Section 6.3.4 */ -int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, - int nof_ports, int codebook_idx, int nof_symbols, float scaling, srslte_mimo_type_t type) { +int srslte_precoding_type(cf_t* x[SRSLTE_MAX_LAYERS], + cf_t* y[SRSLTE_MAX_PORTS], + int nof_layers, + int nof_ports, + int codebook_idx, + int nof_symbols, + float scaling, + srslte_tx_scheme_t type) +{ if (nof_ports > SRSLTE_MAX_PORTS) { - fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, - nof_ports); + ERROR("Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, nof_ports); return -1; } if (nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", - SRSLTE_MAX_LAYERS, nof_layers); + ERROR("Maximum number of layers is %d (nof_layers=%d)\n", SRSLTE_MAX_LAYERS, nof_layers); return -1; } switch (type) { - case SRSLTE_MIMO_TYPE_CDD: + case SRSLTE_TXSCHEME_CDD: return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols, scaling); - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + case SRSLTE_TXSCHEME_PORT0: if (nof_ports == 1 && nof_layers == 1) { return srslte_precoding_single(x[0], y[0], nof_symbols, scaling); } else { - fprintf(stderr, - "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + ERROR("Number of ports and layers must be 1 for transmission on single antenna ports\n"); return -1; } break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + case SRSLTE_TXSCHEME_DIVERSITY: if (nof_ports == nof_layers) { return srslte_precoding_diversity(x, y, nof_ports, nof_symbols, scaling); } else { - fprintf(stderr, - "Error number of layers must equal number of ports in transmit diversity\n"); + ERROR("Error number of layers must equal number of ports in transmit diversity\n"); return -1; } - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_TXSCHEME_SPATIALMUX: return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, (uint32_t) nof_symbols, scaling); default: return SRSLTE_ERROR; @@ -2917,7 +2928,7 @@ int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t no *cn = srslte_precoding_2x2_cn_gen(h, nof_symbols); return SRSLTE_SUCCESS; } else { - DEBUG("MIMO Condition Number calculation not implemented for %d×%d", nof_tx_antennas, nof_rx_antennas); + ERROR("MIMO Condition Number calculation not implemented for %d×%d\n", nof_tx_antennas, nof_rx_antennas); return SRSLTE_ERROR; } } diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index cae668d9e..f33435b12 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -25,20 +25,19 @@ add_executable(layermap_test layermap_test.c) target_link_libraries(layermap_test srslte_phy) -add_test(layermap_single layermap_test -n 1000 -m single -c 1 -l 1) +add_test(layermap_single layermap_test -n 1000 -m p0 -c 1 -l 1) -add_test(layermap_diversity_2 layermap_test -n 1000 -m diversity -c 1 -l 2) -add_test(layermap_diversity_4 layermap_test -n 1000 -m diversity -c 1 -l 4) +add_test(layermap_diversity_2 layermap_test -n 1000 -m div -c 1 -l 2) +add_test(layermap_diversity_4 layermap_test -n 1000 -m div -c 1 -l 4) -add_test(layermap_multiplex_11 layermap_test -n 1000 -m multiplex -c 1 -l 1) -add_test(layermap_multiplex_12 layermap_test -n 1000 -m multiplex -c 1 -l 2) -add_test(layermap_multiplex_13 layermap_test -n 1002 -m multiplex -c 1 -l 3) -add_test(layermap_multiplex_14 layermap_test -n 1000 -m multiplex -c 1 -l 4) +add_test(layermap_multiplex_11 layermap_test -n 1000 -m mux -c 1 -l 1) +add_test(layermap_multiplex_12 layermap_test -n 1000 -m mux -c 1 -l 2) +add_test(layermap_multiplex_13 layermap_test -n 1002 -m mux -c 1 -l 3) +add_test(layermap_multiplex_14 layermap_test -n 1000 -m mux -c 1 -l 4) - -add_test(layermap_multiplex_22 layermap_test -n 1000 -m multiplex -c 2 -l 2) -add_test(layermap_multiplex_23 layermap_test -n 1002 -m multiplex -c 2 -l 3) -add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) +add_test(layermap_multiplex_22 layermap_test -n 1000 -m mux -c 2 -l 2) +add_test(layermap_multiplex_23 layermap_test -n 1002 -m mux -c 2 -l 3) +add_test(layermap_multiplex_24 layermap_test -n 1000 -m mux -c 2 -l 4) ######################################################################## @@ -48,26 +47,26 @@ add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) add_executable(precoding_test precoder_test.c) target_link_libraries(precoding_test srslte_phy) -add_test(precoding_single precoding_test -n 1000 -m single) -add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2) -add_test(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4) +add_test(precoding_single precoding_test -n 1000 -m p0) +add_test(precoding_diversity2 precoding_test -n 1000 -m div -l 2 -p 2) +add_test(precoding_diversity4 precoding_test -n 1024 -m div -l 4 -p 4) add_test(precoding_cdd_2x2_zf precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d zf) add_test(precoding_cdd_2x2_mmse precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d mmse) -add_test(precoding_multiplex_1l_cb0 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 0) -add_test(precoding_multiplex_1l_cb1 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 1) -add_test(precoding_multiplex_1l_cb2 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 2) -add_test(precoding_multiplex_1l_cb3 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 3) +add_test(precoding_multiplex_1l_cb0 precoding_test -m mux -l 1 -p 2 -r 2 -n 14000 -c 0) +add_test(precoding_multiplex_1l_cb1 precoding_test -m mux -l 1 -p 2 -r 2 -n 14000 -c 1) +add_test(precoding_multiplex_1l_cb2 precoding_test -m mux -l 1 -p 2 -r 2 -n 14000 -c 2) +add_test(precoding_multiplex_1l_cb3 precoding_test -m mux -l 1 -p 2 -r 2 -n 14000 -c 3) -add_test(precoding_multiplex_2l_cb0_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d zf) -add_test(precoding_multiplex_2l_cb1_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d zf) -add_test(precoding_multiplex_2l_cb2_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d zf) +add_test(precoding_multiplex_2l_cb0_zf precoding_test -m mux -l 2 -p 2 -r 2 -n 14000 -c 0 -d zf) +add_test(precoding_multiplex_2l_cb1_zf precoding_test -m mux -l 2 -p 2 -r 2 -n 14000 -c 1 -d zf) +add_test(precoding_multiplex_2l_cb2_zf precoding_test -m mux -l 2 -p 2 -r 2 -n 14000 -c 2 -d zf) -add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d mmse) -add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse) -add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse) +add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m mux -l 2 -p 2 -r 2 -n 14000 -c 0 -d mmse) +add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m mux -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse) +add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m mux -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse) ######################################################################## # PMI SELECT TEST diff --git a/lib/src/phy/mimo/test/layermap_test.c b/lib/src/phy/mimo/test/layermap_test.c index 6f026f9d0..c931498bb 100644 --- a/lib/src/phy/mimo/test/layermap_test.c +++ b/lib/src/phy/mimo/test/layermap_test.c @@ -40,7 +40,12 @@ int nof_cw = 1, nof_layers = 1; char *mimo_type_name = NULL; void usage(char *prog) { - printf("Usage: %s -m [single|diversity|multiplex|cdd] -c [nof_cw] -l [nof_layers]\n", prog); + printf("Usage: %s -m [%s|%s|%s|%s] -c [nof_cw] -l [nof_layers]\n", + prog, + srslte_mimotype2str(0), + srslte_mimotype2str(1), + srslte_mimotype2str(2), + srslte_mimotype2str(3)); printf("\t-n num_symbols [Default %d]\n", nof_symbols); } @@ -74,14 +79,14 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { int i, j, num_errors, symbols_layer; cf_t *d[SRSLTE_MAX_CODEWORDS], *x[SRSLTE_MAX_LAYERS], *dp[SRSLTE_MAX_CODEWORDS]; - srslte_mimo_type_t type; + srslte_tx_scheme_t type; int nof_symb_cw[SRSLTE_MAX_CODEWORDS]; int n[2]; parse_args(argc, argv); if (srslte_str2mimotype(mimo_type_name, &type)) { - fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); + ERROR("Invalid MIMO type %s\n", mimo_type_name); exit(-1); } @@ -124,13 +129,13 @@ int main(int argc, char **argv) { /* layer mapping */ if ((symbols_layer = srslte_layermap_type(d, x, nof_cw, nof_layers, nof_symb_cw, type)) < 0) { - fprintf(stderr, "Error layer mapper encoder\n"); + ERROR("Error layer mapper encoder\n"); exit(-1); } /* layer de-mapping */ if (srslte_layerdemap_type(x, dp, nof_layers, nof_cw, nof_symbols/nof_layers, nof_symb_cw, type) < 0) { - fprintf(stderr, "Error layer mapper encoder\n"); + ERROR("Error layer mapper encoder\n"); exit(-1); } diff --git a/lib/src/phy/mimo/test/precoder_mex.c b/lib/src/phy/mimo/test/precoder_mex.c deleted file mode 100644 index b021f422a..000000000 --- a/lib/src/phy/mimo/test/precoder_mex.c +++ /dev/null @@ -1,145 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the predecoder - */ - -#define INPUT prhs[0] -#define NLAYERS prhs[1] -#define NPORTS prhs[2] -#define TXSCHEME prhs[3] -#define NOF_INPUTS 3 - - -void help() -{ - mexErrMsgTxt - ("[output] = srslte_decoder(input, NLayers, NCellRefP, TxScheme)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - cf_t *input = NULL; - cf_t *output = NULL; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - // Read input symbols - int nof_symbols = mexutils_read_cf(INPUT, &input); - if (nof_symbols < 0) { - mexErrMsgTxt("Error reading input\n"); - return; - } - uint32_t nof_layers = mxGetScalar(NLAYERS); - uint32_t nof_tx_ports = mxGetScalar(NPORTS); - uint32_t nof_codewords = 1; - - mexPrintf("nof_tx_ports=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_layers, nof_symbols); - - cf_t *y[SRSLTE_MAX_PORTS]; - cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *d[SRSLTE_MAX_CODEWORDS]; - - d[0] = input; // Single codeword supported only - - /* Allocate memory */ - for (int i = 0; i < nof_layers; i++) { - x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers); - } - - output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports); - for (int i=0;i= NOF_INPUTS) { - txscheme = mxArrayToString(TXSCHEME); - } - srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - if (!strcmp(txscheme, "Port0")) { - type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } else if (!strcmp(txscheme, "TxDiversity")) { - type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (!strcmp(txscheme, "CDD")) { - type = SRSLTE_MIMO_TYPE_CDD; - } else if (!strcmp(txscheme, "SpatialMux")) { - type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else { - mexPrintf("Unsupported TxScheme=%s\n", txscheme); - return; - } - int symbols_layers[SRSLTE_MAX_LAYERS]; - for (int i=0;i= 1) { - switch (type) { - case SRSLTE_MIMO_TYPE_CDD: - mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - default: - mexutils_write_cf(output, &plhs[0], (uint32_t) nof_symbols, nof_tx_ports); - break; - } - } - - if (nlhs >= 2) { - mexutils_write_cf(x[0], &plhs[1], nof_symbols / nof_layers, 1); - } - if (nlhs >= 3) { - mexutils_write_cf(x[1], &plhs[2], nof_symbols / nof_layers, 1); - } - - if (input) { - free(input); - } - if (output) { - free(output); - } - for (int i=0;i SRSLTE_MAX_PORTS || nof_rx_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) { - fprintf(stderr, "Invalid number of layers or ports\n"); + ERROR("Invalid number of layers or ports\n"); exit(-1); } /* Parse MIMO Type */ if (srslte_str2mimotype(mimo_type_name, &type)) { - fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); + ERROR("Invalid MIMO type %s\n", mimo_type_name); exit(-1); } /* Check scenario conditions are OK */ switch (type) { - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - nof_re = nof_layers*nof_symbols; + case SRSLTE_TXSCHEME_DIVERSITY: + nof_re = nof_layers * nof_symbols; break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_TXSCHEME_SPATIALMUX: nof_re = nof_symbols; break; - case SRSLTE_MIMO_TYPE_CDD: + case SRSLTE_TXSCHEME_CDD: nof_re = nof_symbols*nof_tx_ports/nof_layers; if (nof_rx_ports != 2 || nof_tx_ports != 2) { - fprintf(stderr, "CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports); + ERROR("CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports); exit(-1); } break; @@ -257,7 +263,7 @@ int main(int argc, char **argv) { /* Execute Precoding (Tx) */ if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, scaling, type) < 0) { - fprintf(stderr, "Error layer mapper encoder\n"); + ERROR("Error layer mapper encoder\n"); exit(-1); } diff --git a/lib/src/phy/mimo/test/predecoder_mex.c b/lib/src/phy/mimo/test/predecoder_mex.c deleted file mode 100644 index 0465e1ef4..000000000 --- a/lib/src/phy/mimo/test/predecoder_mex.c +++ /dev/null @@ -1,213 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the predecoder - */ - -#define INPUT prhs[0] -#define HEST prhs[1] -#define NEST prhs[2] -#define NLAYERS prhs[3] -#define NCW prhs[4] -#define TXSCHEME prhs[5] -#define CODEBOOK prhs[6] -#define NOF_INPUTS 7 - - -void help() -{ - mexErrMsgTxt - ("[output] = srslte_predecoder(input, hest, nest, Nl, TxScheme)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - const mwSize *dims = mxGetDimensions(INPUT); - mwSize ndims; - cf_t *input = NULL; - cf_t *hest = NULL; - cf_t *output = NULL; - uint32_t nof_symbols = 0; - uint32_t nof_rx_ants = 1; - uint32_t nof_layers; - uint32_t nof_tx_ports = 1; - uint32_t nof_codewords = 1; - uint32_t codebook_idx = 0; - float noise_estimate = 0; - cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - cf_t *y[SRSLTE_MAX_PORTS]; - int symbols_layers[SRSLTE_MAX_LAYERS]; - int i, j; - srslte_mimo_type_t type; - - /* Print help if number of inputs does not match with expected */ - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - /* Read input symbols */ - if (mexutils_read_cf(INPUT, &input) < 0) { - mexErrMsgTxt("Error reading input\n"); - return; - } - - /* Read number of layers */ - nof_layers = (uint32_t) mxGetScalar(NLAYERS); - - /* Read number of codewords */ - nof_codewords = (uint32_t) mxGetScalar(NCW); - - if (nof_layers > SRSLTE_MAX_LAYERS) { - mexErrMsgTxt("Too many layers\n"); - return; - } - - /* Read number of symbols and Rx antennas */ - ndims = mxGetNumberOfDimensions(INPUT); - nof_symbols = (uint32_t) dims[0]; - - if (ndims >= 2) { - nof_rx_ants = (uint32_t) dims[1]; - } - - /* Read channel estimates */ - if (mexutils_read_cf(HEST, &hest) < 0) { - mexErrMsgTxt("Error reading hest\n"); - return; - } - - /* Get number of tx ports */ - dims = mxGetDimensions(HEST); - ndims = mxGetNumberOfDimensions(HEST); - - if (ndims == 3) { - nof_tx_ports = (uint32_t) dims[2]; - } - - /* Print parameters trace */ - mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_codewords=%d, codebook_idx=%d, nof_symbols=%d\n", - nof_tx_ports, nof_rx_ants, nof_layers, nof_codewords, codebook_idx, nof_symbols); - - /* Read noise estimate */ - if (nrhs >= NOF_INPUTS) { - noise_estimate = (float) mxGetScalar(NEST); - } - - /* Initialise x, h & y pointers */ - for (i=0;i= NOF_INPUTS) { - mxGetString_700(TXSCHEME, txscheme, 32); - } - - codebook_idx = (uint32_t) mxGetScalar(CODEBOOK); - - if (srslte_str2mimotype(txscheme, &type)) { - mexPrintf("Unsupported TxScheme=%s\n", txscheme); - return; - } - - /* Populate symbols in layers */ - for (i = 0; i < nof_layers; i++) { - symbols_layers[i] = nof_symbols; - } - - /* Set output pointer */ - cf_t *d[SRSLTE_MAX_CODEWORDS]; - for (i = 0; i= 1) { - mexutils_write_cf(output, &plhs[0], nof_symbols, nof_codewords); - } - - /* Free memory */ - if (input) { - free(input); - } - if (hest) { - free(hest); - } - if (output) { - free(output); - } - for (i=0;imod) { - case SRSLTE_MOD_LAST: case SRSLTE_MOD_BPSK: hard_bpsk_demod(symbols,bits,nsymbols); nbits=nsymbols; diff --git a/lib/src/phy/modem/demod_soft.c b/lib/src/phy/modem/demod_soft.c index d7edd78eb..2d376f2e8 100644 --- a/lib/src/phy/modem/demod_soft.c +++ b/lib/src/phy/modem/demod_soft.c @@ -28,10 +28,10 @@ #include #include -#include "srslte/phy/utils/vector.h" -#include "srslte/phy/utils/bit.h" #include "srslte/phy/modem/demod_soft.h" - +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #ifdef LV_HAVE_SSE #include @@ -427,9 +427,9 @@ int srslte_demod_soft_demodulate(srslte_mod_t modulation, const cf_t* symbols, f case SRSLTE_MOD_64QAM: demod_64qam_lte(symbols, llr, nsymbols); break; - default: - fprintf(stderr, "Invalid modulation %d\n", modulation); - return -1; + default: + ERROR("Invalid modulation %d\n", modulation); + return -1; } return 0; } @@ -448,9 +448,9 @@ int srslte_demod_soft_demodulate_s(srslte_mod_t modulation, const cf_t* symbols, case SRSLTE_MOD_64QAM: demod_64qam_lte_s(symbols, llr, nsymbols); break; - default: - fprintf(stderr, "Invalid modulation %d\n", modulation); - return -1; + default: + ERROR("Invalid modulation %d\n", modulation); + return -1; } return 0; } @@ -470,7 +470,7 @@ int srslte_demod_soft_demodulate_b(srslte_mod_t modulation, const cf_t* symbols, demod_64qam_lte_b(symbols, llr, nsymbols); break; default: - fprintf(stderr, "Invalid modulation %d\n", modulation); + ERROR("Invalid modulation %d\n", modulation); return -1; } return 0; diff --git a/lib/src/phy/modem/mod.c b/lib/src/phy/modem/mod.c index b72fdd133..3c70f1df5 100644 --- a/lib/src/phy/modem/mod.c +++ b/lib/src/phy/modem/mod.c @@ -30,8 +30,9 @@ #include #include -#include "srslte/phy/utils/bit.h" #include "srslte/phy/modem/mod.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" /** Low-level API */ @@ -129,11 +130,11 @@ int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symb { if (!q->byte_tables_init) { - fprintf(stderr, "Error need to initiated modem tables for packeted bits before calling srslte_mod_modulate_bytes()\n"); + ERROR("Error need to initiated modem tables for packeted bits before calling srslte_mod_modulate_bytes()\n"); return -1; } if (nbits % q->nbits_x_symbol) { - fprintf(stderr, "Error modulator expects number of bits (%d) to be multiple of %d\n", nbits, q->nbits_x_symbol); + ERROR("Error modulator expects number of bits (%d) to be multiple of %d\n", nbits, q->nbits_x_symbol); return -1; } switch(q->nbits_x_symbol) { @@ -150,7 +151,7 @@ int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t *bits, cf_t* symb mod_64qam_bytes(q, bits, symbols, nbits); break; default: - fprintf(stderr, "srslte_mod_modulate_bytes() accepts QPSK/16QAM/64QAM modulations only\n"); + ERROR("srslte_mod_modulate_bytes() accepts QPSK/16QAM/64QAM modulations only\n"); return -1; } return nbits/q->nbits_x_symbol; diff --git a/lib/src/phy/modem/modem_table.c b/lib/src/phy/modem/modem_table.c index 3c4ad2417..c19e52e77 100644 --- a/lib/src/phy/modem/modem_table.c +++ b/lib/src/phy/modem/modem_table.c @@ -82,7 +82,6 @@ int srslte_modem_table_set(srslte_modem_table_t* q, cf_t* table, uint32_t nsymbo int srslte_modem_table_lte(srslte_modem_table_t* q, srslte_mod_t modulation) { srslte_modem_table_init(q); switch(modulation) { - case SRSLTE_MOD_LAST: case SRSLTE_MOD_BPSK: q->nbits_x_symbol = 1; q->nsymbols = 2; diff --git a/lib/src/phy/modem/test/modem_test.c b/lib/src/phy/modem/test/modem_test.c index ed9bef522..6ae8200c6 100644 --- a/lib/src/phy/modem/test/modem_test.c +++ b/lib/src/phy/modem/test/modem_test.c @@ -69,8 +69,9 @@ void parse_args(int argc, char **argv) { modulation = SRSLTE_MOD_64QAM; break; default: - fprintf(stderr, "Invalid modulation %d. Possible values: " - "(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", atoi(argv[optind])); + ERROR("Invalid modulation %d. Possible values: " + "(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", + atoi(argv[optind])); break; } break; @@ -93,7 +94,7 @@ int main(int argc, char **argv) { /* initialize objects */ if (srslte_modem_table_lte(&mod, modulation)) { - fprintf(stderr, "Error initializing modem table\n"); + ERROR("Error initializing modem table\n"); exit(-1); } @@ -101,7 +102,7 @@ int main(int argc, char **argv) { /* check that num_bits is multiple of num_bits x symbol */ if (num_bits % mod.nbits_x_symbol) { - fprintf(stderr, "Error num_bits must be multiple of %d\n", mod.nbits_x_symbol); + ERROR("Error num_bits must be multiple of %d\n", mod.nbits_x_symbol); exit(-1); } @@ -192,7 +193,7 @@ int main(int argc, char **argv) { /* check errors */ for (i=0;i +#include +#include #include #include +#include #include #include -#include -#include -#include -#include #include "srslte/phy/phch/cqi.h" #include "srslte/phy/common/phy_common.h" @@ -42,30 +43,30 @@ /******************************************************* * PACKING FUNCTIONS * *******************************************************/ -int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) +static int cqi_hl_subband_pack(srslte_cqi_cfg_t* cfg, srslte_cqi_hl_subband_t* msg, uint8_t* buff) { uint8_t *body_ptr = buff; uint32_t bit_count = 0; /* Unpack codeword 0, common for 3GPP 36.212 Tables 5.2.2.6.2-1 and 5.2.2.6.2-2 */ srslte_bit_unpack(msg->wideband_cqi_cw0, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi_cw0, &body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; + srslte_bit_unpack(msg->subband_diff_cqi_cw0, &body_ptr, 2 * cfg->N); + bit_count += 4 + 2 * cfg->N; /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { srslte_bit_unpack(msg->wideband_cqi_cw1, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi_cw1, &body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; + srslte_bit_unpack(msg->subband_diff_cqi_cw1, &body_ptr, 2 * cfg->N); + bit_count += 4 + 2 * cfg->N; } /* If PMI is present, unpack it */ - if (msg->pmi_present) { - if (msg->four_antenna_ports) { + if (cfg->pmi_present) { + if (cfg->four_antenna_ports) { srslte_bit_unpack(msg->pmi, &body_ptr, 4); bit_count += 4; } else { - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { srslte_bit_unpack(msg->pmi, &body_ptr, 1); bit_count += 1; } else { @@ -78,31 +79,31 @@ int srslte_cqi_hl_subband_pack(srslte_cqi_hl_subband_t *msg, uint8_t buff[SRSLTE return bit_count; } -int srslte_cqi_ue_subband_pack(srslte_cqi_ue_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) +static int cqi_ue_subband_pack(srslte_cqi_cfg_t* cfg, srslte_cqi_ue_subband_t* msg, uint8_t* buff) { - uint8_t *body_ptr = buff; + uint8_t* body_ptr = buff; srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4); - srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2); - srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, msg->L); - - return 4+2+msg->L; + srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, 2); + srslte_bit_unpack(msg->subband_diff_cqi, &body_ptr, cfg->L); + + return 4 + 2 + cfg->L; } /* Pack CQI following 3GPP TS 36.212 Tables 5.2.3.3.1-1 and 5.2.3.3.1-2 */ -int srslte_cqi_format2_wideband_pack(srslte_cqi_format2_wideband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) +static int cqi_format2_wideband_pack(srslte_cqi_cfg_t* cfg, srslte_cqi_format2_wideband_t* msg, uint8_t* buff) { uint8_t *body_ptr = buff; srslte_bit_unpack(msg->wideband_cqi, &body_ptr, 4); - if (msg->pmi_present) { - if (msg->four_antenna_ports) { - if (msg->rank_is_not_one) { + if (cfg->pmi_present) { + if (cfg->four_antenna_ports) { + if (cfg->rank_is_not_one) { srslte_bit_unpack(msg->spatial_diff_cqi, &body_ptr, 3); } srslte_bit_unpack(msg->pmi, &body_ptr, 4); } else { - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { srslte_bit_unpack(msg->spatial_diff_cqi, &body_ptr, 3); srslte_bit_unpack(msg->pmi, &body_ptr, 1); } else { @@ -114,27 +115,27 @@ int srslte_cqi_format2_wideband_pack(srslte_cqi_format2_wideband_t *msg, uint8_t return (int)(body_ptr - buff); } -int srslte_cqi_format2_subband_pack(srslte_cqi_format2_subband_t *msg, uint8_t buff[SRSLTE_CQI_MAX_BITS]) +static int cqi_format2_subband_pack(srslte_cqi_cfg_t* cfg, srslte_cqi_format2_subband_t* msg, uint8_t* buff) { - uint8_t *body_ptr = buff; - srslte_bit_unpack(msg->subband_cqi, &body_ptr, 4); - srslte_bit_unpack(msg->subband_label, &body_ptr, msg->subband_label_2_bits?2:1); - return 4+(msg->subband_label_2_bits)?2:1; + uint8_t* body_ptr = buff; + srslte_bit_unpack(msg->subband_cqi, &body_ptr, 4); + srslte_bit_unpack(msg->subband_label, &body_ptr, cfg->subband_label_2_bits ? 2 : 1); + return 4 + (cfg->subband_label_2_bits) ? 2 : 1; } -int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX_BITS]) +int srslte_cqi_value_pack(srslte_cqi_cfg_t* cfg, srslte_cqi_value_t* value, uint8_t buff[SRSLTE_CQI_MAX_BITS]) { - switch(value->type) { + switch (cfg->type) { case SRSLTE_CQI_TYPE_WIDEBAND: - return srslte_cqi_format2_wideband_pack(&value->wideband, buff); + return cqi_format2_wideband_pack(cfg, &value->wideband, buff); case SRSLTE_CQI_TYPE_SUBBAND: - return srslte_cqi_format2_subband_pack(&value->subband, buff); + return cqi_format2_subband_pack(cfg, &value->subband, buff); case SRSLTE_CQI_TYPE_SUBBAND_UE: - return srslte_cqi_ue_subband_pack(&value->subband_ue, buff); + return cqi_ue_subband_pack(cfg, &value->subband_ue, buff); case SRSLTE_CQI_TYPE_SUBBAND_HL: - return srslte_cqi_hl_subband_pack(&value->subband_hl, buff); + return cqi_hl_subband_pack(cfg, &value->subband_hl, buff); } - return -1; + return -1; } @@ -142,29 +143,29 @@ int srslte_cqi_value_pack(srslte_cqi_value_t *value, uint8_t buff[SRSLTE_CQI_MAX * UNPACKING FUNCTIONS * *******************************************************/ -int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_hl_subband_t *msg) +int cqi_hl_subband_unpack(srslte_cqi_cfg_t* cfg, uint8_t* buff, srslte_cqi_hl_subband_t* msg) { uint8_t *body_ptr = buff; uint32_t bit_count = 0; msg->wideband_cqi_cw0 = (uint8_t) srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi_cw0 = srslte_bit_pack(&body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; + msg->subband_diff_cqi_cw0 = srslte_bit_pack(&body_ptr, 2 * cfg->N); + bit_count += 4 + 2 * cfg->N; /* Unpack codeword 1, 3GPP 36.212 Table 5.2.2.6.2-2 */ - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { msg->wideband_cqi_cw1 = (uint8_t) srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi_cw1 = srslte_bit_pack(&body_ptr, 2*msg->N); - bit_count += 4+2*msg->N; + msg->subband_diff_cqi_cw1 = srslte_bit_pack(&body_ptr, 2 * cfg->N); + bit_count += 4 + 2 * cfg->N; } /* If PMI is present, unpack it */ - if (msg->pmi_present) { - if (msg->four_antenna_ports) { + if (cfg->pmi_present) { + if (cfg->four_antenna_ports) { msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 4); bit_count += 4; } else { - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 1); bit_count += 1; } else { @@ -177,30 +178,30 @@ int srslte_cqi_hl_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_h return bit_count; } -int srslte_cqi_ue_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_ue_subband_t *msg) +int cqi_ue_subband_unpack(srslte_cqi_cfg_t* cfg, uint8_t* buff, srslte_cqi_ue_subband_t* msg) { - uint8_t *body_ptr = buff; + uint8_t* body_ptr = buff; msg->wideband_cqi = srslte_bit_pack(&body_ptr, 4); - msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2); - msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, msg->L); - - return 4+2+msg->L; + msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, 2); + msg->subband_diff_cqi = srslte_bit_pack(&body_ptr, cfg->L); + + return 4 + 2 + cfg->L; } /* Unpack CQI following 3GPP TS 36.212 Tables 5.2.3.3.1-1 and 5.2.3.3.1-2 */ -int srslte_cqi_format2_wideband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_format2_wideband_t *msg) +static int cqi_format2_wideband_unpack(srslte_cqi_cfg_t* cfg, uint8_t* buff, srslte_cqi_format2_wideband_t* msg) { - uint8_t *body_ptr = buff; + uint8_t* body_ptr = buff; msg->wideband_cqi = (uint8_t) srslte_bit_pack(&body_ptr, 4); - if (msg->pmi_present) { - if (msg->four_antenna_ports) { - if (msg->rank_is_not_one) { + if (cfg->pmi_present) { + if (cfg->four_antenna_ports) { + if (cfg->rank_is_not_one) { msg->spatial_diff_cqi = (uint8_t) srslte_bit_pack(&body_ptr, 3); } msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 4); } else { - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { msg->spatial_diff_cqi = (uint8_t) srslte_bit_pack(&body_ptr, 3); msg->pmi = (uint8_t) srslte_bit_pack(&body_ptr, 1); } else { @@ -208,43 +209,45 @@ int srslte_cqi_format2_wideband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte } } } - return 4; + return 4; } -int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_format2_subband_t *msg) +static int cqi_format2_subband_unpack(srslte_cqi_cfg_t* cfg, uint8_t* buff, srslte_cqi_format2_subband_t* msg) { - uint8_t *body_ptr = buff; - msg->subband_cqi = srslte_bit_pack(&body_ptr, 4); - msg->subband_label = srslte_bit_pack(&body_ptr, msg->subband_label_2_bits?2:1); - return 4+(msg->subband_label_2_bits)?2:1; + uint8_t* body_ptr = buff; + msg->subband_cqi = srslte_bit_pack(&body_ptr, 4); + msg->subband_label = srslte_bit_pack(&body_ptr, cfg->subband_label_2_bits ? 2 : 1); + return 4 + (cfg->subband_label_2_bits) ? 2 : 1; } -int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_t *value) +int srslte_cqi_value_unpack(srslte_cqi_cfg_t* cfg, uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_t* value) { - switch(value->type) { + switch (cfg->type) { case SRSLTE_CQI_TYPE_WIDEBAND: - return srslte_cqi_format2_wideband_unpack(buff, &value->wideband); + return cqi_format2_wideband_unpack(cfg, buff, &value->wideband); case SRSLTE_CQI_TYPE_SUBBAND: - return srslte_cqi_format2_subband_unpack(buff, &value->subband); + return cqi_format2_subband_unpack(cfg, buff, &value->subband); case SRSLTE_CQI_TYPE_SUBBAND_UE: - return srslte_cqi_ue_subband_unpack(buff, &value->subband_ue); + return cqi_ue_subband_unpack(cfg, buff, &value->subband_ue); case SRSLTE_CQI_TYPE_SUBBAND_HL: - return srslte_cqi_hl_subband_unpack(buff, &value->subband_hl); + return cqi_hl_subband_unpack(cfg, buff, &value->subband_hl); } - return -1; + return -1; } /******************************************************* * TO STRING FUNCTIONS * *******************************************************/ -static int srslte_cqi_format2_wideband_tostring(srslte_cqi_format2_wideband_t *msg, char *buff, uint32_t buff_len) { +static int +cqi_format2_wideband_tostring(srslte_cqi_cfg_t* cfg, srslte_cqi_format2_wideband_t* msg, char* buff, uint32_t buff_len) +{ int n = 0; n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->wideband_cqi); - if (msg->pmi_present) { - if (msg->rank_is_not_one) { + if (cfg->pmi_present) { + if (cfg->rank_is_not_one) { n += snprintf(buff + n, buff_len - n, ", diff_cqi=%d", msg->spatial_diff_cqi); } n += snprintf(buff + n, buff_len - n, ", pmi=%d", msg->pmi); @@ -253,7 +256,9 @@ static int srslte_cqi_format2_wideband_tostring(srslte_cqi_format2_wideband_t *m return n; } -static int srslte_cqi_format2_subband_tostring(srslte_cqi_format2_subband_t *msg, char *buff, uint32_t buff_len) { +static int +cqi_format2_subband_tostring(srslte_cqi_cfg_t* cfg, srslte_cqi_format2_subband_t* msg, char* buff, uint32_t buff_len) +{ int n = 0; n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->subband_cqi); @@ -262,51 +267,54 @@ static int srslte_cqi_format2_subband_tostring(srslte_cqi_format2_subband_t *msg return n; } -static int srslte_cqi_ue_subband_tostring(srslte_cqi_ue_subband_t *msg, char *buff, uint32_t buff_len) { +static int cqi_ue_subband_tostring(srslte_cqi_cfg_t* cfg, srslte_cqi_ue_subband_t* msg, char* buff, uint32_t buff_len) +{ int n = 0; n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->wideband_cqi); n += snprintf(buff + n, buff_len - n, ", diff_cqi=%d", msg->subband_diff_cqi); - n += snprintf(buff + n, buff_len - n, ", L=%d", msg->L); + n += snprintf(buff + n, buff_len - n, ", L=%d", cfg->L); return n; } -static int srslte_cqi_hl_subband_tostring(srslte_cqi_hl_subband_t *msg, char *buff, uint32_t buff_len) { +static int cqi_hl_subband_tostring(srslte_cqi_cfg_t* cfg, srslte_cqi_hl_subband_t* msg, char* buff, uint32_t buff_len) +{ int n = 0; n += snprintf(buff + n, buff_len - n, ", cqi=%d", msg->wideband_cqi_cw0); n += snprintf(buff + n, buff_len - n, ", diff=%d", msg->subband_diff_cqi_cw0); - if (msg->rank_is_not_one) { + if (cfg->rank_is_not_one) { n += snprintf(buff + n, buff_len - n, ", cqi1=%d", msg->wideband_cqi_cw1); n += snprintf(buff + n, buff_len - n, ", diff1=%d", msg->subband_diff_cqi_cw1); } - if (msg->pmi_present) { + if (cfg->pmi_present) { n += snprintf(buff + n, buff_len - n, ", pmi=%d", msg->pmi); } - n += snprintf(buff + n, buff_len - n, ", N=%d", msg->N); + n += snprintf(buff + n, buff_len - n, ", N=%d", cfg->N); return n; } -int srslte_cqi_value_tostring(srslte_cqi_value_t *value, char *buff, uint32_t buff_len) { +int srslte_cqi_value_tostring(srslte_cqi_cfg_t* cfg, srslte_cqi_value_t* value, char* buff, uint32_t buff_len) +{ int ret = -1; - switch (value->type) { + switch (cfg->type) { case SRSLTE_CQI_TYPE_WIDEBAND: - ret = srslte_cqi_format2_wideband_tostring(&value->wideband, buff, buff_len); + ret = cqi_format2_wideband_tostring(cfg, &value->wideband, buff, buff_len); break; case SRSLTE_CQI_TYPE_SUBBAND: - ret = srslte_cqi_format2_subband_tostring(&value->subband, buff, buff_len); + ret = cqi_format2_subband_tostring(cfg, &value->subband, buff, buff_len); break; case SRSLTE_CQI_TYPE_SUBBAND_UE: - ret = srslte_cqi_ue_subband_tostring(&value->subband_ue, buff, buff_len); + ret = cqi_ue_subband_tostring(cfg, &value->subband_ue, buff, buff_len); break; case SRSLTE_CQI_TYPE_SUBBAND_HL: - ret = srslte_cqi_hl_subband_tostring(&value->subband_hl, buff, buff_len); + ret = cqi_hl_subband_tostring(cfg, &value->subband_hl, buff, buff_len); break; default: /* Do nothing */; @@ -315,23 +323,28 @@ int srslte_cqi_value_tostring(srslte_cqi_value_t *value, char *buff, uint32_t bu return ret; } -int srslte_cqi_size(srslte_cqi_value_t *value) { +int srslte_cqi_size(srslte_cqi_cfg_t* cfg) +{ int size = 0; - switch(value->type) { + if (!cfg->data_enable) { + return 0; + } + + switch (cfg->type) { case SRSLTE_CQI_TYPE_WIDEBAND: /* Compute size according to 3GPP TS 36.212 Tables 5.2.3.3.1-1 and 5.2.3.3.1-2 */ size = 4; - if (value->wideband.pmi_present) { - if (value->wideband.four_antenna_ports) { - if (value->wideband.rank_is_not_one) { + if (cfg->pmi_present) { + if (cfg->four_antenna_ports) { + if (cfg->rank_is_not_one) { size += 3; // Differential } else { size += 0; // Differential } size += 4; // PMI } else { - if (value->wideband.rank_is_not_one) { + if (cfg->rank_is_not_one) { size += 3; // Differential size += 1; // PMI } else { @@ -342,26 +355,26 @@ int srslte_cqi_size(srslte_cqi_value_t *value) { } break; case SRSLTE_CQI_TYPE_SUBBAND: - size = 4 + (value->subband.subband_label_2_bits) ? 2 : 1; + size = 4 + (cfg->subband_label_2_bits) ? 2 : 1; break; case SRSLTE_CQI_TYPE_SUBBAND_UE: - size = 4 + 2 + value->subband_ue.L; + size = 4 + 2 + cfg->L; break; case SRSLTE_CQI_TYPE_SUBBAND_HL: /* First codeword */ - size += 4 + 2 * value->subband_hl.N; + size += 4 + 2 * cfg->N; /* Add Second codeword if required */ - if (value->subband_hl.rank_is_not_one && value->subband_hl.pmi_present) { - size += 4 + 2 * value->subband_hl.N; + if (cfg->rank_is_not_one && cfg->pmi_present) { + size += 4 + 2 * cfg->N; } /* Add PMI if required*/ - if (value->subband_hl.pmi_present) { - if (value->subband_hl.four_antenna_ports) { + if (cfg->pmi_present) { + if (cfg->four_antenna_ports) { size += 4; } else { - if (value->subband_hl.rank_is_not_one) { + if (cfg->rank_is_not_one) { size += 1; } else { size += 2; @@ -375,7 +388,9 @@ int srslte_cqi_size(srslte_cqi_value_t *value) { return size; } -static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) { +static bool cqi_get_N_fdd(uint32_t I_cqi_pmi, uint32_t* N_p, uint32_t* N_offset) +{ + // Acccording to 3GPP 36.213 R10 Table 7.2.2-1A: Mapping of I CQI / PMI to N pd and N OFFSET , CQI for FDD if (I_cqi_pmi <= 1) { *N_p = 2; *N_offset = I_cqi_pmi; @@ -414,64 +429,119 @@ static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offs return true; } -bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) { - - uint32_t N_p = 0; +static bool cqi_get_N_tdd(uint32_t I_cqi_pmi, uint32_t* N_p, uint32_t* N_offset) +{ + // Acccording to 3GPP 36.213 R10 Table 7.2.2-1A: Mapping of I CQI / PMI to N pd and N OFFSET , CQI for TDD + if (I_cqi_pmi == 0) { + *N_p = 1; + *N_offset = I_cqi_pmi; + } else if (I_cqi_pmi <= 5) { + *N_p = 5; + *N_offset = I_cqi_pmi - 1; + } else if (I_cqi_pmi <= 15) { + *N_p = 10; + *N_offset = I_cqi_pmi - 5; + } else if (I_cqi_pmi <= 35) { + *N_p = 20; + *N_offset = I_cqi_pmi - 16; + } else if (I_cqi_pmi <= 75) { + *N_p = 40; + *N_offset = I_cqi_pmi - 36; + } else if (I_cqi_pmi <= 155) { + *N_p = 80; + *N_offset = I_cqi_pmi - 76; + } else if (I_cqi_pmi <= 315) { + *N_p = 160; + *N_offset = I_cqi_pmi - 156; + } else if (I_cqi_pmi == 1023) { + return false; + } + return true; +} + +static bool cqi_send(uint32_t I_cqi_pmi, uint32_t tti, bool is_fdd) +{ + + uint32_t N_p = 0; uint32_t N_offset = 0; - if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset)) { - return false; + if (is_fdd) { + if (!cqi_get_N_fdd(I_cqi_pmi, &N_p, &N_offset)) { + return false; + } + } else { + if (!cqi_get_N_tdd(I_cqi_pmi, &N_p, &N_offset)) { + return false; + } } if (N_p) { if ((tti-N_offset)%N_p == 0) { - return true; - } + return true; + } } return false; } -bool srslte_ri_send(uint32_t I_cqi_pmi, uint32_t I_ri, uint32_t tti) { +static bool ri_send(uint32_t I_cqi_pmi, uint32_t I_ri, uint32_t tti, bool is_fdd) +{ - uint32_t M_ri = 0; - uint32_t N_offset_ri = 0; - uint32_t N_p = 0; - uint32_t N_offset_p = 0; + uint32_t M_ri = 0; + int N_offset_ri = 0; + uint32_t N_p = 0; + uint32_t N_offset_p = 0; - if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset_p)) { - return false; + if (is_fdd) { + if (!cqi_get_N_fdd(I_cqi_pmi, &N_p, &N_offset_p)) { + return false; + } + } else { + if (!cqi_get_N_tdd(I_cqi_pmi, &N_p, &N_offset_p)) { + return false; + } } + // According to 3GPP 36.213 R10 Table 7.2.2-1B Mapping I_RI to M_RI and N_OFFSET_RI if (I_ri <= 160) { - M_ri = 1; - N_offset_ri = I_ri; - } else if (I_ri <= 161) { - M_ri = 2; - N_offset_ri = I_ri - 161; - } else if (I_ri <= 322) { - M_ri = 4; - N_offset_ri = I_ri - 322; - } else if (I_ri <= 483) { - M_ri = 8; - N_offset_ri = I_ri - 483; - } else if (I_ri <= 644) { - M_ri = 16; - N_offset_ri = I_ri - 644; - } else if (I_ri <= 805) { + M_ri = 1; + N_offset_ri = -I_ri; + } else if (I_ri <= 321) { + M_ri = 2; + N_offset_ri = -(I_ri - 161); + } else if (I_ri <= 482) { + M_ri = 4; + N_offset_ri = -(I_ri - 322); + } else if (I_ri <= 643) { + M_ri = 8; + N_offset_ri = -(I_ri - 483); + } else if (I_ri <= 804) { + M_ri = 16; + N_offset_ri = -(I_ri - 644); + } else if (I_ri <= 965) { M_ri = 32; - N_offset_ri = I_ri - 805; - } else if (I_ri <= 966) { + N_offset_ri = -(I_ri - 805); + } else { return false; } if (M_ri && N_p) { - if ((tti - N_offset_p + N_offset_ri) % (N_p * M_ri) == 0) { + if ((tti - N_offset_p - N_offset_ri) % (N_p * M_ri) == 0) { return true; } } return false; } +bool srslte_cqi_periodic_ri_send(srslte_cqi_report_cfg_t* cfg, uint32_t tti, srslte_frame_type_t frame_type) +{ + return cfg->periodic_configured && cfg->ri_idx_present && + ri_send(cfg->pmi_idx, cfg->ri_idx, tti, frame_type == SRSLTE_FDD); +} + +bool srslte_cqi_periodic_send(srslte_cqi_report_cfg_t* cfg, uint32_t tti, srslte_frame_type_t frame_type) +{ + return cfg->periodic_configured && cqi_send(cfg->pmi_idx, tti, frame_type == SRSLTE_FDD); +} // CQI-to-Spectral Efficiency: 36.213 Table 7.2.3-1 */ static float cqi_to_coderate[16] = {0, 0.1523, 0.2344, 0.3770, 0.6016, 0.8770, 1.1758, 1.4766, 1.9141, 2.4063, 2.7305, 3.3223, 3.9023, 4.5234, 5.1152, 5.5547}; @@ -507,7 +577,7 @@ uint8_t srslte_cqi_from_snr(float snr) * i.e., the number of RBs per subband as a function of the cell bandwidth * (Table 7.2.1-3 in TS 36.213) */ -int srslte_cqi_hl_get_subband_size(int nof_prb) +static int cqi_hl_get_subband_size(int nof_prb) { if (nof_prb < 7) { return 0; @@ -527,7 +597,7 @@ int srslte_cqi_hl_get_subband_size(int nof_prb) */ int srslte_cqi_hl_get_no_subbands(int nof_prb) { - int hl_size = srslte_cqi_hl_get_subband_size(nof_prb); + int hl_size = cqi_hl_get_subband_size(nof_prb); if (hl_size > 0) { return (int)ceil((float)nof_prb/hl_size); } else { diff --git a/lib/src/phy/phch/dci.c b/lib/src/phy/phch/dci.c index 0a950b001..1623d7c87 100644 --- a/lib/src/phy/phch/dci.c +++ b/lib/src/phy/phch/dci.c @@ -32,201 +32,78 @@ #include #include #include -#include -#include "srslte/phy/phch/dci.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/dci.h" #include "srslte/phy/utils/bit.h" -#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" -#include "dci_sz_table.h" - -#define HARQ_PID_LEN 3 +#define IS_TDD (cell->frame_type == SRSLTE_TDD) +#define IS_TDD_CFG0 (IS_TDD && (sf->tdd_config.sf_config == 0)) +#define HARQ_PID_LEN ((IS_TDD | IS_TDD_CFG0) ? 4 : 3) -/* Unpacks a DCI message and configures the DL grant object - */ -int srslte_dci_msg_to_dl_grant(srslte_dci_msg_t *msg, uint16_t msg_rnti, - uint32_t nof_prb, uint32_t nof_ports, - srslte_ra_dl_dci_t *dl_dci, - srslte_ra_dl_grant_t *grant) +/* Unpack RAR UL dci as defined in Section 6.2 of 36.213 */ +void srslte_dci_rar_unpack(uint8_t payload[SRSLTE_RAR_GRANT_LEN], srslte_dci_rar_grant_t* rar) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (msg != NULL && - grant != NULL) - { - ret = SRSLTE_ERROR; - - bzero(dl_dci, sizeof(srslte_ra_dl_dci_t)); - bzero(grant, sizeof(srslte_ra_dl_grant_t)); - - bool crc_is_crnti = false; - if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { - crc_is_crnti = true; - } - //srslte_dci_format_t tmp = msg->format; - ret = srslte_dci_msg_unpack_pdsch(msg, dl_dci, nof_prb, nof_ports, crc_is_crnti); - if (ret) { - //fprintf(stderr, "Can't unpack DCI message %s (%d)\n", srslte_dci_format_string(msg->format), msg->format); - return ret; - } - - if (!dl_dci->is_ra_order) { - if (srslte_ra_dl_dci_to_grant(dl_dci, nof_prb, msg_rnti, grant)) { - return ret; - } - - if (SRSLTE_VERBOSE_ISINFO()) { - srslte_ra_pdsch_fprint(stdout, dl_dci, nof_prb); - srslte_ra_dl_grant_fprint(stdout, grant); - } - } + uint8_t* ptr = payload; + rar->hopping_flag = srslte_bit_pack(&ptr, 1) ? true : false; + rar->rba = srslte_bit_pack(&ptr, 10); + rar->trunc_mcs = srslte_bit_pack(&ptr, 4); + rar->tpc_pusch = srslte_bit_pack(&ptr, 3); + rar->ul_delay = srslte_bit_pack(&ptr, 1) ? true : false; + rar->cqi_request = srslte_bit_pack(&ptr, 1) ? true : false; +} - ret = SRSLTE_SUCCESS; - } - return ret; +/* Pack RAR UL dci as defined in Section 6.2 of 36.213 */ +void srslte_dci_rar_pack(srslte_dci_rar_grant_t* rar, uint8_t payload[SRSLTE_RAR_GRANT_LEN]) +{ + uint8_t* ptr = payload; + srslte_bit_unpack(rar->hopping_flag ? 1 : 0, &ptr, 1); + srslte_bit_unpack(rar->rba, &ptr, 10); + srslte_bit_unpack(rar->trunc_mcs, &ptr, 4); + srslte_bit_unpack(rar->tpc_pusch, &ptr, 3); + srslte_bit_unpack(rar->ul_delay ? 1 : 0, &ptr, 1); + srslte_bit_unpack(rar->cqi_request ? 1 : 0, &ptr, 1); } -/* Creates the UL PUSCH resource allocation grant from the random access respone message +/* Creates an equivalent DCI UL grant from the random access respone message */ -int srslte_dci_rar_to_ul_grant(srslte_dci_rar_grant_t *rar, uint32_t nof_prb, - uint32_t n_rb_ho, - srslte_ra_ul_dci_t *ul_dci, - srslte_ra_ul_grant_t *grant) +int srslte_dci_rar_to_ul_dci(srslte_cell_t* cell, srslte_dci_rar_grant_t* rar, srslte_dci_ul_t* dci_ul) { - bzero(ul_dci, sizeof(srslte_ra_ul_dci_t)); - + bzero(dci_ul, sizeof(srslte_dci_ul_t)); + if (!rar->hopping_flag) { - ul_dci->freq_hop_fl = SRSLTE_RA_PUSCH_HOP_DISABLED; + dci_ul->freq_hop_fl = SRSLTE_RA_PUSCH_HOP_DISABLED; } else { - fprintf(stderr, "FIXME: Frequency hopping in RAR not implemented\n"); - ul_dci->freq_hop_fl = 1; + ERROR("FIXME: Frequency hopping in RAR not implemented\n"); + dci_ul->freq_hop_fl = 1; } - uint32_t riv = rar->rba; - // Truncate resource block assignment + uint32_t riv = rar->rba; + // Truncate resource block assignment uint32_t b = 0; - if (nof_prb <= 44) { - b = (uint32_t) (ceilf(log2((float) nof_prb*(nof_prb+1)/2))); - riv = riv & ((1<<(b+1))-1); + if (cell->nof_prb <= 44) { + b = (uint32_t)(ceilf(log2((float)cell->nof_prb * (cell->nof_prb + 1) / 2))); + riv = riv & ((1 << (b + 1)) - 1); } - ul_dci->type2_alloc.riv = riv; - ul_dci->mcs_idx = rar->trunc_mcs; + dci_ul->type2_alloc.riv = riv; + dci_ul->tb.mcs_idx = rar->trunc_mcs; + dci_ul->tb.rv = -1; + dci_ul->dai = 3; - srslte_ra_type2_from_riv(riv, &ul_dci->type2_alloc.L_crb, &ul_dci->type2_alloc.RB_start, - nof_prb, nof_prb); - - if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant)) { - return SRSLTE_ERROR; - } - - if (SRSLTE_VERBOSE_ISINFO()) { - srslte_ra_pusch_fprint(stdout, ul_dci, nof_prb); - srslte_ra_ul_grant_fprint(stdout, grant); - } return SRSLTE_SUCCESS; } -/* Unpack RAR UL grant as defined in Section 6.2 of 36.213 */ -void srslte_dci_rar_grant_unpack(srslte_dci_rar_grant_t *rar, uint8_t grant[SRSLTE_RAR_GRANT_LEN]) -{ - uint8_t *grant_ptr = grant; - rar->hopping_flag = srslte_bit_pack(&grant_ptr, 1)?true:false; - rar->rba = srslte_bit_pack(&grant_ptr, 10); - rar->trunc_mcs = srslte_bit_pack(&grant_ptr, 4); - rar->tpc_pusch = srslte_bit_pack(&grant_ptr, 3); - rar->ul_delay = srslte_bit_pack(&grant_ptr, 1)?true:false; - rar->cqi_request = srslte_bit_pack(&grant_ptr, 1)?true:false; -} - -/* Pack RAR UL grant as defined in Section 6.2 of 36.213 */ -void srslte_dci_rar_grant_pack(srslte_dci_rar_grant_t *rar, uint8_t grant[SRSLTE_RAR_GRANT_LEN]) -{ - uint8_t *grant_ptr = grant; - srslte_bit_unpack(rar->hopping_flag?1:0, &grant_ptr, 1); - srslte_bit_unpack(rar->rba, &grant_ptr, 10); - srslte_bit_unpack(rar->trunc_mcs, &grant_ptr, 4); - srslte_bit_unpack(rar->tpc_pusch, &grant_ptr, 3); - srslte_bit_unpack(rar->ul_delay?1:0, &grant_ptr, 1); - srslte_bit_unpack(rar->cqi_request?1:0, &grant_ptr, 1); -} - -void srslte_dci_rar_grant_fprint(FILE *stream, srslte_dci_rar_grant_t *rar) { - fprintf(stream, "RBA: %d, MCS: %d, TPC: %d, Hopping=%s, UL-Delay=%s, CQI=%s\n", - rar->rba, rar->trunc_mcs, rar->tpc_pusch, - rar->hopping_flag?"yes":"no", - rar->ul_delay?"yes":"no", - rar->cqi_request?"yes":"no" - ); -} - -/* Creates the UL PUSCH resource allocation grant from a DCI format 0 message - */ -int srslte_dci_msg_to_ul_grant(srslte_dci_msg_t *msg, uint32_t nof_prb, - uint32_t n_rb_ho, - srslte_ra_ul_dci_t *ul_dci, - srslte_ra_ul_grant_t *grant, uint32_t harq_pid) +static uint32_t riv_nbits(uint32_t nof_prb) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (msg != NULL && - ul_dci != NULL && - grant != NULL) - { - ret = SRSLTE_ERROR; - - bzero(ul_dci, sizeof(srslte_ra_ul_dci_t)); - bzero(grant, sizeof(srslte_ra_ul_grant_t)); - - if (srslte_dci_msg_unpack_pusch(msg, ul_dci, nof_prb)) { - return ret; - } - - if (srslte_ra_ul_dci_to_grant(ul_dci, nof_prb, n_rb_ho, grant)) { - return ret; - } - - if (SRSLTE_VERBOSE_ISINFO()) { - srslte_ra_pusch_fprint(stdout, ul_dci, nof_prb); - srslte_ra_ul_grant_fprint(stdout, grant); - } - - ret = SRSLTE_SUCCESS; - } - return ret; -} - -int srslte_dci_location_set(srslte_dci_location_t *c, uint32_t L, uint32_t nCCE) { - if (L <= 3) { - c->L = L; - } else { - fprintf(stderr, "Invalid L %d\n", L); - return SRSLTE_ERROR; - } - if (nCCE <= 87) { - c->ncce = nCCE; - } else { - fprintf(stderr, "Invalid nCCE %d\n", nCCE); - return SRSLTE_ERROR; - } - return SRSLTE_SUCCESS; -} - -bool srslte_dci_location_isvalid(srslte_dci_location_t *c) { - if (c->L <= 3 && c->ncce <= 87) { - return true; - } else { - return false; - } -} - -uint32_t riv_nbits(uint32_t nof_prb) { return (uint32_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); } const uint32_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; -bool is_ambiguous_size(uint32_t size) { +static bool is_ambiguous_size(uint32_t size) +{ int i; for (i = 0; i < 10; i++) { if (size == ambiguous_sizes[i]) { @@ -239,14 +116,87 @@ bool is_ambiguous_size(uint32_t size) { /********************************** * PAYLOAD sizeof functions * ********************************/ -uint32_t dci_format0_sizeof_(uint32_t nof_prb) { - return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1; +static uint32_t dci_format0_sizeof_(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n = 0; + + /* Carrier indicator – 0 or 3 bits */ + n += (cfg->cif_enabled) ? 3 : 0; + + /* Flag for format0/format1A differentiation – 1 bit */ + n += 1; + + /* Frequency hopping flag – 1 bit */ + n += 1; + + /* Resource block assignment and hopping resource allocation */ + n += riv_nbits(cell->nof_prb); + + /* Modulation and coding scheme and redundancy version – 5 bits */ + n += 5; + + /* New data indicator – 1 bit */ + n += 1; + + /* TPC command for scheduled PUSCH – 2 bits */ + n += 2; + + /* Cyclic shift for DM RS and OCC index – 3 bits */ + n += 3; + + /* Downlink Assignment Index (DAI) or UL Index – 2 bits (TDD) */ + n += ((IS_TDD | IS_TDD_CFG0) ? 2 : 0); + + /* CSI request – 1 or 2 bits */ + n += (cfg->multiple_csi_request_enabled) ? 2 : 1; + + /* SRS request – 0 or 1 bit */ + n += (cfg->srs_request_enabled) ? 1 : 0; + + /* Resource allocation type – 1 bit (N^UL_RB ≤ N^DL_RB) */ + n += (cfg->ra_format_enabled) ? 1 : 0; + + return n; } -uint32_t dci_format1A_sizeof(uint32_t nof_prb) { - uint32_t n; - n = 1 + 1 + riv_nbits(nof_prb) + 5 + HARQ_PID_LEN + 1 + 2 + 2; - while (n < dci_format0_sizeof_(nof_prb)) { +static uint32_t dci_format1A_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n = 0; + + /* Carrier indicator – 0 or 3 bits */ + n += (cfg->cif_enabled) ? 3 : 0; + + /* Flag for format0/format1A differentiation – 1 bit */ + n += 1; + + /* Localized/Distributed VRB assignment flag – 1 bit */ + n += 1; + + /* Resource block assignment */ + n += riv_nbits(cell->nof_prb); + + /* Modulation and coding scheme and redundancy version – 5 bits */ + n += 5; + + /* HARQ process number – 3 bits (FDD) , 4 bits (TDD) */ + n += HARQ_PID_LEN; + + /* New data indicator – 1 bit */ + n += 1; + + /* Redundancy version – 2 bits */ + n += 2; + + /* TPC command for PUCCH – 2 bits */ + n += 2; + + /* Downlink Assignment Index – 2 bits (TDD) */ + n += (IS_TDD ? 2 : 0); + + /* SRS request – 0 or 1 bit */ + n += (cfg->srs_request_enabled ? 1 : 0); + + while (n < dci_format0_sizeof_(cell, sf, cfg)) { n++; } if (is_ambiguous_size(n)) { @@ -255,74 +205,82 @@ uint32_t dci_format1A_sizeof(uint32_t nof_prb) { return n; } -uint32_t dci_format0_sizeof(uint32_t nof_prb) { - uint32_t n = dci_format0_sizeof_(nof_prb); - while (n < dci_format1A_sizeof(nof_prb)) { +static uint32_t dci_format0_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n = dci_format0_sizeof_(cell, sf, cfg); + while (n < dci_format1A_sizeof(cell, sf, cfg)) { n++; } return n; } -uint32_t dci_format1_sizeof(uint32_t nof_prb) { +static uint32_t dci_format1_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb)) + 5 + HARQ_PID_LEN + 1 + 2 - + 2; - if (nof_prb > 10) { + uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srslte_ra_type0_P(cell->nof_prb)) + 5 + HARQ_PID_LEN + 1 + 2 + 2 + + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0); + if (cell->nof_prb > 10) { n++; } - while (n == dci_format0_sizeof(nof_prb) || n == dci_format1A_sizeof(nof_prb) - || is_ambiguous_size(n)) { + while (n == dci_format0_sizeof(cell, sf, cfg) || n == dci_format1A_sizeof(cell, sf, cfg) || is_ambiguous_size(n)) { n++; } return n; } -uint32_t dci_format1C_sizeof(uint32_t nof_prb) { - uint32_t n_vrb_dl_gap1 = srslte_ra_type2_n_vrb_dl(nof_prb, true); - uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb); +static uint32_t dci_format1C_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n_vrb_dl_gap1 = srslte_ra_type2_n_vrb_dl(cell->nof_prb, true); + uint32_t n_step = srslte_ra_type2_n_rb_step(cell->nof_prb); uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5; - if (nof_prb >= 50) { + if (cell->nof_prb >= 50) { n++; } return n; } -// Number of TPMI bits -uint32_t tpmi_bits(uint32_t nof_ports) { +// Number of TPMI bits +static uint32_t tpmi_bits(uint32_t nof_ports) +{ if (nof_ports <= 2) { - return 2; + return 2; } else { return 4; } } -uint32_t dci_format1B_sizeof(uint32_t nof_prb, uint32_t nof_ports) { +static uint32_t dci_format1B_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ // same as format1A minus the differentiation bit plus TPMI + PMI - uint32_t n = dci_format1A_sizeof(nof_prb)-1+tpmi_bits(nof_ports)+1; - + uint32_t n = dci_format1A_sizeof(cell, sf, cfg) - 1 + tpmi_bits(cell->nof_ports) + 1 + (IS_TDD ? 2 : 0); + while (is_ambiguous_size(n)) { n++; } return n; } -uint32_t dci_format1D_sizeof(uint32_t nof_prb, uint32_t nof_ports) { +static uint32_t dci_format1D_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ // same size as format1B - return dci_format1B_sizeof(nof_prb, nof_ports); + return dci_format1B_sizeof(cell, sf, cfg); } // Number of bits for precoding information -uint32_t precoding_bits_f2(uint32_t nof_ports) { +static uint32_t precoding_bits_f2(uint32_t nof_ports) +{ if (nof_ports <= 2) { - return 3; + return 3; } else { return 6; } } -uint32_t dci_format2_sizeof(uint32_t nof_prb, uint32_t nof_ports) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+HARQ_PID_LEN+1+2*(5+1+2)+precoding_bits_f2(nof_ports); - if (nof_prb > 10) { +static uint32_t dci_format2_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srslte_ra_type0_P(cell->nof_prb)) + 2 + HARQ_PID_LEN + 1 + + 2 * (5 + 1 + 2) + precoding_bits_f2(cell->nof_ports) + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0); + if (cell->nof_prb > 10) { n++; } while (is_ambiguous_size(n)) { @@ -332,7 +290,8 @@ uint32_t dci_format2_sizeof(uint32_t nof_prb, uint32_t nof_ports) { } // Number of bits for precoding information -uint32_t precoding_bits_f2a(uint32_t nof_ports) { +static uint32_t precoding_bits_f2a(uint32_t nof_ports) +{ if (nof_ports <= 2) { return 0; } else { @@ -340,9 +299,11 @@ uint32_t precoding_bits_f2a(uint32_t nof_ports) { } } -uint32_t dci_format2A_sizeof(uint32_t nof_prb, uint32_t nof_ports) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+HARQ_PID_LEN+1+2*(5+1+2)+precoding_bits_f2a(nof_ports); - if (nof_prb > 10) { +static uint32_t dci_format2A_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srslte_ra_type0_P(cell->nof_prb)) + 2 + HARQ_PID_LEN + 1 + + 2 * (5 + 1 + 2) + precoding_bits_f2a(cell->nof_ports) + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0); + if (cell->nof_prb > 10) { n++; } while (is_ambiguous_size(n)) { @@ -352,153 +313,64 @@ uint32_t dci_format2A_sizeof(uint32_t nof_prb, uint32_t nof_ports) { } -uint32_t dci_format2B_sizeof(uint32_t nof_prb, uint32_t nof_ports) { - uint32_t n = (uint32_t) ceilf((float) nof_prb / srslte_ra_type0_P(nof_prb))+2+HARQ_PID_LEN+1+2*(5+1+2); - if (nof_prb > 10) { +static uint32_t dci_format2B_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg) +{ + uint32_t n = (uint32_t)ceilf((float)cell->nof_prb / srslte_ra_type0_P(cell->nof_prb)) + 2 + HARQ_PID_LEN + 1 + + 2 * (5 + 1 + 2) + (cfg->cif_enabled ? 3 : 0) + (IS_TDD ? 2 : 0); + if (cell->nof_prb > 10) { n++; } while (is_ambiguous_size(n)) { n++; } return n; - } -uint32_t srslte_dci_dl_info(char *info_str, uint32_t len, srslte_ra_dl_dci_t *dci_msg, srslte_dci_format_t format) +uint32_t +srslte_dci_format_sizeof(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_format_t format) { - int n = 0; - - switch(dci_msg->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - n += snprintf(&info_str[n], len-n, "type0={rbg=0x%x}, ", dci_msg->type0_alloc.rbg_bitmask); - break; - case SRSLTE_RA_ALLOC_TYPE1: - n += snprintf(&info_str[n], len-n, "type1={vrb=0x%x, rbg_s=%d, sh=%d}, ", - dci_msg->type1_alloc.vrb_bitmask, dci_msg->type1_alloc.rbg_subset, dci_msg->type1_alloc.shift); - break; - case SRSLTE_RA_ALLOC_TYPE2: - n += snprintf(&info_str[n], len-n, "type2={riv=%d, rb=(%d,%d), mode=%s", - dci_msg->type2_alloc.riv, - dci_msg->type2_alloc.RB_start, dci_msg->type2_alloc.RB_start+dci_msg->type2_alloc.L_crb-1, - dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_LOC?"local":"dist"); - if (dci_msg->type2_alloc.mode==SRSLTE_RA_TYPE2_DIST) { - n += snprintf(&info_str[n], len-n, ", ngap=%s, nprb1a=%d", - dci_msg->type2_alloc.n_gap==SRSLTE_RA_TYPE2_NG1?"ng1":"ng2", - dci_msg->type2_alloc.n_prb1a==SRSLTE_RA_TYPE2_NPRB1A_2?2:3); - } - n += snprintf(&info_str[n], len-n, "}, "); - break; + srslte_dl_sf_cfg_t _sf; + if (sf == NULL) { + ZERO_OBJECT(_sf); + sf = &_sf; } - n += snprintf(&info_str[n], len-n, "pid=%d, ", dci_msg->harq_process); - - n += snprintf(&info_str[n], len-n, "mcs={"); - if (dci_msg->tb_en[0]) { - n += snprintf(&info_str[n], len-n, "%d", dci_msg->mcs_idx); - if (dci_msg->tb_en[1]) { - n += snprintf(&info_str[n], len-n, "/"); - } else { - n += snprintf(&info_str[n], len-n, "}, "); - } - } - if (dci_msg->tb_en[1]) { - n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->mcs_idx_1); - } - n += snprintf(&info_str[n], len-n, "rv={"); - if (dci_msg->tb_en[0]) { - n += snprintf(&info_str[n], len-n, "%d", dci_msg->rv_idx); - if (dci_msg->tb_en[1]) { - n += snprintf(&info_str[n], len-n, "/"); - } else { - n += snprintf(&info_str[n], len-n, "}, "); - } + srslte_dci_cfg_t _cfg; + if (cfg == NULL) { + ZERO_OBJECT(_cfg); + cfg = &_cfg; } - if (dci_msg->tb_en[1]) { - n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->rv_idx_1); - } - n += snprintf(&info_str[n], len-n, "ndi={"); - if (dci_msg->tb_en[0]) { - n += snprintf(&info_str[n], len-n, "%d", dci_msg->ndi); - if (dci_msg->tb_en[1]) { - n += snprintf(&info_str[n], len-n, "/"); - } else { - n += snprintf(&info_str[n], len-n, "}, "); - } - } - if (dci_msg->tb_en[1]) { - n += snprintf(&info_str[n], len - n, "%d}, ", dci_msg->ndi_1); - } - - if (format == SRSLTE_DCI_FORMAT1 || format == SRSLTE_DCI_FORMAT1A || format == SRSLTE_DCI_FORMAT1B || - format == SRSLTE_DCI_FORMAT2 || format == SRSLTE_DCI_FORMAT2A || format == SRSLTE_DCI_FORMAT2B) { - n += snprintf(&info_str[n], len-n, "tpc_pucch=%d, ", dci_msg->tpc_pucch); - } - if (format == SRSLTE_DCI_FORMAT2 || format == SRSLTE_DCI_FORMAT2A || format == SRSLTE_DCI_FORMAT2B) { - n += snprintf(&info_str[n], len-n, "tb_sw=%d, pinfo=%d, ", dci_msg->tb_cw_swap, dci_msg->pinfo); - } - return n; -} - -uint32_t srslte_dci_ul_info(char *info_str, uint32_t len, srslte_ra_ul_dci_t *dci_msg) -{ - int n = 0; - - n += snprintf(&info_str[n], len-n, "riv=%d, rb=(%d,%d), ", dci_msg->type2_alloc.riv, - dci_msg->type2_alloc.RB_start, dci_msg->type2_alloc.RB_start+dci_msg->type2_alloc.L_crb-1); - - switch(dci_msg->freq_hop_fl) { - case SRSLTE_RA_PUSCH_HOP_DISABLED: - n += snprintf(&info_str[n], len-n, "f_h=n/a, "); - break; - default: - n += snprintf(&info_str[n], len-n, "f_h=%d, ", dci_msg->freq_hop_fl); - break; - } - n += snprintf(&info_str[n], len-n, "mcs=%d, rv=%d, ndi=%d, ", dci_msg->mcs_idx, dci_msg->rv_idx, dci_msg->ndi); - n += snprintf(&info_str[n], len-n, "tpc_pusch=%d, dmrs_cs=%d, cqi=%s, ", - dci_msg->tpc_pusch, dci_msg->n_dmrs, dci_msg->cqi_request?"yes":"no"); - - return n; -} -uint32_t srslte_dci_format_sizeof(srslte_dci_format_t format, uint32_t nof_prb, uint32_t nof_ports) { switch (format) { - case SRSLTE_DCI_FORMAT0: - return dci_format0_sizeof(nof_prb); - case SRSLTE_DCI_FORMAT1: - return dci_format1_sizeof(nof_prb); - case SRSLTE_DCI_FORMAT1A: - return dci_format1A_sizeof(nof_prb); - case SRSLTE_DCI_FORMAT1C: - return dci_format1C_sizeof(nof_prb); - case SRSLTE_DCI_FORMAT1B: - return dci_format1B_sizeof(nof_prb, nof_ports); - case SRSLTE_DCI_FORMAT1D: - return dci_format1D_sizeof(nof_prb, nof_ports); - case SRSLTE_DCI_FORMAT2: - return dci_format2_sizeof(nof_prb, nof_ports); - case SRSLTE_DCI_FORMAT2A: - return dci_format2A_sizeof(nof_prb, nof_ports); - case SRSLTE_DCI_FORMAT2B: - return dci_format2B_sizeof(nof_prb, nof_ports); - /* - case SRSLTE_DCI_FORMAT3: - return dci_format3_sizeof(nof_prb); - case SRSLTE_DCI_FORMAT3A: - return dci_format3A_sizeof(nof_prb); - */ - default: - printf("Error computing DCI bits: Unknown format %d\n", format); - return 0; + case SRSLTE_DCI_FORMAT0: + return dci_format0_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT1: + return dci_format1_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT1A: + return dci_format1A_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT1C: + return dci_format1C_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT1B: + return dci_format1B_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT1D: + return dci_format1D_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT2: + return dci_format2_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT2A: + return dci_format2A_sizeof(cell, sf, cfg); + case SRSLTE_DCI_FORMAT2B: + return dci_format2B_sizeof(cell, sf, cfg); + /* + case SRSLTE_DCI_FORMAT3: + return dci_format3_sizeof(nof_prb); + case SRSLTE_DCI_FORMAT3A: + return dci_format3A_sizeof(nof_prb); + */ + default: + printf("Error computing DCI bits: Unknown format %d\n", format); + return 0; } } -uint32_t srslte_dci_format_sizeof_lut(srslte_dci_format_t format, uint32_t nof_prb) { - if (nof_prb < 101 && format < 4) { - return dci_sz_table[nof_prb][format]; - } else { - return 0; - } -} /********************************** * DCI Resource Allocation functions * ********************************/ @@ -508,113 +380,133 @@ uint32_t srslte_dci_format_sizeof_lut(srslte_dci_format_t format, uint32_t nof_p * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_pack(srslte_ra_ul_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) { +static int dci_format0_pack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_ul_t* dci, srslte_dci_msg_t* msg) +{ /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; uint32_t n_ul_hop; + if (dci->cif_present) { + srslte_bit_unpack(dci->cif, &y, 3); + } + *y++ = 0; // format differentiation - if (data->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED) { // frequency hopping + if (dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED) { // frequency hopping *y++ = 0; n_ul_hop = 0; } else { *y++ = 1; - if (nof_prb < 50) { + if (cell->nof_prb < 50) { n_ul_hop = 1; // Table 8.4-1 of 36.213 - *y++ = data->freq_hop_fl & 1; + *y++ = dci->freq_hop_fl & 1; } else { n_ul_hop = 2; // Table 8.4-1 of 36.213 - *y++ = (data->freq_hop_fl & 2) >> 1; - *y++ = data->freq_hop_fl & 1; + *y++ = (dci->freq_hop_fl & 2) >> 1; + *y++ = dci->freq_hop_fl & 1; } } /* pack RIV according to 8.1 of 36.213 */ - uint32_t riv; - if (data->type2_alloc.L_crb) { - riv = srslte_ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, - nof_prb); - } else { - riv = data->type2_alloc.riv; - } + uint32_t riv = dci->type2_alloc.riv; - srslte_bit_unpack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); + srslte_bit_unpack(riv, &y, riv_nbits(cell->nof_prb) - n_ul_hop); /* pack MCS according to 8.6.1 of 36.213 */ - srslte_bit_unpack(data->mcs_idx, &y, 5); + srslte_bit_unpack(dci->tb.mcs_idx, &y, 5); - *y++ = data->ndi; + *y++ = dci->tb.ndi; - // TCP command for PUSCH - srslte_bit_unpack(data->tpc_pusch, &y, 2); + // TCP command for PUSCH + srslte_bit_unpack(dci->tpc_pusch, &y, 2); // DM RS not implemented - srslte_bit_unpack(data->n_dmrs, &y, 3); + srslte_bit_unpack(dci->n_dmrs, &y, 3); // CQI request - *y++ = data->cqi_request; + *y++ = dci->cqi_request; // Padding with zeros - uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1); - while (y - msg->data < n) { + uint32_t n = srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT0); + while (y - msg->payload < n) { *y++ = 0; } - msg->nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->payload); return SRSLTE_SUCCESS; } + /* Unpacks DCI format 0 data and store result in msg according * to 36.212 5.3.3.1.1 * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_unpack(srslte_dci_msg_t *msg, srslte_ra_ul_dci_t *data, uint32_t nof_prb) { +static int dci_format0_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_ul_t* dci) +{ /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; uint32_t n_ul_hop; /* Make sure it's a SRSLTE_DCI_FORMAT0 message */ - if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1)) { - fprintf(stderr, "Invalid message length for format 0\n"); + uint32_t msg_len = srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT0); + if (msg->nof_bits != msg_len) { + ERROR("Invalid message length for format 0 (%d != %d)\n", msg->nof_bits, msg_len); return SRSLTE_ERROR; } + + if (cfg->cif_enabled) { + dci->cif = srslte_bit_pack(&y, 3); + dci->cif_present = true; + } + if (*y++ != 0) { INFO("DCI message is Format1A\n"); return SRSLTE_ERROR; } + + // Update DCI format + msg->format = SRSLTE_DCI_FORMAT0; + if (*y++ == 0) { - data->freq_hop_fl = SRSLTE_RA_PUSCH_HOP_DISABLED; - n_ul_hop = 0; + dci->freq_hop_fl = SRSLTE_RA_PUSCH_HOP_DISABLED; + n_ul_hop = 0; } else { - if (nof_prb < 50) { - n_ul_hop = 1; // Table 8.4-1 of 36.213 - data->freq_hop_fl = *y++; + if (cell->nof_prb < 50) { + n_ul_hop = 1; // Table 8.4-1 of 36.213 + dci->freq_hop_fl = *y++; } else { n_ul_hop = 2; // Table 8.4-1 of 36.213 - data->freq_hop_fl = y[0] << 1 | y[1]; + dci->freq_hop_fl = y[0] << 1 | y[1]; y += 2; } } /* unpack RIV according to 8.1 of 36.213 */ - uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - n_ul_hop); - srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, - nof_prb, nof_prb); - data->type2_alloc.riv = riv; + uint32_t riv = srslte_bit_pack(&y, riv_nbits(cell->nof_prb) - n_ul_hop); + dci->type2_alloc.riv = riv; /* unpack MCS according to 8.6 of 36.213 */ - data->mcs_idx = srslte_bit_pack(&y, 5); - - data->ndi = *y++ ? true : false; + dci->tb.mcs_idx = srslte_bit_pack(&y, 5); + dci->tb.ndi = *y++ ? true : false; // TPC command for scheduled PUSCH - data->tpc_pusch = srslte_bit_pack(&y, 2); - + dci->tpc_pusch = srslte_bit_pack(&y, 2); + // Cyclic shift for DMRS - data->n_dmrs = srslte_bit_pack(&y, 3); - + dci->n_dmrs = srslte_bit_pack(&y, 3); + + // TDD fields + if (IS_TDD_CFG0) { + dci->ul_idx = srslte_bit_pack(&y, 2); + dci->is_tdd = true; + } else if (IS_TDD) { + dci->dai = srslte_bit_pack(&y, 2); + dci->is_tdd = true; + } + // CQI request - data->cqi_request = *y++ ? true : false; + dci->cqi_request = *y++ ? true : false; return SRSLTE_SUCCESS; } @@ -625,107 +517,124 @@ int dci_format0_unpack(srslte_dci_msg_t *msg, srslte_ra_ul_dci_t *data, uint32_t * TODO: TPC commands */ -int dci_format1_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) { +static int dci_format1_pack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_dl_t* dci, srslte_dci_msg_t* msg) +{ + uint32_t nof_prb = cell->nof_prb; /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; + + if (dci->cif_present) { + srslte_bit_unpack(dci->cif, &y, 3); + } if (nof_prb > 10) { - *y++ = data->alloc_type; + *y++ = dci->alloc_type; } /* Resource allocation: type0 or type 1 */ uint32_t P = srslte_ra_type0_P(nof_prb); - uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); - switch (data->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - srslte_bit_unpack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size); - break; - case SRSLTE_RA_ALLOC_TYPE1: - srslte_bit_unpack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); - *y++ = data->type1_alloc.shift ? 1 : 0; - srslte_bit_unpack((uint32_t) data->type1_alloc.vrb_bitmask, &y, - alloc_size - (int) ceilf(log2f(P)) - 1); - break; - default: - fprintf(stderr, - "Format 1 accepts type0 or type1 resource allocation only\n"); - return SRSLTE_ERROR; - + uint32_t alloc_size = (uint32_t)ceilf((float)nof_prb / P); + switch (dci->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + srslte_bit_unpack((uint32_t)dci->type0_alloc.rbg_bitmask, &y, alloc_size); + break; + case SRSLTE_RA_ALLOC_TYPE1: + srslte_bit_unpack((uint32_t)dci->type1_alloc.rbg_subset, &y, (int)ceilf(log2f(P))); + *y++ = dci->type1_alloc.shift ? 1 : 0; + srslte_bit_unpack((uint32_t)dci->type1_alloc.vrb_bitmask, &y, alloc_size - (int)ceilf(log2f(P)) - 1); + break; + default: + ERROR("Format 1 accepts type0 or type1 resource allocation only\n"); + return SRSLTE_ERROR; } /* pack MCS */ - srslte_bit_unpack(data->mcs_idx, &y, 5); + srslte_bit_unpack(dci->tb[0].mcs_idx, &y, 5); /* harq process number */ - srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); + srslte_bit_unpack(dci->pid, &y, HARQ_PID_LEN); - *y++ = data->ndi; + *y++ = dci->tb[0].ndi; // rv version - srslte_bit_unpack(data->rv_idx, &y, 2); + srslte_bit_unpack(dci->tb[0].rv, &y, 2); - // TCP command for PUCCH - srslte_bit_unpack(data->tpc_pucch, &y, 2); + // TCP command for PUCCH + srslte_bit_unpack(dci->tpc_pucch, &y, 2); - // Padding with zeros - uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1); - while (y - msg->data < n) { + uint32_t n = srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT1); + while (y - msg->payload < n) { *y++ = 0; } - msg->nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->payload); + + if (msg->nof_bits != dci_format1_sizeof(cell, sf, cfg)) { + ERROR("Invalid message length for format 1A (Cross scheduling %s)\n", dci->cif_present ? "enabled" : "disabled"); + } return SRSLTE_SUCCESS; } -int dci_format1_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb) { +static int dci_format1_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) +{ /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; /* Make sure it's a SRSLTE_DCI_FORMAT1 message */ - if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1)) { - fprintf(stderr, "Invalid message length for format 1\n"); + uint32_t msg_len = srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT1); + if (msg->nof_bits != msg_len) { + ERROR("Invalid message length (%d!=%d) for format 1\n", msg->nof_bits, msg_len); return SRSLTE_ERROR; } - if (nof_prb > 10) { - data->alloc_type = *y++; + if (cfg->cif_enabled) { + dci->cif = srslte_bit_pack(&y, 3); + dci->cif_present = true; + } + + if (cell->nof_prb > 10) { + dci->alloc_type = *y++; } else { - data->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; } /* Resource allocation: type0 or type 1 */ - uint32_t P = srslte_ra_type0_P(nof_prb); - uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); - switch (data->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - data->type0_alloc.rbg_bitmask = srslte_bit_pack(&y, alloc_size); - break; - case SRSLTE_RA_ALLOC_TYPE1: - data->type1_alloc.rbg_subset = srslte_bit_pack(&y, (int) ceilf(log2f(P))); - data->type1_alloc.shift = *y++ ? true : false; - data->type1_alloc.vrb_bitmask = srslte_bit_pack(&y, - alloc_size - (int) ceilf(log2f(P)) - 1); - break; - default: - fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); - return SRSLTE_ERROR; - + uint32_t P = srslte_ra_type0_P(cell->nof_prb); + uint32_t alloc_size = (uint32_t)ceilf((float)cell->nof_prb / P); + switch (dci->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + dci->type0_alloc.rbg_bitmask = srslte_bit_pack(&y, alloc_size); + break; + case SRSLTE_RA_ALLOC_TYPE1: + dci->type1_alloc.rbg_subset = srslte_bit_pack(&y, (int)ceilf(log2f(P))); + dci->type1_alloc.shift = *y++ ? true : false; + dci->type1_alloc.vrb_bitmask = srslte_bit_pack(&y, alloc_size - (int)ceilf(log2f(P)) - 1); + break; + default: + ERROR("Format 1 accepts type0 or type1 resource allocation only\n"); + return SRSLTE_ERROR; } /* unpack MCS according to 7.1.7 of 36.213 */ - data->mcs_idx = srslte_bit_pack(&y, 5); - + dci->tb[0].mcs_idx = srslte_bit_pack(&y, 5); + /* harq process number */ - data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); + dci->pid = srslte_bit_pack(&y, HARQ_PID_LEN); - data->ndi = *y++ ? true : false; + dci->tb[0].ndi = *y++ ? true : false; // rv version - data->rv_idx = srslte_bit_pack(&y, 2); - - // TPC not implemented - - data->tb_en[0] = true; - data->tb_en[1] = false; + dci->tb[0].rv = srslte_bit_pack(&y, 2); + + // TPC PUCCH + dci->tpc_pucch = srslte_bit_pack(&y, 2); + + // TDD + if (IS_TDD) { + dci->dai = srslte_bit_pack(&y, 2); + dci->is_tdd = true; + } return SRSLTE_SUCCESS; } @@ -734,120 +643,104 @@ int dci_format1_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t * * TODO: RA procedure initiated by PDCCH, TPC commands */ -int dci_format1As_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb, - bool crc_is_crnti) { +static int dci_format1As_pack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_dl_t* dci, srslte_dci_msg_t* msg) +{ + uint32_t nof_prb = cell->nof_prb; /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; + if (dci->cif_present) { + srslte_bit_unpack(dci->cif, &y, 3); + } *y++ = 1; // format differentiation - if (data->alloc_type != SRSLTE_RA_ALLOC_TYPE2) { - fprintf(stderr, "Format 1A accepts type2 resource allocation only\n"); + if (dci->alloc_type != SRSLTE_RA_ALLOC_TYPE2) { + ERROR("Format 1A accepts type2 resource allocation only\n"); return SRSLTE_ERROR; } - - data->dci_is_1a = true; - *y++ = data->type2_alloc.mode; // localized or distributed VRB assignment + *y++ = dci->type2_alloc.mode; // localized or distributed VRB assignment - if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - if (data->type2_alloc.L_crb > nof_prb) { - fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", - data->type2_alloc.L_crb); - return SRSLTE_ERROR; - } - } else { - uint32_t n_vrb_dl; - if (crc_is_crnti && nof_prb > 50) { - n_vrb_dl = 16; - } else { - n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); - } - if (data->type2_alloc.L_crb > n_vrb_dl) { - fprintf(stderr, - "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", - data->type2_alloc.L_crb, n_vrb_dl); - return SRSLTE_ERROR; - } - } /* pack RIV according to 7.1.6.3 of 36.213 */ - uint32_t riv; - if (data->type2_alloc.L_crb) { - riv = srslte_ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, - nof_prb); - } else { - riv = data->type2_alloc.riv; - } + uint32_t riv = dci->type2_alloc.riv; uint32_t nb_gap = 0; - if (crc_is_crnti && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) { + if (SRSLTE_RNTI_ISUSER(dci->rnti) && dci->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) { nb_gap = 1; - *y++ = data->type2_alloc.n_gap; + *y++ = dci->type2_alloc.n_gap; } srslte_bit_unpack(riv, &y, riv_nbits(nof_prb) - nb_gap); // in format1A, MCS = TBS according to 7.1.7.2 of 36.213 - srslte_bit_unpack(data->mcs_idx, &y, 5); + srslte_bit_unpack(dci->tb[0].mcs_idx, &y, 5); - srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); + srslte_bit_unpack(dci->pid, &y, HARQ_PID_LEN); - if (crc_is_crnti) { - if (nof_prb >= 50 && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) { - *y++ = data->type2_alloc.n_gap; + if (SRSLTE_RNTI_ISUSER(dci->rnti)) { + if (nof_prb >= 50 && dci->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) { + *y++ = dci->type2_alloc.n_gap; } else { y++; // bit reserved } } else { - *y++ = data->ndi; + *y++ = dci->tb[0].ndi; } // rv version - srslte_bit_unpack(data->rv_idx, &y, 2); + srslte_bit_unpack(dci->tb[0].rv, &y, 2); - if (crc_is_crnti) { + if (SRSLTE_RNTI_ISUSER(dci->rnti)) { // TPC not implemented *y++ = 0; *y++ = 0; } else { y++; // MSB of TPC is reserved - *y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS + *y++ = dci->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS } // Padding with zeros - uint32_t n = srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1); - while (y - msg->data < n) { + uint32_t n = srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT1A); + while (y - msg->payload < n) { *y++ = 0; } - msg->nof_bits = (y - msg->data); - + msg->nof_bits = (y - msg->payload); + return SRSLTE_SUCCESS; } /* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 * */ -int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, - bool crc_is_crnti) { +static int dci_format1As_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) +{ /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; /* Make sure it's a SRSLTE_DCI_FORMAT0 message */ - if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1)) { - fprintf(stderr, "Invalid message length for format 1A\n"); + if (msg->nof_bits != srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT1A)) { + ERROR("Invalid message length for format 1A (Cross scheduling %s)\n", cfg->cif_enabled ? "enabled" : "disabled"); return SRSLTE_ERROR; } + if (cfg->cif_enabled) { + dci->cif = srslte_bit_pack(&y, 3); + dci->cif_present = true; + } + if (*y++ != 1) { INFO("DCI message is Format0\n"); return SRSLTE_ERROR; } - - data->dci_is_1a = true; - + + // Update DCI format + msg->format = SRSLTE_DCI_FORMAT1A; + // Check if RA procedure by PDCCH order if (*y == 0) { - int nof_bits = riv_nbits(nof_prb); + int nof_bits = riv_nbits(cell->nof_prb); int i=0; // Check all bits in RBA are set to 1 while(inof_bits-1 && y[i] == 0) { i++; } @@ -863,116 +756,112 @@ int dci_format1As_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32 // This is a Random access order y+=1+nof_bits; - data->is_ra_order = true; - data->ra_preamble = srslte_bit_pack(&y, 6); - data->ra_mask_idx = srslte_bit_pack(&y, 4); + dci->is_ra_order = true; + dci->ra_preamble = srslte_bit_pack(&y, 6); + dci->ra_mask_idx = srslte_bit_pack(&y, 4); return SRSLTE_SUCCESS; } } } - data->is_ra_order = false; + dci->is_ra_order = false; - data->alloc_type = SRSLTE_RA_ALLOC_TYPE2; - data->type2_alloc.mode = *y++; + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci->type2_alloc.mode = *y++; // by default, set N_gap to 1 - data->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1; + dci->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1; - /* unpack RIV according to 7.1.6.3 of 36.213 */ + /* unpack RIV */ uint32_t nb_gap = 0; - if (crc_is_crnti && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) { - nb_gap = 1; - data->type2_alloc.n_gap = *y++; + if (SRSLTE_RNTI_ISUSER(msg->rnti) && dci->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && cell->nof_prb >= 50) { + nb_gap = 1; + dci->type2_alloc.n_gap = *y++; } - uint32_t nof_vrb; - if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - nof_vrb = nof_prb; - } else { - nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); - } - uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - nb_gap); - srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, - nof_prb, nof_vrb); - data->type2_alloc.riv = riv; + uint32_t riv = srslte_bit_pack(&y, riv_nbits(cell->nof_prb) - nb_gap); + dci->type2_alloc.riv = riv; // unpack MCS - data->mcs_idx = srslte_bit_pack(&y, 5); + dci->tb[0].mcs_idx = srslte_bit_pack(&y, 5); - data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); + dci->pid = srslte_bit_pack(&y, HARQ_PID_LEN); - if (!crc_is_crnti) { - if (nof_prb >= 50 && data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) { - data->type2_alloc.n_gap = *y++; + if (!SRSLTE_RNTI_ISUSER(msg->rnti)) { + if (cell->nof_prb >= 50 && dci->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST) { + dci->type2_alloc.n_gap = *y++; } else { y++; // NDI reserved } } else { - data->ndi = *y++ ? true : false; + dci->tb[0].ndi = *y++ ? true : false; } // rv version - data->rv_idx = srslte_bit_pack(&y, 2); + dci->tb[0].rv = srslte_bit_pack(&y, 2); - if (crc_is_crnti) { + if (SRSLTE_RNTI_ISUSER(msg->rnti)) { // TPC not implemented y++; y++; } else { - y++; // MSB of TPC is reserved - data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS + y++; // MSB of TPC is reserved + dci->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS + } + + // TDD + if (IS_TDD) { + dci->dai = srslte_bit_pack(&y, 2); + dci->is_tdd = true; } - - data->tb_en[0] = true; - data->tb_en[1] = false; return SRSLTE_SUCCESS; } -int dci_format1B_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports) +static int dci_format1B_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) { /* pack bits */ - uint8_t *y = msg->data; - - data->alloc_type = SRSLTE_RA_ALLOC_TYPE2; - data->type2_alloc.mode = *y++; + uint8_t* y = msg->payload; + + if (cfg->cif_enabled) { + dci->cif = srslte_bit_pack(&y, 3); + dci->cif_present = true; + } + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci->type2_alloc.mode = *y++; // by default, set N_gap to 1 - data->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1; + dci->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1; /* unpack RIV according to 7.1.6.3 of 36.213 */ uint32_t nb_gap = 0; - if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) { - nb_gap = 1; - data->type2_alloc.n_gap = *y++; + if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && cell->nof_prb >= 50) { + nb_gap = 1; + dci->type2_alloc.n_gap = *y++; } - uint32_t nof_vrb; - if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - nof_vrb = nof_prb; - } else { - nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); - } - uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - nb_gap); - srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, - nof_prb, nof_vrb); - data->type2_alloc.riv = riv; - - // unpack MCS, Harq pid and ndi - data->mcs_idx = srslte_bit_pack(&y, 5); - data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); - data->ndi = *y++ ? true : false; - data->rv_idx = srslte_bit_pack(&y, 2); - - // Ignore TPC command for PUCCH - y += 2; - - data->pinfo = srslte_bit_pack(&y, tpmi_bits(nof_ports)); - data->pconf = *y++ ? true : false; + uint32_t riv = srslte_bit_pack(&y, riv_nbits(cell->nof_prb) - nb_gap); + dci->type2_alloc.riv = riv; + + // unpack MCS, Harq pid and ndi + dci->tb[0].mcs_idx = srslte_bit_pack(&y, 5); + dci->pid = srslte_bit_pack(&y, HARQ_PID_LEN); + dci->tb[0].ndi = *y++ ? true : false; + dci->tb[0].rv = srslte_bit_pack(&y, 2); + + // TPC PUCCH + dci->tpc_pucch = srslte_bit_pack(&y, 2); - data->tb_en[0] = true; - data->tb_en[1] = false; + // TDD + if (IS_TDD) { + dci->dai = srslte_bit_pack(&y, 2); + dci->is_tdd = true; + } + + dci->pinfo = srslte_bit_pack(&y, tpmi_bits(cell->nof_ports)); + dci->pconf = *y++ ? true : false; return SRSLTE_SUCCESS; } @@ -980,435 +869,482 @@ int dci_format1B_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_ /* Format 1C for compact scheduling of PDSCH words * */ -int dci_format1Cs_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) { +static int dci_format1Cs_pack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_dl_t* dci, srslte_dci_msg_t* msg) +{ + + uint32_t nof_prb = cell->nof_prb; /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; - if (data->alloc_type != SRSLTE_RA_ALLOC_TYPE2 || data->type2_alloc.mode != SRSLTE_RA_TYPE2_DIST) { - fprintf(stderr, - "Format 1C accepts distributed type2 resource allocation only\n"); + if (dci->cif_present) { + srslte_bit_unpack(dci->cif, &y, 3); + } + + if (dci->alloc_type != SRSLTE_RA_ALLOC_TYPE2 || dci->type2_alloc.mode != SRSLTE_RA_TYPE2_DIST) { + ERROR("Format 1C accepts distributed type2 resource allocation only\n"); return SRSLTE_ERROR; } - - data->dci_is_1c = true; if (nof_prb >= 50) { - *y++ = data->type2_alloc.n_gap; + *y++ = dci->type2_alloc.n_gap; } - uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb); - uint32_t n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); + uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb); + uint32_t n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); - if (data->type2_alloc.L_crb > ((uint32_t) n_vrb_dl / n_step) * n_step) { - fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", - data->type2_alloc.L_crb, ((uint32_t) n_vrb_dl / n_step) * n_step); - return SRSLTE_ERROR; - } - if (data->type2_alloc.L_crb % n_step) { - fprintf(stderr, "L_crb must be multiple of n_step\n"); - return SRSLTE_ERROR; - } - if (data->type2_alloc.RB_start % n_step) { - fprintf(stderr, "RB_start must be multiple of n_step\n"); - return SRSLTE_ERROR; - } - uint32_t L_p = data->type2_alloc.L_crb / n_step; - uint32_t RB_p = data->type2_alloc.RB_start / n_step; - uint32_t n_vrb_p = (int) n_vrb_dl / n_step; + uint32_t riv = dci->type2_alloc.riv; - uint32_t riv; - if (data->type2_alloc.L_crb) { - riv = srslte_ra_type2_to_riv(L_p, RB_p, n_vrb_p); - } else { - riv = data->type2_alloc.riv; - } - srslte_bit_unpack(riv, &y, riv_nbits((int) n_vrb_dl / n_step)); + srslte_bit_unpack(riv, &y, riv_nbits((int)n_vrb_dl / n_step)); // in format1C, MCS = TBS according to 7.1.7.2 of 36.213 - srslte_bit_unpack(data->mcs_idx, &y, 5); + srslte_bit_unpack(dci->tb[0].mcs_idx, &y, 5); - msg->nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->payload); return SRSLTE_SUCCESS; } -int dci_format1Cs_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb) { - uint32_t L_p, RB_p; - +static int dci_format1Cs_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) +{ /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; - if (msg->nof_bits != srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1C, nof_prb, 1)) { - fprintf(stderr, "Invalid message length for format 1C\n"); + if (msg->nof_bits != srslte_dci_format_sizeof(cell, sf, cfg, SRSLTE_DCI_FORMAT1C)) { + ERROR("Invalid message length for format 1C\n"); return SRSLTE_ERROR; } - - data->dci_is_1c = true; - - data->alloc_type = SRSLTE_RA_ALLOC_TYPE2; - data->type2_alloc.mode = SRSLTE_RA_TYPE2_DIST; - if (nof_prb >= 50) { - data->type2_alloc.n_gap = *y++; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci->type2_alloc.mode = SRSLTE_RA_TYPE2_DIST; + if (cell->nof_prb >= 50) { + dci->type2_alloc.n_gap = *y++; } - uint32_t n_step = srslte_ra_type2_n_rb_step(nof_prb); - uint32_t n_vrb_dl = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); + uint32_t n_step = srslte_ra_type2_n_rb_step(cell->nof_prb); + uint32_t n_vrb_dl = srslte_ra_type2_n_vrb_dl(cell->nof_prb, dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); - uint32_t riv = srslte_bit_pack(&y, riv_nbits((int) n_vrb_dl / n_step)); - uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step; + uint32_t riv = srslte_bit_pack(&y, riv_nbits((int)n_vrb_dl / n_step)); - srslte_ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); - data->type2_alloc.L_crb = L_p * n_step; - data->type2_alloc.RB_start = RB_p * n_step; - data->type2_alloc.riv = riv; + dci->type2_alloc.riv = riv; - data->mcs_idx = srslte_bit_pack(&y, 5); - - data->rv_idx = -1; // Get RV later - - msg->nof_bits = (y - msg->data); - - data->tb_en[0] = true; - data->tb_en[1] = false; + dci->tb[0].mcs_idx = srslte_bit_pack(&y, 5); + + dci->tb[0].rv = -1; // Get RV later + + msg->nof_bits = (y - msg->payload); return SRSLTE_SUCCESS; } -int dci_format1D_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports) +static int dci_format1D_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) { /* pack bits */ - uint8_t *y = msg->data; - - data->alloc_type = SRSLTE_RA_ALLOC_TYPE2; - data->type2_alloc.mode = *y++; + uint8_t* y = msg->payload; + + if (cfg->cif_enabled) { + dci->cif = srslte_bit_pack(&y, 3); + dci->cif_present = true; + } + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci->type2_alloc.mode = *y++; // by default, set N_gap to 1 - data->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1; + dci->type2_alloc.n_gap = SRSLTE_RA_TYPE2_NG1; /* unpack RIV according to 7.1.6.3 of 36.213 */ uint32_t nb_gap = 0; - if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && nof_prb >= 50) { - nb_gap = 1; - data->type2_alloc.n_gap = *y++; + if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_DIST && cell->nof_prb >= 50) { + nb_gap = 1; + dci->type2_alloc.n_gap = *y++; } - uint32_t nof_vrb; - if (data->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - nof_vrb = nof_prb; - } else { - nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); - } - uint32_t riv = srslte_bit_pack(&y, riv_nbits(nof_prb) - nb_gap); - srslte_ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, - nof_prb, nof_vrb); - data->type2_alloc.riv = riv; - - // unpack MCS, Harq pid and ndi - data->mcs_idx = srslte_bit_pack(&y, 5); - data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); - data->ndi = *y++ ? true : false; - data->rv_idx = srslte_bit_pack(&y, 2); - - // Ignore TPC command for PUCCH - y += 2; - - data->pinfo = srslte_bit_pack(&y, tpmi_bits(nof_ports)); - data->power_offset = *y++ ? true : false; - - data->tb_en[0] = true; - data->tb_en[1] = false; + + uint32_t riv = srslte_bit_pack(&y, riv_nbits(cell->nof_prb) - nb_gap); + dci->type2_alloc.riv = riv; + + // unpack MCS, Harq pid and ndi + dci->tb[0].mcs_idx = srslte_bit_pack(&y, 5); + dci->pid = srslte_bit_pack(&y, HARQ_PID_LEN); + dci->tb[0].ndi = *y++ ? true : false; + dci->tb[0].rv = srslte_bit_pack(&y, 2); + + // TPC PUCCH + dci->tpc_pucch = srslte_bit_pack(&y, 2); + + // TDD + if (IS_TDD) { + dci->dai = srslte_bit_pack(&y, 2); + dci->is_tdd = true; + } + + dci->pinfo = srslte_bit_pack(&y, tpmi_bits(cell->nof_ports)); + dci->power_offset = *y++ ? true : false; return SRSLTE_SUCCESS; } +static int dci_format2AB_pack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_dl_t* dci, srslte_dci_msg_t* msg) +{ -int dci_format2AB_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb, uint32_t nof_ports) { + uint32_t nof_prb = cell->nof_prb; + uint32_t nof_ports = cell->nof_ports; /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; + + if (dci->cif_present) { + srslte_bit_unpack(dci->cif, &y, 3); + } if (nof_prb > 10) { - *y++ = data->alloc_type; + *y++ = dci->alloc_type; } - + /* Resource allocation: type0 or type 1 */ - uint32_t P = srslte_ra_type0_P(nof_prb); + uint32_t P = srslte_ra_type0_P(nof_prb); uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); - switch (data->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - srslte_bit_unpack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size); - break; - case SRSLTE_RA_ALLOC_TYPE1: - srslte_bit_unpack((uint32_t) data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); - *y++ = data->type1_alloc.shift ? 1 : 0; - srslte_bit_unpack((uint32_t) data->type1_alloc.vrb_bitmask, &y, - alloc_size - (int) ceilf(log2f(P)) - 1); - break; - default: - fprintf(stderr, - "Format 1 accepts type0 or type1 resource allocation only\n"); - return SRSLTE_ERROR; - + switch (dci->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + srslte_bit_unpack((uint32_t)dci->type0_alloc.rbg_bitmask, &y, alloc_size); + break; + case SRSLTE_RA_ALLOC_TYPE1: + srslte_bit_unpack((uint32_t)dci->type1_alloc.rbg_subset, &y, (int)ceilf(log2f(P))); + *y++ = dci->type1_alloc.shift ? 1 : 0; + srslte_bit_unpack((uint32_t)dci->type1_alloc.vrb_bitmask, &y, alloc_size - (int)ceilf(log2f(P)) - 1); + break; + default: + ERROR("Format 1 accepts type0 or type1 resource allocation only\n"); + return SRSLTE_ERROR; } /* TCP command for PUCCH */ - srslte_bit_unpack(data->tpc_pucch, &y, 2); + srslte_bit_unpack(dci->tpc_pucch, &y, 2); /* harq process number */ - srslte_bit_unpack(data->harq_process, &y, HARQ_PID_LEN); - - // Transpor block to codeword swap flag + srslte_bit_unpack(dci->pid, &y, HARQ_PID_LEN); + + // Transpor block to codeword swap flag if (msg->format == SRSLTE_DCI_FORMAT2B) { - *y++ = data->sram_id; + *y++ = dci->sram_id; } else { - *y++ = data->tb_cw_swap; + *y++ = dci->tb_cw_swap; } - /* Force MCS_idx and RV_idx in function of block enable according to 7.1.7 of 36.213 */ - if (!data->tb_en[0]) { - data->mcs_idx = 0; - data->rv_idx= 1; - } - if (!data->tb_en[1]) { - data->mcs_idx_1 = 0; - data->rv_idx_1 = 1; - } - /* pack TB1 */ - srslte_bit_unpack(data->mcs_idx, &y, 5); - *y++ = data->ndi; - srslte_bit_unpack(data->rv_idx, &y, 2); + srslte_bit_unpack(dci->tb[0].mcs_idx, &y, 5); + *y++ = dci->tb[0].ndi; + srslte_bit_unpack(dci->tb[0].rv, &y, 2); /* pack TB2 */ - srslte_bit_unpack(data->mcs_idx_1, &y, 5); - *y++ = data->ndi_1; - srslte_bit_unpack(data->rv_idx_1, &y, 2); + srslte_bit_unpack(dci->tb[1].mcs_idx, &y, 5); + *y++ = dci->tb[1].ndi; + srslte_bit_unpack(dci->tb[1].rv, &y, 2); - // Precoding information + // Precoding information if (msg->format == SRSLTE_DCI_FORMAT2) { - srslte_bit_unpack(data->pinfo, &y, precoding_bits_f2(nof_ports)); + srslte_bit_unpack(dci->pinfo, &y, precoding_bits_f2(nof_ports)); } else if (msg->format == SRSLTE_DCI_FORMAT2A) { - srslte_bit_unpack(data->pinfo, &y, precoding_bits_f2a(nof_ports)); + srslte_bit_unpack(dci->pinfo, &y, precoding_bits_f2a(nof_ports)); } - // Padding with zeros - uint32_t n = srslte_dci_format_sizeof(msg->format, nof_prb, nof_ports); - while (y - msg->data < n) { + // Padding with zeros + uint32_t n = srslte_dci_format_sizeof(cell, sf, cfg, msg->format); + while (y - msg->payload < n) { *y++ = 0; } - msg->nof_bits = (y - msg->data); - - + msg->nof_bits = (y - msg->payload); return SRSLTE_SUCCESS; } -int dci_format2AB_unpack(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, uint32_t nof_prb, uint32_t nof_ports) { +static int dci_format2AB_unpack( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) +{ /* pack bits */ - uint8_t *y = msg->data; + uint8_t* y = msg->payload; - if (nof_prb > 10) { - data->alloc_type = *y++; + if (cfg->cif_enabled) { + dci->cif = srslte_bit_pack(&y, 3); + dci->cif_present = true; + } + + if (cell->nof_prb > 10) { + dci->alloc_type = *y++; } else { - data->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; } /* Resource allocation: type0 or type 1 */ - uint32_t P = srslte_ra_type0_P(nof_prb); - uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); - switch (data->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - data->type0_alloc.rbg_bitmask = srslte_bit_pack(&y, alloc_size); - break; - case SRSLTE_RA_ALLOC_TYPE1: - data->type1_alloc.rbg_subset = srslte_bit_pack(&y, (int) ceilf(log2f(P))); - data->type1_alloc.shift = *y++ ? true : false; - data->type1_alloc.vrb_bitmask = srslte_bit_pack(&y, - alloc_size - (int) ceilf(log2f(P)) - 1); - break; - default: - fprintf(stderr, "Format2 accepts type0 or type1 resource allocation only\n"); - return SRSLTE_ERROR; + uint32_t P = srslte_ra_type0_P(cell->nof_prb); + uint32_t alloc_size = (uint32_t)ceilf((float)cell->nof_prb / P); + switch (dci->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + dci->type0_alloc.rbg_bitmask = srslte_bit_pack(&y, alloc_size); + break; + case SRSLTE_RA_ALLOC_TYPE1: + dci->type1_alloc.rbg_subset = srslte_bit_pack(&y, (int)ceilf(log2f(P))); + dci->type1_alloc.shift = *y++ ? true : false; + dci->type1_alloc.vrb_bitmask = srslte_bit_pack(&y, alloc_size - (int)ceilf(log2f(P)) - 1); + break; + default: + ERROR("Format2 accepts type0 or type1 resource allocation only\n"); + return SRSLTE_ERROR; + } + // TPC PUCCH + dci->tpc_pucch = srslte_bit_pack(&y, 2); + + // TDD + if (IS_TDD) { + dci->dai = srslte_bit_pack(&y, 2); + dci->is_tdd = true; } - // unpack TPC command for PUCCH (not implemented) - y+=2; - + /* harq process number */ - data->harq_process = srslte_bit_pack(&y, HARQ_PID_LEN); + dci->pid = srslte_bit_pack(&y, HARQ_PID_LEN); // Transpor block to codeword swap flag if (msg->format == SRSLTE_DCI_FORMAT2B) { - data->sram_id = *y++ ? true : false; + dci->sram_id = *y++ ? true : false; } else { - data->tb_cw_swap = *y++ ? true : false; + dci->tb_cw_swap = *y++ ? true : false; } - + + uint32_t nof_tb = 0; /* unpack MCS according to 7.1.7 of 36.213 */ - data->mcs_idx = srslte_bit_pack(&y, 5); - data->ndi = *y++ ? true : false; - data->rv_idx = srslte_bit_pack(&y, 2); - if (data->mcs_idx == 0 && data->rv_idx == 1) { - data->tb_en[0] = false; - } else { - data->tb_en[0] = true; - } - - // same for tb1 - data->mcs_idx_1 = srslte_bit_pack(&y, 5); - data->ndi_1 = *y++ ? true : false; - data->rv_idx_1 = srslte_bit_pack(&y, 2); - if (data->mcs_idx_1 == 0 && data->rv_idx_1 == 1) { - data->tb_en[1] = false; - } else { - data->tb_en[1] = true; + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + dci->tb[i].mcs_idx = srslte_bit_pack(&y, 5); + dci->tb[i].ndi = *y++ ? true : false; + dci->tb[i].rv = srslte_bit_pack(&y, 2); + if (SRSLTE_DCI_IS_TB_EN(dci->tb[i])) { + nof_tb++; + } } - + // Precoding information if (msg->format == SRSLTE_DCI_FORMAT2) { - data->pinfo = srslte_bit_pack(&y, precoding_bits_f2(nof_ports)); + dci->pinfo = srslte_bit_pack(&y, precoding_bits_f2(cell->nof_ports)); } else if (msg->format == SRSLTE_DCI_FORMAT2A) { - data->pinfo = srslte_bit_pack(&y, precoding_bits_f2a(nof_ports)); + dci->pinfo = srslte_bit_pack(&y, precoding_bits_f2a(cell->nof_ports)); } - // Table 5.3.3.1.5-1 - if (SRSLTE_RA_DL_GRANT_NOF_TB(data) == 2) { - if (data->tb_cw_swap) { - uint32_t tmp = data->rv_idx; - data->rv_idx = data->rv_idx_1; - data->rv_idx_1 = tmp; - - tmp = data->mcs_idx; - data->mcs_idx = data->mcs_idx_1; - data->mcs_idx_1 = tmp; - - bool tmp_ndi = data->ndi; - data->ndi = data->ndi_1; - data->ndi_1 = tmp_ndi; + // Apply TB swap table + if (nof_tb == 2) { + // Table 5.3.3.1.5-1 + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + dci->tb[i].cw_idx = (((dci->tb_cw_swap) ? 1 : 0) + i) % nof_tb; + } + } else { + // Table 5.3.3.1.5-2 + if (!SRSLTE_DCI_IS_TB_EN(dci->tb[0])) { + dci->tb[0] = dci->tb[1]; + } + SRSLTE_DCI_TB_DISABLE(dci->tb[1]); + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + dci->tb[i].cw_idx = 0; } } - // Table 5.3.3.1.5-2 - if (!data->tb_en[0]) { - data->rv_idx = data->rv_idx_1; - data->mcs_idx = data->mcs_idx_1; - data->ndi = data->ndi_1; - - data->tb_en[1] = false; - } - return SRSLTE_SUCCESS; } +int srslte_dci_msg_pack_pdsch( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_dl_t* dci, srslte_dci_msg_t* msg) +{ + msg->rnti = dci->rnti; + msg->location = dci->location; + msg->format = dci->format; + srslte_dci_cfg_t _dci_cfg; + if (!cfg) { + ZERO_OBJECT(_dci_cfg); + cfg = &_dci_cfg; + } -int srslte_dci_msg_pack_pdsch(srslte_ra_dl_dci_t *data, srslte_dci_format_t format, - srslte_dci_msg_t *msg, uint32_t nof_prb, uint32_t nof_ports, - bool crc_is_crnti) -{ - msg->format = format; - switch (format) { - case SRSLTE_DCI_FORMAT1: - msg->format = format; - return dci_format1_pack(data, msg, nof_prb); - case SRSLTE_DCI_FORMAT1A: - msg->format = format; - return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti); - case SRSLTE_DCI_FORMAT1C: - msg->format = format; - return dci_format1Cs_pack(data, msg, nof_prb); - case SRSLTE_DCI_FORMAT2: - case SRSLTE_DCI_FORMAT2A: - case SRSLTE_DCI_FORMAT2B: - msg->format = format; - return dci_format2AB_pack(data, msg, nof_prb, nof_ports); - default: - fprintf(stderr, "DCI pack pdsch: Invalid DCI format %s\n", - srslte_dci_format_string(format)); - return SRSLTE_ERROR; + switch (msg->format) { + case SRSLTE_DCI_FORMAT1: + return dci_format1_pack(cell, sf, cfg, dci, msg); + case SRSLTE_DCI_FORMAT1A: + return dci_format1As_pack(cell, sf, cfg, dci, msg); + case SRSLTE_DCI_FORMAT1C: + return dci_format1Cs_pack(cell, sf, cfg, dci, msg); + case SRSLTE_DCI_FORMAT2: + case SRSLTE_DCI_FORMAT2A: + case SRSLTE_DCI_FORMAT2B: + return dci_format2AB_pack(cell, sf, cfg, dci, msg); + default: + ERROR("DCI pack pdsch: Invalid DCI format %s\n", srslte_dci_format_string(msg->format)); + return SRSLTE_ERROR; } } -int srslte_dci_msg_unpack_pdsch(srslte_dci_msg_t *msg, srslte_ra_dl_dci_t *data, - uint32_t nof_prb, uint32_t nof_ports, bool crc_is_crnti) +int srslte_dci_msg_unpack_pdsch( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_dl_t* dci) { + // Initialize DCI + bzero(dci, sizeof(srslte_dci_dl_t)); + + // Enable just 1 TB per default + for (int i = 1; i < SRSLTE_MAX_CODEWORDS; i++) { + SRSLTE_DCI_TB_DISABLE(dci->tb[i]); + } + dci->rnti = msg->rnti; + dci->location = msg->location; + dci->format = msg->format; + + srslte_dci_cfg_t _dci_cfg; + if (!cfg) { + ZERO_OBJECT(_dci_cfg); + cfg = &_dci_cfg; + } + +#if SRSLTE_DCI_HEXDEBUG + dci->hex_str[0] = '\0'; + srslte_vec_sprint_hex(dci->hex_str, sizeof(dci->hex_str), msg->payload, msg->nof_bits); + dci->nof_bits = msg->nof_bits; +#endif + switch (msg->format) { - case SRSLTE_DCI_FORMAT1: - return dci_format1_unpack(msg, data, nof_prb); - case SRSLTE_DCI_FORMAT1A: - return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti); - case SRSLTE_DCI_FORMAT1B: - return dci_format1B_unpack(msg, data, nof_prb, nof_ports); + case SRSLTE_DCI_FORMAT1: + return dci_format1_unpack(cell, sf, cfg, msg, dci); + case SRSLTE_DCI_FORMAT1A: + return dci_format1As_unpack(cell, sf, cfg, msg, dci); + case SRSLTE_DCI_FORMAT1B: + return dci_format1B_unpack(cell, sf, cfg, msg, dci); case SRSLTE_DCI_FORMAT1C: - return dci_format1Cs_unpack(msg, data, nof_prb); - case SRSLTE_DCI_FORMAT1D: - return dci_format1D_unpack(msg, data, nof_prb, nof_ports); + return dci_format1Cs_unpack(cell, sf, cfg, msg, dci); + case SRSLTE_DCI_FORMAT1D: + return dci_format1D_unpack(cell, sf, cfg, msg, dci); case SRSLTE_DCI_FORMAT2: case SRSLTE_DCI_FORMAT2A: case SRSLTE_DCI_FORMAT2B: - return dci_format2AB_unpack(msg, data, nof_prb, nof_ports); + return dci_format2AB_unpack(cell, sf, cfg, msg, dci); default: - fprintf(stderr, "DCI unpack pdsch: Invalid DCI format %s\n", - srslte_dci_format_string(msg->format)); + ERROR("DCI unpack pdsch: Invalid DCI format %s\n", srslte_dci_format_string(msg->format)); return SRSLTE_ERROR; - } - return SRSLTE_SUCCESS; + } } -int srslte_dci_msg_pack_pusch(srslte_ra_ul_dci_t *data, srslte_dci_msg_t *msg, uint32_t nof_prb) { - return dci_format0_pack(data, msg, nof_prb); +int srslte_dci_msg_pack_pusch( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_ul_t* dci, srslte_dci_msg_t* msg) +{ + msg->rnti = dci->rnti; + msg->location = dci->location; + msg->format = dci->format; + + srslte_dci_cfg_t _dci_cfg; + if (!cfg) { + ZERO_OBJECT(_dci_cfg); + cfg = &_dci_cfg; + } + + return dci_format0_pack(cell, sf, cfg, dci, msg); +} + +int srslte_dci_msg_unpack_pusch( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* cfg, srslte_dci_msg_t* msg, srslte_dci_ul_t* dci) +{ + // Initialize DCI + bzero(dci, sizeof(srslte_dci_ul_t)); + + dci->rnti = msg->rnti; + dci->location = msg->location; + dci->format = msg->format; + + srslte_dci_cfg_t _dci_cfg; + if (!cfg) { + ZERO_OBJECT(_dci_cfg); + cfg = &_dci_cfg; + } + +#ifdef SRSLTE_DCI_HEXDEBUG + dci->hex_str[0] = '\0'; + srslte_vec_sprint_hex(dci->hex_str, sizeof(dci->hex_str), msg->payload, msg->nof_bits); + dci->nof_bits = msg->nof_bits; +#endif + + return dci_format0_unpack(cell, sf, cfg, msg, dci); +} + +int srslte_dci_location_set(srslte_dci_location_t* c, uint32_t L, uint32_t nCCE) +{ + if (L <= 3) { + c->L = L; + } else { + ERROR("Invalid L %d\n", L); + return SRSLTE_ERROR; + } + if (nCCE <= 87) { + c->ncce = nCCE; + } else { + ERROR("Invalid nCCE %d\n", nCCE); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; } -int srslte_dci_msg_unpack_pusch(srslte_dci_msg_t *msg, srslte_ra_ul_dci_t *data, uint32_t nof_prb) { - return dci_format0_unpack(msg, data, nof_prb); +bool srslte_dci_location_isvalid(srslte_dci_location_t* c) +{ + if (c->L <= 3 && c->ncce <= 87) { + return true; + } else { + return false; + } } -srslte_dci_format_t srslte_dci_format_from_string(char *str) { +srslte_dci_format_t srslte_dci_format_from_string(char* str) +{ if (!strcmp(str, "Format0")) { return SRSLTE_DCI_FORMAT0; } else if (!strcmp(str, "Format1")) { - return SRSLTE_DCI_FORMAT1; + return SRSLTE_DCI_FORMAT1; } else if (!strcmp(str, "Format1A")) { - return SRSLTE_DCI_FORMAT1A; + return SRSLTE_DCI_FORMAT1A; } else if (!strcmp(str, "Format1B")) { - return SRSLTE_DCI_FORMAT1B; + return SRSLTE_DCI_FORMAT1B; } else if (!strcmp(str, "Format1C")) { - return SRSLTE_DCI_FORMAT1C; + return SRSLTE_DCI_FORMAT1C; } else if (!strcmp(str, "Format1D")) { - return SRSLTE_DCI_FORMAT1D; + return SRSLTE_DCI_FORMAT1D; } else if (!strcmp(str, "Format2")) { - return SRSLTE_DCI_FORMAT2; + return SRSLTE_DCI_FORMAT2; } else if (!strcmp(str, "Format2A")) { - return SRSLTE_DCI_FORMAT2A; + return SRSLTE_DCI_FORMAT2A; } else if (!strcmp(str, "Format2B")) { - return SRSLTE_DCI_FORMAT2B; + return SRSLTE_DCI_FORMAT2B; } else { return SRSLTE_DCI_NOF_FORMATS; } } -char* srslte_dci_format_string(srslte_dci_format_t format) { +char* srslte_dci_format_string(srslte_dci_format_t format) +{ switch (format) { - case SRSLTE_DCI_FORMAT0: - return "Format0 "; - case SRSLTE_DCI_FORMAT1: - return "Format1 "; - case SRSLTE_DCI_FORMAT1A: - return "Format1A"; - case SRSLTE_DCI_FORMAT1B: - return "Format1B"; - case SRSLTE_DCI_FORMAT1C: - return "Format1C"; - case SRSLTE_DCI_FORMAT1D: - return "Format1D"; - case SRSLTE_DCI_FORMAT2: - return "Format2 "; - case SRSLTE_DCI_FORMAT2A: - return "Format2A"; - case SRSLTE_DCI_FORMAT2B: - return "Format2B"; - default: - return "N/A"; // fatal error + case SRSLTE_DCI_FORMAT0: + return "Format0 "; + case SRSLTE_DCI_FORMAT1: + return "Format1 "; + case SRSLTE_DCI_FORMAT1A: + return "Format1A"; + case SRSLTE_DCI_FORMAT1B: + return "Format1B"; + case SRSLTE_DCI_FORMAT1C: + return "Format1C"; + case SRSLTE_DCI_FORMAT1D: + return "Format1D"; + case SRSLTE_DCI_FORMAT2: + return "Format2 "; + case SRSLTE_DCI_FORMAT2A: + return "Format2A"; + case SRSLTE_DCI_FORMAT2B: + return "Format2B"; + default: + return "N/A"; // fatal error } } @@ -1438,62 +1374,168 @@ char* srslte_dci_format_string_short(srslte_dci_format_t format) { } } -void srslte_dci_msg_type_fprint(FILE *f, srslte_dci_msg_type_t type) { - switch (type.type) { - case SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED: - fprintf(f, "%s PUSCH Scheduling\n", srslte_dci_format_string(type.format)); - break; - case SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED: - fprintf(f, "%s PDSCH Scheduling\n", srslte_dci_format_string(type.format)); - break; - case SRSLTE_DCI_MSG_TYPE_RA_PROC_PDCCH: - fprintf(f, "%s Random access initiated by PDCCH\n", - srslte_dci_format_string(type.format)); - break; - case SRSLTE_DCI_MSG_TYPE_MCCH_CHANGE: - fprintf(f, "%s MCCH change notification\n", srslte_dci_format_string(type.format)); - break; - case SRSLTE_DCI_MSG_TYPE_TPC_COMMAND: - fprintf(f, "%s TPC command\n", srslte_dci_format_string(type.format)); - break; +char* ra_type_string(srslte_ra_type_t alloc_type) +{ + switch (alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + return "Type 0"; + case SRSLTE_RA_ALLOC_TYPE1: + return "Type 1"; + case SRSLTE_RA_ALLOC_TYPE2: + return "Type 2"; + default: + return "N/A"; } } -/** Warning this function will be deprecated. Currently only used in test programs */ -int srslte_dci_msg_get_type(srslte_dci_msg_t *msg, srslte_dci_msg_type_t *type, uint32_t nof_prb, - uint16_t msg_rnti) +void srslte_dci_dl_fprint(FILE* f, srslte_dci_dl_t* dci, uint32_t nof_prb) { - DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x\n", msg->nof_bits, msg_rnti); - if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, nof_prb, 1) - && !msg->data[0]) { - type->type = SRSLTE_DCI_MSG_TYPE_PUSCH_SCHED; - type->format = SRSLTE_DCI_FORMAT0; - return SRSLTE_SUCCESS; - } else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, nof_prb, 1)) { - type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported - type->format = SRSLTE_DCI_FORMAT1; - return SRSLTE_SUCCESS; - } else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1A, nof_prb, 1)) { - /* The RNTI is not the only condition. Also some fields in the packet. - * if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { - type->type = SRSLTE_DCI_MSG_TYPE_RA_PROC_PDCCH; - type->format = SRSLTE_DCI_FORMAT1A; - } else { - */ - type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported - type->format = SRSLTE_DCI_FORMAT1A; - //} - return SRSLTE_SUCCESS; - } else if (msg->nof_bits == srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1C, nof_prb, 1)) { - if (msg_rnti == SRSLTE_MRNTI) { - type->type = SRSLTE_DCI_MSG_TYPE_MCCH_CHANGE; - type->format = SRSLTE_DCI_FORMAT1C; - } else { - type->type = SRSLTE_DCI_MSG_TYPE_PDSCH_SCHED; // only these 2 types supported - type->format = SRSLTE_DCI_FORMAT1C; + fprintf(f, " - Resource Allocation Type:\t\t%s\n", ra_type_string(dci->alloc_type)); + switch (dci->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + fprintf(f, " + Resource Block Group Size:\t\t%d\n", srslte_ra_type0_P(nof_prb)); + fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", dci->type0_alloc.rbg_bitmask); + break; + case SRSLTE_RA_ALLOC_TYPE1: + fprintf(f, " + Resource Block Group Size:\t\t%d\n", srslte_ra_type0_P(nof_prb)); + fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", dci->type1_alloc.vrb_bitmask); + fprintf(f, " + RBG Subset:\t\t\t%d\n", dci->type1_alloc.rbg_subset); + fprintf(f, " + RBG Shift:\t\t\t\t%s\n", dci->type1_alloc.shift ? "Yes" : "No"); + break; + case SRSLTE_RA_ALLOC_TYPE2: + fprintf(f, " + Type:\t\t\t\t%s\n", dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC ? "Localized" : "Distributed"); + fprintf(f, " + Resource Indicator Value:\t\t%d\n", dci->type2_alloc.riv); + break; + } + if (dci->cif_present) { + fprintf(f, " - Carrier idx:\t\t\t\t%d\n", dci->cif); + } + fprintf(f, " - HARQ process:\t\t\t%d\n", dci->pid); + fprintf(f, " - TPC command for PUCCH:\t\t--\n"); + fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap) ? "true" : "false"); + + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + fprintf(f, " - Transport block %d enabled:\t\t%s\n", i, SRSLTE_DCI_IS_TB_EN(dci->tb[i]) ? "true" : "false"); + if (SRSLTE_DCI_IS_TB_EN(dci->tb[i])) { + fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->tb[i].mcs_idx); + fprintf(f, " + New data indicator:\t\t\t%s\n", dci->tb[i].ndi ? "Yes" : "No"); + fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->tb[i].rv); + } + } +} + +static uint32_t print_multi(char* info_str, uint32_t n, uint32_t len, srslte_dci_dl_t* dci_dl, uint32_t value_id) +{ + uint32_t nof_tb = 1; + if (dci_dl->format >= SRSLTE_DCI_FORMAT2) { + nof_tb = 2; + } + for (uint32_t i = 0; i < nof_tb; i++) { + switch (value_id) { + case 0: + n = srslte_print_check(info_str, len, n, "%d", dci_dl->tb[i].mcs_idx); + break; + case 1: + n = srslte_print_check(info_str, len, n, "%d", dci_dl->tb[i].rv); + break; + case 2: + n = srslte_print_check(info_str, len, n, "%d", dci_dl->tb[i].ndi); + break; + } + if (i < SRSLTE_MAX_CODEWORDS - 1 && nof_tb > 1) { + n = srslte_print_check(info_str, len, n, "/"); } - return SRSLTE_SUCCESS; } - return SRSLTE_ERROR; + return n; +} + +uint32_t srslte_dci_dl_info(srslte_dci_dl_t* dci_dl, char* info_str, uint32_t len) +{ + uint32_t n = 0; + n = srslte_print_check(info_str, + len, + 0, + "f=%s, cce=%2d, L=%d", + srslte_dci_format_string_short(dci_dl->format), + dci_dl->location.ncce, + dci_dl->location.L); + +#if SRSLTE_DCI_HEXDEBUG + n = srslte_print_check(info_str, len, n, ", len=%d, hex=%s", dci_dl->nof_bits, dci_dl->hex_str); +#endif + + if (dci_dl->cif_present) { + n = srslte_print_check(info_str, len, n, ", cif=%d", dci_dl->cif); + } + + switch (dci_dl->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + n = srslte_print_check(info_str, len, n, ", rbg=0x%x", dci_dl->type0_alloc.rbg_bitmask); + break; + case SRSLTE_RA_ALLOC_TYPE1: + n = srslte_print_check(info_str, + len, + n, + ", vrb=0x%x, rbg_s=%d, sh=%d", + dci_dl->type1_alloc.vrb_bitmask, + dci_dl->type1_alloc.rbg_subset, + dci_dl->type1_alloc.shift); + break; + case SRSLTE_RA_ALLOC_TYPE2: + n = srslte_print_check(info_str, len, n, ", riv=%d", dci_dl->type2_alloc.riv); + break; + } + + n = srslte_print_check(info_str, len, n, ", pid=%d", dci_dl->pid); + + n = srslte_print_check(info_str, len, n, ", mcs={", 0); + n = print_multi(info_str, n, len, dci_dl, 0); + n = srslte_print_check(info_str, len, n, "}", 0); + n = srslte_print_check(info_str, len, n, ", rv={", 0); + n = print_multi(info_str, n, len, dci_dl, 1); + n = srslte_print_check(info_str, len, n, "}", 0); + n = srslte_print_check(info_str, len, n, ", ndi={", 0); + n = print_multi(info_str, n, len, dci_dl, 2); + n = srslte_print_check(info_str, len, n, "}", 0); + + if (dci_dl->format == SRSLTE_DCI_FORMAT1 || dci_dl->format == SRSLTE_DCI_FORMAT1A || + dci_dl->format == SRSLTE_DCI_FORMAT1B || dci_dl->format == SRSLTE_DCI_FORMAT2 || + dci_dl->format == SRSLTE_DCI_FORMAT2A || dci_dl->format == SRSLTE_DCI_FORMAT2B) { + n = srslte_print_check(info_str, len, n, ", tpc_pucch=%d", dci_dl->tpc_pucch); + } + + if (dci_dl->is_tdd) { + n = srslte_print_check(info_str, len, n, ", dai=%d", dci_dl->dai); + } + + if (dci_dl->format == SRSLTE_DCI_FORMAT2 || dci_dl->format == SRSLTE_DCI_FORMAT2A || + dci_dl->format == SRSLTE_DCI_FORMAT2B) { + n = srslte_print_check(info_str, len, n, ", tb_sw=%d, pinfo=%d", dci_dl->tb_cw_swap, dci_dl->pinfo); + } + + return n; } +uint32_t srslte_dci_ul_info(srslte_dci_ul_t* dci_ul, char* info_str, uint32_t len) +{ + uint32_t n = 0; + + n = srslte_print_check(info_str, len, 0, "f=0, cce=%2d, L=%d", dci_ul->location.ncce, dci_ul->location.L); + + n = srslte_print_check(info_str, len, n, ", riv=%d", dci_ul->type2_alloc.riv); + + n = srslte_print_check( + info_str, len, n, ", mcs=%d, rv=%d, ndi=%d", dci_ul->tb.mcs_idx, dci_ul->tb.rv, dci_ul->tb.ndi); + + if (dci_ul->is_tdd) { + n = srslte_print_check(info_str, len, n, ", ul_idx=%d", dci_ul->ul_idx); + } + + if (dci_ul->is_tdd) { + n = srslte_print_check(info_str, len, n, ", dai=%d", dci_ul->dai); + } + + n = srslte_print_check(info_str, len, n, ", tpc_pusch=%d, dmrs_cs=%d", dci_ul->tpc_pusch, dci_ul->n_dmrs); + + return n; +} diff --git a/lib/src/phy/phch/dci_sz_table.h b/lib/src/phy/phch/dci_sz_table.h deleted file mode 100644 index f48f80d9b..000000000 --- a/lib/src/phy/phch/dci_sz_table.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \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/. - * - */ - - - -static uint32_t dci_sz_table[101][4] = { - {15, 13, 15, 5}, - {15, 17, 15, 5}, - {17, 15, 17, 5}, - {18, 17, 18, 5}, - {19, 17, 19, 7}, - {19, 18, 19, 7}, - {21, 19, 21, 8}, - {21, 22, 21, 8}, - {21, 22, 21, 9}, - {21, 22, 21, 9}, - {21, 23, 21, 9}, - {22, 21, 22, 9}, - {22, 21, 22, 9}, - {22, 21, 22, 9}, - {22, 21, 22, 10}, - {22, 23, 22, 10}, - {23, 22, 23, 11}, - {23, 25, 23, 11}, - {23, 25, 23, 11}, - {23, 25, 23, 11}, - {23, 25, 23, 11}, - {23, 25, 23, 11}, - {23, 25, 23, 11}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 23, 25, 11}, - {25, 27, 25, 11}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 27, 25, 12}, - {25, 27, 25, 13}, - {25, 27, 25, 13}, - {25, 27, 25, 13}, - {25, 27, 25, 13}, - {25, 27, 25, 13}, - {25, 27, 25, 13}, - {25, 28, 25, 13}, - {25, 28, 25, 13}, - {25, 28, 25, 13}, - {25, 29, 25, 13}, - {25, 29, 25, 13}, - {27, 29, 27, 13}, - {27, 30, 27, 13}, - {27, 30, 27, 13}, - {27, 30, 27, 13}, - {27, 31, 27, 13}, - {27, 31, 27, 13}, - {27, 31, 27, 13}, - {27, 33, 27, 13}, - {27, 33, 27, 13}, - {27, 33, 27, 13}, - {27, 33, 27, 13}, - {27, 33, 27, 13}, - {27, 33, 27, 13}, - {27, 34, 27, 13}, - {27, 34, 27, 13}, - {27, 34, 27, 13}, - {27, 35, 27, 13}, - {27, 35, 27, 13}, - {27, 35, 27, 13}, - {27, 30, 27, 14}, - {27, 31, 27, 14}, - {27, 31, 27, 14}, - {27, 31, 27, 14}, - {27, 31, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 33, 27, 14}, - {27, 34, 27, 14}, - {27, 34, 27, 14}, - {27, 34, 27, 14}, - {27, 34, 27, 14}, - {27, 35, 27, 14}, - {27, 35, 27, 14}, - {27, 35, 27, 14}, - {27, 35, 27, 14}, - {27, 36, 27, 14}, - {27, 36, 27, 14}, - {27, 36, 27, 14}, - {27, 36, 27, 14}, - {27, 37, 27, 14}, - {27, 37, 27, 14}, - {28, 37, 28, 14}, - {28, 37, 28, 14}, - {28, 38, 28, 14}, - {28, 38, 28, 15}, - {28, 38, 28, 15}, - {28, 38, 28, 15}, - {28, 39, 28, 15}, - {28, 39, 28, 15}, - {28, 39, 28, 15}, - {28, 39, 28, 15} -}; - diff --git a/lib/src/phy/phch/pbch.c b/lib/src/phy/phch/pbch.c index cdb5f4877..af8add1dc 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -24,16 +24,15 @@ * */ +#include "srslte/srslte.h" +#include +#include +#include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include #include "prb_dl.h" #include "srslte/phy/phch/pbch.h" @@ -252,7 +251,7 @@ int srslte_pbch_set_cell(srslte_pbch_t *q, srslte_cell_t cell) { } if (q->cell.id != cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; if (srslte_sequence_pbch(&q->seq, q->cell.cp, q->cell.id)) { return SRSLTE_ERROR; } @@ -430,7 +429,7 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n, return SRSLTE_SUCCESS; } } else { - fprintf(stderr, "Error in PBCH decoder: Invalid frame pointers dst=%d, src=%d, n=%d\n", src, dst, n); + ERROR("Error in PBCH decoder: Invalid frame pointers dst=%d, src=%d, n=%d\n", src, dst, n); return -1; } @@ -444,24 +443,27 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n, * * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ -int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRSLTE_MAX_PORTS], float noise_estimate, - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, int *sfn_offset) +int srslte_pbch_decode(srslte_pbch_t* q, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], + uint32_t* nof_tx_ports, + int* sfn_offset) { uint32_t src, dst, nb; uint32_t nant; int i; int nof_bits; - cf_t *x[SRSLTE_MAX_LAYERS]; - + cf_t* x[SRSLTE_MAX_LAYERS]; + int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - slot1_symbols != NULL) - { - for (i=0;icell.nof_ports;i++) { - if (ce_slot1[i] == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } + + if (q != NULL && sf_symbols != NULL) { + cf_t* slot1_symbols = &sf_symbols[0][SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)]; + + cf_t* ce_slot1[SRSLTE_MAX_PORTS]; + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + ce_slot1[i] = &channel->ce[i][0][SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)]; } /* Set pointers for layermapping & precoding */ @@ -471,17 +473,17 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } - + /* extract symbols */ if (q->nof_symbols != srslte_pbch_get(slot1_symbols, q->symbols[0], q->cell)) { - fprintf(stderr, "There was an error getting the PBCH symbols\n"); + ERROR("There was an error getting the PBCH symbols\n"); return SRSLTE_ERROR; } /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { if (q->nof_symbols != srslte_pbch_get(ce_slot1[i], q->ce[i], q->cell)) { - fprintf(stderr, "There was an error getting the PBCH symbols\n"); + ERROR("There was an error getting the PBCH symbols\n"); return SRSLTE_ERROR; } } @@ -505,10 +507,9 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS /* in control channels, only diversity is supported */ if (nant == 1) { /* no need for layer demapping */ - srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, NULL, q->nof_symbols, 1.0f, noise_estimate); + srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, NULL, q->nof_symbols, 1.0f, channel->noise_estimate); } else { - srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, - q->nof_symbols, 1.0f); + srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, q->nof_symbols, 1.0f); srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant); } @@ -555,19 +556,16 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission */ -int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], cf_t *slot1_symbols[SRSLTE_MAX_PORTS], uint32_t frame_idx) { +int srslte_pbch_encode(srslte_pbch_t* q, + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + uint32_t frame_idx) +{ int i; int nof_bits; cf_t *x[SRSLTE_MAX_LAYERS]; - - if (q != NULL && - bch_payload != NULL) - { - for (i=0;icell.nof_ports;i++) { - if (slot1_symbols[i] == NULL) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - } + + if (q != NULL && bch_payload != NULL) { /* Set pointers for layermapping & precoding */ nof_bits = 2 * q->nof_symbols; @@ -605,7 +603,7 @@ int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_ /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - srslte_pbch_put(q->symbols[i], slot1_symbols[i], q->cell); + srslte_pbch_put(q->symbols[i], &sf_symbols[i][SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)], q->cell); } return SRSLTE_SUCCESS; } else { diff --git a/lib/src/phy/phch/pcfich.c b/lib/src/phy/phch/pcfich.c index c6f1fe127..d14bef7de 100644 --- a/lib/src/phy/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -57,8 +57,8 @@ bool srslte_pcfich_exists(int nframe, int nslot) { return true; } -/** Initializes the pcfich channel receiver. - * On error, returns -1 and frees the structrure +/** Initializes the pcfich channel receiver. + * On ERROR returns -1 and frees the structrure */ int srslte_pcfich_init(srslte_pcfich_t *q, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -93,7 +93,7 @@ int srslte_pcfich_init(srslte_pcfich_t *q, uint32_t nof_rx_antennas) { } void srslte_pcfich_free(srslte_pcfich_t *q) { - for (int ns = 0; ns < SRSLTE_NSUBFRAMES_X_FRAME; ns++) { + for (int ns = 0; ns < SRSLTE_NOF_SF_X_FRAME; ns++) { srslte_sequence_free(&q->seq[ns]); } srslte_modem_table_free(&q->mod); @@ -110,8 +110,8 @@ int srslte_pcfich_set_cell(srslte_pcfich_t *q, srslte_regs_t *regs, srslte_cell_ { q->regs = regs; if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - for (int nsf = 0; nsf < SRSLTE_NSUBFRAMES_X_FRAME; nsf++) { + q->cell = cell; + for (int nsf = 0; nsf < SRSLTE_NOF_SF_X_FRAME; nsf++) { if (srslte_sequence_pcfich(&q->seq[nsf], 2 * nsf, q->cell.id)) { return SRSLTE_ERROR; } @@ -158,35 +158,23 @@ int srslte_pcfich_cfi_encode(uint32_t cfi, uint8_t bits[PCFICH_CFI_LEN]) { } } -int srslte_pcfich_decode(srslte_pcfich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t *cfi, float *corr_result) -{ - cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; - cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - - _sf_symbols[0] = sf_symbols; - for (int i=0;icell.nof_ports;i++) { - _ce[i][0] = ce[i]; - } - return srslte_pcfich_decode_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi, corr_result); -} - /* Decodes the PCFICH channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t *cfi, float *corr_result) +int srslte_pcfich_decode(srslte_pcfich_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + float* corr_result) { /* Set pointers for layermapping & precoding */ - int i; - cf_t *x[SRSLTE_MAX_LAYERS]; - - if (q != NULL && - sf_symbols != NULL && - nsubframe < SRSLTE_NSUBFRAMES_X_FRAME) - { + int i; + cf_t* x[SRSLTE_MAX_LAYERS]; + + if (q != NULL && sf_symbols != NULL) { + uint32_t sf_idx = sf->tti % 10; /* number of layers equals number of ports */ for (i = 0; i < SRSLTE_MAX_PORTS; i++) { @@ -198,9 +186,8 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P /* extract symbols */ for (int j=0;jnof_rx_antennas;j++) { - if (q->nof_symbols - != srslte_regs_pcfich_get(q->regs, sf_symbols[j], q->symbols[j])) { - fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, sf_symbols[j], q->symbols[j])) { + ERROR("There was an error getting the PCFICH symbols\n"); return SRSLTE_ERROR; } @@ -208,8 +195,8 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { - if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, ce[i][j], q->ce[i][j])) { - fprintf(stderr, "There was an error getting the PCFICH symbols\n"); + if (q->nof_symbols != srslte_regs_pcfich_get(q->regs, channel->ce[i][j], q->ce[i][j])) { + ERROR("There was an error getting the PCFICH symbols\n"); return SRSLTE_ERROR; } q_ce[i][j] = q->ce[i][j]; @@ -219,7 +206,8 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate); + srslte_predecoding_single_multi( + q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, channel->noise_estimate); } else { srslte_predecoding_diversity_multi(q_symbols, q_ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); @@ -229,10 +217,10 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, q->data_f, q->nof_symbols); /* Scramble with the sequence for slot nslot */ - srslte_scrambling_f(&q->seq[nsubframe], q->data_f); + srslte_scrambling_f(&q->seq[sf_idx], q->data_f); /* decode CFI */ - float corr = srslte_pcfich_cfi_decode(q, cfi); + float corr = srslte_pcfich_cfi_decode(q, &sf->cfi); if (corr_result) { *corr_result = corr; } @@ -245,15 +233,13 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P /** Encodes CFI and maps symbols to the slot */ -int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SRSLTE_MAX_PORTS], - uint32_t subframe) { +int srslte_pcfich_encode(srslte_pcfich_t* q, srslte_dl_sf_cfg_t* sf, cf_t* slot_symbols[SRSLTE_MAX_PORTS]) +{ int i; - if (q != NULL && - cfi <= 3 && - slot_symbols != NULL && - subframe < SRSLTE_NSUBFRAMES_X_FRAME) - { + if (q != NULL && slot_symbols != NULL) { + + uint32_t sf_idx = sf->tti % 10; /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; @@ -268,10 +254,10 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR } /* pack CFI */ - srslte_pcfich_cfi_encode(cfi, q->data); + srslte_pcfich_cfi_encode(sf->cfi, q->data); /* scramble for slot sequence nslot */ - srslte_scrambling_b(&q->seq[subframe], q->data); + srslte_scrambling_b(&q->seq[sf_idx], q->data); srslte_mod_modulate(&q->mod, q->data, q->d, PCFICH_CFI_LEN); @@ -286,7 +272,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { if (srslte_regs_pcfich_put(q->regs, q->symbols[i], slot_symbols[i]) < 0) { - fprintf(stderr, "Error putting PCHICH resource elements\n"); + ERROR("Error putting PCHICH resource elements\n"); return SRSLTE_ERROR; } } diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 1c40333e8..facc4e969 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -65,7 +65,7 @@ static int pdcch_init(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_anten q->is_ue = is_ue; /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ q->max_bits = max_prb*3*12*2; - + INFO("Init PDCCH: Max bits: %d\n", q->max_bits); if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { @@ -159,7 +159,7 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { } } } - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { srslte_sequence_free(&q->seq[i]); } @@ -170,7 +170,20 @@ void srslte_pdcch_free(srslte_pdcch_t *q) { } -int srslte_pdcch_set_cell(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) +void srslte_pdcch_set_regs(srslte_pdcch_t* q, srslte_regs_t* regs) +{ + q->regs = regs; + + for (int cfi = 0; cfi < 3; cfi++) { + q->nof_regs[cfi] = (srslte_regs_pdcch_nregs(q->regs, cfi + 1) / 9) * 9; + q->nof_cce[cfi] = q->nof_regs[cfi] / 9; + } + + /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ + q->max_bits = (NOF_REGS(3) / 9) * 72; +} + +int srslte_pdcch_set_cell(srslte_pdcch_t* q, srslte_regs_t* regs, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -178,23 +191,16 @@ int srslte_pdcch_set_cell(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t regs != NULL && srslte_cell_isvalid(&cell)) { - q->regs = regs; - for (int cfi=0;cfi<3;cfi++) { - q->nof_regs[cfi] = (srslte_regs_pdcch_nregs(q->regs, cfi+1) / 9) * 9; - q->nof_cce[cfi] = q->nof_regs[cfi]/ 9; - } - - /* Allocate memory for the maximum number of PDCCH bits (CFI=3) */ - q->max_bits = (NOF_REGS(3)/ 9) * 72; + srslte_pdcch_set_regs(q, regs); INFO("PDCCH: Cell config PCI=%d, %d ports.\n", q->cell.id, q->cell.nof_ports); if (q->cell.id != cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { // we need to pregenerate the sequence for the maximum number of bits, which is 8 times // the maximum number of REGs (for CFI=3) if (srslte_sequence_pdcch(&q->seq[i], 2 * i, q->cell.id, 8*srslte_regs_pdcch_nregs(q->regs, 3))) { @@ -207,18 +213,16 @@ int srslte_pdcch_set_cell(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t return ret; } - -uint32_t srslte_pdcch_ue_locations(srslte_pdcch_t *q, srslte_dci_location_t *c, uint32_t max_candidates, - uint32_t nsubframe, uint32_t cfi, uint16_t rnti) +uint32_t srslte_pdcch_ue_locations( + srslte_pdcch_t* q, srslte_dl_sf_cfg_t* sf, srslte_dci_location_t* c, uint32_t max_candidates, uint16_t rnti) { - return srslte_pdcch_ue_locations_ncce(NOF_CCE(cfi), c, max_candidates, nsubframe, rnti); + return srslte_pdcch_ue_locations_ncce(NOF_CCE(sf->cfi), c, max_candidates, sf->tti % 10, rnti); } - -uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates, - uint32_t nsubframe, uint16_t rnti) +uint32_t srslte_pdcch_ue_locations_ncce( + uint32_t nof_cce, srslte_dci_location_t* c, uint32_t max_candidates, uint32_t sf_idx, uint16_t rnti) { - return srslte_pdcch_ue_locations_ncce_L(nof_cce, c, max_candidates, nsubframe, rnti, -1); + return srslte_pdcch_ue_locations_ncce_L(nof_cce, c, max_candidates, sf_idx, rnti, -1); } /** 36.213 v9.1.1 @@ -226,9 +230,10 @@ uint32_t srslte_pdcch_ue_locations_ncce(uint32_t nof_cce, srslte_dci_location_t * in the structure pointed by c. * Returns the number of candidates saved in the array c. */ -uint32_t srslte_pdcch_ue_locations_ncce_L(uint32_t nof_cce, srslte_dci_location_t *c, uint32_t max_candidates, - uint32_t nsubframe, uint16_t rnti, int Ls) { - +uint32_t srslte_pdcch_ue_locations_ncce_L( + uint32_t nof_cce, srslte_dci_location_t* c, uint32_t max_candidates, uint32_t sf_idx, uint16_t rnti, int Ls) +{ + int l; // this must be int because of the for(;;--) loop uint32_t i, k, L, m; uint32_t Yk, ncce; @@ -236,7 +241,7 @@ uint32_t srslte_pdcch_ue_locations_ncce_L(uint32_t nof_cce, srslte_dci_location_ // Compute Yk for this subframe Yk = rnti; - for (m = 0; m < nsubframe+1; m++) { + for (m = 0; m < sf_idx + 1; m++) { Yk = (39827 * Yk) % 65537; } @@ -265,9 +270,12 @@ uint32_t srslte_pdcch_ue_locations_ncce_L(uint32_t nof_cce, srslte_dci_location_ } } - DEBUG("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x, nsubframe=%d, nof_cce=%d\n", - k, rnti, nsubframe, nof_cce); - + DEBUG("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x, sf_idx=%d, nof_cce=%d\n", + k, + rnti, + sf_idx, + nof_cce); + return k; } @@ -297,8 +305,7 @@ uint32_t srslte_pdcch_common_locations_ncce(uint32_t nof_cce, srslte_dci_locatio if (k < max_candidates && ncce + L <= nof_cce) { c[k].L = l; c[k].ncce = ncce; - DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n", - k, c[k].ncce, c[k].L); + DEBUG("Common SS Candidate %d: nCCE: %d/%d, L: %d\n", k, c[k].ncce, nof_cce, c[k].L); k++; } } @@ -350,7 +357,7 @@ int srslte_pdcch_dci_decode(srslte_pdcch_t *q, float *e, uint8_t *data, uint32_t return SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits); + ERROR("Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits); return SRSLTE_ERROR_INVALID_INPUTS; } } else { @@ -358,139 +365,115 @@ int srslte_pdcch_dci_decode(srslte_pdcch_t *q, float *e, uint8_t *data, uint32_t } } -/** Tries to decode a DCI message from the LLRs stored in the srslte_pdcch_t structure by the function - * srslte_pdcch_extract_llr(). This function can be called multiple times. - * The decoded message is stored in msg and the CRC remainder in crc_rem pointer - * +/** Tries to decode a DCI message from the LLRs stored in the srslte_pdcch_t structure by the function + * srslte_pdcch_extract_llr(). This function can be called multiple times. + * The location to search for is obtained from msg. + * The decoded message is stored in msg and the CRC remainder in msg->rnti + * */ -int srslte_pdcch_decode_msg(srslte_pdcch_t *q, - srslte_dci_msg_t *msg, - srslte_dci_location_t *location, - srslte_dci_format_t format, - uint32_t cfi, - uint16_t *crc_rem) +int srslte_pdcch_decode_msg( + srslte_pdcch_t* q, srslte_dl_sf_cfg_t* sf, srslte_dci_cfg_t* dci_cfg, srslte_dci_msg_t* msg) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - msg != NULL && - srslte_dci_location_isvalid(location)) - { - if (location->ncce * 72 + PDCCH_FORMAT_NOF_BITS(location->L) > - NOF_CCE(cfi)*72) { - fprintf(stderr, "Invalid location: nCCE: %d, L: %d, NofCCE: %d\n", - location->ncce, location->L, NOF_CCE(cfi)); + if (q != NULL && msg != NULL && srslte_dci_location_isvalid(&msg->location)) { + if (msg->location.ncce * 72 + PDCCH_FORMAT_NOF_BITS(msg->location.L) > NOF_CCE(sf->cfi) * 72) { + ERROR("Invalid location: nCCE: %d, L: %d, NofCCE: %d\n", msg->location.ncce, msg->location.L, NOF_CCE(sf->cfi)); } else { ret = SRSLTE_SUCCESS; - - uint32_t nof_bits = srslte_dci_format_sizeof(format, q->cell.nof_prb, q->cell.nof_ports); - uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(location->L); - - double mean = 0; + + uint32_t nof_bits = srslte_dci_format_sizeof(&q->cell, sf, dci_cfg, msg->format); + uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(msg->location.L); + + double mean = 0; for (int i=0;illr[location->ncce * 72 + i]); + mean += fabsf(q->llr[msg->location.ncce * 72 + i]); } - mean /= e_bits; - if (mean > 0.5) { - ret = srslte_pdcch_dci_decode(q, &q->llr[location->ncce * 72], - msg->data, e_bits, nof_bits, crc_rem); + mean /= e_bits; + if (mean > 0.3) { + ret = srslte_pdcch_dci_decode(q, &q->llr[msg->location.ncce * 72], msg->payload, e_bits, nof_bits, &msg->rnti); if (ret == SRSLTE_SUCCESS) { msg->nof_bits = nof_bits; - // Check format differentiation - if (format == SRSLTE_DCI_FORMAT0 || format == SRSLTE_DCI_FORMAT1A) { - msg->format = (msg->data[0] == 0)?SRSLTE_DCI_FORMAT0:SRSLTE_DCI_FORMAT1A; - } else { - msg->format = format; + // Check format differentiation + if (msg->format == SRSLTE_DCI_FORMAT0 || msg->format == SRSLTE_DCI_FORMAT1A) { + msg->format = (msg->payload[dci_cfg->cif_enabled ? 3 : 0] == 0) ? SRSLTE_DCI_FORMAT0 : SRSLTE_DCI_FORMAT1A; } } else { - fprintf(stderr, "Error calling pdcch_dci_decode\n"); - } - if (crc_rem) { - DEBUG("Decoded DCI: nCCE=%d, L=%d, format=%s, msg_len=%d, mean=%f, crc_rem=0x%x\n", - location->ncce, location->L, srslte_dci_format_string(format), nof_bits, mean, *crc_rem); + ERROR("Error calling pdcch_dci_decode\n"); } + DEBUG("Decoded DCI: nCCE=%d, L=%d, format=%s, msg_len=%d, mean=%f, crc_rem=0x%x\n", + msg->location.ncce, + msg->location.L, + srslte_dci_format_string(msg->format), + nof_bits, + mean, + msg->rnti); } else { - DEBUG("Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f\n", - location->ncce, location->L, nof_bits, mean); + DEBUG( + "Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f\n", msg->location.ncce, msg->location.L, nof_bits, mean); } } } else { - fprintf(stderr, "Invalid parameters, location=%d,%d\n", location->ncce, location->L); + ERROR("Invalid parameters, location=%d,%d\n", msg->location.ncce, msg->location.L); } return ret; } int cnt=0; -int srslte_pdcch_extract_llr(srslte_pdcch_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t cfi) -{ - cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; - cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - - _sf_symbols[0] = sf_symbols; - for (int i=0;icell.nof_ports;i++) { - _ce[i][0] = ce[i]; - } - return srslte_pdcch_extract_llr_multi(q, _sf_symbols, _ce, noise_estimate, nsubframe, cfi); -} -/** Extracts the LLRs from srslte_dci_location_t location of the subframe and stores them in the srslte_pdcch_t structure. - * DCI messages can be extracted from this location calling the function srslte_pdcch_decode_msg(). - * Every time this function is called (with a different location), the last demodulated symbols are overwritten and - * new messages from other locations can be decoded +/** Performs PDCCH receiver processing to extract LLR for all control region. LLR bits are stored in srslte_pdcch_t object. + * DCI can be decoded from given locations in successive calls to srslte_pdcch_decode_msg() */ -int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t nsubframe, uint32_t cfi) +int srslte_pdcch_extract_llr(srslte_pdcch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - + /* Set pointers for layermapping & precoding */ uint32_t i, nof_symbols; cf_t *x[SRSLTE_MAX_LAYERS]; - if (q != NULL && - nsubframe < 10 && - cfi > 0 && - cfi < 4) - { - - uint32_t e_bits = 72*NOF_CCE(cfi); + if (q != NULL && sf->cfi > 0 && sf->cfi < 4) { + + uint32_t e_bits = 72 * NOF_CCE(sf->cfi); nof_symbols = e_bits/2; - ret = SRSLTE_ERROR; + ret = SRSLTE_ERROR; bzero(q->llr, sizeof(float) * q->max_bits); - - DEBUG("Extracting LLRs: E: %d, SF: %d, CFI: %d\n", - e_bits, nsubframe, cfi); + + DEBUG("Extracting LLRs: E: %d, SF: %d, CFI: %d\n", e_bits, sf->tti % 10, sf->cfi); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - + /* extract symbols */ for (int j=0;jnof_rx_antennas;j++) { - int n = srslte_regs_pdcch_get(q->regs, cfi, sf_symbols[j], q->symbols[j]); + int n = srslte_regs_pdcch_get(q->regs, sf->cfi, sf_symbols[j], q->symbols[j]); if (nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + ERROR("Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); return ret; } /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_regs_pdcch_get(q->regs, cfi, ce[i][j], q->ce[i][j]); + n = srslte_regs_pdcch_get(q->regs, sf->cfi, channel->ce[i][j], q->ce[i][j]); if (nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + ERROR("Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); return ret; } } } - + /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2); + srslte_predecoding_single_multi( + q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, nof_symbols, 1.0f, channel->noise_estimate / 2); } else { srslte_predecoding_diversity_multi(q->symbols, q->ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); @@ -500,15 +483,13 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, q->llr, nof_symbols); /* descramble */ - srslte_scrambling_f_offset(&q->seq[nsubframe], q->llr, 0, e_bits); + srslte_scrambling_f_offset(&q->seq[sf->tti % 10], q->llr, 0, e_bits); ret = SRSLTE_SUCCESS; } return ret; } - - static void crc_set_mask_rnti(uint8_t *crc, uint16_t rnti) { uint32_t i; uint8_t mask[16]; @@ -574,43 +555,42 @@ int srslte_pdcch_dci_encode(srslte_pdcch_t *q, uint8_t *data, uint8_t *e, uint32 * * @TODO: Use a bitmask and CFI to ensure message locations are valid and old messages are not overwritten. */ -int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_location_t location, uint16_t rnti, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], uint32_t nsubframe, uint32_t cfi) +int srslte_pdcch_encode(srslte_pdcch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_dci_msg_t* msg, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t i; - cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t* x[SRSLTE_MAX_LAYERS]; uint32_t nof_symbols; - - if (q != NULL && - sf_symbols != NULL && - nsubframe < 10 && - cfi > 0 && - cfi < 4 && - srslte_dci_location_isvalid(&location)) - { - uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(location.L); + if (q != NULL && sf_symbols != NULL && sf->cfi > 0 && sf->cfi < 4 && srslte_dci_location_isvalid(&msg->location)) { + + uint32_t e_bits = PDCCH_FORMAT_NOF_BITS(msg->location.L); nof_symbols = e_bits/2; ret = SRSLTE_ERROR; - - if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= NOF_CCE(cfi) && - msg->nof_bits < SRSLTE_DCI_MAX_BITS - 16) - { + + if (msg->location.ncce + PDCCH_FORMAT_NOF_CCE(msg->location.L) <= NOF_CCE(sf->cfi) && + msg->nof_bits < SRSLTE_DCI_MAX_BITS - 16) { DEBUG("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - msg->nof_bits, e_bits, location.ncce, location.L, rnti); + msg->nof_bits, + e_bits, + msg->location.ncce, + msg->location.L, + msg->rnti); + + srslte_pdcch_dci_encode(q, msg->payload, q->e, msg->nof_bits, e_bits, msg->rnti); - srslte_pdcch_dci_encode(q, msg->data, q->e, msg->nof_bits, e_bits, rnti); - /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - srslte_scrambling_b_offset(&q->seq[nsubframe], q->e, 72 * location.ncce, e_bits); - + srslte_scrambling_b_offset(&q->seq[sf->tti % 10], q->e, 72 * msg->location.ncce, e_bits); + DEBUG("Scrambling output: "); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_b(stdout, q->e, e_bits); @@ -628,18 +608,25 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - srslte_regs_pdcch_put_offset(q->regs, cfi, q->symbols[i], sf_symbols[i], - location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + srslte_regs_pdcch_put_offset(q->regs, + sf->cfi, + q->symbols[i], + sf_symbols[i], + msg->location.ncce * 9, + PDCCH_FORMAT_NOF_REGS(msg->location.L)); } ret = SRSLTE_SUCCESS; - + } else { - fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d, nof_bits=%d\n", location.ncce, location.L, NOF_CCE(cfi), msg->nof_bits); + ERROR("Illegal DCI message nCCE: %d, L: %d, nof_cce: %d, nof_bits=%d\n", + msg->location.ncce, + msg->location.L, + NOF_CCE(sf->cfi), + msg->nof_bits); } } else { - fprintf(stderr, "Invalid parameters: cfi=%d, L=%d, nCCE=%d\n", cfi, location.L, location.ncce); + ERROR("Invalid parameters: cfi=%d, L=%d, nCCE=%d\n", sf->cfi, msg->location.L, msg->location.ncce); } return ret; } - diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index a203d459d..46683e84b 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -24,13 +24,12 @@ * */ +#include "srslte/srslte.h" +#include #include #include -#include #include -#include -#include -#include +#include #include #include @@ -47,36 +46,28 @@ #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) +/* 3GPP 36.213 Table 5.2-1: The cell-specific ratio rho_B / rho_A for 1, 2, or 4 cell specific antenna ports */ +const static float pdsch_cfg_cell_specific_ratio_table[2][4] = { + /* One antenna port */ {1.0f / 1.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f}, + /* Two or more antenna port */ {5.0f / 4.0f, 1.0f / 1.0f, 3.0f / 4.0f, 1.0f / 2.0f}}; const static srslte_mod_t modulations[4] = { SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; - -//#define DEBUG_IDX - -#ifdef DEBUG_IDX -cf_t *offset_original=NULL; -extern int indices[100000]; -extern int indices_ptr; -#endif - - typedef struct { /* Thread identifier: they must set before thread creation */ pthread_t pthread; - uint32_t cw_idx; uint32_t tb_idx; void *pdsch_ptr; bool *ack; /* Configuration Encoder/Decoder: they must be set before posting start semaphore */ - srslte_pdsch_cfg_t *cfg; - srslte_sch_t dl_sch; - uint16_t rnti; + srslte_dl_sf_cfg_t* sf; + srslte_pdsch_cfg_t* cfg; + srslte_sch_t dl_sch; /* Encoder/Decoder data pointers: they must be set before posting start semaphore */ uint8_t *data; - void *softbuffer; /* Execution status */ int ret_status; @@ -92,15 +83,21 @@ typedef struct { static void *srslte_pdsch_decode_thread (void *arg); -int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_grant_t *grant, uint32_t lstart_grant, uint32_t nsubframe, bool put) +int srslte_pdsch_cp(srslte_pdsch_t* q, + cf_t* input, + cf_t* output, + srslte_pdsch_grant_t* grant, + uint32_t lstart_grant, + uint32_t sf_idx, + bool put) { - uint32_t s, n, l, lp, lstart, lend, nof_refs; - bool is_pbch, is_sss; + uint32_t s, n, l, lp, lstart, nof_refs; + bool skip_symbol; cf_t *in_ptr = input, *out_ptr = output; uint32_t offset = 0; -#ifdef DEBUG_IDX - indices_ptr = 0; +#ifdef DEBUG_IDX + indices_ptr = 0; if (put) { offset_original = output; } else { @@ -115,36 +112,42 @@ int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_g } for (s = 0; s < 2; s++) { - for (l = 0; l < SRSLTE_CP_NSYMB(q->cell.cp); l++) { + if (s == 0) { + lstart = lstart_grant; + } else { + lstart = 0; + } + for (l = lstart; l < grant->nof_symb_slot[s]; l++) { for (n = 0; n < q->cell.nof_prb; n++) { // If this PRB is assigned if (grant->prb_idx[s][n]) { - if (s == 0) { - lstart = lstart_grant; - } else { - lstart = 0; - } - lend = SRSLTE_CP_NSYMB(q->cell.cp); - is_pbch = is_sss = false; - - // Skip PSS/SSS signals - if (s == 0 && (nsubframe == 0 || nsubframe == 5)) { - if (n >= q->cell.nof_prb / 2 - 3 - && n < q->cell.nof_prb / 2 + 3 + (q->cell.nof_prb%2)) { - lend = SRSLTE_CP_NSYMB(q->cell.cp) - 2; - is_sss = true; + + skip_symbol = false; + + // Skip center block signals + if ((n >= q->cell.nof_prb / 2 - 3 && n < q->cell.nof_prb / 2 + 3 + (q->cell.nof_prb % 2))) { + if (q->cell.frame_type == SRSLTE_FDD) { + // FDD PSS/SSS + if (s == 0 && (sf_idx == 0 || sf_idx == 5) && (l >= grant->nof_symb_slot[s] - 2)) { + skip_symbol = true; + } + } else { + // TDD SSS + if (s == 1 && (sf_idx == 0 || sf_idx == 5) && (l >= grant->nof_symb_slot[s] - 1)) { + skip_symbol = true; + } + // TDD PSS + if (s == 0 && (sf_idx == 1 || sf_idx == 6) && (l == 2)) { + skip_symbol = true; + } } - } - // Skip PBCH - if (s == 1 && nsubframe == 0) { - if (n >= q->cell.nof_prb / 2 - 3 - && n < q->cell.nof_prb / 2 + 3 + (q->cell.nof_prb%2)) { - lstart = 4; - is_pbch = true; + // PBCH same in FDD and TDD + if (s == 1 && sf_idx == 0 && l < 4) { + skip_symbol = true; } } - lp = l + s * SRSLTE_CP_NSYMB(q->cell.cp); + lp = l + s * grant->nof_symb_slot[0]; if (put) { out_ptr = &output[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; @@ -153,13 +156,13 @@ int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_g * SRSLTE_NRE]; } // This is a symbol in a normal PRB with or without references - if (l >= lstart && l < lend) { + if (!skip_symbol) { if (SRSLTE_SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { if (nof_refs == 2) { if (l == 0) { offset = q->cell.id % 6; } else { - offset = (q->cell.id + 3) % 6; + offset = (q->cell.id + 3) % 6; } } else { offset = q->cell.id % 3; @@ -169,9 +172,9 @@ int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_g prb_cp(&in_ptr, &out_ptr, 1); } } - // This is a symbol in a PRB with PBCH or Synch signals (SS). + // This is a symbol in a PRB with PBCH or Synch signals (SS). // If the number or total PRB is odd, half of the the PBCH or SS will fall into the symbol - if ((q->cell.nof_prb % 2) && ((is_pbch && l < lstart) || (is_sss && l >= lend))) { + if ((q->cell.nof_prb % 2) && skip_symbol) { if (n == q->cell.nof_prb / 2 - 3) { if (SRSLTE_SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); @@ -192,18 +195,18 @@ int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_g } } } - } + } } } - - int r; + + int r; if (put) { r = abs((int) (input - in_ptr)); } else { r = abs((int) (output - out_ptr)); } - return r; + return r; } /** @@ -213,8 +216,8 @@ int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_g * * 36.211 10.3 section 6.3.5 */ -int srslte_pdsch_put(srslte_pdsch_t *q, cf_t *symbols, cf_t *sf_symbols, - srslte_ra_dl_grant_t *grant, uint32_t lstart, uint32_t subframe) +int srslte_pdsch_put( + srslte_pdsch_t* q, cf_t* symbols, cf_t* sf_symbols, srslte_pdsch_grant_t* grant, uint32_t lstart, uint32_t subframe) { return srslte_pdsch_cp(q, symbols, sf_symbols, grant, lstart, subframe, true); } @@ -226,8 +229,8 @@ int srslte_pdsch_put(srslte_pdsch_t *q, cf_t *symbols, cf_t *sf_symbols, * * 36.211 10.3 section 6.3.5 */ -int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols, - srslte_ra_dl_grant_t *grant, uint32_t lstart, uint32_t subframe) +int srslte_pdsch_get( + srslte_pdsch_t* q, cf_t* sf_symbols, cf_t* symbols, srslte_pdsch_grant_t* grant, uint32_t lstart, uint32_t subframe) { return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false); } @@ -295,7 +298,7 @@ static int pdsch_init(srslte_pdsch_t *q, uint32_t max_prb, bool is_ue, uint32_t q->users = calloc(sizeof(srslte_pdsch_user_t*), q->is_ue?1:(1+SRSLTE_SIRNTI)); if (!q->users) { - perror("malloc"); + ERROR("malloc"); goto clean; } @@ -303,10 +306,19 @@ static int pdsch_init(srslte_pdsch_t *q, uint32_t max_prb, bool is_ue, uint32_t goto clean; } + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (!q->csi[i]) { + q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re * 2); + if (!q->csi[i]) { + return SRSLTE_ERROR; + } + } + } + ret = SRSLTE_SUCCESS; } - clean: +clean: if (ret == SRSLTE_ERROR) { srslte_pdsch_free(q); } @@ -341,6 +353,46 @@ static void srslte_pdsch_disable_coworker(srslte_pdsch_t *q) { } } +int srslte_pdsch_enable_coworker(srslte_pdsch_t* q) +{ + int ret = SRSLTE_SUCCESS; + + if (!q->coworker_ptr) { + srslte_pdsch_coworker_t* h = calloc(sizeof(srslte_pdsch_coworker_t), 1); + + if (!h) { + ERROR("Allocating coworker"); + ret = SRSLTE_ERROR; + goto clean; + } + q->coworker_ptr = h; + + if (srslte_sch_init(&h->dl_sch)) { + ERROR("Initiating DL SCH"); + ret = SRSLTE_ERROR; + goto clean; + } + + if (sem_init(&h->start, 0, 0)) { + ERROR("Creating semaphore"); + ret = SRSLTE_ERROR; + goto clean; + } + if (sem_init(&h->finish, 0, 0)) { + ERROR("Creating semaphore"); + ret = SRSLTE_ERROR; + goto clean; + } + pthread_create(&h->pthread, NULL, srslte_pdsch_decode_thread, (void*)h); + } + +clean: + if (ret) { + srslte_pdsch_disable_coworker(q); + } + return ret; +} + void srslte_pdsch_free(srslte_pdsch_t *q) { srslte_pdsch_disable_coworker(q); @@ -403,10 +455,8 @@ int srslte_pdsch_set_cell(srslte_pdsch_t *q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) - { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + if (q != NULL && srslte_cell_isvalid(&cell)) { + q->cell = cell; q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); INFO("PDSCH: Cell config PCI=%d, %d ports, %d PRBs, max_symbols: %d\n", @@ -417,7 +467,7 @@ int srslte_pdsch_set_cell(srslte_pdsch_t *q, srslte_cell_t cell) return ret; } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while +/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. */ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { @@ -426,60 +476,41 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { if (!q->users[rnti_idx] || q->is_ue) { if (!q->users[rnti_idx]) { q->users[rnti_idx] = calloc(1, sizeof(srslte_pdsch_user_t)); - if(!q->users[rnti_idx]) { - perror("calloc"); + if (!q->users[rnti_idx]) { + ERROR("calloc"); return -1; } } q->users[rnti_idx]->sequence_generated = false; - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { - if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][i], rnti, j, 2 * i, q->cell.id, - q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) - { - fprintf(stderr, "Error initializing PDSCH scrambling sequence\n"); + if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][i], + rnti, + j, + 2 * i, + q->cell.id, + q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + ERROR("Error initializing PDSCH scrambling sequence\n"); srslte_pdsch_free_rnti(q, rnti); return SRSLTE_ERROR; } } } - q->ue_rnti = rnti; + q->ue_rnti = rnti; q->users[rnti_idx]->cell_id = q->cell.id; q->users[rnti_idx]->sequence_generated = true; } else { - fprintf(stderr, "Error generating PDSCH sequence: rnti=0x%x already generated\n", rnti); + ERROR("Error generating PDSCH sequence: rnti=0x%x already generated\n", rnti); } return SRSLTE_SUCCESS; } -void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) { - if (q) { - q->rho_a = rho_a; - } -} - -int srslte_pdsch_enable_csi(srslte_pdsch_t *q, bool enable) { - if (enable) { - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (!q->csi[i]) { - q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re * 2); - if (!q->csi[i]) { - return SRSLTE_ERROR; - } - } - } - } - q->csi_enabled = enable; - - return SRSLTE_SUCCESS; -} - void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { uint32_t rnti_idx = q->is_ue?0:rnti; if (q->users[rnti_idx]) { - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { srslte_sequence_free(&q->users[rnti_idx]->seq[j][i]); } @@ -489,128 +520,42 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) q->ue_rnti = 0; } } - -static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) +static float apply_power_allocation(srslte_pdsch_t* q, srslte_pdsch_cfg_t* cfg, cf_t* sf_symbols_m[SRSLTE_MAX_PORTS]) { - if (SRSLTE_VERBOSE_ISDEBUG()) { - char filename[FILENAME_MAX]; - for (int j = 0; j < q->nof_rx_antennas; j++) { - if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { - ERROR("Generating file name"); - break; - } - DEBUG("SAVED FILE %s: received subframe symbols\n", filename); - srslte_vec_save_file(filename, sf_symbols[j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - - for (int i = 0; i < q->cell.nof_ports; i++) { - if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { - ERROR("Generating file name"); - break; - } - DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i); - srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - } - } - for (int i=0;inof_layers;i++) { - if (snprintf(filename, FILENAME_MAX, "pdsch_symbols_%d.dat", i) < 0) { - ERROR("Generating file name"); - break; - } - DEBUG("SAVED FILE %s: symbols after equalization\n", filename); - srslte_vec_save_file(filename, q->d[i], cfg->nbits[0].nof_re*sizeof(cf_t)); - - if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) { - ERROR("Generating file name"); - break; - } - DEBUG("SAVED FILE %s: LLR estimates after demodulation and descrambling\n", filename); - srslte_vec_save_file(filename, q->e[i], cfg->nbits[0].nof_bits*sizeof(int16_t)); - } - } -} - - -/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. - * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant - */ -int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, - uint32_t sf_idx, int rvidx) { - int _rvids[SRSLTE_MAX_CODEWORDS] = {1}; - _rvids[0] = rvidx; - return srslte_pdsch_cfg_mimo(cfg, cell, grant, cfi, sf_idx, _rvids, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0); -} - -/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg. - * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant - */ -int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, - uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type, - uint32_t pmi) { - if (cfg && grant) { - uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); - memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); - - - for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { - if (grant->tb_en[cw]) { - if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) { - fprintf(stderr, "Error computing Codeword (%d) segmentation for TBS=%d\n", cw, cfg->grant.mcs[cw].tbs); - return SRSLTE_ERROR; - } - } - } - srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits); - - cfg->sf_idx = sf_idx; - memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS); - cfg->mimo_type = mimo_type; - cfg->tb_cw_swap = grant->tb_cw_swap; - - /* Check and configure PDSCH transmission modes */ - switch(mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - if (nof_tb != 1) { - ERROR("Wrong number of transport blocks (%d) for single antenna.", nof_tb); - return SRSLTE_ERROR; - } - cfg->nof_layers = 1; - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - if (nof_tb != 1) { - ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); - return SRSLTE_ERROR; - } - cfg->nof_layers = cell.nof_ports; - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - if (nof_tb == 1) { - cfg->codebook_idx = pmi; - cfg->nof_layers = 1; - } else if (nof_tb == 2) { - cfg->codebook_idx = pmi + 1; - cfg->nof_layers = 2; + uint32_t nof_symbols_slot = cfg->grant.nof_symb_slot[0]; + uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb; + + /* Set power allocation according to 3GPP 36.213 clause 5.2 Downlink power allocation */ + float rho_a = powf(10.0f, cfg->p_a / 20.0f) * ((q->cell.nof_ports == 1) ? 1.0f : sqrtf(2.0f)); + + uint32_t idx0 = (q->cell.nof_ports == 1) ? 0 : 1; + float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][cfg->p_b]; + float rho_b = sqrtf(cell_specific_ratio); + + /* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */ + if (rho_b != 0.0f && rho_b != 1.0f) { + float scaling = 1.0f / rho_b; + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + for (uint32_t j = 0; j < 2; j++) { + cf_t* ptr; + ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + if (q->cell.cp == SRSLTE_CP_NORM) { + ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } else { - ERROR("Wrong number of transport blocks (%d) for spatial multiplexing.", nof_tb); - return SRSLTE_ERROR; + ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } - INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n", - nof_tb, cfg->nof_layers, cfg->codebook_idx); - break; - case SRSLTE_MIMO_TYPE_CDD: - if (nof_tb != 2) { - ERROR("Wrong number of transport blocks (%d) for CDD.", nof_tb); - return SRSLTE_ERROR; + if (q->cell.nof_ports == 4) { + ptr = sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } - cfg->nof_layers = 2; - break; + } } - - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; } + return rho_a; } static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, @@ -631,54 +576,11 @@ static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, } } -static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, - srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx, uint32_t tb_idx) { - srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx]; - srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx]; - uint32_t rv = cfg->rv[tb_idx]; - bool valid_inputs = true; - - if (!softbuffer) { - ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx); - valid_inputs = false; - } - - if (nbits->nof_bits && valid_inputs) { - INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, tb_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, - nbits->nof_re, nbits->nof_bits, rv); - - /* Channel coding */ - if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], tb_idx)) { - ERROR("Error encoding (TB%d -> CW%d)", tb_idx, codeword_idx); - return SRSLTE_ERROR; - } - - /* Select scrambling sequence */ - srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits); - - /* Bit scrambling */ - srslte_scrambling_bytes(seq, (uint8_t *) q->e[codeword_idx], nbits->nof_bits); - - /* Bit mapping */ - srslte_mod_modulate_bytes(&q->mod[mcs->mod], - (uint8_t *) q->e[codeword_idx], - q->d[codeword_idx], nbits->nof_bits); - - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - return SRSLTE_SUCCESS; -} - static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t codeword_idx, uint32_t tb_idx, void *e) { - srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx]; uint32_t qm = 0; - switch(cfg->grant.mcs[tb_idx].mod) { + switch (cfg->grant.tb[tb_idx].mod) { case SRSLTE_MOD_BPSK: qm = 1; @@ -696,16 +598,16 @@ static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t ERROR("No modulation"); } - const uint32_t csi_max_idx = srslte_vec_max_fi(q->csi[codeword_idx], nbits->nof_bits / qm); + const uint32_t csi_max_idx = srslte_vec_max_fi(q->csi[codeword_idx], cfg->grant.tb[tb_idx].nof_bits / qm); float csi_max = 1.0f; - if (csi_max_idx < nbits->nof_bits / qm) { + if (csi_max_idx < cfg->grant.tb[tb_idx].nof_bits / qm) { csi_max = q->csi[codeword_idx][csi_max_idx]; } int8_t *e_b = e; int16_t *e_s = e; - float *csi_v = q->csi[codeword_idx]; + float* csi_v = q->csi[codeword_idx]; if (q->llr_is_8bit) { - for (int i = 0; i < nbits->nof_bits / qm; i++) { + for (int i = 0; i < cfg->grant.tb[tb_idx].nof_bits / qm; i++) { const float csi = *(csi_v++) / csi_max; for (int k = 0; k < qm; k++) { *e_b = (int8_t) ((float) *e_b * csi); @@ -717,11 +619,11 @@ static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t #ifdef LV_HAVE_SSE __m128 _csi_scale = _mm_set1_ps(INT16_MAX / csi_max); - __m64 *_e = (__m64 *) e; + __m64* _e = (__m64*)e; - switch(cfg->grant.mcs[tb_idx].mod) { + switch (cfg->grant.tb[tb_idx].mod) { case SRSLTE_MOD_QPSK: - for (; i < nbits->nof_bits - 3; i += 4) { + for (; i < cfg->grant.tb[tb_idx].nof_bits - 3; i += 4) { __m128 _csi1 = _mm_set1_ps(*(csi_v++)); __m128 _csi2 = _mm_set1_ps(*(csi_v++)); _csi1 = _mm_blend_ps(_csi1, _csi2, 3); @@ -733,7 +635,7 @@ static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t } break; case SRSLTE_MOD_16QAM: - for (; i < nbits->nof_bits - 3; i += 4) { + for (; i < cfg->grant.tb[tb_idx].nof_bits - 3; i += 4) { __m128 _csi = _mm_set1_ps(*(csi_v++)); _csi = _mm_mul_ps(_csi, _csi_scale); @@ -743,7 +645,7 @@ static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t } break; case SRSLTE_MOD_64QAM: - for (; i < nbits->nof_bits - 11; i += 12) { + for (; i < cfg->grant.tb[tb_idx].nof_bits - 11; i += 12) { __m128 _csi1 = _mm_set1_ps(*(csi_v++)); __m128 _csi3 = _mm_set1_ps(*(csi_v++)); @@ -758,15 +660,13 @@ static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t } break; case SRSLTE_MOD_BPSK: - case SRSLTE_MOD_LAST: - /* Do nothing */ break; } i /= qm; #endif /* LV_HAVE_SSE */ - for (; i < nbits->nof_bits / qm; i++) { + for (; i < cfg->grant.tb[tb_idx].nof_bits / qm; i++) { const float csi = q->csi[codeword_idx][i] / csi_max; for (int k = 0; k < qm; k++) { e_s[qm * i + k] = (int16_t) ((float) e_s[qm * i + k] * csi); @@ -775,47 +675,106 @@ static void csi_correction(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, uint32_t } } -static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_sch_t *dl_sch, - srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, - uint32_t codeword_idx, uint32_t tb_idx, bool *ack) { - srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx]; - srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx]; - uint32_t rv = cfg->rv[tb_idx]; +static void pdsch_decode_debug(srslte_pdsch_t* q, + srslte_pdsch_cfg_t* cfg, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + cf_t* ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) +{ + if (SRSLTE_VERBOSE_ISDEBUG()) { + char filename[FILENAME_MAX]; + for (int j = 0; j < q->nof_rx_antennas; j++) { + if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: received subframe symbols\n", filename); + srslte_vec_save_file(filename, sf_symbols[j], SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); + + for (int i = 0; i < q->cell.nof_ports; i++) { + if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i); + srslte_vec_save_file(filename, ce[i][j], SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); + } + } + for (int i = 0; i < cfg->grant.nof_layers; i++) { + if (snprintf(filename, FILENAME_MAX, "pdsch_symbols_%d.dat", i) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: symbols after equalization\n", filename); + srslte_vec_save_file(filename, q->d[i], cfg->grant.nof_re * sizeof(cf_t)); + + if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: LLR estimates after demodulation and descrambling\n", filename); + srslte_vec_save_file(filename, q->e[i], cfg->grant.tb[0].nof_bits * sizeof(int16_t)); + } + } +} + +static int srslte_pdsch_codeword_decode(srslte_pdsch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* cfg, + srslte_sch_t* dl_sch, + uint8_t* data, + uint32_t tb_idx, + bool* ack) +{ + srslte_ra_tb_t* mcs = &cfg->grant.tb[tb_idx]; + uint32_t rv = mcs->rv; + uint32_t codeword_idx = mcs->cw_idx; + uint32_t nof_layers = cfg->grant.nof_layers; + srslte_softbuffer_rx_t* softbuffer = cfg->softbuffers.rx[tb_idx]; + int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (softbuffer && data && ack && nbits->nof_bits && nbits->nof_re) { + if (softbuffer && data && ack && cfg->grant.tb[tb_idx].nof_bits && cfg->grant.nof_re) { INFO("Decoding PDSCH SF: %d (CW%d -> TB%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, codeword_idx, tb_idx, srslte_mod_string(mcs->mod), mcs->tbs, - nbits->nof_re, nbits->nof_bits, rv); + sf->tti % 10, + codeword_idx, + tb_idx, + srslte_mod_string(mcs->mod), + mcs->tbs, + cfg->grant.nof_re, + cfg->grant.tb[tb_idx].nof_bits, + rv); /* demodulate symbols * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ if (q->llr_is_8bit) { - srslte_demod_soft_demodulate_b(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], nbits->nof_re); + srslte_demod_soft_demodulate_b(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], cfg->grant.nof_re); } else { - srslte_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], nbits->nof_re); + srslte_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], cfg->grant.nof_re); } /* Select scrambling sequence */ - srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits); + srslte_sequence_t* seq = + get_user_sequence(q, cfg->rnti, codeword_idx, sf->tti % 10, cfg->grant.tb[tb_idx].nof_bits); + if (!seq) { + ERROR("Error getting user sequence for rnti=0x%x\n", cfg->rnti); + return -1; + } /* Bit scrambling */ if (q->llr_is_8bit) { - srslte_scrambling_sb_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); + srslte_scrambling_sb_offset(seq, q->e[codeword_idx], 0, cfg->grant.tb[tb_idx].nof_bits); } else { - srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); + srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, cfg->grant.tb[tb_idx].nof_bits); } - if (q->csi_enabled) { + if (cfg->csi_enable) { csi_correction(q, cfg, codeword_idx, tb_idx, q->e[codeword_idx]); } /* Return */ - ret = srslte_dlsch_decode2(dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx); - - q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch); + ret = srslte_dlsch_decode2(dl_sch, cfg, q->e[codeword_idx], data, tb_idx, nof_layers); if (ret == SRSLTE_SUCCESS) { *ack = true; @@ -827,8 +786,13 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c ret = SRSLTE_ERROR; } } else { - ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p, nbits=%d, nof_re=%d", - codeword_idx, softbuffer, (void*)data, ack, nbits->nof_bits, nbits->nof_re); + ERROR("Invalid parameters in TB%d &softbuffer=%p &data=%p &ack=%p, nbits=%d, nof_re=%d\n", + codeword_idx, + softbuffer, + (void*)data, + ack, + cfg->grant.tb[tb_idx].nof_bits, + cfg->grant.nof_re); } return ret; @@ -841,15 +805,7 @@ static void *srslte_pdsch_decode_thread(void *arg) { sem_wait(&q->start); while (!q->quit) { - q->ret_status = srslte_pdsch_codeword_decode(q->pdsch_ptr, - q->cfg, - &q->dl_sch, - q->softbuffer, - q->rnti, - q->data, - q->cw_idx, - q->tb_idx, - q->ack); + q->ret_status = srslte_pdsch_codeword_decode(q->pdsch_ptr, q->sf, q->cfg, &q->dl_sch, q->data, q->tb_idx, q->ack); /* Post finish semaphore */ sem_post(&q->finish); @@ -865,39 +821,63 @@ static void *srslte_pdsch_decode_thread(void *arg) { /** Decodes the PDSCH from the received symbols */ -int srslte_pdsch_decode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS], - bool acks[SRSLTE_MAX_CODEWORDS]) +int srslte_pdsch_decode(srslte_pdsch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* cfg, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + srslte_pdsch_res_t data[SRSLTE_MAX_CODEWORDS]) { /* Set pointers for layermapping & precoding */ uint32_t i; - cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t* x[SRSLTE_MAX_LAYERS]; - if (q != NULL && - sf_symbols != NULL && - data != NULL && - cfg != NULL) - { - uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant); + if (q != NULL && sf_symbols != NULL && data != NULL && cfg != NULL) { + + struct timeval t[3]; + if (cfg->meas_time_en) { + gettimeofday(&t[1], NULL); + } + + uint32_t nof_tb = cfg->grant.nof_tb; + + float pdsch_scaling = 1.0f; + if (cfg->power_scale) { + float rho_a = apply_power_allocation(q, cfg, sf_symbols); + if (rho_a != 0.0f && isnormal(rho_a)) { + pdsch_scaling = rho_a; + } + } - INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, mimo_type=%s, nof_layers=%d, nof_tb=%d\n", - cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb, srslte_mod_string(cfg->grant.mcs->mod), cfg->nof_layers, nof_tb); + if (cfg->max_nof_iterations) { + srslte_sch_set_max_noi(&q->dl_sch, cfg->max_nof_iterations); + } + + float noise_estimate = cfg->decoder_type == SRSLTE_MIMO_DECODER_ZF ? 0 : channel->noise_estimate; + + INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, mod=%s, nof_layers=%d, nof_tb=%d\n", + sf->tti % 10, + cfg->rnti, + cfg->grant.nof_re, + cfg->grant.nof_prb, + srslte_mod_string(cfg->grant.tb[0].mod), + cfg->grant.nof_layers, + nof_tb); // Extract Symbols and Channel Estimates + uint32_t lstart = SRSLTE_NOF_CTRL_SYMBOLS(q->cell, sf->cfi); for (int j=0;jnof_rx_antennas;j++) { - int n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); - if (n != cfg->nbits[0].nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); + int n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, lstart, sf->tti % 10); + if (n != cfg->grant.nof_re) { + ERROR("Error expecting %d symbols but got %d\n", cfg->grant.nof_re, n); return SRSLTE_ERROR; } for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); - if (n != cfg->nbits[0].nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); + n = srslte_pdsch_get(q, channel->ce[i][j], q->ce[i][j], &cfg->grant, lstart, sf->tti % 10); + if (n != cfg->grant.nof_re) { + ERROR("Error expecting %d symbols but got %d\n", cfg->grant.nof_re, n); return SRSLTE_ERROR; } } @@ -905,72 +885,69 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, // Prepare layers int nof_symbols [SRSLTE_MAX_CODEWORDS]; - nof_symbols[0] = cfg->nbits[0].nof_re * nof_tb / cfg->nof_layers; - nof_symbols[1] = cfg->nbits[1].nof_re * nof_tb / cfg->nof_layers; + nof_symbols[0] = cfg->grant.nof_re * nof_tb / cfg->grant.nof_layers; + nof_symbols[1] = cfg->grant.nof_re * nof_tb / cfg->grant.nof_layers; - if (cfg->nof_layers == nof_tb) { + if (cfg->grant.nof_layers == nof_tb) { /* Skip layer demap */ - for (i = 0; i < cfg->nof_layers; i++) { + for (i = 0; i < cfg->grant.nof_layers; i++) { x[i] = q->d[i]; } } else { /* number of layers equals number of ports */ - for (i = 0; i < cfg->nof_layers; i++) { + for (i = 0; i < cfg->grant.nof_layers; i++) { x[i] = q->x[i]; } - memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); - } - - float pdsch_scaling = 1.0f; - if (q->rho_a != 0.0f) { - pdsch_scaling = q->rho_a; + memset(&x[cfg->grant.nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->grant.nof_layers)); } // Pre-decoder - if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, - cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) { - DEBUG("Error predecoding\n"); + uint32_t codebook_idx = nof_tb == 1 ? cfg->grant.pmi : (cfg->grant.pmi + 1); + if (srslte_predecoding_type(q->symbols, + q->ce, + x, + q->csi, + q->nof_rx_antennas, + q->cell.nof_ports, + cfg->grant.nof_layers, + codebook_idx, + cfg->grant.nof_re, + cfg->grant.tx_scheme, + pdsch_scaling, + noise_estimate) < 0) { + ERROR("Error predecoding\n"); return SRSLTE_ERROR; } // Layer demapping only if necessary - if (cfg->nof_layers != nof_tb) { - srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb, - nof_symbols[0], nof_symbols, cfg->mimo_type); + if (cfg->grant.nof_layers != nof_tb) { + srslte_layerdemap_type(x, q->d, cfg->grant.nof_layers, nof_tb, nof_symbols[0], nof_symbols, cfg->grant.tx_scheme); } /* Codeword decoding: Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */ - uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0; for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + /* Decode only if transport block is enabled and the default ACK is not true */ - if (cfg->grant.tb_en[tb_idx]) { - if (!acks[tb_idx]) { + if (cfg->grant.tb[tb_idx].enabled) { + if (!data[tb_idx].crc) { int ret = SRSLTE_SUCCESS; - if (SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant) > 1 && tb_idx == 0 && q->coworker_ptr) { + if (cfg->grant.nof_tb > 1 && tb_idx == 0 && q->coworker_ptr) { srslte_pdsch_coworker_t *h = (srslte_pdsch_coworker_t *) q->coworker_ptr; h->pdsch_ptr = q; h->cfg = cfg; - h->softbuffer = softbuffers[tb_idx]; - h->rnti = rnti; - h->data = data[tb_idx]; - h->cw_idx = cw_idx; + h->sf = sf; + h->data = data[tb_idx].payload; h->tb_idx = tb_idx; - h->ack = &acks[tb_idx]; + h->ack = &data[tb_idx].crc; h->dl_sch.max_iterations = q->dl_sch.max_iterations; h->started = true; sem_post(&h->start); } else { - ret = srslte_pdsch_codeword_decode(q, - cfg, - &q->dl_sch, - softbuffers[tb_idx], - rnti, - data[tb_idx], - cw_idx, - tb_idx, - &acks[tb_idx]); + ret = srslte_pdsch_codeword_decode(q, sf, cfg, &q->dl_sch, data[tb_idx].payload, tb_idx, &data[tb_idx].crc); + + data[tb_idx].avg_iterations_block = srslte_sch_last_noi(&q->dl_sch); } /* Check if there has been any execution error */ @@ -978,156 +955,218 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, /* Do Nothing */ } } - - cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS; } } if (q->coworker_ptr) { - srslte_pdsch_coworker_t *h = (srslte_pdsch_coworker_t *) q->coworker_ptr; + srslte_pdsch_coworker_t* h = (srslte_pdsch_coworker_t*)q->coworker_ptr; if (h->started) { int err = sem_wait(&h->finish); if (err) { - printf("SCH coworker: %s (nof_tb=%d)\n", strerror(errno), SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)); + printf("SCH coworker: %s (nof_tb=%d)\n", strerror(errno), cfg->grant.nof_tb); } if (h->ret_status) { ERROR("PDSCH Coworker Decoder: Error decoding"); } - - h->started = false; + data[h->tb_idx].avg_iterations_block = srslte_sch_last_noi(&q->dl_sch); + h->started = false; } } - pdsch_decode_debug(q, cfg, sf_symbols, ce); + pdsch_decode_debug(q, cfg, sf_symbols, channel->ce); + + if (cfg->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + cfg->meas_time_value = t[0].tv_usec; + } return SRSLTE_SUCCESS; } else { + ERROR("Invalid inputs\n"); return SRSLTE_ERROR_INVALID_INPUTS; } } -int srslte_pdsch_pmi_select(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce, - uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) { - - if (q->cell.nof_ports == 2 && q->nof_rx_antennas <= 2) { - int nof_layers = 1; - for (; nof_layers <= q->nof_rx_antennas; nof_layers++ ) { - if (sinr[nof_layers - 1] && pmi) { - if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1], - sinr[nof_layers - 1]) < 0) { - ERROR("PMI Select for %d layers", nof_layers); - return SRSLTE_ERROR; - } - } +static int srslte_pdsch_codeword_encode(srslte_pdsch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* cfg, + srslte_softbuffer_tx_t* softbuffer, + uint8_t* data, + uint32_t tb_idx, + uint32_t nof_layers) +{ + srslte_ra_tb_t* mcs = &cfg->grant.tb[tb_idx]; + uint32_t rv = cfg->grant.tb[tb_idx].rv; + + uint32_t codeword_idx = cfg->grant.tb[tb_idx].cw_idx; + + if (!softbuffer) { + ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (cfg->grant.tb[tb_idx].enabled) { + if (cfg->rnti != SRSLTE_SIRNTI) { + INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + sf->tti % 10, + tb_idx, + codeword_idx, + srslte_mod_string(mcs->mod), + mcs->tbs, + cfg->grant.nof_re, + cfg->grant.tb[tb_idx].nof_bits, + rv); } - /* FIXME: Set other layers to 0 */ - for (; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++ ) { - if (sinr[nof_layers - 1] && pmi) { - for (int cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) { - sinr[nof_layers - 1][cb] = -INFINITY; - } - pmi[nof_layers - 1] = 0; - } + /* Channel coding */ + if (srslte_dlsch_encode2(&q->dl_sch, cfg, data, q->e[codeword_idx], tb_idx, nof_layers)) { + ERROR("Error encoding (TB%d -> CW%d)", tb_idx, codeword_idx); + return SRSLTE_ERROR; } + + /* Select scrambling sequence */ + srslte_sequence_t* seq = + get_user_sequence(q, cfg->rnti, codeword_idx, sf->tti % 10, cfg->grant.tb[tb_idx].nof_bits); + if (!seq) { + ERROR("Error getting user sequence for rnti=0x%x\n", cfg->rnti); + return -1; + } + + /* Bit scrambling */ + srslte_scrambling_bytes(seq, (uint8_t*)q->e[codeword_idx], cfg->grant.tb[tb_idx].nof_bits); + + /* Bit mapping */ + srslte_mod_modulate_bytes( + &q->mod[mcs->mod], (uint8_t*)q->e[codeword_idx], q->d[codeword_idx], cfg->grant.tb[tb_idx].nof_bits); + } else { - DEBUG("Not implemented configuration"); return SRSLTE_ERROR_INVALID_INPUTS; } return SRSLTE_SUCCESS; } -int srslte_pdsch_cn_compute(srslte_pdsch_t *q, - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_ce, float *cn) { - return srslte_precoding_cn(ce, q->cell.nof_ports, q->nof_rx_antennas, nof_ce, cn); -} - -int srslte_pdsch_encode(srslte_pdsch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) +int srslte_pdsch_encode(srslte_pdsch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* cfg, + uint8_t* data[SRSLTE_MAX_CODEWORDS], + cf_t* sf_symbols[SRSLTE_MAX_PORTS]) { int i; /* Set pointers for layermapping & precoding */ - cf_t *x[SRSLTE_MAX_LAYERS]; + cf_t* x[SRSLTE_MAX_LAYERS]; int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - cfg != NULL) { - uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant); + if (q != NULL && cfg != NULL) { + struct timeval t[3]; + if (cfg->meas_time_en) { + gettimeofday(&t[1], NULL); + } + uint32_t nof_tb = cfg->grant.nof_tb; for (i = 0; i < q->cell.nof_ports; i++) { if (sf_symbols[i] == NULL) { + ERROR("Error NULL pointer in sf_symbols[%d]\n", i); return SRSLTE_ERROR_INVALID_INPUTS; } } /* If both transport block size is zero return error */ if (!nof_tb) { + ERROR("Error number of TB is zero\n"); return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->nbits[0].nof_re > q->max_re || cfg->nbits[1].nof_re > q->max_re) { - fprintf(stderr, - "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); + if (cfg->grant.nof_re > q->max_re || cfg->grant.nof_re > q->max_re) { + ERROR("Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + cfg->grant.nof_re, + q->max_re, + q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } + float rho_a = apply_power_allocation(q, cfg, sf_symbols); + /* Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */ - uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0; for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { - if (cfg->grant.tb_en[tb_idx]) { - ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx); - cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS; + if (cfg->grant.tb[tb_idx].enabled) { + ret |= srslte_pdsch_codeword_encode( + q, sf, cfg, cfg->softbuffers.tx[tb_idx], data[tb_idx], tb_idx, cfg->grant.nof_layers); } } /* Set scaling configured by Power Allocation */ float scaling = 1.0f; - if (q->rho_a != 0.0f) { - scaling = q->rho_a; + if (rho_a != 0.0f) { + scaling = rho_a; + } + + if (cfg->rnti != SRSLTE_SIRNTI) { + INFO("Encoding PDSCH SF: %d rho_a=%f, nof_ports=%d, nof_layers=%d, nof_tb=%d, pmi=%d, tx_scheme=%s\n", + sf->tti % 10, + rho_a, + q->cell.nof_ports, + cfg->grant.nof_layers, + nof_tb, + cfg->grant.pmi, + srslte_mimotype2str(cfg->grant.tx_scheme)); } // Layer mapping & precode if necessary if (q->cell.nof_ports > 1) { int nof_symbols; /* If number of layers is equal to transport blocks (codewords) skip layer mapping */ - if (cfg->nof_layers == nof_tb) { - for (i = 0; i < cfg->nof_layers; i++) { + if (cfg->grant.nof_layers == nof_tb) { + for (i = 0; i < cfg->grant.nof_layers; i++) { x[i] = q->d[i]; } - nof_symbols = cfg->nbits[0].nof_re; + nof_symbols = cfg->grant.nof_re; } else { /* Initialise layer map pointers */ - for (i = 0; i < cfg->nof_layers; i++) { + for (i = 0; i < cfg->grant.nof_layers; i++) { x[i] = q->x[i]; } - memset(&x[cfg->nof_layers], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); - - nof_symbols = srslte_layermap_type(q->d, x, nof_tb, cfg->nof_layers, - (int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits[0].nof_re, cfg->nbits[1].nof_re}, - cfg->mimo_type); + memset(&x[cfg->grant.nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->grant.nof_layers)); + + nof_symbols = srslte_layermap_type(q->d, + x, + nof_tb, + cfg->grant.nof_layers, + (int[SRSLTE_MAX_CODEWORDS]){cfg->grant.nof_re, cfg->grant.nof_re}, + cfg->grant.tx_scheme); } /* Precode */ - srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, - nof_symbols, scaling, cfg->mimo_type); + uint32_t codebook_idx = nof_tb == 1 ? cfg->grant.pmi : (cfg->grant.pmi + 1); + srslte_precoding_type(x, + q->symbols, + cfg->grant.nof_layers, + q->cell.nof_ports, + codebook_idx, + nof_symbols, + scaling, + cfg->grant.tx_scheme); } else { if (scaling == 1.0f) { - memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); + memcpy(q->symbols[0], q->d[0], cfg->grant.nof_re * sizeof(cf_t)); } else { - srslte_vec_sc_prod_cfc(q->d[0], scaling, q->symbols[0], cfg->nbits[0].nof_re); + srslte_vec_sc_prod_cfc(q->d[0], scaling, q->symbols[0], cfg->grant.nof_re); } } /* mapping to resource elements */ + uint32_t lstart = SRSLTE_NOF_CTRL_SYMBOLS(q->cell, sf->cfi); for (i = 0; i < q->cell.nof_ports; i++) { - srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx); + srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, lstart, sf->tti % 10); + } + + if (cfg->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + cfg->meas_time_value = t[0].tv_usec; } ret = SRSLTE_SUCCESS; @@ -1135,68 +1174,82 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, return ret; } -void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) { - srslte_sch_set_max_noi(&q->dl_sch, max_iter); -} +int srslte_pdsch_select_pmi(srslte_pdsch_t* q, + srslte_chest_dl_res_t* channel, + uint32_t nof_layers, + uint32_t* best_pmi, + float sinr[SRSLTE_MAX_CODEBOOKS]) +{ + uint32_t nof_ce = SRSLTE_NOF_RE(q->cell); + uint32_t pmi = 0; -float srslte_pdsch_last_noi(srslte_pdsch_t *q) { - float niters = 0; - int active_cw = 0; - for (int i=0;ilast_nof_iterations[i]) { - niters += q->last_nof_iterations[i]; - active_cw++; - } + if (srslte_precoding_pmi_select(channel->ce, nof_ce, channel->noise_estimate, nof_layers, &pmi, sinr) < 0) { + ERROR("PMI Select for %d layers", nof_layers); + return SRSLTE_ERROR; } - if (active_cw) { - return niters/active_cw; - } else { - return 0; + + if (best_pmi) { + *best_pmi = pmi; } -} -int srslte_pdsch_enable_coworker(srslte_pdsch_t *q) { - int ret = SRSLTE_SUCCESS; + return SRSLTE_SUCCESS; +} - if (!q->coworker_ptr) { - srslte_pdsch_coworker_t *h = calloc(sizeof(srslte_pdsch_coworker_t), 1); +int srslte_pdsch_compute_cn(srslte_pdsch_t* q, srslte_chest_dl_res_t* channel, float* cn) +{ + return srslte_precoding_cn(channel->ce, q->cell.nof_ports, q->nof_rx_antennas, SRSLTE_NOF_RE(q->cell), cn); +} - if (!h) { - ERROR("Allocating coworker"); - ret = SRSLTE_ERROR; - goto clean; - } - q->coworker_ptr = h; +uint32_t srslte_pdsch_grant_rx_info(srslte_pdsch_grant_t* grant, + srslte_pdsch_res_t res[SRSLTE_MAX_CODEWORDS], + char* str, + uint32_t str_len) +{ - if (srslte_sch_init(&h->dl_sch)) { - ERROR("Initiating DL SCH"); - ret = SRSLTE_ERROR; - goto clean; - } + uint32_t len = srslte_ra_dl_info(grant, str, str_len); - if (sem_init(&h->start, 0, 0)) { - ERROR("Creating semaphore"); - ret = SRSLTE_ERROR; - goto clean; - } - if (sem_init(&h->finish, 0, 0)) { - ERROR("Creating semaphore"); - ret = SRSLTE_ERROR; - goto clean; + len = srslte_print_check(str, str_len, len, ", crc={", 0); + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb[i].enabled) { + len = srslte_print_check(str, str_len, len, "%s", res[i].crc ? "OK" : "KO"); + if (i < SRSLTE_MAX_CODEWORDS - 1) { + if (grant->tb[i + 1].enabled) { + len = srslte_print_check(str, str_len, len, "/", 0); + } + } } - pthread_create(&h->pthread, NULL, srslte_pdsch_decode_thread, (void *) h); } + len = srslte_print_check(str, str_len, len, "}", 0); - clean: - if (ret) { - srslte_pdsch_disable_coworker(q); - } - return ret; + // Average iterations between nof TB and divide by 2 to get full decoder iterations + len = srslte_print_check( + str, str_len, len, ", it=%.1f", (res[0].avg_iterations_block + res[1].avg_iterations_block) / grant->nof_tb / 2); + + return len; } -uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, uint32_t cw_idx) { - return q->last_nof_iterations[cw_idx]; +uint32_t +srslte_pdsch_rx_info(srslte_pdsch_cfg_t* cfg, srslte_pdsch_res_t res[SRSLTE_MAX_CODEWORDS], char* str, uint32_t str_len) +{ + + uint32_t len = srslte_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti); + len += srslte_pdsch_grant_rx_info(&cfg->grant, res, &str[len], str_len - len); + + if (cfg->meas_time_en) { + len = srslte_print_check(str, str_len, len, ", t=%d us\n", cfg->meas_time_value); + } + + return len; } +uint32_t srslte_pdsch_tx_info(srslte_pdsch_cfg_t* cfg, char* str, uint32_t str_len) +{ - + uint32_t len = srslte_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti); + len += srslte_ra_dl_info(&cfg->grant, &str[len], str_len); + + if (cfg->meas_time_en) { + len = srslte_print_check(str, str_len, len, ", t=%d us", cfg->meas_time_value); + } + return len; +} diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index 21bfb040b..78a905df1 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "srslte/phy/phch/regs.h" #include "srslte/phy/phch/phich.h" @@ -94,7 +93,7 @@ int srslte_phich_init(srslte_phich_t *q, uint32_t nof_rx_antennas) } void srslte_phich_free(srslte_phich_t *q) { - for (int ns = 0; ns < SRSLTE_NSUBFRAMES_X_FRAME; ns++) { + for (int ns = 0; ns < SRSLTE_NOF_SF_X_FRAME; ns++) { srslte_sequence_free(&q->seq[ns]); } srslte_modem_table_free(&q->mod); @@ -102,6 +101,11 @@ void srslte_phich_free(srslte_phich_t *q) { bzero(q, sizeof(srslte_phich_t)); } +void srslte_phich_set_regs(srslte_phich_t* q, srslte_regs_t* regs) +{ + q->regs = regs; +} + int srslte_phich_set_cell(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -114,8 +118,8 @@ int srslte_phich_set_cell(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t q->regs = regs; if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - for (int nsf = 0; nsf < SRSLTE_NSUBFRAMES_X_FRAME; nsf++) { + q->cell = cell; + for (int nsf = 0; nsf < SRSLTE_NOF_SF_X_FRAME; nsf++) { if (srslte_sequence_phich(&q->seq[nsf], 2 * nsf, q->cell.id)) { return SRSLTE_ERROR; } @@ -129,12 +133,17 @@ int srslte_phich_set_cell(srslte_phich_t *q, srslte_regs_t *regs, srslte_cell_t /* Computes n_group and n_seq according to Section 9.1.2 in 36.213 */ -void srslte_phich_calc(srslte_phich_t *q, uint32_t n_prb_lowest, uint32_t n_dmrs, - uint32_t *ngroup, uint32_t *nseq) +void srslte_phich_calc(srslte_phich_t* q, srslte_phich_grant_t* grant, srslte_phich_resource_t* n_phich) { - uint32_t Ngroups = srslte_phich_ngroups(q); - *ngroup = (n_prb_lowest+n_dmrs)%Ngroups; - *nseq = ((n_prb_lowest/Ngroups)+n_dmrs)%(2*srslte_phich_nsf(q)); + uint32_t Ngroups = srslte_phich_ngroups(q); + if (Ngroups) { + if (n_phich) { + n_phich->ngroup = (grant->n_prb_lowest + grant->n_dmrs) % Ngroups + grant->I_phich * Ngroups; + n_phich->nseq = ((grant->n_prb_lowest / Ngroups) + grant->n_dmrs) % (2 * srslte_phich_nsf(q)); + } + } else { + ERROR("PHICH: Error computing PHICH groups. Ngroups is zero\n"); + } } @@ -153,7 +162,7 @@ uint8_t srslte_phich_ack_decode(float bits[SRSLTE_PHICH_NBITS], float *distance) } for (i = 0; i < 2; i++) { - float corr = srslte_vec_dot_prod_fff(ack_table[i], bits, SRSLTE_PHICH_NBITS); + float corr = srslte_vec_dot_prod_fff(ack_table[i], bits, SRSLTE_PHICH_NBITS) / SRSLTE_PHICH_NBITS; INFO("Corr%d=%f\n", i, corr); if (corr > max_corr) { max_corr = corr; @@ -173,9 +182,13 @@ void srslte_phich_ack_encode(uint8_t ack, uint8_t bits[SRSLTE_PHICH_NBITS]) { memset(bits, ack, 3 * sizeof(uint8_t)); } -int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { +int srslte_phich_decode(srslte_phich_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_chest_dl_res_t* channel, + srslte_phich_resource_t n_phich, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + srslte_phich_res_t* result) +{ /* Set pointers for layermapping & precoding */ int i, j; @@ -185,28 +198,30 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], return SRSLTE_ERROR_INVALID_INPUTS; } - if (subframe >= SRSLTE_NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", subframe); + uint32_t sf_idx = sf->tti % 10; + + if (sf_idx >= SRSLTE_NOF_SF_X_FRAME) { + ERROR("Invalid nslot %d\n", sf_idx); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(q->cell.cp)) { - if (nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { - fprintf(stderr, "Invalid nseq %d\n", nseq); + if (n_phich.nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { + ERROR("Invalid nseq %d\n", n_phich.nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } else { - if (nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { - fprintf(stderr, "Invalid nseq %d\n", nseq); + if (n_phich.nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { + ERROR("Invalid nseq %d\n", n_phich.nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } - if (ngroup >= srslte_regs_phich_ngroups(q->regs)) { - fprintf(stderr, "Invalid ngroup %d\n", ngroup); + if (n_phich.ngroup >= srslte_regs_phich_ngroups(q->regs)) { + ERROR("Invalid ngroup %d\n", n_phich.ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } - DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); + DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", n_phich.ngroup, n_phich.nseq); /* number of layers equals number of ports */ for (i = 0; i < SRSLTE_MAX_PORTS; i++) { @@ -218,17 +233,16 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], /* extract symbols */ for (int j=0;jnof_rx_antennas;j++) { - if (SRSLTE_PHICH_MAX_NSYMB - != srslte_regs_phich_get(q->regs, sf_symbols[j], q->sf_symbols[j], ngroup)) { - fprintf(stderr, "There was an error getting the phich symbols\n"); + if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, sf_symbols[j], q->sf_symbols[j], n_phich.ngroup)) { + ERROR("There was an error getting the phich symbols\n"); return SRSLTE_ERROR; } q_sf_symbols[j] = q->sf_symbols[j]; /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { - if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i][j], q->ce[i][j], ngroup)) { - fprintf(stderr, "There was an error getting the phich symbols\n"); + if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, channel->ce[i][j], q->ce[i][j], n_phich.ngroup)) { + ERROR("There was an error getting the phich symbols\n"); return SRSLTE_ERROR; } q_ce[i][j] = q->ce[i][j]; @@ -239,7 +253,8 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ - srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, NULL, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate); + srslte_predecoding_single_multi( + q_sf_symbols, q_ce[0], q->d0, NULL, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, channel->noise_estimate); } else { srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); @@ -250,7 +265,7 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], srslte_vec_fprint_c(stdout, q->d0, SRSLTE_PHICH_MAX_NSYMB); if (SRSLTE_CP_ISEXT(q->cell.cp)) { - if (ngroup % 2) { + if (n_phich.ngroup % 2) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d[2 * i + 0] = q->d0[4 * i + 2]; q->d[2 * i + 1] = q->d0[4 * i + 3]; @@ -269,23 +284,21 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d, SRSLTE_PHICH_EXT_MSYMB); - srslte_scrambling_c(&q->seq[subframe], q->d); + srslte_scrambling_c(&q->seq[sf_idx], q->d); /* De-spreading */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { for (i = 0; i < SRSLTE_PHICH_NBITS; i++) { q->z[i] = 0; for (j = 0; j < SRSLTE_PHICH_EXT_NSF; j++) { - q->z[i] += conjf(w_ext[nseq][j]) - * q->d[i * SRSLTE_PHICH_EXT_NSF + j] / SRSLTE_PHICH_EXT_NSF; + q->z[i] += conjf(w_ext[n_phich.nseq][j]) * q->d[i * SRSLTE_PHICH_EXT_NSF + j] / SRSLTE_PHICH_EXT_NSF; } } } else { for (i = 0; i < SRSLTE_PHICH_NBITS; i++) { q->z[i] = 0; for (j = 0; j < SRSLTE_PHICH_NORM_NSF; j++) { - q->z[i] += conjf(w_normal[nseq][j]) - * q->d[i * SRSLTE_PHICH_NORM_NSF + j] / SRSLTE_PHICH_NORM_NSF; + q->z[i] += conjf(w_normal[n_phich.nseq][j]) * q->d[i * SRSLTE_PHICH_NORM_NSF + j] / SRSLTE_PHICH_NORM_NSF; } } } @@ -296,8 +309,8 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], srslte_demod_soft_demodulate(SRSLTE_MOD_BPSK, q->z, q->data_rx, SRSLTE_PHICH_NBITS); - if (ack) { - *ack = srslte_phich_ack_decode(q->data_rx, distance); + if (result) { + result->ack_value = srslte_phich_ack_decode(q->data_rx, &result->distance); } return SRSLTE_SUCCESS; @@ -306,36 +319,41 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], /** Encodes ACK/NACK bits, modulates and inserts into resource. * The parameter ack is an array of srslte_phich_ngroups() pointers to buffers of nof_sequences uint8_ts */ -int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_t nseq, uint32_t subframe, - cf_t *slot_symbols[SRSLTE_MAX_PORTS]) { +int srslte_phich_encode(srslte_phich_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_phich_resource_t n_phich, + uint8_t ack, + cf_t* sf_symbols[SRSLTE_MAX_PORTS]) +{ int i; - if (q == NULL || slot_symbols == NULL) { + if (q == NULL || sf_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (subframe >= SRSLTE_NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", subframe); + uint32_t sf_idx = sf->tti % 10; + + if (sf_idx >= SRSLTE_NOF_SF_X_FRAME) { + ERROR("Invalid nslot %d\n", sf_idx); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(q->cell.cp)) { - if (nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { - fprintf(stderr, "Invalid nseq %d\n", nseq); + if (n_phich.nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { + ERROR("Invalid nseq %d\n", n_phich.nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } else { - if (nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { - fprintf(stderr, "Invalid nseq %d\n", nseq); + if (n_phich.nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { + ERROR("Invalid nseq %d\n", n_phich.nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } - if (ngroup >= srslte_regs_phich_ngroups(q->regs)) { - fprintf(stderr, "Invalid ngroup %d\n", ngroup); + if (n_phich.ngroup >= srslte_regs_phich_ngroups(q->regs)) { + ERROR("Invalid ngroup %d\n", n_phich.ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } - /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; cf_t *symbols_precoding[SRSLTE_MAX_PORTS]; @@ -360,13 +378,11 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ /* Spread with w */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB; i++) { - q->d[i] = w_ext[nseq][i % SRSLTE_PHICH_EXT_NSF] - * q->z[i / SRSLTE_PHICH_EXT_NSF]; + q->d[i] = w_ext[n_phich.nseq][i % SRSLTE_PHICH_EXT_NSF] * q->z[i / SRSLTE_PHICH_EXT_NSF]; } } else { for (i = 0; i < SRSLTE_PHICH_NORM_MSYMB; i++) { - q->d[i] = w_normal[nseq][i % SRSLTE_PHICH_NORM_NSF] - * q->z[i / SRSLTE_PHICH_NORM_NSF]; + q->d[i] = w_normal[n_phich.nseq][i % SRSLTE_PHICH_NORM_NSF] * q->z[i / SRSLTE_PHICH_NORM_NSF]; } } @@ -374,11 +390,11 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d, SRSLTE_PHICH_EXT_MSYMB); - srslte_scrambling_c(&q->seq[subframe], q->d); + srslte_scrambling_c(&q->seq[sf_idx], q->d); /* align to REG */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { - if (ngroup % 2) { + if (n_phich.ngroup % 2) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d0[4 * i + 0] = 0; q->d0[4 * i + 1] = 0; @@ -413,9 +429,8 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_ /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - if (srslte_regs_phich_add(q->regs, q->sf_symbols[i], ngroup, slot_symbols[i]) - < 0) { - fprintf(stderr, "Error putting PCHICH resource elements\n"); + if (srslte_regs_phich_add(q->regs, q->sf_symbols[i], n_phich.ngroup, sf_symbols[i]) < 0) { + ERROR("Error putting PCHICH resource elements\n"); return SRSLTE_ERROR; } } diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c index c5d4ad24c..626e648cf 100644 --- a/lib/src/phy/phch/pmch.c +++ b/lib/src/phy/phch/pmch.c @@ -34,33 +34,18 @@ #include #include "prb_dl.h" -#include "srslte/phy/phch/sch.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/pmch.h" #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" - #define MAX_PMCH_RE (2 * SRSLTE_CP_EXT_NSYMB * 12) - const static srslte_mod_t modulations[4] = { SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; - -//#define DEBUG_IDX - -#ifdef DEBUG_IDX -cf_t *offset_original=NULL; -extern int indices[100000]; -extern int indices_ptr; -#endif -float srslte_pmch_coderate(uint32_t tbs, uint32_t nof_re) -{ - return (float) (tbs + 24)/(nof_re); -} - -int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put) +static int pmch_cp(srslte_pmch_t* q, cf_t* input, cf_t* output, uint32_t lstart_grant, bool put) { uint32_t s, n, l, lp, lstart, lend, nof_refs; cf_t *in_ptr = input, *out_ptr = output; @@ -127,9 +112,9 @@ int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_ * * 36.211 10.3 section 6.3.5 */ -int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart) +static int pmch_put(srslte_pmch_t* q, cf_t* symbols, cf_t* sf_symbols, uint32_t lstart) { - return srslte_pmch_cp(q, symbols, sf_symbols, lstart, true); + return pmch_cp(q, symbols, sf_symbols, lstart, true); } /** @@ -139,17 +124,12 @@ int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t * * 36.211 10.3 section 6.3.5 */ -int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart) -{ - return srslte_pmch_cp(q, sf_symbols, symbols, lstart, false); -} - -int srslte_pmch_init(srslte_pmch_t *q, uint32_t max_prb) +static int pmch_get(srslte_pmch_t* q, cf_t* sf_symbols, cf_t* symbols, uint32_t lstart) { - return srslte_pmch_init_multi(q, max_prb, 1); + return pmch_cp(q, sf_symbols, symbols, lstart, false); } -int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas) +int srslte_pmch_init(srslte_pmch_t* q, uint32_t max_prb, uint32_t nof_rx_antennas) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -271,7 +251,7 @@ int srslte_pmch_set_cell(srslte_pmch_t *q, srslte_cell_t cell) if (q != NULL && srslte_cell_isvalid(&cell)) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; q->max_re = q->cell.nof_prb * MAX_PMCH_RE; INFO("PMCH: Cell config PCI=%d, %d ports, %d PRBs, max_symbols: %d\n", q->cell.nof_ports, @@ -290,9 +270,9 @@ int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id) { if (!q->seqs[area_id]) { q->seqs[area_id] = calloc(1, sizeof(srslte_pmch_seq_t)); if (q->seqs[area_id]) { - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { if (srslte_sequence_pmch(&q->seqs[area_id]->seq[i], 2 * i , area_id, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } } @@ -303,7 +283,7 @@ int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id) { void srslte_pmch_free_area_id(srslte_pmch_t* q, uint16_t area_id) { if (q->seqs[area_id]) { - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { srslte_sequence_free(&q->seqs[area_id]->seq[i]); } free(q->seqs[area_id]); @@ -311,150 +291,162 @@ void srslte_pmch_free_area_id(srslte_pmch_t* q, uint16_t area_id) } } -int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx) -{ - if (cfg) { - if (grant) { - memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); - } - if (srslte_cbsegm(&cfg->cb_segm[0], cfg->grant.mcs[0].tbs)) { - fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs[0].tbs); - return SRSLTE_ERROR; - } - srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits); - cfg->sf_idx = sf_idx; - cfg->rv[0] = SRSLTE_PMCH_RV; - - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - - -int srslte_pmch_decode(srslte_pmch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint16_t area_id, uint8_t *data) -{ - cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; - cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - - _sf_symbols[0] = sf_symbols; - for (int i=0;icell.nof_ports;i++) { - _ce[i][0] = ce[i]; - } - return srslte_pmch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, area_id, data); -} - /** Decodes the pmch from the received symbols */ -int srslte_pmch_decode_multi(srslte_pmch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, - uint16_t area_id, uint8_t *data) +int srslte_pmch_decode(srslte_pmch_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pmch_cfg_t* cfg, + srslte_chest_dl_res_t* channel, + cf_t* sf_symbols[SRSLTE_MAX_PORTS], + srslte_pdsch_res_t* out) { /* Set pointers for layermapping & precoding */ uint32_t i, n; cf_t *x[SRSLTE_MAX_LAYERS]; - - if (q != NULL && - sf_symbols != NULL && - data != NULL && - cfg != NULL) - { - INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n", - cfg->sf_idx, area_id, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, cfg->nbits[0].nof_re, - cfg->nbits[0].nof_bits, 0, cfg->grant.nof_prb, cfg->nbits[0].lstart-1); + + if (q != NULL && sf_symbols != NULL && out != NULL && cfg != NULL) { + INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, " + "C_prb=%d, cfi=%d\n", + sf->tti % 10, + cfg->area_id, + srslte_mod_string(cfg->pdsch_cfg.grant.tb[0].mod), + cfg->pdsch_cfg.grant.tb[0].tbs, + cfg->pdsch_cfg.grant.nof_re, + cfg->pdsch_cfg.grant.tb[0].nof_bits, + 0, + cfg->pdsch_cfg.grant.nof_prb, + sf->cfi); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); - - for (int j=0;jnof_rx_antennas;j++) { + + uint32_t lstart = SRSLTE_NOF_CTRL_SYMBOLS(q->cell, sf->cfi); + for (int j = 0; j < q->nof_rx_antennas; j++) { /* extract symbols */ - n = srslte_pmch_get(q, sf_symbols[j], q->symbols[j], cfg->nbits[0].lstart); - if (n != cfg->nbits[0].nof_re) { - - fprintf(stderr, "PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", cfg->nbits[0].nof_re, n, cfg->nbits[0].lstart); + n = pmch_get(q, sf_symbols[j], q->symbols[j], lstart); + if (n != cfg->pdsch_cfg.grant.nof_re) { + + ERROR("PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", + cfg->pdsch_cfg.grant.nof_re, + n, + lstart); return SRSLTE_ERROR; } - + /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { - n = srslte_pmch_get(q, ce[i][j], q->ce[i][j], cfg->nbits[0].lstart); - if (n != cfg->nbits[0].nof_re) { - fprintf(stderr, "PMCH 2 extract chest error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); + n = pmch_get(q, channel->ce[i][j], q->ce[i][j], lstart); + if (n != cfg->pdsch_cfg.grant.nof_re) { + ERROR("PMCH 2 extract chest error expecting %d symbols but got %d\n", cfg->pdsch_cfg.grant.nof_re, n); return SRSLTE_ERROR; } - } + } } - + // No tx diversity in MBSFN - srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate); - + srslte_predecoding_single_multi(q->symbols, + q->ce[0], + q->d, + NULL, + q->nof_rx_antennas, + cfg->pdsch_cfg.grant.nof_re, + 1.0f, + channel->noise_estimate); + if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); - srslte_vec_save_file("subframe.dat", sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("subframe2.dat", q->symbols[0], cfg->pdsch_cfg.grant.nof_re * sizeof(cf_t)); DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n"); - srslte_vec_save_file("hest0.dat", ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + printf("nof_prb=%d, cp=%d, nof_re=%d, grant_re=%d\n", + q->cell.nof_prb, + q->cell.cp, + SRSLTE_NOF_RE(q->cell), + cfg->pdsch_cfg.grant.nof_re); + srslte_vec_save_file("hest2.dat", channel->ce[0][0], SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n"); - srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); + srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->pdsch_cfg.grant.nof_re * sizeof(cf_t)); } - - /* demodulate symbols - * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, - * thus we don't need tot set it in thde LLRs normalization - */ - srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re); - + + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in thde LLRs normalization + */ + srslte_demod_soft_demodulate_s(cfg->pdsch_cfg.grant.tb[0].mod, q->d, q->e, cfg->pdsch_cfg.grant.nof_re); + /* descramble */ - srslte_scrambling_s_offset(&q->seqs[area_id]->seq[cfg->sf_idx], q->e, 0, cfg->nbits[0].nof_bits); - + srslte_scrambling_s_offset(&q->seqs[cfg->area_id]->seq[sf->tti % 10], q->e, 0, cfg->pdsch_cfg.grant.tb[0].nof_bits); + + if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n"); - srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); + srslte_vec_save_file("llr.dat", q->e, cfg->pdsch_cfg.grant.tb[0].nof_bits * sizeof(int16_t)); } - return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); + out[0].crc = (srslte_dlsch_decode(&q->dl_sch, &cfg->pdsch_cfg, q->e, out[0].payload) == 0); + out[0].avg_iterations_block = srslte_sch_last_noi(&q->dl_sch); + + return SRSLTE_SUCCESS; } else { return SRSLTE_ERROR_INVALID_INPUTS; } } +void srslte_configure_pmch(srslte_pmch_cfg_t* pmch_cfg, srslte_cell_t* cell, srslte_mbsfn_cfg_t* mbsfn_cfg) +{ + pmch_cfg->area_id = 1; + pmch_cfg->pdsch_cfg.grant.nof_layers = 1; + pmch_cfg->pdsch_cfg.grant.nof_prb = cell->nof_prb; + pmch_cfg->pdsch_cfg.grant.tb[0].mcs_idx = mbsfn_cfg->mbsfn_mcs; + pmch_cfg->pdsch_cfg.grant.tb[0].enabled = mbsfn_cfg->enable; + pmch_cfg->pdsch_cfg.grant.tb[0].rv = SRSLTE_PMCH_RV; + pmch_cfg->pdsch_cfg.grant.last_tbs[0] = 0; + srslte_dl_fill_ra_mcs( + &pmch_cfg->pdsch_cfg.grant.tb[0], pmch_cfg->pdsch_cfg.grant.last_tbs[0], pmch_cfg->pdsch_cfg.grant.nof_prb); + pmch_cfg->pdsch_cfg.grant.nof_tb = 1; + pmch_cfg->pdsch_cfg.grant.nof_layers = 1; + for (int i = 0; i < 2; i++) { + for (uint32_t j = 0; j < pmch_cfg->pdsch_cfg.grant.nof_prb; j++) { + pmch_cfg->pdsch_cfg.grant.prb_idx[i][j] = true; + } + } +} -int srslte_pmch_encode(srslte_pmch_t *q, - srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint16_t area_id, cf_t *sf_symbols[SRSLTE_MAX_PORTS]) +int srslte_pmch_encode( + srslte_pmch_t* q, srslte_dl_sf_cfg_t* sf, srslte_pmch_cfg_t* cfg, uint8_t* data, cf_t* sf_symbols[SRSLTE_MAX_PORTS]) { - + int i; /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; - int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && cfg != NULL) - { - for (i=0;icell.nof_ports;i++) { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && cfg != NULL) { + for (i = 0; i < q->cell.nof_ports; i++) { if (sf_symbols[i] == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } } - - if (cfg->grant.mcs[0].tbs == 0) { + + if (cfg->pdsch_cfg.grant.tb[0].tbs == 0) { return SRSLTE_ERROR_INVALID_INPUTS; } - - if (cfg->nbits[0].nof_re > q->max_re) { - fprintf(stderr, - "Error too many RE per subframe (%d). PMCH configured for %d RE (%d PRB)\n", - cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); + + if (cfg->pdsch_cfg.grant.nof_re > q->max_re) { + ERROR("Error too many RE per subframe (%d). PMCH configured for %d RE (%d PRB)\n", + cfg->pdsch_cfg.grant.nof_re, + q->max_re, + q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } INFO("Encoding PMCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, - cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, 0); + sf->tti % 10, + srslte_mod_string(cfg->pdsch_cfg.grant.tb[0].mod), + cfg->pdsch_cfg.grant.tb[0].tbs, + cfg->pdsch_cfg.grant.nof_re, + cfg->pdsch_cfg.grant.tb[0].nof_bits, + 0); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -463,22 +455,25 @@ int srslte_pmch_encode(srslte_pmch_t *q, memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); // TODO: use tb_encode directly - if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) { - fprintf(stderr, "Error encoding TB\n"); + if (srslte_dlsch_encode(&q->dl_sch, &cfg->pdsch_cfg, data, q->e)) { + ERROR("Error encoding TB\n"); return SRSLTE_ERROR; } /* scramble */ - srslte_scrambling_bytes(&q->seqs[area_id]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits[0].nof_bits); + srslte_scrambling_bytes( + &q->seqs[cfg->area_id]->seq[sf->tti % 10], (uint8_t*)q->e, cfg->pdsch_cfg.grant.tb[0].nof_bits); + + srslte_mod_modulate_bytes( + &q->mod[cfg->pdsch_cfg.grant.tb[0].mod], (uint8_t*)q->e, q->d, cfg->pdsch_cfg.grant.tb[0].nof_bits); - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs[0].mod], (uint8_t*) q->e, q->d, cfg->nbits[0].nof_bits); - /* No tx diversity in MBSFN */ - memcpy(q->symbols[0], q->d, cfg->nbits[0].nof_re * sizeof(cf_t)); + memcpy(q->symbols[0], q->d, cfg->pdsch_cfg.grant.nof_re * sizeof(cf_t)); /* mapping to resource elements */ + uint32_t lstart = SRSLTE_NOF_CTRL_SYMBOLS(q->cell, sf->cfi); for (i = 0; i < q->cell.nof_ports; i++) { - srslte_pmch_put(q, q->symbols[i], sf_symbols[i], cfg->nbits[0].lstart); + pmch_put(q, q->symbols[i], sf_symbols[i], lstart); } ret = SRSLTE_SUCCESS; @@ -486,10 +481,6 @@ int srslte_pmch_encode(srslte_pmch_t *q, return ret; } -uint32_t srslte_pmch_last_noi(srslte_pmch_t *q) { - return q->dl_sch.nof_iterations; -} - diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index 85717a3f3..d9b8ec2bd 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -24,15 +24,17 @@ * */ +#include "srslte/srslte.h" #include #include -#include #include "srslte/phy/common/phy_common.h" #include "srslte/phy/phch/prach.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" +#include "prach_tables.h" + float save_corr[4096]; //PRACH detection threshold is PRACH_DETECT_FACTOR*average @@ -49,132 +51,13 @@ float save_corr[4096]; #define PRACH_AMP 1.0 -/****************************************************** - * Reference tables from 3GPP TS 36.211 v10.7.0 - *****************************************************/ - -// Table 5.7.1-1 T_cp for preamble formats -uint32_t prach_Tcp[5] = {3168, 21024, 6240, 21024, 448}; - -// Table 5.7.1-1 T_seq for preamble formats -uint32_t prach_Tseq[5] = {24576, 24576, 2 * 24576, 2 * 24576, 4096}; - -// Table 5.7.2-2 - N_cs values for unrestricted sets -uint32_t prach_Ncs_unrestricted[16] = {0, 13, 15, 18, 22, 26, 32, 38, 46, 59, 76, 93, 119, 167, 279, 419}; - -#define MAX_N_zc 839 - -// Table 5.7.2-2 - N_cs values for restricted sets -uint32_t prach_Ncs_restricted[15] = {15, 18, 22, 26, 32, 38, 46, 55, 68, 82, 100, 128, 158, 202, 237}; - -// Table 5.7.2-3 - N_cs values for preamble format 4 -uint32_t prach_Ncs_format4[7] = {2, 4, 6, 8, 10, 12, 15}; - -// Table 5.7.2-4 - Root ZC sequence order -uint32_t prach_zc_roots[838] = { - 129, 710, 140, 699, 120, 719, 210, 629, 168, 671, 84, 755, - 105, 734, 93, 746, 70, 769, 60, 779, 2, 837, 1, 838, - 56, 783, 112, 727, 148, 691, 80, 759, 42, 797, 40, 799, - 35, 804, 73, 766, 146, 693, 31, 808, 28, 811, 30, 809, - 27, 812, 29, 810, 24, 815, 48, 791, 68, 771, 74, 765, - 178, 661, 136, 703, 86, 753, 78, 761, 43, 796, 39, 800, - 20, 819, 21, 818, 95, 744, 202, 637, 190, 649, 181, 658, - 137, 702, 125, 714, 151, 688, 217, 622, 128, 711, 142, 697, - 122, 717, 203, 636, 118, 721, 110, 729, 89, 750, 103, 736, - 61, 778, 55, 784, 15, 824, 14, 825, 12, 827, 23, 816, - 34, 805, 37, 802, 46, 793, 207, 632, 179, 660, 145, 694, - 130, 709, 223, 616, 228, 611, 227, 612, 132, 707, 133, 706, - 143, 696, 135, 704, 161, 678, 201, 638, 173, 666, 106, 733, - 83, 756, 91, 748, 66, 773, 53, 786, 10, 829, 9, 830, - 7, 832, 8, 831, 16, 823, 47, 792, 64, 775, 57, 782, - 104, 735, 101, 738, 108, 731, 208, 631, 184, 655, 197, 642, - 191, 648, 121, 718, 141, 698, 149, 690, 216, 623, 218, 621, - 152, 687, 144, 695, 134, 705, 138, 701, 199, 640, 162, 677, - 176, 663, 119, 720, 158, 681, 164, 675, 174, 665, 171, 668, - 170, 669, 87, 752, 169, 670, 88, 751, 107, 732, 81, 758, - 82, 757, 100, 739, 98, 741, 71, 768, 59, 780, 65, 774, - 50, 789, 49, 790, 26, 813, 17, 822, 13, 826, 6, 833, - 5, 834, 33, 806, 51, 788, 75, 764, 99, 740, 96, 743, - 97, 742, 166, 673, 172, 667, 175, 664, 187, 652, 163, 676, - 185, 654, 200, 639, 114, 725, 189, 650, 115, 724, 194, 645, - 195, 644, 192, 647, 182, 657, 157, 682, 156, 683, 211, 628, - 154, 685, 123, 716, 139, 700, 212, 627, 153, 686, 213, 626, - 215, 624, 150, 689, 225, 614, 224, 615, 221, 618, 220, 619, - 127, 712, 147, 692, 124, 715, 193, 646, 205, 634, 206, 633, - 116, 723, 160, 679, 186, 653, 167, 672, 79, 760, 85, 754, - 77, 762, 92, 747, 58, 781, 62, 777, 69, 770, 54, 785, - 36, 803, 32, 807, 25, 814, 18, 821, 11, 828, 4, 835, - 3, 836, 19, 820, 22, 817, 41, 798, 38, 801, 44, 795, - 52, 787, 45, 794, 63, 776, 67, 772, 72, 767, 76, 763, - 94, 745, 102, 737, 90, 749, 109, 730, 165, 674, 111, 728, - 209, 630, 204, 635, 117, 722, 188, 651, 159, 680, 198, 641, - 113, 726, 183, 656, 180, 659, 177, 662, 196, 643, 155, 684, - 214, 625, 126, 713, 131, 708, 219, 620, 222, 617, 226, 613, - 230, 609, 232, 607, 262, 577, 252, 587, 418, 421, 416, 423, - 413, 426, 411, 428, 376, 463, 395, 444, 283, 556, 285, 554, - 379, 460, 390, 449, 363, 476, 384, 455, 388, 451, 386, 453, - 361, 478, 387, 452, 360, 479, 310, 529, 354, 485, 328, 511, - 315, 524, 337, 502, 349, 490, 335, 504, 324, 515, 323, 516, - 320, 519, 334, 505, 359, 480, 295, 544, 385, 454, 292, 547, - 291, 548, 381, 458, 399, 440, 380, 459, 397, 442, 369, 470, - 377, 462, 410, 429, 407, 432, 281, 558, 414, 425, 247, 592, - 277, 562, 271, 568, 272, 567, 264, 575, 259, 580, 237, 602, - 239, 600, 244, 595, 243, 596, 275, 564, 278, 561, 250, 589, - 246, 593, 417, 422, 248, 591, 394, 445, 393, 446, 370, 469, - 365, 474, 300, 539, 299, 540, 364, 475, 362, 477, 298, 541, - 312, 527, 313, 526, 314, 525, 353, 486, 352, 487, 343, 496, - 327, 512, 350, 489, 326, 513, 319, 520, 332, 507, 333, 506, - 348, 491, 347, 492, 322, 517, 330, 509, 338, 501, 341, 498, - 340, 499, 342, 497, 301, 538, 366, 473, 401, 438, 371, 468, - 408, 431, 375, 464, 249, 590, 269, 570, 238, 601, 234, 605, - 257, 582, 273, 566, 255, 584, 254, 585, 245, 594, 251, 588, - 412, 427, 372, 467, 282, 557, 403, 436, 396, 443, 392, 447, - 391, 448, 382, 457, 389, 450, 294, 545, 297, 542, 311, 528, - 344, 495, 345, 494, 318, 521, 331, 508, 325, 514, 321, 518, - 346, 493, 339, 500, 351, 488, 306, 533, 289, 550, 400, 439, - 378, 461, 374, 465, 415, 424, 270, 569, 241, 598, 231, 608, - 260, 579, 268, 571, 276, 563, 409, 430, 398, 441, 290, 549, - 304, 535, 308, 531, 358, 481, 316, 523, 293, 546, 288, 551, - 284, 555, 368, 471, 253, 586, 256, 583, 263, 576, 242, 597, - 274, 565, 402, 437, 383, 456, 357, 482, 329, 510, 317, 522, - 307, 532, 286, 553, 287, 552, 266, 573, 261, 578, 236, 603, - 303, 536, 356, 483, 355, 484, 405, 434, 404, 435, 406, 433, - 235, 604, 267, 572, 302, 537, 309, 530, 265, 574, 233, 606, - 367, 472, 296, 543, 336, 503, 305, 534, 373, 466, 280, 559, - 279, 560, 419, 420, 240, 599, 258, 581, 229, 610}; - -// Table 5.7.2-5 - Root ZC sequence order for preamble format 4 -uint32_t prach_zc_roots_format4[138] = { - 1, 138, 2, 137, 3, 136, 4, 135, 5, 134, 6, 133, - 7, 132, 8, 131, 9, 130, 10, 129, 11, 128, 12, 127, - 13, 126, 14, 125, 15, 124, 16, 123, 17, 122, 18, 121, - 19, 120, 20, 119, 21, 118, 22, 117, 23, 116, 24, 115, - 25, 114, 26, 113, 27, 112, 28, 111, 29, 110, 30, 109, - 31, 108, 32, 107, 33, 106, 34, 105, 35, 104, 36, 103, - 37, 102, 38, 101, 39, 100, 40, 99, 41, 98, 42, 97, - 43, 96, 44, 95, 45, 94, 46, 93, 47, 92, 48, 91, - 49, 90, 50, 89, 51, 88, 52, 87, 53, 86, 54, 85, - 55, 84, 56, 83, 57, 82, 58, 81, 59, 80, 60, 79, - 61, 78, 62, 77, 63, 76, 64, 75, 65, 74, 66, 73, - 67, 72, 68, 71, 69, 70}; - -srslte_prach_sf_config_t prach_sf_config[16] = { - {1, {1, 0, 0, 0, 0}}, - {1, {4, 0, 0, 0, 0}}, - {1, {7, 0, 0, 0, 0}}, - {1, {1, 0, 0, 0, 0}}, - {1, {4, 0, 0, 0, 0}}, - {1, {7, 0, 0, 0, 0}}, - {2, {1, 6, 0, 0, 0}}, - {2, {2, 7, 0, 0, 0}}, - {2, {3, 8, 0, 0, 0}}, - {3, {1, 4, 7, 0, 0}}, - {3, {2, 5, 8, 0, 0}}, - {3, {3, 6, 9, 0, 0}}, - {5, {0, 2, 4, 6, 8}}, - {5, {1, 3, 5, 7, 9}}, - {-1, {0, 0, 0, 0, 0}}, // this means all subframes - {1, {9, 0, 0, 0, 0}}}; +int srslte_prach_set_cell_(srslte_prach_t* p, + uint32_t N_ifft_ul, + uint32_t config_idx, + uint32_t root_seq_index, + bool high_speed_flag, + uint32_t zero_corr_zone_config, + srslte_tdd_config_t* tdd_config); uint32_t srslte_prach_get_preamble_format(uint32_t config_idx) { return config_idx / 16; @@ -193,10 +76,15 @@ srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx) { */ bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe) { uint32_t config_idx = p->config_idx; - return srslte_prach_tti_opportunity_config(config_idx,current_tti,allowed_subframe); + if (!p->tdd_config.configured) { + return srslte_prach_tti_opportunity_config_fdd(config_idx, current_tti, allowed_subframe); + } else { + return srslte_prach_tti_opportunity_config_tdd( + config_idx, p->tdd_config.sf_config, current_tti, &p->current_prach_idx); + } } -bool srslte_prach_tti_opportunity_config(uint32_t config_idx, uint32_t current_tti, int allowed_subframe) +bool srslte_prach_tti_opportunity_config_fdd(uint32_t config_idx, uint32_t current_tti, int allowed_subframe) { // Get SFN and sf_idx from the PRACH configuration index srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx); @@ -218,7 +106,112 @@ bool srslte_prach_tti_opportunity_config(uint32_t config_idx, uint32_t current_t } } return false; +} + +uint32_t srslte_prach_nof_f_idx_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config) +{ + if (config_idx < 64 && tdd_ul_dl_config < 7) { + return prach_tdd_loc_table[config_idx][tdd_ul_dl_config].nof_elems; + } else { + ERROR("PRACH: Invalid parmeters config_idx=%d, tdd_ul_config=%d\n", config_idx, tdd_ul_dl_config); + return 0; + } +} + +uint32_t srslte_prach_f_id_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config, uint32_t prach_idx) +{ + if (config_idx < 64 && tdd_ul_dl_config < 7) { + return prach_tdd_loc_table[config_idx][tdd_ul_dl_config].elems[prach_idx].f; + } else { + ERROR("PRACH: Invalid parmeters config_idx=%d, tdd_ul_config=%d\n", config_idx, tdd_ul_dl_config); + return 0; + } +} + +uint32_t srslte_prach_f_ra_tdd(uint32_t config_idx, + uint32_t tdd_ul_dl_config, + uint32_t current_tti, + uint32_t prach_idx, + uint32_t prach_offset, + uint32_t n_rb_ul) +{ + + if (config_idx >= 64 && tdd_ul_dl_config >= 7) { + ERROR("PRACH: Invalid parmeters config_idx=%d, tdd_ul_config=%d\n", config_idx, tdd_ul_dl_config); + return 0; + } + uint32_t f_ra = prach_tdd_loc_table[config_idx][tdd_ul_dl_config].elems[prach_idx].f; + + if (config_idx < 48) { + if ((f_ra % 2) == 0) { + return prach_offset + 6 * (f_ra / 2); + } else { + return n_rb_ul - 6 - prach_offset + 6 * (f_ra / 2); + } + } else { + uint32_t N_sp; + if (tdd_ul_dl_config >= 3 && tdd_ul_dl_config <= 5) { + N_sp = 1; + } else { + N_sp = 2; + } + + uint32_t t1 = prach_tdd_loc_table[config_idx][tdd_ul_dl_config].elems[prach_idx].t1; + + uint32_t sfn = current_tti / 10; + + if ((((sfn % 2) * (2 - N_sp) + t1) % 2) == 0) { + return 6 * f_ra; + } else { + return n_rb_ul - 6 * (f_ra + 1); + } + } +} + +bool srslte_prach_tti_opportunity_config_tdd(uint32_t config_idx, + uint32_t tdd_ul_dl_config, + uint32_t current_tti, + uint32_t* prach_idx) +{ + if (config_idx >= 64 && tdd_ul_dl_config >= 7) { + ERROR("PRACH: Invalid parmeters config_idx=%d, tdd_ul_config=%d\n", config_idx, tdd_ul_dl_config); + return 0; + } + uint32_t nof_elems = prach_tdd_loc_table[config_idx][tdd_ul_dl_config].nof_elems; + + // Table 5.7.1-4 allocates in time then in frequency + for (uint32_t i = 0; i < nof_elems; i++) { + uint32_t t0 = prach_tdd_loc_table[config_idx][tdd_ul_dl_config].elems[i].t0; + uint32_t t1 = prach_tdd_loc_table[config_idx][tdd_ul_dl_config].elems[i].t1; + uint32_t t2 = prach_tdd_loc_table[config_idx][tdd_ul_dl_config].elems[i].t2; + + uint32_t sfn = current_tti / 10; + uint32_t sf_idx = current_tti % 10; + + if (((sfn % 2) && t0 == 2) || (!(sfn % 2) && t0 == 1) || (t0 == 0)) { + if ((sf_idx < 5 && t1 == 0) || (sf_idx >= 5 && t1 == 1)) { + if (config_idx < 48) { // format 0 to 3 + if ((sf_idx) % 5 == (t2 + 2)) { + if (prach_idx) { + *prach_idx = i; + } + return true; + } + } else { + // Only UpTs subframes + srslte_tdd_config_t c = {tdd_ul_dl_config, 0, true}; + if (srslte_sfidx_tdd_type(c, sf_idx) == SRSLTE_TDD_SF_S) { + if (prach_idx) { + *prach_idx = i; + } + return true; + } + } + } + } + } + return false; } void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config) { @@ -333,16 +326,15 @@ int srslte_prach_gen_seqs(srslte_prach_t *p) { return 0; } -int srslte_prach_init_cfg(srslte_prach_t *p, srslte_prach_cfg_t *cfg, uint32_t nof_prb) { - if (srslte_prach_init(p, srslte_symbol_sz(nof_prb))) { - return -1; - } - return srslte_prach_set_cell(p, - srslte_symbol_sz(nof_prb), - cfg->config_idx, - cfg->root_seq_idx, - cfg->hs_flag, - cfg->zero_corr_zone); +int srslte_prach_set_cfg(srslte_prach_t* p, srslte_prach_cfg_t* cfg, uint32_t nof_prb) +{ + return srslte_prach_set_cell_(p, + srslte_symbol_sz(nof_prb), + cfg->config_idx, + cfg->root_seq_idx, + cfg->hs_flag, + cfg->zero_corr_zone, + &cfg->tdd_config); } int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul) { @@ -373,23 +365,23 @@ int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul) { uint32_t fft_size_alloc = max_N_ifft_ul * DELTA_F / DELTA_F_RA; - p->ifft_in = (cf_t *) srslte_vec_malloc(fft_size_alloc * sizeof(cf_t)); + p->ifft_in = (cf_t*)srslte_vec_malloc(fft_size_alloc * sizeof(cf_t)); p->ifft_out = (cf_t *) srslte_vec_malloc(fft_size_alloc * sizeof(cf_t)); if (srslte_dft_plan(&p->ifft, fft_size_alloc, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error creating DFT plan\n"); + ERROR("Error creating DFT plan\n"); return -1; } srslte_dft_plan_set_mirror(&p->ifft, true); srslte_dft_plan_set_norm(&p->ifft, true); if (srslte_dft_plan(&p->fft, fft_size_alloc, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error creating DFT plan\n"); + ERROR("Error creating DFT plan\n"); return -1; } p->signal_fft = srslte_vec_malloc(sizeof(cf_t) * fft_size_alloc); if (!p->signal_fft) { - fprintf(stderr, "Error allocating memory\n"); + ERROR("Error allocating memory\n"); return -1; } @@ -398,25 +390,27 @@ int srslte_prach_init(srslte_prach_t *p, uint32_t max_N_ifft_ul) { ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters\n"); + ERROR("Invalid parameters\n"); } return ret; } -int srslte_prach_set_cell(srslte_prach_t *p, - uint32_t N_ifft_ul, - uint32_t config_idx, - uint32_t root_seq_index, - bool high_speed_flag, - uint32_t zero_corr_zone_config) { +int srslte_prach_set_cell_(srslte_prach_t* p, + uint32_t N_ifft_ul, + uint32_t config_idx, + uint32_t root_seq_index, + bool high_speed_flag, + uint32_t zero_corr_zone_config, + srslte_tdd_config_t* tdd_config) +{ int ret = SRSLTE_ERROR; if (p != NULL && N_ifft_ul < 2049 && config_idx < 64 && root_seq_index < MAX_ROOTS) { if (N_ifft_ul > p->max_N_ifft_ul) { - fprintf(stderr, "PRACH: Error in set_cell(): N_ifft_ul must be lower or equal max_N_ifft_ul in init()\n"); + ERROR("PRACH: Error in set_cell(): N_ifft_ul must be lower or equal max_N_ifft_ul in init()\n"); return -1; } @@ -427,7 +421,9 @@ int srslte_prach_set_cell(srslte_prach_t *p, p->hs = high_speed_flag; p->zczc = zero_corr_zone_config; p->detect_factor = PRACH_DETECT_FACTOR; - + if (tdd_config) { + p->tdd_config = *tdd_config; + } // Determine N_zc and N_cs if (4 == preamble_format) { @@ -435,7 +431,7 @@ int srslte_prach_set_cell(srslte_prach_t *p, p->N_zc = 139; p->N_cs = prach_Ncs_format4[p->zczc]; } else { - fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for format4\n", p->zczc); + ERROR("Invalid zeroCorrelationZoneConfig=%d for format4\n", p->zczc); return SRSLTE_ERROR; } } else { @@ -444,14 +440,14 @@ int srslte_prach_set_cell(srslte_prach_t *p, if (p->zczc < 15) { p->N_cs = prach_Ncs_restricted[p->zczc]; } else { - fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc); + ERROR("Invalid zeroCorrelationZoneConfig=%d for restricted set\n", p->zczc); return SRSLTE_ERROR; } } else { if (p->zczc < 16) { p->N_cs = prach_Ncs_unrestricted[p->zczc]; } else { - fprintf(stderr, "Invalid zeroCorrelationZoneConfig=%d\n", p->zczc); + ERROR("Invalid zeroCorrelationZoneConfig=%d\n", p->zczc); return SRSLTE_ERROR; } } @@ -495,11 +491,11 @@ int srslte_prach_set_cell(srslte_prach_t *p, }*/ if (srslte_dft_replan(&p->ifft, p->N_ifft_prach)) { - fprintf(stderr, "Error creating DFT plan\n"); + ERROR("Error creating DFT plan\n"); return -1; } if (srslte_dft_replan(&p->fft, p->N_ifft_prach)) { - fprintf(stderr, "Error creating DFT plan\n"); + ERROR("Error creating DFT plan\n"); return -1; } @@ -510,7 +506,7 @@ int srslte_prach_set_cell(srslte_prach_t *p, ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters\n"); + ERROR("Invalid parameters\n"); } return ret; @@ -521,9 +517,7 @@ int srslte_prach_gen(srslte_prach_t *p, uint32_t freq_offset, cf_t *signal) { int ret = SRSLTE_ERROR; - if (p != NULL && - seq_index < N_SEQS && - signal != NULL) { + if (p != NULL && seq_index < N_SEQS && signal != NULL) { // Calculate parameters uint32_t N_rb_ul = srslte_nof_prb(p->N_ifft_ul); uint32_t k_0 = freq_offset * N_RB_SC - N_rb_ul * N_RB_SC / 2 + p->N_ifft_ul / 2; @@ -531,7 +525,7 @@ int srslte_prach_gen(srslte_prach_t *p, uint32_t begin = PHI + (K * k_0) + (K / 2); if (6 + freq_offset > N_rb_ul) { - fprintf(stderr, "Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, N_rb_ul); + ERROR("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, N_rb_ul); return ret; } @@ -572,14 +566,15 @@ int srslte_prach_detect(srslte_prach_t *p, return srslte_prach_detect_offset(p, freq_offset, signal, sig_len, indices, NULL, NULL, n_indices); } -int srslte_prach_detect_offset(srslte_prach_t *p, - uint32_t freq_offset, - cf_t *signal, - uint32_t sig_len, - uint32_t *indices, - float *t_offsets, - float *peak_to_avg, - uint32_t *n_indices) { +int srslte_prach_detect_offset(srslte_prach_t* p, + uint32_t freq_offset, + cf_t* signal, + uint32_t sig_len, + uint32_t* indices, + float* t_offsets, + float* peak_to_avg, + uint32_t* n_indices) +{ int ret = SRSLTE_ERROR; if (p != NULL && signal != NULL && @@ -587,7 +582,7 @@ int srslte_prach_detect_offset(srslte_prach_t *p, indices != NULL) { if (sig_len < p->N_ifft_prach) { - fprintf(stderr, "srslte_prach_detect: Signal length is %d and should be %d\n", sig_len, p->N_ifft_prach); + ERROR("srslte_prach_detect: Signal length is %d and should be %d\n", sig_len, p->N_ifft_prach); return SRSLTE_ERROR_INVALID_INPUTS; } diff --git a/lib/src/phy/phch/prach_tables.h b/lib/src/phy/phch/prach_tables.h new file mode 100644 index 000000000..17f1f34ee --- /dev/null +++ b/lib/src/phy/phch/prach_tables.h @@ -0,0 +1,200 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/phy/phch/prach.h" + +/****************************************************** + * Reference tables from 3GPP TS 36.211 v10.7.0 + *****************************************************/ + +// Table 5.7.1-1 T_cp for preamble formats +uint32_t prach_Tcp[5] = {3168, 21024, 6240, 21024, 448}; + +// Table 5.7.1-1 T_seq for preamble formats +uint32_t prach_Tseq[5] = {24576, 24576, 2 * 24576, 2 * 24576, 4096}; + +// Table 5.7.2-2 - N_cs values for unrestricted sets +uint32_t prach_Ncs_unrestricted[16] = {0, 13, 15, 18, 22, 26, 32, 38, 46, 59, 76, 93, 119, 167, 279, 419}; + +#define MAX_N_zc 839 + +// Table 5.7.2-2 - N_cs values for restricted sets +uint32_t prach_Ncs_restricted[15] = {15, 18, 22, 26, 32, 38, 46, 55, 68, 82, 100, 128, 158, 202, 237}; + +// Table 5.7.2-3 - N_cs values for preamble format 4 +uint32_t prach_Ncs_format4[7] = {2, 4, 6, 8, 10, 12, 15}; + +// Table 5.7.2-4 - Root ZC sequence order +uint32_t prach_zc_roots[838] = { + 129, 710, 140, 699, 120, 719, 210, 629, 168, 671, 84, 755, + 105, 734, 93, 746, 70, 769, 60, 779, 2, 837, 1, 838, + 56, 783, 112, 727, 148, 691, 80, 759, 42, 797, 40, 799, + 35, 804, 73, 766, 146, 693, 31, 808, 28, 811, 30, 809, + 27, 812, 29, 810, 24, 815, 48, 791, 68, 771, 74, 765, + 178, 661, 136, 703, 86, 753, 78, 761, 43, 796, 39, 800, + 20, 819, 21, 818, 95, 744, 202, 637, 190, 649, 181, 658, + 137, 702, 125, 714, 151, 688, 217, 622, 128, 711, 142, 697, + 122, 717, 203, 636, 118, 721, 110, 729, 89, 750, 103, 736, + 61, 778, 55, 784, 15, 824, 14, 825, 12, 827, 23, 816, + 34, 805, 37, 802, 46, 793, 207, 632, 179, 660, 145, 694, + 130, 709, 223, 616, 228, 611, 227, 612, 132, 707, 133, 706, + 143, 696, 135, 704, 161, 678, 201, 638, 173, 666, 106, 733, + 83, 756, 91, 748, 66, 773, 53, 786, 10, 829, 9, 830, + 7, 832, 8, 831, 16, 823, 47, 792, 64, 775, 57, 782, + 104, 735, 101, 738, 108, 731, 208, 631, 184, 655, 197, 642, + 191, 648, 121, 718, 141, 698, 149, 690, 216, 623, 218, 621, + 152, 687, 144, 695, 134, 705, 138, 701, 199, 640, 162, 677, + 176, 663, 119, 720, 158, 681, 164, 675, 174, 665, 171, 668, + 170, 669, 87, 752, 169, 670, 88, 751, 107, 732, 81, 758, + 82, 757, 100, 739, 98, 741, 71, 768, 59, 780, 65, 774, + 50, 789, 49, 790, 26, 813, 17, 822, 13, 826, 6, 833, + 5, 834, 33, 806, 51, 788, 75, 764, 99, 740, 96, 743, + 97, 742, 166, 673, 172, 667, 175, 664, 187, 652, 163, 676, + 185, 654, 200, 639, 114, 725, 189, 650, 115, 724, 194, 645, + 195, 644, 192, 647, 182, 657, 157, 682, 156, 683, 211, 628, + 154, 685, 123, 716, 139, 700, 212, 627, 153, 686, 213, 626, + 215, 624, 150, 689, 225, 614, 224, 615, 221, 618, 220, 619, + 127, 712, 147, 692, 124, 715, 193, 646, 205, 634, 206, 633, + 116, 723, 160, 679, 186, 653, 167, 672, 79, 760, 85, 754, + 77, 762, 92, 747, 58, 781, 62, 777, 69, 770, 54, 785, + 36, 803, 32, 807, 25, 814, 18, 821, 11, 828, 4, 835, + 3, 836, 19, 820, 22, 817, 41, 798, 38, 801, 44, 795, + 52, 787, 45, 794, 63, 776, 67, 772, 72, 767, 76, 763, + 94, 745, 102, 737, 90, 749, 109, 730, 165, 674, 111, 728, + 209, 630, 204, 635, 117, 722, 188, 651, 159, 680, 198, 641, + 113, 726, 183, 656, 180, 659, 177, 662, 196, 643, 155, 684, + 214, 625, 126, 713, 131, 708, 219, 620, 222, 617, 226, 613, + 230, 609, 232, 607, 262, 577, 252, 587, 418, 421, 416, 423, + 413, 426, 411, 428, 376, 463, 395, 444, 283, 556, 285, 554, + 379, 460, 390, 449, 363, 476, 384, 455, 388, 451, 386, 453, + 361, 478, 387, 452, 360, 479, 310, 529, 354, 485, 328, 511, + 315, 524, 337, 502, 349, 490, 335, 504, 324, 515, 323, 516, + 320, 519, 334, 505, 359, 480, 295, 544, 385, 454, 292, 547, + 291, 548, 381, 458, 399, 440, 380, 459, 397, 442, 369, 470, + 377, 462, 410, 429, 407, 432, 281, 558, 414, 425, 247, 592, + 277, 562, 271, 568, 272, 567, 264, 575, 259, 580, 237, 602, + 239, 600, 244, 595, 243, 596, 275, 564, 278, 561, 250, 589, + 246, 593, 417, 422, 248, 591, 394, 445, 393, 446, 370, 469, + 365, 474, 300, 539, 299, 540, 364, 475, 362, 477, 298, 541, + 312, 527, 313, 526, 314, 525, 353, 486, 352, 487, 343, 496, + 327, 512, 350, 489, 326, 513, 319, 520, 332, 507, 333, 506, + 348, 491, 347, 492, 322, 517, 330, 509, 338, 501, 341, 498, + 340, 499, 342, 497, 301, 538, 366, 473, 401, 438, 371, 468, + 408, 431, 375, 464, 249, 590, 269, 570, 238, 601, 234, 605, + 257, 582, 273, 566, 255, 584, 254, 585, 245, 594, 251, 588, + 412, 427, 372, 467, 282, 557, 403, 436, 396, 443, 392, 447, + 391, 448, 382, 457, 389, 450, 294, 545, 297, 542, 311, 528, + 344, 495, 345, 494, 318, 521, 331, 508, 325, 514, 321, 518, + 346, 493, 339, 500, 351, 488, 306, 533, 289, 550, 400, 439, + 378, 461, 374, 465, 415, 424, 270, 569, 241, 598, 231, 608, + 260, 579, 268, 571, 276, 563, 409, 430, 398, 441, 290, 549, + 304, 535, 308, 531, 358, 481, 316, 523, 293, 546, 288, 551, + 284, 555, 368, 471, 253, 586, 256, 583, 263, 576, 242, 597, + 274, 565, 402, 437, 383, 456, 357, 482, 329, 510, 317, 522, + 307, 532, 286, 553, 287, 552, 266, 573, 261, 578, 236, 603, + 303, 536, 356, 483, 355, 484, 405, 434, 404, 435, 406, 433, + 235, 604, 267, 572, 302, 537, 309, 530, 265, 574, 233, 606, + 367, 472, 296, 543, 336, 503, 305, 534, 373, 466, 280, 559, + 279, 560, 419, 420, 240, 599, 258, 581, 229, 610}; + +// Table 5.7.2-5 - Root ZC sequence order for preamble format 4 +uint32_t prach_zc_roots_format4[138] = { + 1, 138, 2, 137, 3, 136, 4, 135, 5, 134, 6, 133, + 7, 132, 8, 131, 9, 130, 10, 129, 11, 128, 12, 127, + 13, 126, 14, 125, 15, 124, 16, 123, 17, 122, 18, 121, + 19, 120, 20, 119, 21, 118, 22, 117, 23, 116, 24, 115, + 25, 114, 26, 113, 27, 112, 28, 111, 29, 110, 30, 109, + 31, 108, 32, 107, 33, 106, 34, 105, 35, 104, 36, 103, + 37, 102, 38, 101, 39, 100, 40, 99, 41, 98, 42, 97, + 43, 96, 44, 95, 45, 94, 46, 93, 47, 92, 48, 91, + 49, 90, 50, 89, 51, 88, 52, 87, 53, 86, 54, 85, + 55, 84, 56, 83, 57, 82, 58, 81, 59, 80, 60, 79, + 61, 78, 62, 77, 63, 76, 64, 75, 65, 74, 66, 73, + 67, 72, 68, 71, 69, 70}; + +srslte_prach_sf_config_t prach_sf_config[16] = { + {1, {1, 0, 0, 0, 0}}, + {1, {4, 0, 0, 0, 0}}, + {1, {7, 0, 0, 0, 0}}, + {1, {1, 0, 0, 0, 0}}, + {1, {4, 0, 0, 0, 0}}, + {1, {7, 0, 0, 0, 0}}, + {2, {1, 6, 0, 0, 0}}, + {2, {2, 7, 0, 0, 0}}, + {2, {3, 8, 0, 0, 0}}, + {3, {1, 4, 7, 0, 0}}, + {3, {2, 5, 8, 0, 0}}, + {3, {3, 6, 9, 0, 0}}, + {5, {0, 2, 4, 6, 8}}, + {5, {1, 3, 5, 7, 9}}, + {-1, {0, 0, 0, 0, 0}}, // this means all subframes + {1, {9, 0, 0, 0, 0}}}; + +srslte_prach_tdd_loc_table_t prach_tdd_loc_table[64][7] = { + { {1,{{0,1,0,2}}},{1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {1,{{0,1,0,2}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {1,{{0,1,0,2}}}}, + { {1,{{0,2,0,2}}},{1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {1,{{0,2,0,2}}}, {1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {1,{{0,2,0,2}}}}, + { {1,{{0,1,1,2}}},{1,{{0,1,1,1}}}, {1,{{0,1,1,0}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,1,1}}}}, + { {1,{{0,0,0,2}}},{1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {1,{{0,0,0,2}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {1,{{0,0,0,2}}}}, + { {1,{{0,0,1,2}}},{1,{{0,0,1,1}}}, {1,{{0,0,1,0}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,1,1}}}}, + { {1,{{0,0,0,1}}},{1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}}, + { {2,{{0,0,0,2},{0,0,1,2}}}, {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {2,{{0,0,0,1},{0,0,0,2}}}, {2,{{0,0,0,0},{0,0,0,1}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {2,{{0,0,0,2},{0,0,1,1}}}}, + { {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{0,0,0,2}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{0,0,1,0}}}}, + { {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{0,0,0,1}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{0,0,1,1}}}}, + { {3,{{0,0,0,1},{0,0,0,2},{0,0,1,2}}}, {3,{{0,0,0,0},{0,0,0,1},{0,0,1,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,1},{0,0,0,2}}}, {3,{{0,0,0,0},{0,0,0,1},{1,0,0,1}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {3,{{0,0,0,1},{0,0,0,2},{0,0,1,1}}}}, + { {3,{{0,0,0,0},{0,0,1,0},{0,0,1,1}}}, {3,{{0,0,0,1},{0,0,1,0},{0,0,1,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,1},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,2},{0,0,1,0}}}}, + { {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{0,0,0,1},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{0,0,1,0},{0,0,1,1}}}}, + { {4,{{0,0,0,1},{0,0,0,2},{0,0,1,1},{0,0,1,2}}}, {4,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1}}}, {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}}, {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,2}}}, {4,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1}}}, {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}}, {4,{{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1}}}}, + { {4,{{0,0,0,0},{0,0,0,2},{0,0,1,0},{0,0,1,2}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,1}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,1}}}}, + { {4,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,0},{0,0,0,2},{0,0,1,0},{0,0,1,1}}}}, + { {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,1},{0,0,1,2}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,1}}}, {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,1},{1,0,0,2}}}, {5,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1},{2,0,0,1}}}, {5,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1}}}}, + { {5,{{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{0,0,1,2}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,1,1}}}, {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,1,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0},{1,0,0,2}}}, {5,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}}, + { {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,2}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0},{1,0,0,1}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}}, + { {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{0,0,1,2}}}, {6,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,1},{1,0,1,1}}}, {6,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0},{2,0,1,0}}}, {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{1,0,0,0},{1,0,0,1},{1,0,0,2}}}, {6,{{0,0,0,0},{0,0,0,1},{1,0,0,0},{1,0,0,1},{2,0,0,0},{2,0,0,1}}}, {6,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0},{5,0,0,0}}}, {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{1,0,0,2}}}}, + { {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {6,{{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,0,1,1},{1,0,0,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {6,{{0,0,0,0},{0,0,0,1},{0,0,0,2},{0,0,1,0},{0,0,1,1},{1,0,1,1}}}}, + { {1,{{0,1,0,1}}},{1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}}, + { {1,{{0,2,0,1}}},{1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}}, + { {1,{{0,1,1,1}}},{1,{{0,1,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,1,0}}}}, + { {1,{{0,0,0,1}}},{1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}}, + { {1,{{0,0,1,1}}},{1,{{0,0,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,1,0}}}}, + { {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{1,0,0,1}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{0,0,1,0}}}}, + { {3,{{0,0,0,1},{0,0,1,1},{1,0,0,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{1,0,0,1},{2,0,0,1}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{0,0,1,0},{1,0,0,1}}}}, + { {4,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1}}}, {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1}}}, {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0}}}}, + { {5,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1}}}, {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1}}}, {5,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1}}}}, + { {6,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1},{2,0,1,1}}}, {6,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0},{2,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {6,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1},{5,0,0,1}}}, {6,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0},{5,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {6,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1},{2,0,1,0}}}}, + { {1,{{0,1,0,1}}},{1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,1}}}}, + { {1,{{0,2,0,1}}},{1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}, {1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,1}}}}, + { {1,{{0,1,1,1}}},{1,{{0,1,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,1,0}}}}, + { {1,{{0,0,0,1}}},{1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,1}}}}, + { {1,{{0,0,1,1}}},{1,{{0,0,1,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,1,0}}}}, + { {2,{{0,0,0,1},{0,0,1,1}}}, {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{1,0,0,1}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,1},{0,0,1,0}}}}, + { {3,{{0,0,0,1},{0,0,1,1},{1,0,0,1}}}, {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{1,0,0,1},{2,0,0,1}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,1},{0,0,1,0},{1,0,0,1}}}}, + { {4,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1}}}, {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1}}}, {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0}}}}, + { {5,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1}}}, {5,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1}}}, {5,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {5,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1}}}}, + { {6,{{0,0,0,1},{0,0,1,1},{1,0,0,1},{1,0,1,1},{2,0,0,1},{2,0,1,1}}}, {6,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0},{2,0,0,0},{2,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {6,{{0,0,0,1},{1,0,0,1},{2,0,0,1},{3,0,0,1},{4,0,0,1},{5,0,0,1}}}, {6,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0},{4,0,0,0},{5,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {6,{{0,0,0,1},{0,0,1,0},{1,0,0,1},{1,0,1,0},{2,0,0,1},{2,0,1,0}}}}, + { {1,{{0,1,0,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,1,0,0}}}}, + { {1,{{0,2,0,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,2,0,0}}}}, + { {1,{{0,1,1,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}}, + { {1,{{0,0,0,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {1,{{0,0,0,0}}}}, + { {1,{{0,0,1,0}}},{0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}, {0,{{0,0,0,0}}}}, + { {2,{{0,0,0,0},{0,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0}}}, {2,{{0,0,0,0},{1,0,0,0}}}}, + { {3,{{0,0,0,0},{0,0,1,0},{1,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {3,{{0,0,0,0},{1,0,0,0},{2,0,0,0}}}}, + { {4,{{0,0,0,0},{0,0,1,0},{1,0,0,0},{1,0,1,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}}, {4,{{0,0,0,0},{1,0,0,0},{2,0,0,0},{3,0,0,0}}}} +}; \ No newline at end of file diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index ff94483d4..cbb346338 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -24,16 +24,16 @@ * */ +#include "srslte/srslte.h" +#include +#include +#include +#include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include #include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/phch/pucch.h" @@ -47,376 +47,9 @@ #define MAX_PUSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) -uint32_t pucch_symbol_format1_cpnorm[4] = {0, 1, 5, 6}; -uint32_t pucch_symbol_format1_cpext[4] = {0, 1, 4, 5}; -uint32_t pucch_symbol_format2_cpnorm[5] = {0, 2, 3, 4, 6}; -uint32_t pucch_symbol_format2_cpext[5] = {0, 1, 2, 4, 5}; - -float w_n_oc[2][3][4] = { - // Table 5.4.1-2 Orthogonal sequences w for N_sf=4 (complex argument) - {{0, 0, 0, 0}, - {0,M_PI, 0, M_PI}, - {0,M_PI, M_PI, 0}}, - // Table 5.4.1-3 Orthogonal sequences w for N_sf=3 - {{0, 0, 0, 0}, - {0,2*M_PI/3, 4*M_PI/3,0}, - {0,4*M_PI/3,2*M_PI/3,0}}, - -}; - - -/* Verify PUCCH configuration as given in Section 5.4 36.211 */ -bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t *cfg, uint32_t nof_prb) { - if (cfg->delta_pucch_shift > 0 && cfg->delta_pucch_shift < 4 && - cfg->N_cs < 8 && (cfg->N_cs%cfg->delta_pucch_shift) == 0 && - cfg->n_rb_2 <= nof_prb) { - return true; - } else { - return false; - } -} - -// Verifies n_2_pucch as defined in 5.4 -bool srslte_pucch_n2_isvalid(srslte_pucch_cfg_t *cfg, uint32_t n_pucch_2) { - if (n_pucch_2 < cfg->n_rb_2*SRSLTE_NRE+(uint32_t) ceilf((float) cfg->N_cs/8)*(SRSLTE_NRE-cfg->N_cs-2)) { - return true; - } else { - return false; - } -} - -void srslte_pucch_cfg_default(srslte_pucch_cfg_t *cfg) { - cfg->delta_pucch_shift = 1; -} - -uint32_t get_N_sf(srslte_pucch_format_t format, uint32_t slot_idx, bool shortened) { - switch (format) { - case SRSLTE_PUCCH_FORMAT_1: - case SRSLTE_PUCCH_FORMAT_1A: - case SRSLTE_PUCCH_FORMAT_1B: - if (!slot_idx) { - return 4; - } else { - return shortened?3:4; - } - case SRSLTE_PUCCH_FORMAT_2: - case SRSLTE_PUCCH_FORMAT_2A: - case SRSLTE_PUCCH_FORMAT_2B: - return 5; - default: - return 0; - } - return 0; -} - -uint32_t srslte_pucch_nof_symbols(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, bool shortened) { - uint32_t len=0; - for (uint32_t ns=0;ns<2;ns++) { - len += SRSLTE_NRE*get_N_sf(format, ns, shortened); - } - return len; -} - -// Number of bits per subframe (M_bit) Table 5.4-1 36.211 -uint32_t srslte_pucch_nbits_format(srslte_pucch_format_t format) { - switch(format) { - case SRSLTE_PUCCH_FORMAT_1: - return 0; - case SRSLTE_PUCCH_FORMAT_1A: - return 1; - case SRSLTE_PUCCH_FORMAT_1B: - return 2; - case SRSLTE_PUCCH_FORMAT_2: - return 20; - case SRSLTE_PUCCH_FORMAT_2A: - return 21; - case SRSLTE_PUCCH_FORMAT_2B: - return 22; - default: - return 0; - } - return 0; -} - -uint32_t get_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) { - switch (format) { - case SRSLTE_PUCCH_FORMAT_1: - case SRSLTE_PUCCH_FORMAT_1A: - case SRSLTE_PUCCH_FORMAT_1B: - if (m < 4) { - if (SRSLTE_CP_ISNORM(cp)) { - return pucch_symbol_format1_cpnorm[m]; - } else { - return pucch_symbol_format1_cpext[m]; - } - } - break; - case SRSLTE_PUCCH_FORMAT_2: - case SRSLTE_PUCCH_FORMAT_2A: - case SRSLTE_PUCCH_FORMAT_2B: - if (m < 5) { - if (SRSLTE_CP_ISNORM(cp)) { - return pucch_symbol_format2_cpnorm[m]; - } else { - return pucch_symbol_format2_cpext[m]; - } - } - break; - default: - return 0; - } - return 0; -} - -/* Choose PUCCH format based on pending transmission as described in 10.1 of 36.213 */ -srslte_pucch_format_t srslte_pucch_get_format(srslte_uci_data_t *uci_data, srslte_cp_t cp) -{ - srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; - // No CQI data - if (uci_data->uci_cqi_len == 0 && uci_data->uci_ri_len == 0) { - // 1-bit ACK + optional SR - if (uci_data->uci_ack_len == 1) { - format = SRSLTE_PUCCH_FORMAT_1A; - } - // 2-bit ACK + optional SR - else if (uci_data->uci_ack_len == 2) { - format = SRSLTE_PUCCH_FORMAT_1B; - } - // SR only - else if (uci_data->scheduling_request) { - format = SRSLTE_PUCCH_FORMAT_1; - } - } - // CQI data - else { - // CQI and no ack - if (uci_data->uci_ack_len == 0) { - format = SRSLTE_PUCCH_FORMAT_2; - } - // CQI + 1-bit ACK - else if (uci_data->uci_ack_len == 1 && SRSLTE_CP_ISNORM(cp)) { - format = SRSLTE_PUCCH_FORMAT_2A; - } - // CQI + 2-bit ACK - else if (uci_data->uci_ack_len == 2) { - format = SRSLTE_PUCCH_FORMAT_2B; - } - // CQI + 2-bit ACK + cyclic prefix - else if (uci_data->uci_ack_len == 1 && SRSLTE_CP_ISEXT(cp)) { - format = SRSLTE_PUCCH_FORMAT_2B; - } - } - return format; -} - -/** Choose PUCCH resource as desribed in 10.1 of 36.213 */ -uint32_t srslte_pucch_get_npucch(uint32_t n_cce, srslte_pucch_format_t format, bool has_scheduling_request, srslte_pucch_sched_t *pucch_sched) -{ - uint32_t n_pucch = 0; - if (has_scheduling_request) { - n_pucch = pucch_sched->n_pucch_sr; - } else if (format < SRSLTE_PUCCH_FORMAT_2) { - if (pucch_sched->sps_enabled) { - n_pucch = pucch_sched->n_pucch_1[pucch_sched->tpc_for_pucch%4]; - } else { - n_pucch = n_cce + pucch_sched->N_pucch_1; - } - } else { - n_pucch = pucch_sched->n_pucch_2; - } - return n_pucch; -} - -uint32_t srslte_pucch_n_prb(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch, - uint32_t nof_prb, srslte_cp_t cp, uint32_t ns) -{ - uint32_t m = srslte_pucch_m(cfg, format, n_pucch, cp); - // Determine n_prb - uint32_t n_prb = m/2; - if ((m+ns)%2) { - n_prb = nof_prb-1-m/2; - } - return n_prb; -} - -// Compute m according to Section 5.4.3 of 36.211 -uint32_t srslte_pucch_m(srslte_pucch_cfg_t *cfg, srslte_pucch_format_t format, uint32_t n_pucch, srslte_cp_t cp) { - uint32_t m=0; - switch (format) { - case SRSLTE_PUCCH_FORMAT_1: - case SRSLTE_PUCCH_FORMAT_1A: - case SRSLTE_PUCCH_FORMAT_1B: - m = cfg->n_rb_2; - - uint32_t c=SRSLTE_CP_ISNORM(cp)?3:2; - if (n_pucch >= c*cfg->N_cs/cfg->delta_pucch_shift) { - m = (n_pucch-c*cfg->N_cs/cfg->delta_pucch_shift)/(c*SRSLTE_NRE/cfg->delta_pucch_shift) - +cfg->n_rb_2+(uint32_t)ceilf((float) cfg->N_cs/8); - } - break; - case SRSLTE_PUCCH_FORMAT_2: - case SRSLTE_PUCCH_FORMAT_2A: - case SRSLTE_PUCCH_FORMAT_2B: - m = n_pucch/SRSLTE_NRE; - break; - default: - m = 0; - break; - } - return m; -} - -/* Generates n_cs_cell according to Sec 5.4 of 36.211 */ -int srslte_pucch_n_cs_cell(srslte_cell_t cell, uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]) -{ - srslte_sequence_t seq; - bzero(&seq, sizeof(srslte_sequence_t)); - - srslte_sequence_LTE_pr(&seq, 8*SRSLTE_CP_NSYMB(cell.cp)*SRSLTE_NSLOTS_X_FRAME, cell.id); - - for (uint32_t ns=0;nsN_cs/cfg->delta_pucch_shift)?cfg->N_cs:SRSLTE_NRE; - - uint32_t n_prime = n_pucch; - if (n_pucch >= c*cfg->N_cs/cfg->delta_pucch_shift) { - n_prime = (n_pucch-c*cfg->N_cs/cfg->delta_pucch_shift)%(c*SRSLTE_NRE/cfg->delta_pucch_shift); - } - if (ns%2) { - if (n_pucch >= c*cfg->N_cs/cfg->delta_pucch_shift) { - n_prime = (c*(n_prime+1))%(c*SRSLTE_NRE/cfg->delta_pucch_shift+1)-1; - } else { - uint32_t d=SRSLTE_CP_ISNORM(cp)?2:0; - uint32_t h=(n_prime+d)%(c*N_prime/cfg->delta_pucch_shift); - n_prime = (h/c)+(h%c)*N_prime/cfg->delta_pucch_shift; - } - } - - if (n_prime_ns) { - *n_prime_ns = n_prime; - } - - uint32_t n_oc_div = (!is_dmrs && SRSLTE_CP_ISEXT(cp))?2:1; - - uint32_t n_oc = n_prime*cfg->delta_pucch_shift/N_prime; - if (!is_dmrs && SRSLTE_CP_ISEXT(cp)) { - n_oc *= 2; - } - if (n_oc_ptr) { - *n_oc_ptr = n_oc; - } - uint32_t n_cs = 0; - if (SRSLTE_CP_ISNORM(cp)) { - n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+(n_oc%cfg->delta_pucch_shift))%N_prime)%SRSLTE_NRE; - } else { - n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%SRSLTE_NRE; - } - - DEBUG("n_cs=%d, N_prime=%d, delta_pucch=%d, n_prime=%d, ns=%d, l=%d, ns_cs_cell=%d\n", - n_cs, N_prime, cfg->delta_pucch_shift, n_prime, ns, l, n_cs_cell[ns][l]); - - return 2 * M_PI * (n_cs) / SRSLTE_NRE; -} - -/* Calculates alpha for format 2/a/b according to 5.4.2 of 36.211 */ -float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], - srslte_pucch_cfg_t *cfg, - uint32_t n_pucch, - uint32_t ns, uint32_t l) +/** Initializes the PUCCH transmitter and receiver */ +int srslte_pucch_init_(srslte_pucch_t* q, bool is_ue) { - uint32_t n_prime = n_pucch%SRSLTE_NRE; - if (n_pucch >= SRSLTE_NRE*cfg->n_rb_2) { - n_prime = (n_pucch + cfg->N_cs + 1)%SRSLTE_NRE; - } - if (ns%2) { - n_prime = (SRSLTE_NRE*(n_prime+1))%(SRSLTE_NRE+1)-1; - if (n_pucch >= SRSLTE_NRE*cfg->n_rb_2) { - int x = (SRSLTE_NRE-2-(int) n_pucch)%SRSLTE_NRE; - if (x >= 0) { - n_prime = (uint32_t) x; - } else { - n_prime = SRSLTE_NRE+x; - } - } - } - uint32_t n_cs = (n_cs_cell[ns][l]+n_prime)%SRSLTE_NRE; - float alpha = 2 * M_PI * (n_cs) / SRSLTE_NRE; - DEBUG("n_pucch: %d, ns: %d, l: %d, n_prime: %d, n_cs: %d, alpha=%f\n", n_pucch, ns, l, n_prime, n_cs, alpha); - return alpha; -} - -/* Map PUCCH symbols to physical resources according to 5.4.3 in 36.211 */ -static int pucch_cp(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *source, cf_t *dest, bool source_is_grid) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q && source && dest) { - ret = SRSLTE_ERROR; - uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp)?SRSLTE_CP_NORM_NSYMB:SRSLTE_CP_EXT_NSYMB; - - uint32_t n_re = 0; - uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); - for (uint32_t ns=0;ns<2;ns++) { - uint32_t N_sf = get_N_sf(format, ns%2, q->shortened); - - // Determine n_prb - uint32_t n_prb = srslte_pucch_n_prb(&q->pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); - q->last_n_prb = n_prb; - if (n_prb < q->cell.nof_prb) { - for (uint32_t i=0;icell.cp); - if (!source_is_grid) { - memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], - &source[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE], - SRSLTE_NRE*sizeof(cf_t)); - } else { - memcpy(&dest[i*SRSLTE_NRE+ns*N_sf_0*SRSLTE_NRE], - &source[SRSLTE_RE_IDX(q->cell.nof_prb, l+ns*nsymbols, n_prb*SRSLTE_NRE)], - SRSLTE_NRE*sizeof(cf_t)); - } - n_re += SRSLTE_NRE; - } - } else { - return SRSLTE_ERROR; - } - } - ret = n_re; - } - return ret; -} - -static int pucch_put(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *z, cf_t *output) { - return pucch_cp(q, format, n_pucch, z, output, false); -} - -static int pucch_get(srslte_pucch_t *q, srslte_pucch_format_t format, uint32_t n_pucch, cf_t *input, cf_t *z) { - return pucch_cp(q, format, n_pucch, input, z, true); -} - -void srslte_pucch_set_threshold(srslte_pucch_t *q, float format1_threshold) { - q->threshold_format1 = format1_threshold; -} - -/** Initializes the PDCCH transmitter and receiver */ -int srslte_pucch_init_(srslte_pucch_t *q, bool is_ue) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL) { ret = SRSLTE_ERROR; @@ -447,8 +80,6 @@ int srslte_pucch_init_(srslte_pucch_t *q, bool is_ue) { q->ce = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS); } - q->threshold_format1 = 0.8; - ret = SRSLTE_SUCCESS; } clean_exit: @@ -469,10 +100,10 @@ int srslte_pucch_init_enb(srslte_pucch_t *q) { void srslte_pucch_free(srslte_pucch_t *q) { if (q->users) { if (q->is_ue) { - srslte_pucch_clear_rnti(q, 0); + srslte_pucch_free_rnti(q, 0); } else { for (int rnti = 0; rnti <= SRSLTE_SIRNTI; rnti++) { - srslte_pucch_clear_rnti(q, rnti); + srslte_pucch_free_rnti(q, rnti); } } free(q->users); @@ -499,10 +130,8 @@ int srslte_pucch_set_cell(srslte_pucch_t *q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && srslte_cell_isvalid(&cell)) { - srslte_pucch_cfg_default(&q->pucch_cfg); - if (cell.id != q->cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; // Precompute group hopping values u. if (srslte_group_hopping_f_gh(q->f_gh, q->cell.id)) { @@ -519,12 +148,12 @@ int srslte_pucch_set_cell(srslte_pucch_t *q, srslte_cell_t cell) { return ret; } - -void srslte_pucch_clear_rnti(srslte_pucch_t *q, uint16_t rnti) { +void srslte_pucch_free_rnti(srslte_pucch_t* q, uint16_t rnti) +{ uint32_t rnti_idx = q->is_ue?0:rnti; if (q->users[rnti_idx]) { - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { srslte_sequence_free(&q->users[rnti_idx]->seq_f2[i]); } free(q->users[rnti_idx]); @@ -533,7 +162,8 @@ void srslte_pucch_clear_rnti(srslte_pucch_t *q, uint16_t rnti) { } } -int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) { +int srslte_pucch_set_rnti(srslte_pucch_t* q, uint16_t rnti) +{ uint32_t rnti_idx = q->is_ue?0:rnti; if (!q->users[rnti_idx] || q->is_ue) { @@ -545,11 +175,11 @@ int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) { } } q->users[rnti_idx]->sequence_generated = false; - for (uint32_t sf_idx=0;sf_idxusers[rnti_idx]->seq_f2[sf_idx], rnti, 2*sf_idx, q->cell.id)) { - fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n"); - srslte_pucch_clear_rnti(q, rnti); + if (srslte_sequence_pucch(&q->users[rnti_idx]->seq_f2[sf_idx], rnti, 2 * sf_idx, q->cell.id)) { + ERROR("Error computing PUCCH Format 2 scrambling sequence\n"); + srslte_pucch_free_rnti(q, rnti); return SRSLTE_ERROR; } } @@ -557,26 +187,11 @@ int srslte_pucch_set_crnti(srslte_pucch_t *q, uint16_t rnti) { q->users[rnti_idx]->cell_id = q->cell.id; q->users[rnti_idx]->sequence_generated = true; } else { - fprintf(stderr, "Error generating PUSCH sequence: rnti=0x%x already generated\n", rnti); + ERROR("Error generating PUSCH sequence: rnti=0x%x already generated\n", rnti); } return SRSLTE_SUCCESS; } -bool srslte_pucch_set_cfg(srslte_pucch_t *q, srslte_pucch_cfg_t *cfg, bool group_hopping_en) -{ - q->group_hopping_en = group_hopping_en; - if (cfg) { - if (srslte_pucch_cfg_isvalid(cfg, q->cell.nof_prb)) { - memcpy(&q->pucch_cfg, cfg, sizeof(srslte_pucch_cfg_t)); - return true; - } else { - return false; - } - } else { - return false; - } -} - static cf_t uci_encode_format1() { return 1.0; } @@ -601,35 +216,6 @@ static cf_t uci_encode_format1b(uint8_t bits[2]) { } } -/* Modulates bit 20 and 21 for Formats 2a and 2b as in Table 5.4.2-1 in 36.211 */ -int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uint8_t bits[2], cf_t *d_10) { - if (d_10) { - if (format == SRSLTE_PUCCH_FORMAT_2A) { - *d_10 = bits[0]?-1.0:1.0; - return SRSLTE_SUCCESS; - } else if (format == SRSLTE_PUCCH_FORMAT_2B) { - if (bits[0] == 0) { - if (bits[1] == 0) { - *d_10 = 1.0; - } else { - *d_10 = -I; - } - } else { - if (bits[1] == 0) { - *d_10 = I; - } else { - *d_10 = -1.0; - } - } - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR; - } - } else { - return SRSLTE_ERROR; - } -} - static srslte_sequence_t *get_user_sequence(srslte_pucch_t *q, uint16_t rnti, uint32_t sf_idx) { uint32_t rnti_idx = q->is_ue?0:rnti; @@ -644,23 +230,24 @@ static srslte_sequence_t *get_user_sequence(srslte_pucch_t *q, uint16_t rnti, ui return &q->users[rnti_idx]->seq_f2[sf_idx]; } else { if (srslte_sequence_pucch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id)) { - fprintf(stderr, "Error computing PUCCH Format 2 scrambling sequence\n"); + ERROR("Error computing PUCCH Format 2 scrambling sequence\n"); return NULL; } return &q->tmp_seq; } } else { - fprintf(stderr, "Invalid RNTI=0x%x\n", rnti); + ERROR("Invalid RNTI=0x%x\n", rnti); return NULL; } } /* Encode PUCCH bits according to Table 5.4.1-1 in Section 5.4.1 of 36.211 */ -static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t sf_idx, uint16_t rnti) -{ - uint8_t tmp[2]; +static int +uci_mod_bits(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, uint8_t bits[SRSLTE_PUCCH_MAX_BITS]) +{ + uint8_t tmp[2]; srslte_sequence_t *seq; - switch(format) { + switch (cfg->format) { case SRSLTE_PUCCH_FORMAT_1: q->d[0] = uci_encode_format1(); break; @@ -675,18 +262,29 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2B: - seq = get_user_sequence(q, rnti, sf_idx); + seq = get_user_sequence(q, cfg->rnti, sf->tti % 10); if (seq) { memcpy(q->bits_scram, bits, SRSLTE_PUCCH2_NOF_BITS*sizeof(uint8_t)); - srslte_scrambling_b(seq, q->bits_scram); + srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH2_NOF_BITS); srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH2_NOF_BITS); } else { - fprintf(stderr, "Error modulating PUCCH2 bits: could not generate sequence\n"); - return -1; + ERROR("Error modulating PUCCH2 bits: could not generate sequence\n"); + return -1; + } + break; + case SRSLTE_PUCCH_FORMAT_3: + seq = get_user_sequence(q, cfg->rnti, sf->tti % 10); + if (seq) { + memcpy(q->bits_scram, bits, SRSLTE_PUCCH3_NOF_BITS * sizeof(uint8_t)); + srslte_scrambling_b_offset(seq, q->bits_scram, 0, SRSLTE_PUCCH3_NOF_BITS); + srslte_mod_modulate(&q->mod, q->bits_scram, q->d, SRSLTE_PUCCH3_NOF_BITS); + } else { + fprintf(stderr, "Error modulating PUCCH3 bits: rnti not set\n"); + return -1; } break; default: - fprintf(stderr, "PUCCH format 2 not supported\n"); + ERROR("PUCCH format %s not supported\n", srslte_pucch_format_text(cfg->format)); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; @@ -695,247 +293,831 @@ static int uci_mod_bits(srslte_pucch_t *q, srslte_pucch_format_t format, uint8_t // Declare this here, since we can not include refsignal_ul.h void srslte_refsignal_r_uv_arg_1prb(float *arg, uint32_t u); +/* 3GPP 36211 Table 5.5.2.2.2-1: Demodulation reference signal location for different PUCCH formats. */ +static const uint32_t pucch_symbol_format1_cpnorm[4] = {0, 1, 5, 6}; +static const uint32_t pucch_symbol_format1_cpext[4] = {0, 1, 4, 5}; +static const uint32_t pucch_symbol_format2_3_cpnorm[5] = {0, 2, 3, 4, 6}; +static const uint32_t pucch_symbol_format2_3_cpext[5] = {0, 1, 2, 4, 5}; -static int pucch_encode_(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS], bool signal_only) -{ - if (!signal_only) { - if (uci_mod_bits(q, format, bits, sf_idx, rnti)) { - fprintf(stderr, "Error encoding PUCCH bits\n"); - return SRSLTE_ERROR; - } - } else { - for (int i=0;id[i] = 1.0; - } - } - uint32_t N_sf_0 = get_N_sf(format, 0, q->shortened); - for (uint32_t ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - uint32_t N_sf = get_N_sf(format, ns%2, q->shortened); - DEBUG("ns=%d, N_sf=%d\n", ns, N_sf); - // Get group hopping number u - uint32_t f_gh=0; - if (q->group_hopping_en) { - f_gh = q->f_gh[ns]; - } - uint32_t u = (f_gh + (q->cell.id%30))%30; - - srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u); - uint32_t N_sf_widx = N_sf==3?1:0; - for (uint32_t m=0;mcell.cp); - float alpha=0; - if (format >= SRSLTE_PUCCH_FORMAT_2) { - alpha = srslte_pucch_alpha_format2(q->n_cs_cell, &q->pucch_cfg, n_pucch, ns, l); - for (uint32_t n=0;nd[(ns%2)*N_sf+m]*cexpf(I*(q->tmp_arg[n]+alpha*n)); - } - } else { - uint32_t n_prime_ns=0; - uint32_t n_oc=0; - alpha = srslte_pucch_alpha_format1(q->n_cs_cell, &q->pucch_cfg, n_pucch, q->cell.cp, true, ns, l, &n_oc, &n_prime_ns); - float S_ns = 0; - if (n_prime_ns%2) { - S_ns = M_PI/2; - } - DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d, n_rb_2=%d\n", - __real__ q->d[0], __imag__ q->d[0], alpha, n_oc, n_prime_ns, q->pucch_cfg.n_rb_2); +static const float w_n_oc[2][3][4] = { + // Table 5.4.1-2 Orthogonal sequences w for N_sf=4 (complex argument) + {{0, 0, 0, 0}, {0, M_PI, 0, M_PI}, {0, M_PI, M_PI, 0}}, + // Table 5.4.1-3 Orthogonal sequences w for N_sf=3 + {{0, 0, 0, 0}, {0, 2 * M_PI / 3, 4 * M_PI / 3, 0}, {0, 4 * M_PI / 3, 2 * M_PI / 3, 0}}, - for (uint32_t n=0;nd[0]*cexpf(I*(w_n_oc[N_sf_widx][n_oc%3][m]+q->tmp_arg[n]+alpha*n+S_ns)); - } - } - } - } - return SRSLTE_SUCCESS; -} +}; -static int pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS], cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]) -{ - return pucch_encode_(q, format, n_pucch, sf_idx, rnti, bits, z, false); -} +static const cf_t pucch3_w_n_oc_5[5][5] = { + {1, 1, 1, 1, 1}, + {1, cexpf(I * 2 * M_PI / 5), cexpf(I * 4 * M_PI / 5), cexpf(I * 6 * M_PI / 5), cexpf(I * 8 * M_PI / 5)}, + {1, cexpf(I * 4 * M_PI / 5), cexpf(I * 8 * M_PI / 5), cexpf(I * 2 * M_PI / 5), cexpf(I * 6 * M_PI / 5)}, + {1, cexpf(I * 6 * M_PI / 5), cexpf(I * 2 * M_PI / 5), cexpf(I * 8 * M_PI / 5), cexpf(I * 4 * M_PI / 5)}, + {1, cexpf(I * 8 * M_PI / 5), cexpf(I * 6 * M_PI / 5), cexpf(I * 4 * M_PI / 5), cexpf(I * 2 * M_PI / 5)}}; +static const cf_t pucch3_w_n_oc_4[4][4] = {{+1, +1, +1, +1}, {+1, -1, +1, -1}, {+1, +1, -1, -1}, {+1, -1, -1, +1}}; -/* Encode, modulate and resource mapping of PUCCH bits according to Section 5.4.1 of 36.211 */ -int srslte_pucch_encode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], - cf_t *sf_symbols) +static uint32_t get_N_sf(srslte_pucch_format_t format, uint32_t slot_idx, bool shortened) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - sf_symbols != NULL) - { - ret = SRSLTE_ERROR; - - // Shortened PUCCH happen in every cell-specific SRS subframes for Format 1/1a/1b - if (q->pucch_cfg.srs_configured && format < SRSLTE_PUCCH_FORMAT_2) { - q->shortened = false; - // If CQI is not transmitted, PUCCH will be normal unless ACK/NACK and SRS simultaneous transmission is enabled - if (q->pucch_cfg.srs_simul_ack) { - // If simultaneous ACK and SRS is enabled, PUCCH is shortened in cell-specific SRS subframes - if (srslte_refsignal_srs_send_cs(q->pucch_cfg.srs_cs_subf_cfg, sf_idx) == 1) { - q->shortened = true; - } + switch (format) { + case SRSLTE_PUCCH_FORMAT_1: + case SRSLTE_PUCCH_FORMAT_1A: + case SRSLTE_PUCCH_FORMAT_1B: + if (!slot_idx) { + return 4; + } else { + return shortened ? 3 : 4; } - } - - q->last_n_pucch = n_pucch; - - if (pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z)) { - return SRSLTE_ERROR; - } - if (pucch_put(q, format, n_pucch, q->z, sf_symbols) < 0) { - fprintf(stderr, "Error putting PUCCH symbols\n"); - return SRSLTE_ERROR; - } - ret = SRSLTE_SUCCESS; + case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_2A: + case SRSLTE_PUCCH_FORMAT_2B: + return 5; + case SRSLTE_PUCCH_FORMAT_3: + if (!slot_idx) { + return 5; + } else { + return shortened ? 4 : 5; + } + default: + return 0; } - - return ret; + return 0; } -float srslte_pucch_get_last_corr(srslte_pucch_t* q) -{ - return q->last_corr; -} - -/* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */ -int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, - uint32_t n_pucch, uint32_t sf_idx, uint16_t rnti, cf_t *sf_symbols, cf_t *ce, float noise_estimate, - uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits) +static uint32_t get_pucch_symbol(uint32_t m, srslte_pucch_format_t format, srslte_cp_t cp) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - srslte_sequence_t *seq; - - if (q != NULL && - ce != NULL && - sf_symbols != NULL) - { - ret = SRSLTE_ERROR; - cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS]; - int16_t llr_pucch2[32]; - - // Shortened PUCCH happen in every cell-specific SRS subframes for Format 1/1a/1b - if (q->pucch_cfg.srs_configured && format < SRSLTE_PUCCH_FORMAT_2) { - q->shortened = false; - // If CQI is not transmitted, PUCCH will be normal unless ACK/NACK and SRS simultaneous transmission is enabled - if (q->pucch_cfg.srs_simul_ack) { - // If simultaneous ACK and SRS is enabled, PUCCH is shortened in cell-specific SRS subframes - if (srslte_refsignal_srs_send_cs(q->pucch_cfg.srs_cs_subf_cfg, sf_idx) == 1) { - q->shortened = true; - } - } - } - - q->last_n_pucch = n_pucch; - - int nof_re = pucch_get(q, format, n_pucch, sf_symbols, q->z_tmp); - if (nof_re < 0) { - fprintf(stderr, "Error getting PUCCH symbols\n"); - return SRSLTE_ERROR; - } + switch (format) { + case SRSLTE_PUCCH_FORMAT_1: + case SRSLTE_PUCCH_FORMAT_1A: + case SRSLTE_PUCCH_FORMAT_1B: + if (m < 4) { + if (SRSLTE_CP_ISNORM(cp)) { + return pucch_symbol_format1_cpnorm[m]; + } else { + return pucch_symbol_format1_cpext[m]; + } + } + break; + case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_2A: + case SRSLTE_PUCCH_FORMAT_2B: + if (m < 5) { + if (SRSLTE_CP_ISNORM(cp)) { + return pucch_symbol_format2_3_cpnorm[m]; + } else { + return pucch_symbol_format2_3_cpext[m]; + } + } + break; + case SRSLTE_PUCCH_FORMAT_3: + if (SRSLTE_CP_ISNORM(cp)) { + return pucch_symbol_format2_3_cpnorm[m % 5]; + } else { + return pucch_symbol_format2_3_cpext[m % 5]; + } + break; + default: + return 0; + } + return 0; +} + +/* Map PUCCH symbols to physical resources according to 5.4.3 in 36.211 */ +static int pucch_cp( + srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, cf_t* source, cf_t* dest, bool source_is_grid) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q && source && dest) { + ret = SRSLTE_ERROR; + uint32_t nsymbols = SRSLTE_CP_ISNORM(q->cell.cp) ? SRSLTE_CP_NORM_NSYMB : SRSLTE_CP_EXT_NSYMB; + + uint32_t n_re = 0; + uint32_t N_sf_0 = get_N_sf(cfg->format, 0, sf->shortened); + for (uint32_t ns = 0; ns < 2; ns++) { + uint32_t N_sf = get_N_sf(cfg->format, ns % 2, sf->shortened); - if (pucch_get(q, format, n_pucch, ce, q->ce) < 0) { - fprintf(stderr, "Error getting PUCCH symbols\n"); - return SRSLTE_ERROR; + // Determine n_prb + uint32_t n_prb = srslte_pucch_n_prb(&q->cell, cfg, ns); + if (n_prb < q->cell.nof_prb) { + for (uint32_t i = 0; i < N_sf; i++) { + uint32_t l = get_pucch_symbol(i, cfg->format, q->cell.cp); + if (!source_is_grid) { + memcpy(&dest[SRSLTE_RE_IDX(q->cell.nof_prb, l + ns * nsymbols, n_prb * SRSLTE_NRE)], + &source[i * SRSLTE_NRE + ns * N_sf_0 * SRSLTE_NRE], + SRSLTE_NRE * sizeof(cf_t)); + } else { + memcpy(&dest[i * SRSLTE_NRE + ns * N_sf_0 * SRSLTE_NRE], + &source[SRSLTE_RE_IDX(q->cell.nof_prb, l + ns * nsymbols, n_prb * SRSLTE_NRE)], + SRSLTE_NRE * sizeof(cf_t)); + } + n_re += SRSLTE_NRE; + } + } else { + ERROR("Invalid PUCCH n_prb=%d\n", n_prb); + return SRSLTE_ERROR; + } } - - // Equalization - srslte_predecoding_single(q->z_tmp, q->ce, q->z, NULL, nof_re, 1.0f, noise_estimate); + ret = n_re; + } + return ret; +} - // Perform ML-decoding - float corr=0, corr_max=-1e9; - uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK - switch(format) { - case SRSLTE_PUCCH_FORMAT_1: - bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); - pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); +static int pucch_put(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, cf_t* z, cf_t* output) +{ + return pucch_cp(q, sf, cfg, z, output, false); +} + +static int pucch_get(srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, cf_t* input, cf_t* z) +{ + return pucch_cp(q, sf, cfg, input, z, true); +} + +static int encode_signal_format12(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], + cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS], + bool signal_only) +{ + if (!signal_only) { + if (uci_mod_bits(q, sf, cfg, bits)) { + ERROR("Error encoding PUCCH bits\n"); + return SRSLTE_ERROR; + } + } else { + for (int i = 0; i < SRSLTE_PUCCH_MAX_BITS / 2; i++) { + q->d[i] = 1.0; + } + } + uint32_t N_sf_0 = get_N_sf(cfg->format, 0, sf->shortened); + for (uint32_t ns = 2 * (sf->tti % 10); ns < 2 * ((sf->tti % 10) + 1); ns++) { + uint32_t N_sf = get_N_sf(cfg->format, ns % 2, sf->shortened); + DEBUG("ns=%d, N_sf=%d\n", ns, N_sf); + // Get group hopping number u + uint32_t f_gh = 0; + if (cfg->group_hopping_en) { + f_gh = q->f_gh[ns]; + } + uint32_t u = (f_gh + (q->cell.id % 30)) % 30; + + srslte_refsignal_r_uv_arg_1prb(q->tmp_arg, u); + uint32_t N_sf_widx = N_sf == 3 ? 1 : 0; + for (uint32_t m = 0; m < N_sf; m++) { + uint32_t l = get_pucch_symbol(m, cfg->format, q->cell.cp); + float alpha = 0; + if (cfg->format >= SRSLTE_PUCCH_FORMAT_2) { + alpha = srslte_pucch_alpha_format2(q->n_cs_cell, cfg, ns, l); + for (uint32_t n = 0; n < SRSLTE_PUCCH_N_SEQ; n++) { + z[(ns % 2) * N_sf * SRSLTE_PUCCH_N_SEQ + m * SRSLTE_PUCCH_N_SEQ + n] = + q->d[(ns % 2) * N_sf + m] * cexpf(I * (q->tmp_arg[n] + alpha * n)); + } + } else { + uint32_t n_prime_ns = 0; + uint32_t n_oc = 0; + alpha = srslte_pucch_alpha_format1(q->n_cs_cell, cfg, q->cell.cp, true, ns, l, &n_oc, &n_prime_ns); + float S_ns = 0; + if (n_prime_ns % 2) { + S_ns = M_PI / 2; + } + DEBUG("PUCCH d_0: %.1f+%.1fi, alpha: %.1f, n_oc: %d, n_prime_ns: %d, n_rb_2=%d\n", + __real__ q->d[0], + __imag__ q->d[0], + alpha, + n_oc, + n_prime_ns, + cfg->n_rb_2); + + for (uint32_t n = 0; n < SRSLTE_PUCCH_N_SEQ; n++) { + z[(ns % 2) * N_sf_0 * SRSLTE_PUCCH_N_SEQ + m * SRSLTE_PUCCH_N_SEQ + n] = + q->d[0] * cexpf(I * (w_n_oc[N_sf_widx][n_oc % 3][m] + q->tmp_arg[n] + alpha * n + S_ns)); + } + } + } + } + return SRSLTE_SUCCESS; +} + +static int encode_signal_format3(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], + cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS], + bool signal_only) +{ + if (!signal_only) { + if (uci_mod_bits(q, sf, cfg, bits)) { + ERROR("Error encoding PUCCH bits\n"); + return SRSLTE_ERROR; + } + } else { + for (int i = 0; i < SRSLTE_PUCCH_MAX_BITS / 2; i++) { + q->d[i] = 1.0; + } + } + + uint32_t N_sf_0 = get_N_sf(cfg->format, 0, sf->shortened); + uint32_t N_sf_1 = get_N_sf(cfg->format, 1, sf->shortened); + + uint32_t n_oc_0 = cfg->n_pucch % N_sf_1; + uint32_t n_oc_1 = (N_sf_1 == 5) ? ((3 * cfg->n_pucch) % N_sf_1) : (n_oc_0 % N_sf_1); + + cf_t* w_n_oc_0 = (cf_t*)pucch3_w_n_oc_5[n_oc_0]; + cf_t* w_n_oc_1 = (cf_t*)((N_sf_1 == 5) ? pucch3_w_n_oc_5[n_oc_1] : pucch3_w_n_oc_4[n_oc_1]); + + for (uint32_t n = 0; n < N_sf_0 + N_sf_1; n++) { + uint32_t l = get_pucch_symbol(n, cfg->format, q->cell.cp); + uint32_t n_cs_cell = q->n_cs_cell[(2 * (sf->tti % 10) + ((n < N_sf_0) ? 0 : 1)) % SRSLTE_NSLOTS_X_FRAME][l]; + + cf_t y_n[SRSLTE_NRE]; + bzero(y_n, sizeof(cf_t) * SRSLTE_NRE); + + cf_t h; + if (n < N_sf_0) { + h = w_n_oc_0[n] * cexpf(I * M_PI * floorf(n_cs_cell / 64) / 2); + for (uint32_t i = 0; i < SRSLTE_NRE; i++) { + y_n[i] = h * q->d[(i + n_cs_cell) % SRSLTE_NRE]; + } + } else { + h = w_n_oc_1[n - N_sf_0] * cexpf(I * M_PI * floorf(n_cs_cell / 64) / 2); + for (uint32_t i = 0; i < SRSLTE_NRE; i++) { + y_n[i] = h * q->d[((i + n_cs_cell) % SRSLTE_NRE) + SRSLTE_NRE]; + } + } + + for (int k = 0; k < SRSLTE_NRE; k++) { + cf_t acc = 0.0f; + for (int i = 0; i < SRSLTE_NRE; i++) { + acc += y_n[i] * cexpf(-I * 2.0 * M_PI * i * k / (float)SRSLTE_NRE); + } + z[n * SRSLTE_NRE + k] = acc / sqrtf(SRSLTE_NRE); + } + } + + return SRSLTE_SUCCESS; +} + +static int encode_signal(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + uint8_t bits[SRSLTE_PUCCH_MAX_BITS], + cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS]) +{ + if (cfg->format == SRSLTE_PUCCH_FORMAT_3) { + return encode_signal_format3(q, sf, cfg, bits, z, false); + } else { + return encode_signal_format12(q, sf, cfg, bits, z, false); + } +} + +// Encode bits from uci_data +static int encode_bits(srslte_pucch_cfg_t* cfg, + srslte_uci_value_t* uci_data, + srslte_pucch_format_t format, + uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], + uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS]) +{ + if (format < SRSLTE_PUCCH_FORMAT_2) { + memcpy(pucch_bits, uci_data->ack.ack_value, cfg->uci_cfg.ack.nof_acks * sizeof(uint8_t)); + } else if (format >= SRSLTE_PUCCH_FORMAT_2 && format < SRSLTE_PUCCH_FORMAT_3) { + /* Put RI (goes alone) */ + if (cfg->uci_cfg.cqi.ri_len) { + uint8_t temp[2] = {uci_data->ri, 0}; + srslte_uci_encode_cqi_pucch(temp, cfg->uci_cfg.cqi.ri_len, pucch_bits); + } else { + /* Put CQI Report*/ + uint8_t buff[SRSLTE_CQI_MAX_BITS]; + int uci_cqi_len = srslte_cqi_value_pack(&cfg->uci_cfg.cqi, &uci_data->cqi, buff); + if (uci_cqi_len < 0) { + ERROR("Error encoding CQI\n"); + return SRSLTE_ERROR; + } + srslte_uci_encode_cqi_pucch(buff, (uint32_t)uci_cqi_len, pucch_bits); + } + if (format > SRSLTE_PUCCH_FORMAT_2) { + pucch2_bits[0] = uci_data->ack.ack_value[0]; + pucch2_bits[1] = uci_data->ack.ack_value[1]; // this will be ignored in format 2a + } + } else if (format == SRSLTE_PUCCH_FORMAT_3) { + uint8_t temp[SRSLTE_UCI_MAX_ACK_BITS + 1]; + uint32_t k = 0; + for (; k < cfg->uci_cfg.ack.nof_acks; k++) { + temp[k] = (uint8_t)((uci_data->ack.ack_value[k] == 1) ? 1 : 0); + } + if (cfg->uci_cfg.is_scheduling_request_tti) { + temp[k] = (uint8_t)(uci_data->scheduling_request ? 1 : 0); + k++; + } + srslte_uci_encode_ack_sr_pucch3(temp, k, pucch_bits); + for (k = 32; k < SRSLTE_PUCCH3_NOF_BITS; k++) { + pucch_bits[k] = pucch_bits[k % 32]; + } + } + return SRSLTE_SUCCESS; +} + +static bool decode_signal(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + uint8_t pucch_bits[SRSLTE_CQI_MAX_BITS], + uint32_t nof_re, + uint32_t nof_uci_bits, + float* correlation) +{ + int16_t llr_pucch2[SRSLTE_CQI_MAX_BITS]; + bool detected = false; + float corr = 0, corr_max = -1e9; + uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK + + srslte_sequence_t* seq; + cf_t ref[SRSLTE_PUCCH_MAX_SYMBOLS]; + + switch (cfg->format) { + case SRSLTE_PUCCH_FORMAT_1: + encode_signal(q, sf, cfg, pucch_bits, q->z_tmp); + corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); + if (corr >= cfg->threshold_format1) { + detected = true; + } + DEBUG("format1 corr=%f, nof_re=%d, th=%f\n", corr, nof_re, cfg->threshold_format1); + break; + case SRSLTE_PUCCH_FORMAT_1A: + detected = 0; + for (uint8_t b = 0; b < 2; b++) { + pucch_bits[0] = b; + encode_signal(q, sf, cfg, pucch_bits, q->z_tmp); corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); - if (corr >= q->threshold_format1) { - ret = 1; - } else { - ret = 0; + if (corr > corr_max) { + corr_max = corr; + b_max = b; } - q->last_corr = corr; - DEBUG("format1 corr=%f, nof_re=%d, th=%f\n", corr, nof_re, q->threshold_format1); - break; - case SRSLTE_PUCCH_FORMAT_1A: - bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); - ret = 0; - for (uint8_t b=0;b<2;b++) { - bits[0] = b; - pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); + if (corr_max > cfg->threshold_format1) { // check with format1 in case ack+sr because ack only is binary + detected = true; + } + DEBUG("format1a b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re); + } + corr = corr_max; + pucch_bits[0] = b_max; + break; + case SRSLTE_PUCCH_FORMAT_1B: + detected = 0; + for (uint8_t b = 0; b < 2; b++) { + for (uint8_t b2 = 0; b2 < 2; b2++) { + pucch_bits[0] = b; + pucch_bits[1] = b2; + encode_signal(q, sf, cfg, pucch_bits, q->z_tmp); corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); if (corr > corr_max) { - corr_max = corr; - b_max = b; + corr_max = corr; + b_max = b; + b2_max = b2; } - if (corr_max > q->threshold_format1) { // check with format1 in case ack+sr because ack only is binary - ret = 1; + if (corr_max > cfg->threshold_format1) { // check with format1 in case ack+sr because ack only is binary + detected = true; } - DEBUG("format1a b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re); + DEBUG("format1b b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re); } - q->last_corr = corr_max; - bits[0] = b_max; - break; - case SRSLTE_PUCCH_FORMAT_1B: - bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); - ret = 0; - for (uint8_t b=0;b<2;b++) { - for (uint8_t b2 = 0; b2 < 2; b2++) { - bits[0] = b; - bits[1] = b2; - pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); - corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); - if (corr > corr_max) { - corr_max = corr; - b_max = b; - b2_max = b2; - } - if (corr_max > q->threshold_format1) { // check with format1 in case ack+sr because ack only is binary - ret = 1; - } - DEBUG("format1b b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re); + } + corr = corr_max; + pucch_bits[0] = b_max; + pucch_bits[1] = b2_max; + break; + case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_2A: + case SRSLTE_PUCCH_FORMAT_2B: + seq = get_user_sequence(q, cfg->rnti, sf->tti % 10); + if (seq) { + encode_signal_format12(q, sf, cfg, NULL, ref, true); + srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS); + for (int i = 0; i < SRSLTE_PUCCH2_NOF_BITS / 2; i++) { + q->z[i] = 0; + for (int j = 0; j < SRSLTE_NRE; j++) { + q->z[i] += q->z_tmp[i * SRSLTE_NRE + j] / SRSLTE_NRE; } } - q->last_corr = corr_max; - bits[0] = b_max; - bits[1] = b2_max; + srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS / 2); + srslte_scrambling_s_offset(seq, llr_pucch2, 0, SRSLTE_PUCCH2_NOF_BITS); + corr = (float)srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, pucch_bits, nof_uci_bits) / 2000; + detected = true; + } else { + ERROR("Decoding PUCCH2: could not generate sequence\n"); + return -1; + } + break; + default: + ERROR("PUCCH format %d not implemented\n", cfg->format); + return SRSLTE_ERROR; + } + if (correlation) { + *correlation = corr; + } + return detected; +} + +static void decode_bits(srslte_uci_cfg_t* uci_cfg, + bool pucch_found, + uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], + uint8_t pucch_dmrs_bits[SRSLTE_PUCCH2_MAX_DMRS_BITS], + srslte_uci_value_t* uci_data) +{ + // If was looking for scheduling request, update value + if (uci_cfg->is_scheduling_request_tti) { + uci_data->scheduling_request = pucch_found; + } + + // Save ACK bits + for (uint32_t a = 0; a < uci_cfg->ack.nof_acks; a++) { + if (uci_cfg->cqi.data_enable || uci_cfg->cqi.ri_len) { + uci_data->ack.ack_value[a] = pucch_dmrs_bits[a]; + } else { + uci_data->ack.ack_value[a] = pucch_bits[a]; + } + } + + // PUCCH2 CQI bits are already decoded + if (uci_cfg->cqi.data_enable) { + srslte_cqi_value_unpack(&uci_cfg->cqi, pucch_bits, &uci_data->cqi); + } + + if (uci_cfg->cqi.ri_len) { + uci_data->ri = pucch_bits[0]; /* Assume only one bit of RI */ + } +} + +/* Encode, modulate and resource mapping of UCI data over PUCCH */ +int srslte_pucch_encode( + srslte_pucch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data, cf_t* sf_symbols) +{ + uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; + bzero(pucch_bits, SRSLTE_PUCCH_MAX_BITS * sizeof(uint8_t)); + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL && sf_symbols != NULL) { + // Encode bits from UCI data for this format + encode_bits(cfg, uci_data, cfg->format, pucch_bits, cfg->pucch2_drs_bits); + + if (encode_signal(q, sf, cfg, pucch_bits, q->z)) { + return SRSLTE_ERROR; + } + + if (pucch_put(q, sf, cfg, q->z, sf_symbols) < 0) { + ERROR("Error putting PUCCH symbols\n"); + return SRSLTE_ERROR; + } + ret = SRSLTE_SUCCESS; + } + + return ret; +} + +/* Equalize, demodulate and decode PUCCH bits according to Section 5.4.1 of 36.211 */ +int srslte_pucch_decode(srslte_pucch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pucch_cfg_t* cfg, + srslte_chest_ul_res_t* channel, + cf_t* sf_symbols, + srslte_pucch_res_t* data) +{ + uint8_t pucch_bits[SRSLTE_CQI_MAX_BITS]; + bzero(pucch_bits, SRSLTE_CQI_MAX_BITS * sizeof(uint8_t)); + + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && cfg != NULL && channel != NULL && data != NULL) { + + uint32_t nof_cqi_bits = srslte_cqi_size(&cfg->uci_cfg.cqi); + uint32_t nof_uci_bits = cfg->uci_cfg.cqi.ri_len ? cfg->uci_cfg.cqi.ri_len : nof_cqi_bits; + + int nof_re = pucch_get(q, sf, cfg, sf_symbols, q->z_tmp); + if (nof_re < 0) { + ERROR("Error getting PUCCH symbols\n"); + return SRSLTE_ERROR; + } + + if (pucch_get(q, sf, cfg, channel->ce, q->ce) < 0) { + ERROR("Error getting PUCCH symbols\n"); + return SRSLTE_ERROR; + } + + // Equalization + srslte_predecoding_single(q->z_tmp, q->ce, q->z, NULL, nof_re, 1.0f, channel->noise_estimate); + + // Perform ML-decoding + bool pucch_found = decode_signal(q, sf, cfg, pucch_bits, nof_re, nof_uci_bits, &data->correlation); + + // Convert bits to UCI data + decode_bits(&cfg->uci_cfg, pucch_found, pucch_bits, cfg->pucch2_drs_bits, &data->uci_data); + + data->detected = pucch_found; + + // Accept ACK and CQI only if correlation above threshold + switch (cfg->format) { + case SRSLTE_PUCCH_FORMAT_1A: + case SRSLTE_PUCCH_FORMAT_1B: + data->uci_data.ack.valid = data->correlation > cfg->threshold_data_valid_format1a; break; case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2B: - seq = get_user_sequence(q, rnti, sf_idx); - if (seq) { - pucch_encode_(q, format, n_pucch, sf_idx, rnti, NULL, ref, true); - srslte_vec_prod_conj_ccc(q->z, ref, q->z_tmp, SRSLTE_PUCCH_MAX_SYMBOLS); - for (int i=0;iz[i] = 0; - for (int j=0;jz[i] += q->z_tmp[i*SRSLTE_NRE+j]/SRSLTE_NRE; - } - } - srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->z, llr_pucch2, SRSLTE_PUCCH2_NOF_BITS/2); - srslte_scrambling_s(seq, llr_pucch2); - q->last_corr = (float) srslte_uci_decode_cqi_pucch(&q->cqi, llr_pucch2, bits, nof_bits)/2000; - ret = 1; - } else { - fprintf(stderr, "Decoding PUCCH2: could not generate sequence\n"); - return -1; - } + data->uci_data.ack.valid = data->correlation > cfg->threshold_data_valid_format2; + data->uci_data.cqi.data_crc = data->correlation > cfg->threshold_data_valid_format2; break; + case SRSLTE_PUCCH_FORMAT_1: + case SRSLTE_PUCCH_FORMAT_3: default: - fprintf(stderr, "PUCCH format %d not implemented\n", format); - return SRSLTE_ERROR; + /* Not considered, do nothing */; + } + + ret = SRSLTE_SUCCESS; + } + + return ret; +} + +char* srslte_pucch_format_text(srslte_pucch_format_t format) +{ + char* ret = NULL; + + switch (format) { + + case SRSLTE_PUCCH_FORMAT_1: + ret = "Format 1"; + break; + case SRSLTE_PUCCH_FORMAT_1A: + ret = "Format 1A"; + break; + case SRSLTE_PUCCH_FORMAT_1B: + ret = "Format 1B"; + break; + case SRSLTE_PUCCH_FORMAT_2: + ret = "Format 2"; + break; + case SRSLTE_PUCCH_FORMAT_2A: + ret = "Format 2A"; + break; + case SRSLTE_PUCCH_FORMAT_2B: + ret = "Format 2B"; + break; + case SRSLTE_PUCCH_FORMAT_3: + ret = "Format 3"; + break; + case SRSLTE_PUCCH_FORMAT_ERROR: + ret = "Format Error"; + break; + } + + return ret; +} + +char* srslte_pucch_format_text_short(srslte_pucch_format_t format) +{ + char* ret = NULL; + + switch (format) { + + case SRSLTE_PUCCH_FORMAT_1: + ret = "1"; + break; + case SRSLTE_PUCCH_FORMAT_1A: + ret = "1a"; + break; + case SRSLTE_PUCCH_FORMAT_1B: + ret = "1b"; + break; + case SRSLTE_PUCCH_FORMAT_2: + ret = "2"; + break; + case SRSLTE_PUCCH_FORMAT_2A: + ret = "2a"; + break; + case SRSLTE_PUCCH_FORMAT_2B: + ret = "2b"; + break; + case SRSLTE_PUCCH_FORMAT_3: + ret = "3"; + break; + case SRSLTE_PUCCH_FORMAT_ERROR: + ret = "Err"; + break; + } + + return ret; +} + +/* Verify PUCCH configuration as given in Section 5.4 36.211 */ +bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t* cfg, uint32_t nof_prb) +{ + if (cfg->delta_pucch_shift > 0 && cfg->delta_pucch_shift < 4 && cfg->N_cs < 8 && + (cfg->N_cs % cfg->delta_pucch_shift) == 0 && cfg->n_rb_2 <= nof_prb) { + return true; + } else { + return false; + } +} + +uint32_t srslte_pucch_n_prb(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns) +{ + uint32_t m = srslte_pucch_m(cfg, cell->cp); + // Determine n_prb + uint32_t n_prb = m / 2; + if ((m + ns) % 2) { + n_prb = cell->nof_prb - 1 - m / 2; + } + return n_prb; +} + +// Compute m according to Section 5.4.3 of 36.211 +uint32_t srslte_pucch_m(srslte_pucch_cfg_t* cfg, srslte_cp_t cp) +{ + uint32_t m = 0; + switch (cfg->format) { + case SRSLTE_PUCCH_FORMAT_1: + case SRSLTE_PUCCH_FORMAT_1A: + case SRSLTE_PUCCH_FORMAT_1B: + m = cfg->n_rb_2; + + uint32_t c = SRSLTE_CP_ISNORM(cp) ? 3 : 2; + if (cfg->n_pucch >= c * cfg->N_cs / cfg->delta_pucch_shift) { + m = (cfg->n_pucch - c * cfg->N_cs / cfg->delta_pucch_shift) / (c * SRSLTE_NRE / cfg->delta_pucch_shift) + + cfg->n_rb_2 + (uint32_t)ceilf((float)cfg->N_cs / 8); + } + break; + case SRSLTE_PUCCH_FORMAT_2: + case SRSLTE_PUCCH_FORMAT_2A: + case SRSLTE_PUCCH_FORMAT_2B: + m = cfg->n_pucch / SRSLTE_NRE; + break; + case SRSLTE_PUCCH_FORMAT_3: + m = cfg->n_pucch / 5; + break; + default: + m = 0; + break; + } + return m; +} + +/* Generates n_cs_cell according to Sec 5.4 of 36.211 */ +int srslte_pucch_n_cs_cell(srslte_cell_t cell, uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]) +{ + srslte_sequence_t seq; + bzero(&seq, sizeof(srslte_sequence_t)); + + srslte_sequence_LTE_pr(&seq, 8 * SRSLTE_CP_NSYMB(cell.cp) * SRSLTE_NSLOTS_X_FRAME, cell.id); + + for (uint32_t ns = 0; ns < SRSLTE_NSLOTS_X_FRAME; ns++) { + for (uint32_t l = 0; l < SRSLTE_CP_NSYMB(cell.cp); l++) { + n_cs_cell[ns][l] = 0; + for (uint32_t i = 0; i < 8; i++) { + n_cs_cell[ns][l] += seq.c[8 * SRSLTE_CP_NSYMB(cell.cp) * ns + 8 * l + i] << i; + } + } + } + srslte_sequence_free(&seq); + return SRSLTE_SUCCESS; +} + +/* Calculates alpha for format 1/a/b according to 5.5.2.2.2 (is_dmrs=true) or 5.4.1 (is_dmrs=false) of 36.211 */ +float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], + srslte_pucch_cfg_t* cfg, + srslte_cp_t cp, + bool is_dmrs, + uint32_t ns, + uint32_t l, + uint32_t* n_oc_ptr, + uint32_t* n_prime_ns) +{ + uint32_t c = SRSLTE_CP_ISNORM(cp) ? 3 : 2; + uint32_t N_prime = (cfg->n_pucch < c * cfg->N_cs / cfg->delta_pucch_shift) ? cfg->N_cs : SRSLTE_NRE; + + uint32_t n_prime = cfg->n_pucch; + if (cfg->n_pucch >= c * cfg->N_cs / cfg->delta_pucch_shift) { + n_prime = (cfg->n_pucch - c * cfg->N_cs / cfg->delta_pucch_shift) % (c * SRSLTE_NRE / cfg->delta_pucch_shift); + } + if (ns % 2) { + if (cfg->n_pucch >= c * cfg->N_cs / cfg->delta_pucch_shift) { + n_prime = (c * (n_prime + 1)) % (c * SRSLTE_NRE / cfg->delta_pucch_shift + 1) - 1; + } else { + uint32_t d = SRSLTE_CP_ISNORM(cp) ? 2 : 0; + uint32_t h = (n_prime + d) % (c * N_prime / cfg->delta_pucch_shift); + n_prime = (h / c) + (h % c) * N_prime / cfg->delta_pucch_shift; } } - return ret; + if (n_prime_ns) { + *n_prime_ns = n_prime; + } + + uint32_t n_oc_div = (!is_dmrs && SRSLTE_CP_ISEXT(cp)) ? 2 : 1; + + uint32_t n_oc = n_prime * cfg->delta_pucch_shift / N_prime; + if (!is_dmrs && SRSLTE_CP_ISEXT(cp)) { + n_oc *= 2; + } + if (n_oc_ptr) { + *n_oc_ptr = n_oc; + } + uint32_t n_cs = 0; + if (SRSLTE_CP_ISNORM(cp)) { + n_cs = (n_cs_cell[ns][l] + (n_prime * cfg->delta_pucch_shift + (n_oc % cfg->delta_pucch_shift)) % N_prime) % + SRSLTE_NRE; + } else { + n_cs = (n_cs_cell[ns][l] + (n_prime * cfg->delta_pucch_shift + n_oc / n_oc_div) % N_prime) % SRSLTE_NRE; + } + + DEBUG("n_cs=%d, N_prime=%d, delta_pucch=%d, n_prime=%d, ns=%d, l=%d, ns_cs_cell=%d\n", + n_cs, + N_prime, + cfg->delta_pucch_shift, + n_prime, + ns, + l, + n_cs_cell[ns][l]); + + return 2 * M_PI * (n_cs) / SRSLTE_NRE; +} + +/* Calculates alpha for format 2/a/b according to 5.4.2 of 36.211 */ +float srslte_pucch_alpha_format2(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], + srslte_pucch_cfg_t* cfg, + uint32_t ns, + uint32_t l) +{ + uint32_t n_prime = cfg->n_pucch % SRSLTE_NRE; + if (cfg->n_pucch >= SRSLTE_NRE * cfg->n_rb_2) { + n_prime = (cfg->n_pucch + cfg->N_cs + 1) % SRSLTE_NRE; + } + if (ns % 2) { + n_prime = (SRSLTE_NRE * (n_prime + 1)) % (SRSLTE_NRE + 1) - 1; + if (cfg->n_pucch >= SRSLTE_NRE * cfg->n_rb_2) { + int x = (SRSLTE_NRE - 2 - (int)cfg->n_pucch) % SRSLTE_NRE; + if (x >= 0) { + n_prime = (uint32_t)x; + } else { + n_prime = SRSLTE_NRE + x; + } + } + } + uint32_t n_cs = (n_cs_cell[ns][l] + n_prime) % SRSLTE_NRE; + float alpha = 2 * M_PI * (n_cs) / SRSLTE_NRE; + DEBUG("n_pucch: %d, ns: %d, l: %d, n_prime: %d, n_cs: %d, alpha=%f\n", cfg->n_pucch, ns, l, n_prime, n_cs, alpha); + return alpha; +} + +/* Modulates bit 20 and 21 for Formats 2a and 2b as in Table 5.4.2-1 in 36.211 */ +int srslte_pucch_format2ab_mod_bits(srslte_pucch_format_t format, uint8_t bits[2], cf_t* d_10) +{ + if (d_10) { + if (format == SRSLTE_PUCCH_FORMAT_2A) { + *d_10 = bits[0] ? -1.0 : 1.0; + return SRSLTE_SUCCESS; + } else if (format == SRSLTE_PUCCH_FORMAT_2B) { + if (bits[0] == 0) { + if (bits[1] == 0) { + *d_10 = 1.0; + } else { + *d_10 = -I; + } + } else { + if (bits[1] == 0) { + *d_10 = I; + } else { + *d_10 = -1.0; + } + } + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR; + } + } else { + return SRSLTE_ERROR; + } } +void srslte_pucch_tx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len) +{ + uint32_t n = srslte_print_check(str, + str_len, + 0, + "rnti=0x%x, f=%s, n_pucch=%d", + cfg->rnti, + srslte_pucch_format_text_short(cfg->format), + cfg->n_pucch); + + if (uci_data) { + srslte_uci_data_info(&cfg->uci_cfg, uci_data, &str[n], str_len - n); + } +} - +void srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len) +{ + uint32_t n = srslte_print_check(str, + str_len, + 0, + "rnti=0x%x, f=%s, n_pucch=%d", + cfg->rnti, + srslte_pucch_format_text_short(cfg->format), + cfg->n_pucch); + + if (uci_data) { + srslte_uci_data_info(&cfg->uci_cfg, uci_data, &str[n], str_len - n); + } +} diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index 0f06ef1bb..357330dee 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -24,16 +24,15 @@ * */ +#include "srslte/srslte.h" +#include +#include +#include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include #include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/phch/pusch.h" @@ -47,108 +46,27 @@ #define MAX_PUSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) - +#define ACK_SNR_TH -1.0 const static srslte_mod_t modulations[4] = { SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; - -static int f_hop_sum(srslte_pusch_t *q, uint32_t i) { - uint32_t sum = 0; - for (uint32_t k=i*10+1;kseq_type2_fo.c[k]<<(k-(i*10+1))); - } - return sum; -} - -static int f_hop(srslte_pusch_t *q, srslte_pusch_hopping_cfg_t *hopping, int i) { - if (i == -1) { - return 0; - } else { - if (hopping->n_sb == 1) { - return 0; - } else if (hopping->n_sb == 2) { - return (f_hop(q, hopping, i-1) + f_hop_sum(q, i))%2; - } else { - return (f_hop(q, hopping, i-1) + f_hop_sum(q, i)%(hopping->n_sb-1)+1)%hopping->n_sb; - } - } -} - -static int f_m(srslte_pusch_t *q, srslte_pusch_hopping_cfg_t *hopping, uint32_t i, uint32_t current_tx_nb) { - if (hopping->n_sb == 1) { - if (hopping->hop_mode == SRSLTE_PUSCH_HOP_MODE_INTER_SF) { - return current_tx_nb%2; - } else { - return i%2; - } - } else { - return q->seq_type2_fo.c[i*10]; - } -} - -/* Computes PUSCH frequency hopping as defined in Section 8.4 of 36.213 */ -void compute_freq_hopping(srslte_pusch_t *q, srslte_ra_ul_grant_t *grant, - srslte_pusch_hopping_cfg_t *hopping, - uint32_t sf_idx, uint32_t current_tx_nb) -{ - - for (uint32_t slot=0;slot<2;slot++) { - - INFO("PUSCH Freq hopping: %d\n", grant->freq_hopping); - uint32_t n_prb_tilde = grant->n_prb[slot]; - - if (grant->freq_hopping == 1) { - if (hopping->hop_mode == SRSLTE_PUSCH_HOP_MODE_INTER_SF) { - n_prb_tilde = grant->n_prb[current_tx_nb%2]; - } else { - n_prb_tilde = grant->n_prb[slot]; - } - } - if (grant->freq_hopping == 2) { - /* Freq hopping type 2 as defined in 5.3.4 of 36.211 */ - uint32_t n_vrb_tilde = grant->n_prb[0]; - if (hopping->n_sb > 1) { - n_vrb_tilde -= (hopping->hopping_offset-1)/2+1; - } - int i=0; - if (hopping->hop_mode == SRSLTE_PUSCH_HOP_MODE_INTER_SF) { - i = sf_idx; - } else { - i = 2*sf_idx+slot; - } - uint32_t n_rb_sb = q->cell.nof_prb; - if (hopping->n_sb > 1) { - n_rb_sb = (n_rb_sb-hopping->hopping_offset-hopping->hopping_offset%2)/hopping->n_sb; - } - n_prb_tilde = (n_vrb_tilde+f_hop(q, hopping, i)*n_rb_sb+ - (n_rb_sb-1)-2*(n_vrb_tilde%n_rb_sb)*f_m(q, hopping, i, current_tx_nb))%(n_rb_sb*hopping->n_sb); - - INFO("n_prb_tilde: %d, n_vrb_tilde: %d, n_rb_sb: %d, n_sb: %d\n", - n_prb_tilde, n_vrb_tilde, n_rb_sb, hopping->n_sb); - if (hopping->n_sb > 1) { - n_prb_tilde += (hopping->hopping_offset-1)/2+1; - } - - } - grant->n_prb_tilde[slot] = n_prb_tilde; - } -} /* Allocate/deallocate PUSCH RBs to the resource grid */ -int pusch_cp(srslte_pusch_t *q, srslte_ra_ul_grant_t *grant, cf_t *input, cf_t *output, bool advance_input) +static int pusch_cp( + srslte_pusch_t* q, srslte_pusch_grant_t* grant, cf_t* input, cf_t* output, bool is_shortened, bool advance_input) { - cf_t *in_ptr = input; - cf_t *out_ptr = output; - + cf_t* in_ptr = input; + cf_t* out_ptr = output; + uint32_t L_ref = 3; if (SRSLTE_CP_ISEXT(q->cell.cp)) { L_ref = 2; } - for (uint32_t slot=0;slot<2;slot++) { - uint32_t N_srs = 0; - if (q->shortened && slot == 1) { + for (uint32_t slot = 0; slot < 2; slot++) { + uint32_t N_srs = 0; + if (is_shortened && slot == 1) { N_srs = 1; } INFO("%s PUSCH %d PRB to index %d at slot %d\n",advance_input?"Allocating":"Getting",grant->L_prb, grant->n_prb_tilde[slot], slot); @@ -177,17 +95,19 @@ int pusch_cp(srslte_pusch_t *q, srslte_ra_ul_grant_t *grant, cf_t *input, cf_t * } } -int pusch_put(srslte_pusch_t *q, srslte_ra_ul_grant_t *grant, cf_t *input, cf_t *output) { - return pusch_cp(q, grant, input, output, true); +static int pusch_put(srslte_pusch_t* q, srslte_pusch_grant_t* grant, cf_t* input, cf_t* output, bool is_shortened) +{ + return pusch_cp(q, grant, input, output, is_shortened, true); } -int pusch_get(srslte_pusch_t *q, srslte_ra_ul_grant_t *grant, cf_t *input, cf_t *output) { - return pusch_cp(q, grant, input, output, false); +static int pusch_get(srslte_pusch_t* q, srslte_pusch_grant_t* grant, cf_t* input, cf_t* output, bool is_shortened) +{ + return pusch_cp(q, grant, input, output, is_shortened, false); } - /** Initializes the PDCCH transmitter and receiver */ -int pusch_init(srslte_pusch_t *q, uint32_t max_prb, bool is_ue) { +static int pusch_init(srslte_pusch_t* q, uint32_t max_prb, bool is_ue) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; @@ -222,7 +142,7 @@ int pusch_init(srslte_pusch_t *q, uint32_t max_prb, bool is_ue) { srslte_sch_init(&q->ul_sch); if (srslte_dft_precoding_init(&q->dft_precoding, max_prb, is_ue)) { - fprintf(stderr, "Error initiating DFT transform precoding\n"); + ERROR("Error initiating DFT transform precoding\n"); goto clean; } @@ -302,8 +222,6 @@ void srslte_pusch_free(srslte_pusch_t *q) { free(q->users); } - srslte_sequence_free(&q->seq_type2_fo); - srslte_sequence_free(&q->tmp_seq); for (i = 0; i < 4; i++) { @@ -318,116 +236,15 @@ void srslte_pusch_free(srslte_pusch_t *q) { int srslte_pusch_set_cell(srslte_pusch_t *q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && srslte_cell_isvalid(&cell)) - { - - q->max_re = cell.nof_prb * MAX_PUSCH_RE(q->cell.cp); - - INFO("PUSCH: Cell config PCI=%d, %d ports %d PRBs, max_symbols: %d\n", - q->cell.id, q->cell.nof_ports, q->cell.nof_prb, q->max_re); - - if (q->cell.id != cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - /* Precompute sequence for type2 frequency hopping */ - if (srslte_sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) { - fprintf(stderr, "Error initiating type2 frequency hopping sequence\n"); - return SRSLTE_ERROR; - } + if (q != NULL && srslte_cell_isvalid(&cell)) { - } + q->cell = cell; + q->max_re = cell.nof_prb * MAX_PUSCH_RE(cell.cp); ret = SRSLTE_SUCCESS; } return ret; } - - -/* Configures the structure srslte_pusch_cfg_t from the UL DCI allocation dci_msg. - * If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant - */ -int srslte_pusch_cfg(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, - srslte_ra_ul_grant_t *grant, - srslte_uci_cfg_t *uci_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg, - uint32_t tti, - uint32_t rv_idx, - uint32_t current_tx_nb) -{ - if (q && cfg && grant) { - memcpy(&cfg->grant, grant, sizeof(srslte_ra_ul_grant_t)); - - if (srslte_cbsegm(&cfg->cb_segm, cfg->grant.mcs.tbs)) { - fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs.tbs); - return SRSLTE_ERROR; - } - - /* Compute PUSCH frequency hopping */ - if (hopping_cfg) { - compute_freq_hopping(q, &cfg->grant, hopping_cfg, tti%10, current_tx_nb); - } else { - cfg->grant.n_prb_tilde[0] = cfg->grant.n_prb[0]; - cfg->grant.n_prb_tilde[1] = cfg->grant.n_prb[1]; - } - if (srs_cfg) { - q->shortened = false; - if (srs_cfg->configured) { - // If UE-specific SRS is configured, PUSCH is shortened every time UE transmits SRS even if overlaping in the same RB or not - if (srslte_refsignal_srs_send_cs(srs_cfg->subframe_config, tti%10) == 1 && - srslte_refsignal_srs_send_ue(srs_cfg->I_srs, tti) == 1) - { - q->shortened = true; - /* If RBs are contiguous, PUSCH is not shortened */ - uint32_t k0_srs = srslte_refsignal_srs_rb_start_cs(srs_cfg->bw_cfg, q->cell.nof_prb); - uint32_t nrb_srs = srslte_refsignal_srs_rb_L_cs(srs_cfg->bw_cfg, q->cell.nof_prb); - for (uint32_t ns=0;ns<2 && q->shortened;ns++) { - if (cfg->grant.n_prb_tilde[ns] == k0_srs + nrb_srs || // If PUSCH is contiguous on the right-hand side of SRS - cfg->grant.n_prb_tilde[ns] + cfg->grant.L_prb == k0_srs) // If SRS is contiguous on the left-hand side of PUSCH - { - q->shortened = false; - } - } - } - // If not coincides with UE transmission. PUSCH shall be shortened if cell-specific SRS transmission RB - //coincides with PUSCH allocated RB - if (!q->shortened) { - if (srslte_refsignal_srs_send_cs(srs_cfg->subframe_config, tti%10) == 1) { - uint32_t k0_srs = srslte_refsignal_srs_rb_start_cs(srs_cfg->bw_cfg, q->cell.nof_prb); - uint32_t nrb_srs = srslte_refsignal_srs_rb_L_cs(srs_cfg->bw_cfg, q->cell.nof_prb); - for (uint32_t ns=0;ns<2 && !q->shortened;ns++) { - if ((cfg->grant.n_prb_tilde[ns] >= k0_srs && cfg->grant.n_prb_tilde[ns] < k0_srs + nrb_srs) || - (cfg->grant.n_prb_tilde[ns] + cfg->grant.L_prb >= k0_srs && - cfg->grant.n_prb_tilde[ns] + cfg->grant.L_prb < k0_srs + nrb_srs) || - (cfg->grant.n_prb_tilde[ns] <= k0_srs && cfg->grant.n_prb_tilde[ns] + cfg->grant.L_prb >= k0_srs + nrb_srs)) - { - q->shortened = true; - } - } - } - } - } - } - - /* Compute final number of bits and RE */ - srslte_ra_ul_grant_to_nbits(&cfg->grant, q->cell.cp, q->shortened?1:0, &cfg->nbits); - - cfg->sf_idx = tti%10; - cfg->tti = tti; - cfg->rv = rv_idx; - cfg->cp = q->cell.cp; - - // Save UCI configuration - if (uci_cfg) { - memcpy(&cfg->uci_cfg, uci_cfg, sizeof(srslte_uci_cfg_t)); - } - - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR_INVALID_INPUTS; - } -} - /* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. * For the connection procedure, use srslte_pusch_encode() functions */ @@ -445,20 +262,20 @@ int srslte_pusch_set_rnti(srslte_pusch_t *q, uint16_t rnti) { } } q->users[rnti_idx]->sequence_generated = false; - for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { if (srslte_sequence_pusch(&q->users[rnti_idx]->seq[i], rnti, 2 * i, q->cell.id, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { - fprintf(stderr, "Error initializing PUSCH scrambling sequence\n"); + ERROR("Error initializing PUSCH scrambling sequence\n"); srslte_pusch_free_rnti(q, rnti); return SRSLTE_ERROR; } } - q->ue_rnti = rnti; + q->ue_rnti = rnti; q->users[rnti_idx]->cell_id = q->cell.id; q->users[rnti_idx]->sequence_generated = true; } else { - fprintf(stderr, "Error generating PUSCH sequence: rnti=0x%x already generated\n", rnti); + ERROR("Error generating PUSCH sequence: rnti=0x%x already generated\n", rnti); } return SRSLTE_SUCCESS; } @@ -468,7 +285,7 @@ void srslte_pusch_free_rnti(srslte_pusch_t *q, uint16_t rnti) { uint32_t rnti_idx = q->is_ue?0:rnti; if (q->users[rnti_idx]) { - for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { srslte_sequence_free(&q->users[rnti_idx]->seq[i]); } free(q->users[rnti_idx]); @@ -477,36 +294,32 @@ void srslte_pusch_free_rnti(srslte_pusch_t *q, uint16_t rnti) { } } -static srslte_sequence_t *get_user_sequence(srslte_pusch_t *q, uint16_t rnti, uint32_t sf_idx, uint32_t len) +static srslte_sequence_t* get_user_sequence(srslte_pusch_t* q, uint16_t rnti, uint32_t sf_idx, uint32_t len) { uint32_t rnti_idx = q->is_ue?0:rnti; - if (rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) { + if (SRSLTE_RNTI_ISUSER(rnti)) { // The scrambling sequence is pregenerated for all RNTIs in the eNodeB but only for C-RNTI in the UE - if (q->users[rnti_idx] && - q->users[rnti_idx]->sequence_generated && - q->users[rnti_idx]->cell_id == q->cell.id && - (!q->is_ue || q->ue_rnti == rnti)) - { + if (q->users[rnti_idx] && q->users[rnti_idx]->sequence_generated && q->users[rnti_idx]->cell_id == q->cell.id && + (!q->is_ue || q->ue_rnti == rnti)) { return &q->users[rnti_idx]->seq[sf_idx]; } else { if (srslte_sequence_pusch(&q->tmp_seq, rnti, 2 * sf_idx, q->cell.id, len)) { - fprintf(stderr, "Error generating temporal scrambling sequence\n"); + ERROR("Error generating temporal scrambling sequence\n"); return NULL; } return &q->tmp_seq; } } else { - fprintf(stderr, "Invalid RNTI=0x%x\n", rnti); + ERROR("Invalid RNTI=0x%x\n", rnti); return NULL; } } /** Converts the PUSCH data bits to symbols mapped to the slot ready for transmission */ -int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, srslte_uci_data_t uci_data, uint16_t rnti, - cf_t *sf_symbols) +int srslte_pusch_encode( + srslte_pusch_t* q, srslte_ul_sf_cfg_t* sf, srslte_pusch_cfg_t* cfg, srslte_pusch_data_t* data, cf_t* sf_symbols) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -514,160 +327,245 @@ int srslte_pusch_encode(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srslte_softb cfg != NULL) { - if (cfg->nbits.nof_re > q->max_re) { - fprintf(stderr, "Error too many RE per subframe (%d). PUSCH configured for %d RE (%d PRB)\n", - cfg->nbits.nof_re, q->max_re, q->cell.nof_prb); + /* Limit UL modulation if not supported by the UE or disabled by higher layers */ + if (!cfg->enable_64qam) { + if (cfg->grant.tb.mod >= SRSLTE_MOD_64QAM) { + cfg->grant.tb.mod = SRSLTE_MOD_16QAM; + cfg->grant.tb.nof_bits = cfg->grant.nof_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_16QAM); + } + } + + if (cfg->grant.nof_re > q->max_re) { + ERROR("Error too many RE per subframe (%d). PUSCH configured for %d RE (%d PRB)\n", + cfg->grant.nof_re, + q->max_re, + q->cell.nof_prb); return SRSLTE_ERROR_INVALID_INPUTS; } + if (!srslte_dft_precoding_valid_prb(cfg->grant.L_prb)) { + ERROR("Error encoding PUSCH: invalid L_prb=%d\n", cfg->grant.L_prb); + return -1; + } + + if (cfg->grant.tb.rv < 0 || cfg->grant.tb.rv > 3) { + ERROR("Error encoding PUSCH: invalid rv=%d\n", cfg->grant.tb.rv); + return -1; + } + + if (cfg->grant.tb.tbs < 0) { + ERROR("Error encoding PUSCH: invalid tbs=%d\n", cfg->grant.tb.tbs); + return -1; + } + INFO("Encoding PUSCH SF: %d, Mod %s, RNTI: %d, TBS: %d, NofRE: %d, NofSymbols=%d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), rnti, - cfg->grant.mcs.tbs, cfg->nbits.nof_re, cfg->nbits.nof_symb, cfg->nbits.nof_bits, cfg->rv); - - if (srslte_ulsch_uci_encode(&q->ul_sch, cfg, softbuffer, data, uci_data, q->g, q->q)) { - fprintf(stderr, "Error encoding TB\n"); + sf->tti % 10, + srslte_mod_string(cfg->grant.tb.mod), + cfg->rnti, + cfg->grant.tb.tbs, + cfg->grant.nof_re, + cfg->grant.nof_symb, + cfg->grant.tb.nof_bits, + cfg->grant.tb.rv); + + bzero(q->q, cfg->grant.tb.nof_bits); + if ((ret = srslte_ulsch_encode(&q->ul_sch, cfg, data->ptr, &data->uci, q->g, q->q)) < 0) { + ERROR("Error encoding TB\n"); return SRSLTE_ERROR; } - // Generate scrambling sequence if not pre-generated - srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); + uint32_t nof_ri_ack_bits = (uint32_t)ret; - // Run scrambling + // Generate scrambling sequence if not pre-generated + srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10, cfg->grant.tb.nof_bits); if (!seq) { - fprintf(stderr, "Error getting scrambling sequence\n"); - return SRSLTE_ERROR; + ERROR("Error getting user sequence for rnti=0x%x\n", cfg->rnti); + return -1; } - srslte_scrambling_bytes(seq, (uint8_t*) q->q, cfg->nbits.nof_bits); + + // Run scrambling + srslte_scrambling_bytes(seq, (uint8_t*)q->q, cfg->grant.tb.nof_bits); // Correct UCI placeholder/repetition bits - uint8_t *d = q->q; - for (int i = 0; i < q->ul_sch.nof_ri_ack_bits; i++) { + uint8_t* d = q->q; + for (int i = 0; i < nof_ri_ack_bits; i++) { if (q->ul_sch.ack_ri_bits[i].type == UCI_BIT_PLACEHOLDER) { d[q->ul_sch.ack_ri_bits[i].position/8] |= (1<<(7-q->ul_sch.ack_ri_bits[i].position%8)); } else if (q->ul_sch.ack_ri_bits[i].type == UCI_BIT_REPETITION) { if (q->ul_sch.ack_ri_bits[i].position > 1) { uint32_t p=q->ul_sch.ack_ri_bits[i].position; - uint8_t bit = d[(p-1)/8] & (1<<(7-(p-1)%8)); + uint8_t bit = d[(p - 1) / 8] & (1 << (7 - (p - 1) % 8)); if (bit) { - d[p/8] |= 1<<(7-p%8); + d[p / 8] |= 1 << (7 - p % 8); } else { d[p/8] &= ~(1<<(7-p%8)); } } } } - + // Bit mapping - srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->q, q->d, cfg->nbits.nof_bits); + srslte_mod_modulate_bytes(&q->mod[cfg->grant.tb.mod], (uint8_t*)q->q, q->d, cfg->grant.tb.nof_bits); // DFT precoding - srslte_dft_precoding(&q->dft_precoding, q->d, q->z, cfg->grant.L_prb, cfg->nbits.nof_symb); - + srslte_dft_precoding(&q->dft_precoding, q->d, q->z, cfg->grant.L_prb, cfg->grant.nof_symb); + // Mapping to resource elements - pusch_put(q, &cfg->grant, q->z, sf_symbols); - + uint32_t n = pusch_put(q, &cfg->grant, q->z, sf_symbols, sf->shortened); + if (n != cfg->grant.nof_re) { + ERROR("Error trying to allocate %d symbols but %d were allocated (tti=%d, short=%d, L=%d)\n", + cfg->grant.nof_re, + n, + sf->tti, + sf->shortened, + cfg->grant.L_prb); + return SRSLTE_ERROR; + } + ret = SRSLTE_SUCCESS; } return ret; } - /** Decodes the PUSCH from the received symbols */ -int srslte_pusch_decode(srslte_pusch_t *q, - srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - cf_t *sf_symbols, - cf_t *ce, float noise_estimate, uint16_t rnti, - uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data) +int srslte_pusch_decode(srslte_pusch_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_cfg_t* cfg, + srslte_chest_ul_res_t* channel, + cf_t* sf_symbols, + srslte_pusch_res_t* out) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; + int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t n; - - if (q != NULL && - sf_symbols != NULL && - data != NULL && - cfg != NULL) - { - + + if (q != NULL && sf_symbols != NULL && out != NULL && cfg != NULL) { + + struct timeval t[3]; + if (cfg->meas_time_en) { + gettimeofday(&t[1], NULL); + } + + /* Limit UL modulation if not supported by the UE or disabled by higher layers */ + if (!cfg->enable_64qam) { + if (cfg->grant.tb.mod >= SRSLTE_MOD_64QAM) { + cfg->grant.tb.mod = SRSLTE_MOD_16QAM; + cfg->grant.tb.nof_bits = cfg->grant.nof_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_16QAM); + } + } + INFO("Decoding PUSCH SF: %d, Mod %s, NofBits: %d, NofRE: %d, NofSymbols=%d, NofBitsE: %d, rv_idx: %d\n", - cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, - cfg->nbits.nof_re, cfg->nbits.nof_symb, cfg->nbits.nof_bits, cfg->rv); + sf->tti % 10, + srslte_mod_string(cfg->grant.tb.mod), + cfg->grant.tb.tbs, + cfg->grant.nof_re, + cfg->grant.nof_symb, + cfg->grant.tb.nof_bits, + cfg->grant.tb.rv); /* extract symbols */ - n = pusch_get(q, &cfg->grant, sf_symbols, q->d); - if (n != cfg->nbits.nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); + n = pusch_get(q, &cfg->grant, sf_symbols, q->d, sf->shortened); + if (n != cfg->grant.nof_re) { + ERROR("Error expecting %d symbols but got %d\n", cfg->grant.nof_re, n); return SRSLTE_ERROR; } - + /* extract channel estimates */ - n = pusch_get(q, &cfg->grant, ce, q->ce); - if (n != cfg->nbits.nof_re) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); + n = pusch_get(q, &cfg->grant, channel->ce, q->ce, sf->shortened); + if (n != cfg->grant.nof_re) { + ERROR("Error expecting %d symbols but got %d\n", cfg->grant.nof_re, n); return SRSLTE_ERROR; } // Equalization - srslte_predecoding_single(q->d, q->ce, q->z, NULL, cfg->nbits.nof_re, 1.0f, noise_estimate); - + srslte_predecoding_single(q->d, q->ce, q->z, NULL, cfg->grant.nof_re, 1.0f, channel->noise_estimate); + // DFT predecoding - srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); - + srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->grant.nof_symb); + // Soft demodulation if (q->llr_is_8bit) { - srslte_demod_soft_demodulate_b(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); + srslte_demod_soft_demodulate_b(cfg->grant.tb.mod, q->d, q->q, cfg->grant.nof_re); } else { - srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re); + srslte_demod_soft_demodulate_s(cfg->grant.tb.mod, q->d, q->q, cfg->grant.nof_re); } // Generate scrambling sequence if not pre-generated - srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); - - // Set CQI len assuming RI = 1 (3GPP 36.212 Clause 5.2.4.1. Uplink control information on PUSCH without UL-SCH data) - if (cqi_value) { - if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL && cqi_value->subband_hl.ri_present) { - cqi_value->subband_hl.rank_is_not_one = false; - uci_data->uci_ri_len = (q->cell.nof_ports == 4) ? 2 : 1; - } - uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); - } - - // Decode RI/HARQ bits before descrambling - if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { - fprintf(stderr, "Error decoding RI/HARQ bits\n"); - return SRSLTE_ERROR; + srslte_sequence_t* seq = get_user_sequence(q, cfg->rnti, sf->tti % 10, cfg->grant.tb.nof_bits); + if (!seq) { + ERROR("Error getting user sequence for rnti=0x%x\n", cfg->rnti); + return -1; } - // Set CQI len with corresponding RI - if (cqi_value) { - if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) { - cqi_value->subband_hl.rank_is_not_one = (uci_data->uci_ri != 0); - } - uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value); - } - // Descrambling if (q->llr_is_8bit) { - srslte_scrambling_sb_offset(seq, q->q, 0, cfg->nbits.nof_bits); + srslte_scrambling_sb_offset(seq, q->q, 0, cfg->grant.tb.nof_bits); } else { - srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); + srslte_scrambling_s_offset(seq, q->q, 0, cfg->grant.tb.nof_bits); } // Decode - ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data); + ret = srslte_ulsch_decode(&q->ul_sch, cfg, q->q, q->g, seq->c, out->data, &out->uci); + out->crc = (ret == 0); - // Unpack CQI value if available - if (cqi_value) { - srslte_cqi_value_unpack(uci_data->uci_cqi, cqi_value); + // Accept ACK only if SNR is above threshold + out->uci.ack.valid = channel->snr_db > ACK_SNR_TH; + out->avg_iterations_block = q->ul_sch.avg_iterations; + + // Save O_cqi for power control + cfg->last_O_cqi = srslte_cqi_size(&cfg->uci_cfg.cqi); + ret = SRSLTE_SUCCESS; + + if (cfg->meas_time_en) { + gettimeofday(&t[2], NULL); + get_time_interval(t); + cfg->meas_time_value = t[0].tv_usec; } } return ret; } -uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) { - return q->ul_sch.nof_iterations; +uint32_t srslte_pusch_grant_tx_info( + srslte_pusch_grant_t* grant, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len) +{ + + uint32_t len = srslte_ra_ul_info(grant, str, str_len); + + if (uci_data) { + len += srslte_uci_data_info(uci_cfg, uci_data, &str[len], str_len - len); + } + + return len; +} + +uint32_t srslte_pusch_tx_info(srslte_pusch_cfg_t* cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len) +{ + + uint32_t len = srslte_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti); + + len += srslte_pusch_grant_tx_info(&cfg->grant, &cfg->uci_cfg, uci_data, &str[len], str_len - len); + + if (cfg->meas_time_en) { + len = srslte_print_check(str, str_len, len, ", t=%d us", cfg->meas_time_value); + } + return len; } +uint32_t srslte_pusch_rx_info(srslte_pusch_cfg_t* cfg, srslte_pusch_res_t* res, char* str, uint32_t str_len) +{ - + uint32_t len = srslte_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti); + + len += srslte_ra_ul_info(&cfg->grant, &str[len], str_len); + + len = srslte_print_check( + str, str_len, len, ", crc=%s, avg_iter=%.1f", res->crc ? "OK" : "KO", res->avg_iterations_block); + + len += srslte_uci_data_info(&cfg->uci_cfg, &res->uci, &str[len], str_len - len); + + if (cfg->meas_time_en) { + len = srslte_print_check(str, str_len, len, ", t=%d us", cfg->meas_time_value); + } + return len; +} diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 6eb2c8f5a..e0a228c37 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -24,582 +24,43 @@ * */ -#include -#include -#include -#include +#include "srslte/phy/phch/ra.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/utils/bit.h" -#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/debug.h" -#include "srslte/phy/phch/ra.h" -#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" +#include +#include +#include +#include +#include #include "tbs_tables.h" #define min(a,b) (a= nof_prb / 2 - 3 && prb_idx < nof_prb / 2 + 3 + (nof_prb%2))) { - if (subframe == 0) { - if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE; - } else { - if (SRSLTE_CP_ISEXT(cp_)) { - re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE; - skip_refs = false; - } else { - re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE + 2 * nof_ports; - } - } - } else if (subframe == 5) { - if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE; - } - } - if ((nof_prb % 2) - && (prb_idx == nof_prb / 2 - 3 || prb_idx == nof_prb / 2 + 3)) { - if (slot == 0) { - re += 2 * SRSLTE_NRE / 2; - } else if (subframe == 0) { - re += 4 * SRSLTE_NRE / 2 - nof_ports; - if (SRSLTE_CP_ISEXT(cp_)) { - re -= nof_ports > 2 ? 2 : nof_ports; - } - } - } - } - - // remove references - if (skip_refs) { - if(sf_type == SRSLTE_SF_NORM){ - switch (nof_ports) { - case 1: - case 2: - re -= 2 * (slot + 1) * nof_ports; - break; - case 4: - if (slot == 1) { - re -= 12; - } else { - re -= 4; - if (nof_ctrl_symbols == 1) { - re -= 4; - } - } - break; - } - } - if(sf_type == SRSLTE_SF_MBSFN){ - re -= 6*(slot + 1); - } - } - return re; -} - -int srslte_ra_ul_dci_to_grant_prb_allocation(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant, uint32_t n_rb_ho, uint32_t nof_prb) -{ - bzero(grant, sizeof(srslte_ra_ul_grant_t)); - - grant->ncs_dmrs = dci->n_dmrs; - grant->L_prb = dci->type2_alloc.L_crb; - uint32_t n_prb_1 = dci->type2_alloc.RB_start; - uint32_t n_rb_pusch = 0; - - if (n_rb_ho%2) { - n_rb_ho++; - } - - if (dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED || dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_TYPE2) { - /* For no freq hopping or type2 freq hopping, n_prb is the same - * n_prb_tilde is calculated during resource mapping - */ - for (uint32_t i=0;i<2;i++) { - grant->n_prb[i] = n_prb_1; - } - if (dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED) { - grant->freq_hopping = 0; - } else { - grant->freq_hopping = 2; - } - INFO("prb1: %d, prb2: %d, L: %d\n", grant->n_prb[0], grant->n_prb[1], grant->L_prb); - } else { - /* Type1 frequency hopping as defined in 8.4.1 of 36.213 - * frequency offset between 1st and 2nd slot is fixed. - */ - n_rb_pusch = nof_prb - n_rb_ho - (nof_prb%2); - - // starting prb idx for slot 0 is as given by resource grant - grant->n_prb[0] = n_prb_1; - if (n_prb_1 < n_rb_ho/2) { - INFO("Invalid Frequency Hopping parameters. Offset: %d, n_prb_1: %d\n", n_rb_ho, n_prb_1); - return SRSLTE_ERROR; - } - uint32_t n_prb_1_tilde = n_prb_1; - - // prb idx for slot 1 - switch(dci->freq_hop_fl) { - case SRSLTE_RA_PUSCH_HOP_QUART: - grant->n_prb[1] = (n_rb_pusch/4+ n_prb_1_tilde)%n_rb_pusch; - break; - case SRSLTE_RA_PUSCH_HOP_QUART_NEG: - if (n_prb_1 < n_rb_pusch/4) { - grant->n_prb[1] = (n_rb_pusch+ n_prb_1_tilde -n_rb_pusch/4); - } else { - grant->n_prb[1] = (n_prb_1_tilde -n_rb_pusch/4); - } - break; - case SRSLTE_RA_PUSCH_HOP_HALF: - grant->n_prb[1] = (n_rb_pusch/2+ n_prb_1_tilde)%n_rb_pusch; - break; - default: - break; - } - INFO("n_rb_pusch: %d, prb1: %d, prb2: %d, L: %d\n", n_rb_pusch, grant->n_prb[0], grant->n_prb[1], grant->L_prb); - grant->freq_hopping = 1; - } - - if (grant->n_prb[0] + grant->L_prb <= nof_prb && - grant->n_prb[1] + grant->L_prb <= nof_prb) - { - return SRSLTE_SUCCESS; - } else { - return SRSLTE_ERROR; - } -} - -static void ul_dci_to_grant_mcs(srslte_ra_ul_dci_t *dci, srslte_ra_ul_grant_t *grant) { - // 8.6.2 First paragraph - if (dci->mcs_idx <= 28) { - grant->mcs.mod = srslte_ra_ul_mod_from_mcs(dci->mcs_idx); - grant->mcs.tbs = srslte_ra_tbs_from_idx(srslte_ra_ul_tbs_idx_from_mcs(dci->mcs_idx), grant->L_prb); - if (grant->mcs.mod >= SRSLTE_MOD_LAST || grant->mcs.tbs < 0) { - fprintf(stderr, "Invalid MCS index %d\n", dci->mcs_idx); - } - } else if (dci->mcs_idx == 29 && dci->cqi_request && grant->L_prb <= 4) { - // 8.6.1 and 8.6.2 36.213 second paragraph - grant->mcs.mod = SRSLTE_MOD_QPSK; - grant->mcs.tbs = 0; - dci->rv_idx = 1; - } else if (dci->mcs_idx >= 29) { - // Else use last TBS/Modulation and use mcs to obtain rv_idx - grant->mcs.tbs = -1; - grant->mcs.mod = SRSLTE_MOD_LAST; - dci->rv_idx = dci->mcs_idx - 28; - DEBUG("mcs_idx=%d, tbs=%d, mod=%d, rv=%d\n", - dci->mcs_idx, grant->mcs.tbs/8, grant->mcs.mod, dci->rv_idx); - } -} - -void srslte_ra_ul_grant_to_nbits(srslte_ra_ul_grant_t *grant, srslte_cp_t cp, uint32_t N_srs, srslte_ra_nbits_t *nbits) -{ - nbits->nof_symb = 2*(SRSLTE_CP_NSYMB(cp)-1) - N_srs; - nbits->nof_re = nbits->nof_symb*grant->M_sc; - nbits->nof_bits = nbits->nof_re * grant->Qm; -} - -/** Compute PRB allocation for Uplink as defined in 8.1 and 8.4 of 36.213 */ -int srslte_ra_ul_dci_to_grant(srslte_ra_ul_dci_t *dci, uint32_t nof_prb, uint32_t n_rb_ho, srslte_ra_ul_grant_t *grant) -{ - - // Compute PRB allocation - if (!srslte_ra_ul_dci_to_grant_prb_allocation(dci, grant, n_rb_ho, nof_prb)) { - - // Compute MCS - ul_dci_to_grant_mcs(dci, grant); - - // Fill rest of grant structure - grant->mcs.idx = dci->mcs_idx; - grant->M_sc = grant->L_prb*SRSLTE_NRE; - grant->M_sc_init = grant->M_sc; // FIXME: What should M_sc_init be? - grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); - - } else { - return SRSLTE_ERROR; - } - return SRSLTE_SUCCESS; -} - -uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols) -{ - uint32_t nof_refs = 0; - uint32_t nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nof_ctrl_symbols; - switch(cell.nof_ports) { - case 1: - nof_refs = 2*3; - break; - case 2: - nof_refs = 4*3; - break; - case 4: - nof_refs = 4*4; - break; - } - return nof_prb * (nof_symb*SRSLTE_NRE-nof_refs); -} - -/* Computes the number of RE for each PRB in the prb_dist structure */ -uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, - uint32_t sf_idx, uint32_t nof_ctrl_symbols) +/* Convert Type2 scheduling L_crb and RB_start to RIV value */ +uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { - uint32_t j, s; - // Compute number of RE per PRB - uint32_t nof_re = 0; - for (s = 0; s < 2; s++) { - for (j = 0; j < cell.nof_prb; j++) { - if (grant->prb_idx[s][j]) { - nof_re += ra_re_x_prb(sf_idx, s, j, cell.nof_prb, cell.nof_ports, - nof_ctrl_symbols, cell.cp, grant->sf_type); - } - } - } - return nof_re; -} - - -/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 - * Decode dci->type?_alloc to grant - * This function only reads dci->type?_alloc and dci->alloc_type fields. - * This function only writes grant->prb_idx and grant->nof_prb. - */ -/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ -int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *grant, uint32_t nof_prb) { - int i, j; - uint32_t bitmask; - uint32_t P = srslte_ra_type0_P(nof_prb); - uint32_t n_rb_rbg_subset, n_rb_type1; - - bzero(grant, sizeof(srslte_ra_dl_grant_t)); - switch (dci->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - bitmask = dci->type0_alloc.rbg_bitmask; - int nb = (int) ceilf((float) nof_prb / P); - for (i = 0; i < nb; i++) { - if (bitmask & (1 << (nb - i - 1))) { - for (j = 0; j < P; j++) { - if (i*P+j < nof_prb) { - grant->prb_idx[0][i * P + j] = true; - grant->nof_prb++; - } - } - } - } - memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB*sizeof(bool)); - break; - case SRSLTE_RA_ALLOC_TYPE1: - // Make sure the rbg_subset is valid - if (dci->type1_alloc.rbg_subset >= P) { - return SRSLTE_ERROR; - } - n_rb_type1 = srslte_ra_type1_N_rb(nof_prb); - uint32_t temp = ((nof_prb - 1) / P) % P; - if (dci->type1_alloc.rbg_subset < temp) { - n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P + P; - } else if (dci->type1_alloc.rbg_subset == temp) { - n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P + ((nof_prb - 1) % P) + 1; - } else { - n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P; - } - int shift = dci->type1_alloc.shift ? (n_rb_rbg_subset - n_rb_type1) : 0; - bitmask = dci->type1_alloc.vrb_bitmask; - for (i = 0; i < n_rb_type1; i++) { - if (bitmask & (1 << (n_rb_type1 - i - 1))) { - uint32_t idx = (((i + shift) / P) * P * P + dci->type1_alloc.rbg_subset * P + (i + shift) % P); - if (idx < nof_prb) { - grant->prb_idx[0][idx] = true; - grant->nof_prb++; - } else { - return SRSLTE_ERROR; - } - } - } - memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB*sizeof(bool)); - break; - case SRSLTE_RA_ALLOC_TYPE2: - if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - for (i = 0; i < dci->type2_alloc.L_crb; i++) { - grant->prb_idx[0][i + dci->type2_alloc.RB_start] = true; - grant->nof_prb++; - } - memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB*sizeof(bool)); - } else { - /* Mapping of Virtual to Physical RB for distributed type is defined in - * 6.2.3.2 of 36.211 - */ - int N_gap, N_tilde_vrb, n_tilde_vrb, n_tilde_prb, n_tilde2_prb, N_null, - N_row, n_vrb; - int n_tilde_prb_odd, n_tilde_prb_even; - if (dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1) { - N_tilde_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, true); - N_gap = srslte_ra_type2_ngap(nof_prb, true); - } else { - N_tilde_vrb = 2 * srslte_ra_type2_n_vrb_dl(nof_prb, true); - N_gap = srslte_ra_type2_ngap(nof_prb, false); - } - N_row = (int) ceilf((float) N_tilde_vrb / (4 * P)) * P; - N_null = 4 * N_row - N_tilde_vrb; - for (i = 0; i < dci->type2_alloc.L_crb; i++) { - n_vrb = i + dci->type2_alloc.RB_start; - n_tilde_vrb = n_vrb % N_tilde_vrb; - n_tilde_prb = 2 * N_row * (n_tilde_vrb % 2) + n_tilde_vrb / 2 - + N_tilde_vrb * (n_vrb / N_tilde_vrb); - n_tilde2_prb = N_row * (n_tilde_vrb % 4) + n_tilde_vrb / 4 - + N_tilde_vrb * (n_vrb / N_tilde_vrb); - - if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) - && (n_tilde_vrb % 2) == 1) { - n_tilde_prb_odd = n_tilde_prb - N_row; - } else if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) - && (n_tilde_vrb % 2) == 0) { - n_tilde_prb_odd = n_tilde_prb - N_row + N_null / 2; - } else if (N_null != 0 && n_tilde_vrb < (N_tilde_vrb - N_null) - && (n_tilde_vrb % 4) >= 2) { - n_tilde_prb_odd = n_tilde2_prb - N_null / 2; - } else { - n_tilde_prb_odd = n_tilde2_prb; - } - n_tilde_prb_even = (n_tilde_prb_odd + N_tilde_vrb / 2) % N_tilde_vrb - + N_tilde_vrb * (n_vrb / N_tilde_vrb); - - if (n_tilde_prb_odd < N_tilde_vrb / 2) { - if (n_tilde_prb_odd < nof_prb) { - grant->prb_idx[0][n_tilde_prb_odd] = true; - } else { - return SRSLTE_ERROR; - } - } else { - if (n_tilde_prb_odd + N_gap - N_tilde_vrb / 2 < nof_prb) { - grant->prb_idx[0][n_tilde_prb_odd + N_gap - N_tilde_vrb / 2] = true; - } else { - return SRSLTE_ERROR; - } - } - grant->nof_prb++; - if (n_tilde_prb_even < N_tilde_vrb / 2) { - if(n_tilde_prb_even < nof_prb) { - grant->prb_idx[1][n_tilde_prb_even] = true; - } else { - return SRSLTE_ERROR; - } - } else { - if (n_tilde_prb_even + N_gap - N_tilde_vrb / 2 < nof_prb) { - grant->prb_idx[1][n_tilde_prb_even + N_gap - N_tilde_vrb / 2] = true; - } else { - return SRSLTE_ERROR; - } - } - } - } - break; - default: - return SRSLTE_ERROR; - } - - return SRSLTE_SUCCESS; -} - -int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { - int i_tbs = 0; - if (mcs->idx < 10) { - mcs->mod = SRSLTE_MOD_QPSK; - i_tbs = mcs->idx; - } else if (mcs->idx < 17) { - mcs->mod = SRSLTE_MOD_16QAM; - i_tbs = mcs->idx-1; - } else if (mcs->idx < 29) { - mcs->mod = SRSLTE_MOD_64QAM; - i_tbs = mcs->idx-2; - } else if (mcs->idx == 29) { - mcs->mod = SRSLTE_MOD_QPSK; - i_tbs = -1; - } else if (mcs->idx == 30) { - mcs->mod = SRSLTE_MOD_16QAM; - i_tbs = -1; - } else if (mcs->idx == 31) { - mcs->mod = SRSLTE_MOD_64QAM; - i_tbs = -1; - } - - int tbs = -1; - if (i_tbs >= 0) { - tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); - mcs->tbs = tbs; - } - return tbs; -} - -int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { - uint32_t i_tbs = 0; - int tbs = -1; - if (mcs->idx < 5) { - mcs->mod = SRSLTE_MOD_QPSK; - i_tbs = mcs->idx*2; - }else if (mcs->idx < 6) { - mcs->mod = SRSLTE_MOD_16QAM; - i_tbs = mcs->idx*2; - }else if (mcs->idx < 11) { - mcs->mod = SRSLTE_MOD_16QAM; - i_tbs = mcs->idx + 5; - }else if (mcs->idx < 20) { - mcs->mod = SRSLTE_MOD_64QAM; - i_tbs = mcs->idx + 5; - }else if (mcs->idx < 28) { - //mcs->mod = SRSLTE_MOD_256QAM; - i_tbs = mcs->idx + 5; - }else if (mcs->idx == 28) { - mcs->mod = SRSLTE_MOD_QPSK; - tbs = 0; - i_tbs = 0; - }else if (mcs->idx == 29) { - mcs->mod = SRSLTE_MOD_16QAM; - tbs = 0; - i_tbs = 0; - }else if (mcs->idx == 30) { - mcs->mod = SRSLTE_MOD_64QAM; - tbs = 0; - i_tbs = 0; - }else if (mcs->idx == 31) { - mcs->mod = SRSLTE_MOD_64QAM; - tbs = 0; - i_tbs = 0; - } - - - if (tbs == -1) { - tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); - if (tbs >= 0) { - mcs->tbs = tbs; - } - } - return tbs; -} - -/* Modulation order and transport block size determination 7.1.7 in 36.213 - * This looks at DCI type, type of RNTI and reads fields dci->type?_alloc, dci->mcs_idx, - * dci->dci_is_1a and dci->dci_is_1c - * Reads global variable last_dl_tbs if mcs>=29 - * Writes global variable last_dl_tbs if mcs<29 - * */ -static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *grant, bool crc_is_crnti) { - uint32_t n_prb=0; - int tbs = -1; - uint32_t i_tbs = 0; - - if (!crc_is_crnti) { - if (dci->dci_is_1a) { - n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3; - i_tbs = dci->mcs_idx; - tbs = srslte_ra_tbs_from_idx(i_tbs, n_prb); - } else if (dci->dci_is_1c) { - if (dci->mcs_idx < 32) { - tbs = tbs_format1c_table[dci->mcs_idx]; - } else { - fprintf(stderr, "Error decoding DCI: Invalid mcs_idx=%d in Format1C\n", dci->mcs_idx); - } - } else { - fprintf(stderr, "Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n"); - return SRSLTE_ERROR; - } - grant->mcs[0].mod = SRSLTE_MOD_QPSK; - grant->mcs[0].tbs = (uint32_t) tbs; - grant->mcs[0].idx = dci->mcs_idx; + uint32_t riv; + if ((L_crb - 1) <= nof_prb / 2) { + riv = nof_prb * (L_crb - 1) + RB_start; } else { - n_prb = grant->nof_prb; - if (dci->tb_en[0]) { - grant->mcs[0].idx = dci->mcs_idx; - grant->mcs[0].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); - } else { - grant->mcs[0].tbs = 0; - } - if (dci->tb_en[1]) { - grant->mcs[1].idx = dci->mcs_idx_1; - grant->mcs[1].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[1], n_prb); - } else { - grant->mcs[1].tbs = 0; - } - } - for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - grant->tb_en[tb] = dci->tb_en[tb]; - if (dci->tb_en[tb]) { - grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod); - } - } - grant->pinfo = dci->pinfo; - grant->tb_cw_swap = dci->tb_cw_swap; - - if (grant->mcs[0].tbs < 0 || grant->mcs[1].tbs < 0) { - return SRSLTE_ERROR; - } else { - return SRSLTE_SUCCESS; - } -} - -void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, - srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]) -{ - // Compute number of RE - for (int i = 0; i < SRSLTE_MAX_TB; i++) { - /* Compute number of RE for first transport block */ - nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); - nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; - if (SRSLTE_SF_NORM == grant->sf_type) { - nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; - } else if (SRSLTE_SF_MBSFN == grant->sf_type) { - nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart; - } - if (grant->tb_en[i]) { - nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; - } + riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start; } + return riv; } -/** Obtains a DL grant from a DCI grant for PDSCH */ -int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, - uint32_t nof_prb, uint16_t msg_rnti, srslte_ra_dl_grant_t *grant) +/* Convert Type2 scheduling RIV value to L_crb and RB_start values */ +void srslte_ra_type2_from_riv(uint32_t riv, uint32_t* L_crb, uint32_t* RB_start, uint32_t nof_prb, uint32_t nof_vrb) { - grant->sf_type = SRSLTE_SF_NORM; - bool crc_is_crnti = false; - if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { - crc_is_crnti = true; - } - // Compute PRB allocation - int ret =srslte_ra_dl_dci_to_grant_prb_allocation(dci, grant, nof_prb); - if (!ret) { - // Compute MCS - ret = dl_dci_to_grant_mcs(dci, grant, crc_is_crnti); - if (ret == SRSLTE_SUCCESS) { - // Apply Section 7.1.7.3. If RA-RNTI and Format1C rv_idx=0 - if (dci->dci_is_1c) { - if ((msg_rnti >= SRSLTE_RARNTI_START && msg_rnti <= SRSLTE_RARNTI_END) || msg_rnti == SRSLTE_PRNTI) - { - dci->rv_idx = 0; - } - } - } else { - return SRSLTE_ERROR; - } - } else { - return SRSLTE_ERROR; + *L_crb = (uint32_t)(riv / nof_prb) + 1; + *RB_start = (uint32_t)(riv % nof_prb); + if (*L_crb > nof_vrb - *RB_start) { + *L_crb = nof_prb - (int)(riv / nof_prb) + 1; + *RB_start = nof_prb - riv % nof_prb - 1; } - return SRSLTE_SUCCESS; } /* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */ @@ -621,28 +82,6 @@ uint32_t srslte_ra_type1_N_rb(uint32_t nof_prb) { return (uint32_t) ceilf((float) nof_prb / P) - (uint32_t) ceilf(log2f((float) P)) - 1; } -/* Convert Type2 scheduling L_crb and RB_start to RIV value */ -uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { - uint32_t riv; - if ((L_crb - 1) <= nof_prb / 2) { - riv = nof_prb * (L_crb - 1) + RB_start; - } else { - riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start; - } - return riv; -} - -/* Convert Type2 scheduling RIV value to L_crb and RB_start values */ -void srslte_ra_type2_from_riv(uint32_t riv, uint32_t *L_crb, uint32_t *RB_start, - uint32_t nof_prb, uint32_t nof_vrb) { - *L_crb = (uint32_t) (riv / nof_prb) + 1; - *RB_start = (uint32_t) (riv % nof_prb); - if (*L_crb > nof_vrb - *RB_start) { - *L_crb = nof_prb - (int) (riv / nof_prb) + 1; - *RB_start = nof_prb - riv % nof_prb - 1; - } -} - /* Table 6.2.3.2-1 in 36.211 */ uint32_t srslte_ra_type2_ngap(uint32_t nof_prb, bool ngap_is_1) { if (nof_prb <= 10) { @@ -686,16 +125,16 @@ uint32_t srslte_ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1) { } /* Modulation and TBS index table for PDSCH from 3GPP TS 36.213 v10.3.0 table 7.1.7.1-1 */ -int srslte_ra_dl_tbs_idx_from_mcs(uint32_t mcs) +static int srslte_ra_dl_tbs_idx_from_mcs(uint32_t mcs) { - if(mcs < 29) { + if (mcs < 29) { return dl_mcs_tbs_idx_table[mcs]; } else { return SRSLTE_ERROR; } } -int srslte_ra_ul_tbs_idx_from_mcs(uint32_t mcs) +static int srslte_ra_ul_tbs_idx_from_mcs(uint32_t mcs) { if (mcs < 29) { return ul_mcs_tbs_idx_table[mcs]; @@ -704,6 +143,11 @@ int srslte_ra_ul_tbs_idx_from_mcs(uint32_t mcs) } } +int srslte_ra_tbs_idx_from_mcs(uint32_t mcs, bool is_ul) +{ + return (is_ul) ? srslte_ra_ul_tbs_idx_from_mcs(mcs) : srslte_ra_dl_tbs_idx_from_mcs(mcs); +} + srslte_mod_t srslte_ra_dl_mod_from_mcs(uint32_t mcs) { if (mcs <= 10 || mcs == 29) { @@ -725,11 +169,11 @@ srslte_mod_t srslte_ra_ul_mod_from_mcs(uint32_t mcs) } else if (mcs <= 28) { return SRSLTE_MOD_64QAM; } else { - return SRSLTE_MOD_LAST; + return SRSLTE_MOD_BPSK; } } -int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx) +static int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx) { for (int i = 0; i < 29; i++) { if (tbs_idx == dl_mcs_tbs_idx_table[i]) { @@ -739,7 +183,7 @@ int srslte_ra_dl_mcs_from_tbs_idx(uint32_t tbs_idx) return SRSLTE_ERROR; } -int srslte_ra_ul_mcs_from_tbs_idx(uint32_t tbs_idx) +static int srslte_ra_ul_mcs_from_tbs_idx(uint32_t tbs_idx) { for (int i = 0; i < 29; i++) { if (tbs_idx == ul_mcs_tbs_idx_table[i]) { @@ -749,8 +193,14 @@ int srslte_ra_ul_mcs_from_tbs_idx(uint32_t tbs_idx) return SRSLTE_ERROR; } +int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx, bool is_ul) +{ + return is_ul ? srslte_ra_ul_mcs_from_tbs_idx(tbs_idx) : srslte_ra_dl_mcs_from_tbs_idx(tbs_idx); +} + /* Table 7.1.7.2.1-1: Transport block size table on 36.213 */ -int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { +int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) +{ if (tbs_idx < 27 && n_prb > 0 && n_prb <= SRSLTE_MAX_PRB) { return tbs_table[tbs_idx][n_prb - 1]; } else { @@ -764,7 +214,7 @@ int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) { uint32_t idx; if (n_prb > 0 && n_prb <= SRSLTE_MAX_PRB) { - + if (tbs <= tbs_table[0][n_prb-1]) { return 0; } @@ -779,129 +229,3 @@ int srslte_ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) { } return SRSLTE_ERROR; } - -void srslte_ra_pusch_fprint(FILE *f, srslte_ra_ul_dci_t *dci, uint32_t nof_prb) { - fprintf(f, " - Resource Allocation Type 2 mode :\t%s\n", - dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC ? "Localized" : "Distributed"); - - fprintf(f, " + Frequency Hopping:\t\t\t"); - if (dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED) { - fprintf(f, "No\n"); - } else { - fprintf(f, "Yes\n"); - } - fprintf(f, " + Resource Indicator Value:\t\t%d\n", dci->type2_alloc.riv); - if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", - dci->type2_alloc.L_crb, dci->type2_alloc.RB_start); - } else { - fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", - dci->type2_alloc.L_crb, dci->type2_alloc.RB_start); - fprintf(f, " + VRB gap selection:\t\t\tGap %d\n", - dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1 ? 1 : 2); - fprintf(f, " + VRB gap:\t\t\t\t%d\n", - srslte_ra_type2_ngap(nof_prb, dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1)); - - } - - fprintf(f, " - Modulation and coding scheme index:\t%d\n", dci->mcs_idx); - fprintf(f, " - New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No"); - fprintf(f, " - Redundancy version:\t\t\t%d\n", dci->rv_idx); - fprintf(f, " - TPC command for PUCCH:\t\t--\n"); -} - -void srslte_ra_ul_grant_fprint(FILE *f, srslte_ra_ul_grant_t *grant) { - fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->L_prb); - fprintf(f, " - Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs.mod)); - fprintf(f, " - Transport block size:\t\t%d\n", grant->mcs.tbs); -} - -char *ra_type_string(srslte_ra_type_t alloc_type) { - switch (alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - return "Type 0"; - case SRSLTE_RA_ALLOC_TYPE1: - return "Type 1"; - case SRSLTE_RA_ALLOC_TYPE2: - return "Type 2"; - default: - return "N/A"; - } -} - -void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb) { - fprintf(f, " - Resource Allocation Type:\t\t%s\n", - ra_type_string(dci->alloc_type)); - switch (dci->alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - fprintf(f, " + Resource Block Group Size:\t\t%d\n", srslte_ra_type0_P(nof_prb)); - fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", dci->type0_alloc.rbg_bitmask); - break; - case SRSLTE_RA_ALLOC_TYPE1: - fprintf(f, " + Resource Block Group Size:\t\t%d\n", srslte_ra_type0_P(nof_prb)); - fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", dci->type1_alloc.vrb_bitmask); - fprintf(f, " + RBG Subset:\t\t\t%d\n", dci->type1_alloc.rbg_subset); - fprintf(f, " + RBG Shift:\t\t\t\t%s\n", - dci->type1_alloc.shift ? "Yes" : "No"); - break; - case SRSLTE_RA_ALLOC_TYPE2: - fprintf(f, " + Type:\t\t\t\t%s\n", - dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC ? "Localized" : "Distributed"); - fprintf(f, " + Resource Indicator Value:\t\t%d\n", dci->type2_alloc.riv); - if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { - fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", - dci->type2_alloc.L_crb, dci->type2_alloc.RB_start); - } else { - fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", - dci->type2_alloc.L_crb, dci->type2_alloc.RB_start); - fprintf(f, " + VRB gap selection:\t\t\tGap %d\n", - dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1 ? 1 : 2); - fprintf(f, " + VRB gap:\t\t\t\t%d\n", - srslte_ra_type2_ngap(nof_prb, dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1)); - } - break; - } - fprintf(f, " - HARQ process:\t\t\t%d\n", dci->harq_process); - fprintf(f, " - TPC command for PUCCH:\t\t--\n"); - fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap)?"true":"false"); - fprintf(f, " - Transport block 1 enabled:\t\t%s\n", (dci->tb_en[0])?"true":"false"); - if (dci->tb_en[0]) { - fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx); - fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No"); - fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx); - } - fprintf(f, " - Transport block 2 enabled:\t\t%s\n", (dci->tb_en[1])?"true":"false"); - if (dci->tb_en[1]) { - fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx_1); - fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi_1 ? "Yes" : "No"); - fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx_1); - } -} - -void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { - srslte_ra_prb_fprint(f, grant); - fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); - fprintf(f, " - Number of TBs:\t\t\t%d\n", SRSLTE_RA_DL_GRANT_NOF_TB(grant)); - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (grant->tb_en[i]) { - fprintf(f, " - Transport block:\t\t\t%d\n", i); - fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod)); - fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs); - } - } -} - -void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { - if (grant->nof_prb > 0) { - for (int j=0;j<2;j++) { - fprintf(f, " - PRB Bitmap Assignment %dst slot:\n", j); - for (int i=0;iprb_idx[j][i]) { - fprintf(f, "%d, ", i); - } - } - fprintf(f, "\n"); - } - } - -} diff --git a/lib/src/phy/phch/ra_dl.c b/lib/src/phy/phch/ra_dl.c new file mode 100644 index 000000000..85db4a69e --- /dev/null +++ b/lib/src/phy/phch/ra_dl.c @@ -0,0 +1,732 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/phy/phch/ra_dl.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" +#include +#include +#include +#include +#include + +#define min(a, b) (a < b ? a : b) + +const int tbs_format1c_table[32] = {40, 56, 72, 120, 136, 144, 176, 208, 224, 256, 280, + 296, 328, 336, 392, 488, 552, 600, 632, 696, 776, 840, + 904, 1000, 1064, 1128, 1224, 1288, 1384, 1480, 1608, 1736}; + +/********** + * STATIC FUNCTIONS + * + **********/ + +/* Returns the number of RE in a PRB in a slot and subframe */ +static uint32_t ra_re_x_prb(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, uint32_t slot, uint32_t prb_idx) +{ + + uint32_t subframe = sf->tti % 10; + uint32_t nof_ctrl_symbols = SRSLTE_NOF_CTRL_SYMBOLS((*cell), sf->cfi); + + uint32_t re; + bool skip_refs = true; + srslte_cp_t cp_ = cell->cp; + if (SRSLTE_SF_MBSFN == sf->sf_type) { + cp_ = SRSLTE_CP_EXT; + } + + uint32_t nof_symbols = SRSLTE_CP_NSYMB(cp_); + if (cell->frame_type == SRSLTE_TDD && srslte_sfidx_tdd_type(sf->tdd_config, subframe) == SRSLTE_TDD_SF_S) { + nof_symbols = srslte_sfidx_tdd_nof_dw_slot(sf->tdd_config, slot, cp_); + } + + if (slot == 0) { + re = (nof_symbols - nof_ctrl_symbols) * SRSLTE_NRE; + } else { + re = nof_symbols * SRSLTE_NRE; + } + + /* if it's the prb in the middle, there are less RE due to PBCH and PSS/SSS */ + if (cell->frame_type == SRSLTE_FDD) { + if ((subframe == 0 || subframe == 5) && + (prb_idx >= cell->nof_prb / 2 - 3 && prb_idx < cell->nof_prb / 2 + 3 + (cell->nof_prb % 2))) { + if (subframe == 0) { + if (slot == 0) { + re = (nof_symbols - nof_ctrl_symbols - 2) * SRSLTE_NRE; + } else { + if (SRSLTE_CP_ISEXT(cp_)) { + re = (nof_symbols - 4) * SRSLTE_NRE; + skip_refs = false; + } else { + re = (nof_symbols - 4) * SRSLTE_NRE + 2 * cell->nof_ports; + } + } + } else if (subframe == 5) { + if (slot == 0) { + re = (nof_symbols - nof_ctrl_symbols - 2) * SRSLTE_NRE; + } + } + if ((cell->nof_prb % 2) && (prb_idx == cell->nof_prb / 2 - 3 || prb_idx == cell->nof_prb / 2 + 3)) { + if (slot == 0) { + re += 2 * SRSLTE_NRE / 2; + } else if (subframe == 0) { + re += 4 * SRSLTE_NRE / 2 - cell->nof_ports; + if (SRSLTE_CP_ISEXT(cp_)) { + re -= cell->nof_ports > 2 ? 2 : cell->nof_ports; + } + } + } + } + } else { + if ((((subframe == 0 || subframe == 5) && slot == 1) || ((subframe == 1 || subframe == 6) && slot == 0)) && + (prb_idx >= cell->nof_prb / 2 - 3 && prb_idx < cell->nof_prb / 2 + 3 + (cell->nof_prb % 2))) { + if (subframe == 0) { + if (SRSLTE_CP_ISEXT(cp_)) { + re = (nof_symbols - 5) * SRSLTE_NRE; + skip_refs = false; + } else { + re = (nof_symbols - 5) * SRSLTE_NRE + 2 * cell->nof_ports; + } + } else if (subframe == 5) { + re = (nof_symbols - 1) * SRSLTE_NRE; + } else if (subframe == 1) { + re = (nof_symbols - nof_ctrl_symbols - 1) * SRSLTE_NRE; + } else if (subframe == 6) { + re = (nof_symbols - nof_ctrl_symbols - 1) * SRSLTE_NRE; + } + if ((cell->nof_prb % 2) && (prb_idx == cell->nof_prb / 2 - 3 || prb_idx == cell->nof_prb / 2 + 3)) { + re += SRSLTE_NRE / 2; + if (subframe == 0) { + re += 4 * SRSLTE_NRE / 2 - cell->nof_ports; + if (SRSLTE_CP_ISEXT(cp_)) { + re -= cell->nof_ports > 2 ? 2 : cell->nof_ports; + } + } + } + } + } + + // remove references + if (skip_refs) { + if (sf->sf_type == SRSLTE_SF_NORM) { + switch (cell->nof_ports) { + case 1: + case 2: + if (nof_symbols >= 5) { + re -= 2 * (slot + 1) * cell->nof_ports; + } else if (slot == 1) { + re -= 2 * cell->nof_ports; + } + break; + case 4: + if (slot == 1) { + re -= 12; + } else { + re -= 4; + if (nof_ctrl_symbols == 1) { + re -= 4; + } + } + break; + } + } + if (sf->sf_type == SRSLTE_SF_MBSFN) { + re -= 6 * (slot + 1); + } + } + return re; +} + +/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 + * Decode grant->type?_alloc to grant + * This function only reads grant->type?_alloc and grant->alloc_type fields. + * This function only writes grant->prb_idx and grant->nof_prb. + */ +/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ +int srslte_ra_dl_grant_to_grant_prb_allocation(srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant, uint32_t nof_prb) +{ + int i, j; + uint32_t bitmask; + uint32_t P = srslte_ra_type0_P(nof_prb); + uint32_t n_rb_rbg_subset, n_rb_type1; + uint32_t L_crb = 0, RB_start = 0, nof_vrb = 0, nof_prb_t2 = 0, n_step = 0; + + switch (dci->alloc_type) { + case SRSLTE_RA_ALLOC_TYPE0: + bitmask = dci->type0_alloc.rbg_bitmask; + int nb = (int)ceilf((float)nof_prb / P); + for (i = 0; i < nb; i++) { + if (bitmask & (1 << (nb - i - 1))) { + for (j = 0; j < P; j++) { + if (i * P + j < nof_prb) { + grant->prb_idx[0][i * P + j] = true; + grant->nof_prb++; + } + } + } + } + memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB * sizeof(bool)); + break; + case SRSLTE_RA_ALLOC_TYPE1: + // Make sure the rbg_subset is valid + if (dci->type1_alloc.rbg_subset >= P) { + ERROR("Invalid RBG subset=%d for nof_prb=%d where P=%d\n", dci->type1_alloc.rbg_subset, nof_prb, P); + return SRSLTE_ERROR; + } + n_rb_type1 = srslte_ra_type1_N_rb(nof_prb); + uint32_t temp = ((nof_prb - 1) / P) % P; + if (dci->type1_alloc.rbg_subset < temp) { + n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P + P; + } else if (dci->type1_alloc.rbg_subset == temp) { + n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P + ((nof_prb - 1) % P) + 1; + } else { + n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P; + } + int shift = dci->type1_alloc.shift ? (n_rb_rbg_subset - n_rb_type1) : 0; + bitmask = dci->type1_alloc.vrb_bitmask; + for (i = 0; i < n_rb_type1; i++) { + if (bitmask & (1 << (n_rb_type1 - i - 1))) { + uint32_t idx = (((i + shift) / P) * P * P + dci->type1_alloc.rbg_subset * P + (i + shift) % P); + if (idx < nof_prb) { + grant->prb_idx[0][idx] = true; + grant->nof_prb++; + } else { + ERROR("Invalid idx=%d in Type1 RA, nof_prb=%d\n", idx, nof_prb); + return SRSLTE_ERROR; + } + } + } + memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB * sizeof(bool)); + break; + case SRSLTE_RA_ALLOC_TYPE2: + + if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { + nof_vrb = nof_prb; + } else { + nof_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1); + } + if (dci->format == SRSLTE_DCI_FORMAT1C) { + n_step = srslte_ra_type2_n_rb_step(nof_prb); + nof_vrb /= n_step; + nof_prb_t2 = nof_vrb; + } else { + nof_prb_t2 = nof_prb; + } + srslte_ra_type2_from_riv(dci->type2_alloc.riv, &L_crb, &RB_start, nof_prb_t2, nof_vrb); + + if (dci->format == SRSLTE_DCI_FORMAT1C) { + L_crb *= n_step; + RB_start *= n_step; + } + + if (dci->type2_alloc.mode == SRSLTE_RA_TYPE2_LOC) { + for (i = 0; i < L_crb; i++) { + grant->prb_idx[0][i + RB_start] = true; + grant->nof_prb++; + } + memcpy(&grant->prb_idx[1], &grant->prb_idx[0], SRSLTE_MAX_PRB * sizeof(bool)); + } else { + /* Mapping of Virtual to Physical RB for distributed type is defined in + * 6.2.3.2 of 36.211 + */ + int N_gap, N_tilde_vrb, n_tilde_vrb, n_tilde_prb, n_tilde2_prb, N_null, N_row, n_vrb; + int n_tilde_prb_odd, n_tilde_prb_even; + if (dci->type2_alloc.n_gap == SRSLTE_RA_TYPE2_NG1) { + N_tilde_vrb = srslte_ra_type2_n_vrb_dl(nof_prb, true); + N_gap = srslte_ra_type2_ngap(nof_prb, true); + } else { + N_tilde_vrb = 2 * srslte_ra_type2_n_vrb_dl(nof_prb, true); + N_gap = srslte_ra_type2_ngap(nof_prb, false); + } + N_row = (int)ceilf((float)N_tilde_vrb / (4 * P)) * P; + N_null = 4 * N_row - N_tilde_vrb; + for (i = 0; i < L_crb; i++) { + n_vrb = i + RB_start; + n_tilde_vrb = n_vrb % N_tilde_vrb; + n_tilde_prb = 2 * N_row * (n_tilde_vrb % 2) + n_tilde_vrb / 2 + N_tilde_vrb * (n_vrb / N_tilde_vrb); + n_tilde2_prb = N_row * (n_tilde_vrb % 4) + n_tilde_vrb / 4 + N_tilde_vrb * (n_vrb / N_tilde_vrb); + + if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb % 2) == 1) { + n_tilde_prb_odd = n_tilde_prb - N_row; + } else if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb % 2) == 0) { + n_tilde_prb_odd = n_tilde_prb - N_row + N_null / 2; + } else if (N_null != 0 && n_tilde_vrb < (N_tilde_vrb - N_null) && (n_tilde_vrb % 4) >= 2) { + n_tilde_prb_odd = n_tilde2_prb - N_null / 2; + } else { + n_tilde_prb_odd = n_tilde2_prb; + } + n_tilde_prb_even = (n_tilde_prb_odd + N_tilde_vrb / 2) % N_tilde_vrb + N_tilde_vrb * (n_vrb / N_tilde_vrb); + + if (n_tilde_prb_odd < N_tilde_vrb / 2) { + if (n_tilde_prb_odd < nof_prb) { + grant->prb_idx[0][n_tilde_prb_odd] = true; + } else { + return SRSLTE_ERROR; + } + } else { + if (n_tilde_prb_odd + N_gap - N_tilde_vrb / 2 < nof_prb) { + grant->prb_idx[0][n_tilde_prb_odd + N_gap - N_tilde_vrb / 2] = true; + } else { + return SRSLTE_ERROR; + } + } + grant->nof_prb++; + if (n_tilde_prb_even < N_tilde_vrb / 2) { + if (n_tilde_prb_even < nof_prb) { + grant->prb_idx[1][n_tilde_prb_even] = true; + } else { + return SRSLTE_ERROR; + } + } else { + if (n_tilde_prb_even + N_gap - N_tilde_vrb / 2 < nof_prb) { + grant->prb_idx[1][n_tilde_prb_even + N_gap - N_tilde_vrb / 2] = true; + } else { + return SRSLTE_ERROR; + } + } + } + } + break; + default: + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_dl_fill_ra_mcs(srslte_ra_tb_t* tb, int last_tbs, uint32_t nprb) +{ + int i_tbs = 0; + if (tb->mcs_idx < 10) { + tb->mod = SRSLTE_MOD_QPSK; + i_tbs = tb->mcs_idx; + } else if (tb->mcs_idx < 17) { + tb->mod = SRSLTE_MOD_16QAM; + i_tbs = tb->mcs_idx - 1; + } else if (tb->mcs_idx < 29) { + tb->mod = SRSLTE_MOD_64QAM; + i_tbs = tb->mcs_idx - 2; + } else if (tb->mcs_idx == 29) { + tb->mod = SRSLTE_MOD_QPSK; + i_tbs = -1; + } else if (tb->mcs_idx == 30) { + tb->mod = SRSLTE_MOD_16QAM; + i_tbs = -1; + } else if (tb->mcs_idx == 31) { + tb->mod = SRSLTE_MOD_64QAM; + i_tbs = -1; + } + + // If i_tbs = -1, TBS is determined from the latest PDCCH for this TB (7.1.7.2 36.213) + int tbs = 0; + if (i_tbs >= 0) { + tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); + tb->tbs = tbs; + } else { + tb->tbs = last_tbs; + } + + return tbs; +} + +/* Modulation order and transport block size determination 7.1.7 in 36.213 + * */ +static int dl_dci_compute_tb(srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant) +{ + uint32_t n_prb = 0; + int tbs = -1; + uint32_t i_tbs = 0; + + // Copy info and Enable/Disable TB + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + grant->tb[i].mcs_idx = dci->tb[i].mcs_idx; + grant->tb[i].rv = dci->tb[i].rv; + grant->tb[i].cw_idx = dci->tb[i].cw_idx; + if ((SRSLTE_DCI_IS_TB_EN(dci->tb[i]) && dci->format >= SRSLTE_DCI_FORMAT2) || + (dci->format < SRSLTE_DCI_FORMAT2 && i == 0)) { + grant->tb[i].enabled = true; + grant->nof_tb++; + } else { + grant->tb[i].enabled = false; + } + } + + if (!SRSLTE_RNTI_ISUSER(dci->rnti) && !SRSLTE_RNTI_ISMBSFN(dci->rnti)) { + if (dci->format == SRSLTE_DCI_FORMAT1A) { + n_prb = dci->type2_alloc.n_prb1a == SRSLTE_RA_TYPE2_NPRB1A_2 ? 2 : 3; + i_tbs = dci->tb[0].mcs_idx; + tbs = srslte_ra_tbs_from_idx(i_tbs, n_prb); + if (tbs < 0) { + ERROR("Invalid TBS_index=%d or n_prb=%d\n", i_tbs, n_prb); + return SRSLTE_ERROR; + } + } else if (dci->format == SRSLTE_DCI_FORMAT1C) { + if (dci->tb[0].mcs_idx < 32) { + tbs = tbs_format1c_table[dci->tb[0].mcs_idx]; + } else { + ERROR("Error decoding DCI: Invalid mcs_idx=%d in Format1C\n", dci->tb[0].mcs_idx); + return SRSLTE_ERROR; + } + } else { + ERROR("Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n"); + return SRSLTE_ERROR; + } + grant->tb[0].mod = SRSLTE_MOD_QPSK; + if (tbs >= 0) { + grant->tb[0].tbs = (uint32_t)tbs; + } else { + ERROR("Invalid TBS=%d\n", tbs); + return SRSLTE_ERROR; + } + } else { + if (dci->is_dwpts) { + n_prb = SRSLTE_MAX(1, 0.75 * grant->nof_prb); + } else { + n_prb = grant->nof_prb; + } + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb[i].enabled) { + grant->tb[i].tbs = srslte_dl_fill_ra_mcs(&grant->tb[i], grant->last_tbs[i], n_prb); + if (grant->tb[i].tbs < 0) { + ERROR("Computing TBS from MCS=%d, n_prb=%d\n", grant->tb[i].mcs_idx, n_prb); + return SRSLTE_ERROR; + } + } else { + grant->tb[i].tbs = 0; + } + } + } + return SRSLTE_SUCCESS; +} + +void srslte_ra_dl_compute_nof_re(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_pdsch_grant_t* grant) +{ + // Compute number of RE + grant->nof_re = srslte_ra_dl_grant_nof_re(cell, sf, grant); + srslte_cp_t cp_ = SRSLTE_SF_NORM == sf->sf_type ? cell->cp : SRSLTE_CP_EXT; + if (cell->frame_type == SRSLTE_FDD) { + grant->nof_symb_slot[0] = SRSLTE_CP_NSYMB(cp_); + grant->nof_symb_slot[1] = SRSLTE_CP_NSYMB(cp_); + } else { + if (srslte_sfidx_tdd_type(sf->tdd_config, sf->tti % 10) == SRSLTE_TDD_SF_S) { + grant->nof_symb_slot[0] = srslte_sfidx_tdd_nof_dw_slot(sf->tdd_config, 0, cp_); + grant->nof_symb_slot[1] = srslte_sfidx_tdd_nof_dw_slot(sf->tdd_config, 1, cp_); + } else { + grant->nof_symb_slot[0] = SRSLTE_CP_NSYMB(cp_); + grant->nof_symb_slot[1] = SRSLTE_CP_NSYMB(cp_); + } + } + + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + /* Compute number of RE for first transport block */ + if (grant->tb[i].enabled) { + grant->tb[i].nof_bits = grant->nof_re * srslte_mod_bits_x_symbol(grant->tb[i].mod); + } + } +} + +/* Determine MIMO type based on number of cell ports and receive antennas, transport blocks and pinfo */ +static int config_mimo_type(srslte_cell_t* cell, srslte_tm_t tm, srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant) +{ + grant->tx_scheme = SRSLTE_TXSCHEME_PORT0; + bool valid_config = true; + + uint32_t nof_tb = grant->nof_tb; + switch (tm) { + /* Implemented Tx Modes */ + case SRSLTE_TM1: + case SRSLTE_TM2: + if (cell->nof_ports > 1) { + grant->tx_scheme = SRSLTE_TXSCHEME_DIVERSITY; + } else { + grant->tx_scheme = SRSLTE_TXSCHEME_PORT0; + } + if (nof_tb != 1) { + ERROR("Wrong number of transport blocks (%d) for %s.\n", nof_tb, srslte_mimotype2str(grant->tx_scheme)); + valid_config = false; + } + break; + case SRSLTE_TM3: + if (nof_tb == 1) { + grant->tx_scheme = SRSLTE_TXSCHEME_DIVERSITY; + } else if (nof_tb == 2) { + grant->tx_scheme = SRSLTE_TXSCHEME_CDD; + } else { + ERROR("Invalid number of transport blocks (%d) for TM3\n", nof_tb); + valid_config = false; + } + break; + case SRSLTE_TM4: + if (nof_tb == 1) { + grant->tx_scheme = (dci->pinfo == 0) ? SRSLTE_TXSCHEME_DIVERSITY : SRSLTE_TXSCHEME_SPATIALMUX; + } else if (nof_tb == 2) { + grant->tx_scheme = SRSLTE_TXSCHEME_SPATIALMUX; + } else { + ERROR("Invalid number of transport blocks (%d) for TM4\n", nof_tb); + valid_config = false; + } + break; + + /* Not implemented cases */ + case SRSLTE_TM5: + case SRSLTE_TM6: + case SRSLTE_TM7: + case SRSLTE_TM8: + ERROR("Not implemented Tx mode (%d)\n", tm + 1); + break; + + /* Error cases */ + default: + ERROR("Wrong Tx mode (%d)\n", tm + 1); + } + return valid_config ? SRSLTE_SUCCESS : SRSLTE_ERROR; +} + +/* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ +static int config_mimo_pmi(srslte_cell_t* cell, srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant) +{ + uint32_t nof_tb = grant->nof_tb; + if (grant->tx_scheme == SRSLTE_TXSCHEME_SPATIALMUX) { + if (nof_tb == 1) { + if (dci->pinfo > 0 && dci->pinfo < 5) { + grant->pmi = dci->pinfo - 1; + } else { + ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, dci->pinfo); + return -1; + } + } else { + if (dci->pinfo == 2) { + ERROR("Not implemented codebook index (nof_tb=%d (%d/%d), pinfo=%d)", + nof_tb, + SRSLTE_DCI_IS_TB_EN(grant->tb[0]), + SRSLTE_DCI_IS_TB_EN(grant->tb[1]), + dci->pinfo); + return -1; + } else if (dci->pinfo > 2) { + ERROR("Reserved codebook index (nof_tb=%d, pinfo=%d)", nof_tb, dci->pinfo); + return -1; + } + grant->pmi = dci->pinfo % 2; + } + } + + return 0; +} + +/* Determine number of MIMO layers */ +static int config_mimo_layers(srslte_cell_t* cell, srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant) +{ + uint32_t nof_tb = grant->nof_tb; + switch (grant->tx_scheme) { + case SRSLTE_TXSCHEME_PORT0: + if (nof_tb != 1) { + ERROR("Wrong number of transport blocks (%d) for single antenna.\n", nof_tb); + return SRSLTE_ERROR; + } + grant->nof_layers = 1; + break; + case SRSLTE_TXSCHEME_DIVERSITY: + if (nof_tb != 1) { + ERROR("Wrong number of transport blocks (%d) for transmit diversity.\n", nof_tb); + return SRSLTE_ERROR; + } + grant->nof_layers = cell->nof_ports; + break; + case SRSLTE_TXSCHEME_SPATIALMUX: + if (nof_tb == 1) { + grant->nof_layers = 1; + } else if (nof_tb == 2) { + grant->nof_layers = 2; + } else { + ERROR("Wrong number of transport blocks (%d) for spatial multiplexing.\n", nof_tb); + return SRSLTE_ERROR; + } + INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; pmi=%d\n", + nof_tb, + grant->nof_layers, + grant->pmi); + break; + case SRSLTE_TXSCHEME_CDD: + if (nof_tb != 2) { + ERROR("Wrong number of transport blocks (%d) for CDD.\n", nof_tb); + return SRSLTE_ERROR; + } + grant->nof_layers = 2; + break; + } + return 0; +} + +static int config_mimo(srslte_cell_t* cell, srslte_tm_t tm, srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant) +{ + + if (config_mimo_type(cell, tm, dci, grant)) { + ERROR("Configuring MIMO type\n"); + return -1; + } + + if (config_mimo_pmi(cell, dci, grant)) { + ERROR("Configuring MIMO PMI\n"); + return -1; + } + + if (config_mimo_layers(cell, dci, grant)) { + ERROR("Configuring MIMO layers\n"); + return -1; + } + + return 0; +} + +/********** + * NON-STATIC FUNCTIONS + * + **********/ + +/** Compute the DL grant parameters */ +int srslte_ra_dl_dci_to_grant( + srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_tm_t tm, srslte_dci_dl_t* dci, srslte_pdsch_grant_t* grant) +{ + bzero(grant, sizeof(srslte_pdsch_grant_t)); + + // Compute PRB allocation + int ret = srslte_ra_dl_grant_to_grant_prb_allocation(dci, grant, cell->nof_prb); + if (ret == SRSLTE_SUCCESS) { + // Compute MCS + ret = dl_dci_compute_tb(dci, grant); + if (ret == SRSLTE_SUCCESS) { + // Compute number of RE and number of ack_value in grant + srslte_ra_dl_compute_nof_re(cell, sf, grant); + + // Apply Section 7.1.7.3. If RA-RNTI and Format1C rv_idx=0 + if (dci->format == SRSLTE_DCI_FORMAT1C) { + if ((SRSLTE_RNTI_ISRAR(dci->rnti)) || dci->rnti == SRSLTE_PRNTI) { + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + grant->tb[i].rv = 0; + } + } + } + } else { + ERROR("Configuring TB Info\n"); + return SRSLTE_ERROR; + } + } else { + ERROR("Configuring resource allocation\n"); + return SRSLTE_ERROR; + } + + // Configure MIMO for this TM + return config_mimo(cell, tm, dci, grant); +} + +uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t* cell, uint32_t nof_prb, uint32_t nof_ctrl_symbols) +{ + uint32_t nof_refs = 0; + uint32_t nof_symb = 2 * SRSLTE_CP_NSYMB(cell->cp) - nof_ctrl_symbols; + switch (cell->nof_ports) { + case 1: + nof_refs = 2 * 3; + break; + case 2: + nof_refs = 4 * 3; + break; + case 4: + nof_refs = 4 * 4; + break; + } + return nof_prb * (nof_symb * SRSLTE_NRE - nof_refs); +} + +/* Computes the number of RE for each PRB in the prb_dist structure */ +uint32_t srslte_ra_dl_grant_nof_re(srslte_cell_t* cell, srslte_dl_sf_cfg_t* sf, srslte_pdsch_grant_t* grant) +{ + uint32_t j, s; + // Compute number of RE per PRB + uint32_t nof_re = 0; + for (s = 0; s < 2; s++) { + for (j = 0; j < cell->nof_prb; j++) { + if (grant->prb_idx[s][j]) { + nof_re += ra_re_x_prb(cell, sf, s, j); + } + } + } + return nof_re; +} + +static uint32_t print_multi(char* info_str, uint32_t n, uint32_t len, srslte_pdsch_grant_t* grant, uint32_t value_id) +{ + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (grant->tb[i].enabled) { + switch (value_id) { + case 0: + n = srslte_print_check(info_str, len, n, "%d", grant->tb[i].rv); + break; + case 1: + n = srslte_print_check(info_str, len, n, "%d", grant->tb[i].tbs / 8); + break; + case 2: + n = srslte_print_check(info_str, len, n, "%d", srslte_mod_bits_x_symbol(grant->tb[i].mod)); + break; + } + if (i < SRSLTE_MAX_CODEWORDS - 1) { + if (grant->tb[i + 1].enabled) { + n = srslte_print_check(info_str, len, n, "/"); + } + } + } + } + return n; +} + +uint32_t srslte_ra_dl_info(srslte_pdsch_grant_t* grant, char* info_str, uint32_t len) +{ + int n = 0; + + n = srslte_print_check(info_str, len, n, ", nof_prb=%d, nof_re=%d", grant->nof_prb, grant->nof_re); + + n = srslte_print_check(info_str, len, n, ", tbs={", 0); + n = print_multi(info_str, n, len, grant, 1); + n = srslte_print_check(info_str, len, n, "}", 0); + n = srslte_print_check(info_str, len, n, ", mod={", 0); + n = print_multi(info_str, n, len, grant, 2); + n = srslte_print_check(info_str, len, n, "}", 0); + n = srslte_print_check(info_str, len, n, ", rv={", 0); + n = print_multi(info_str, n, len, grant, 0); + n = srslte_print_check(info_str, len, n, "}", 0); + + if (grant->tx_scheme != SRSLTE_TXSCHEME_PORT0) { + n = srslte_print_check(info_str, + len, + n, + ", tx=%s, nof_tb=%d, nof_l=%d", + srslte_mimotype2str(grant->tx_scheme), + grant->nof_tb, + grant->nof_layers); + if (grant->tx_scheme == SRSLTE_TXSCHEME_SPATIALMUX) { + n = srslte_print_check(info_str, len, n, ", pmi=%d", grant->pmi); + } + } + return n; +} diff --git a/lib/src/phy/phch/ra_ul.c b/lib/src/phy/phch/ra_ul.c new file mode 100644 index 000000000..3b5bed2db --- /dev/null +++ b/lib/src/phy/phch/ra_ul.c @@ -0,0 +1,321 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/phy/common/phy_common.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" +#include +#include +#include +#include +#include + +#define min(a, b) (a < b ? a : b) + +/********** + * STATIC FUNCTIONS + * + **********/ + +static int f_hop_sum(srslte_ra_ul_pusch_hopping_t* q, uint32_t i) +{ + uint32_t sum = 0; + for (uint32_t k = i * 10 + 1; k < i * 10 + 9; i++) { + sum += (q->seq_type2_fo.c[k] << (k - (i * 10 + 1))); + } + return sum; +} + +static int f_hop(srslte_ra_ul_pusch_hopping_t* q, srslte_pusch_hopping_cfg_t* hopping, int i) +{ + if (i == -1) { + return 0; + } else { + if (hopping->n_sb == 1) { + return 0; + } else if (hopping->n_sb == 2) { + return (f_hop(q, hopping, i - 1) + f_hop_sum(q, i)) % 2; + } else { + return (f_hop(q, hopping, i - 1) + f_hop_sum(q, i) % (hopping->n_sb - 1) + 1) % hopping->n_sb; + } + } +} + +static int f_m(srslte_ra_ul_pusch_hopping_t* q, srslte_pusch_hopping_cfg_t* hopping, uint32_t i, uint32_t current_tx_nb) +{ + if (hopping->n_sb == 1) { + if (hopping->hop_mode == SRSLTE_PUSCH_HOP_MODE_INTER_SF) { + return current_tx_nb % 2; + } else { + return i % 2; + } + } else { + return q->seq_type2_fo.c[i * 10]; + } +} +/* Computes PUSCH frequency hopping as defined in Section 8.4 of 36.213 */ +static void compute_freq_hopping(srslte_ra_ul_pusch_hopping_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_hopping_cfg_t* hopping_cfg, + srslte_pusch_grant_t* grant) +{ + + if (q->cell.frame_type == SRSLTE_TDD) { + ERROR("Error frequency hopping for TDD not implemented (c_init for each subframe, see end of 5.3.4 36.211)\n"); + } + + for (uint32_t slot = 0; slot < 2; slot++) { + + INFO("PUSCH Freq hopping: %d\n", grant->freq_hopping); + uint32_t n_prb_tilde = grant->n_prb[slot]; + + if (grant->freq_hopping == 1) { + if (hopping_cfg->hop_mode == SRSLTE_PUSCH_HOP_MODE_INTER_SF) { + n_prb_tilde = grant->n_prb[hopping_cfg->current_tx_nb % 2]; + } else { + n_prb_tilde = grant->n_prb[slot]; + } + } + if (grant->freq_hopping == 2) { + /* Freq hopping type 2 as defined in 5.3.4 of 36.211 */ + uint32_t n_vrb_tilde = grant->n_prb[0]; + if (hopping_cfg->n_sb > 1) { + n_vrb_tilde -= (hopping_cfg->hopping_offset - 1) / 2 + 1; + } + int i = 0; + if (hopping_cfg->hop_mode == SRSLTE_PUSCH_HOP_MODE_INTER_SF) { + i = sf->tti % 10; + } else { + i = 2 * sf->tti % 10 + slot; + } + uint32_t n_rb_sb = q->cell.nof_prb; + if (hopping_cfg->n_sb > 1) { + n_rb_sb = (n_rb_sb - hopping_cfg->hopping_offset - hopping_cfg->hopping_offset % 2) / hopping_cfg->n_sb; + } + n_prb_tilde = (n_vrb_tilde + f_hop(q, hopping_cfg, i) * n_rb_sb + (n_rb_sb - 1) - + 2 * (n_vrb_tilde % n_rb_sb) * f_m(q, hopping_cfg, i, hopping_cfg->current_tx_nb)) % + (n_rb_sb * hopping_cfg->n_sb); + + INFO("n_prb_tilde: %d, n_vrb_tilde: %d, n_rb_sb: %d, n_sb: %d\n", + n_prb_tilde, + n_vrb_tilde, + n_rb_sb, + hopping_cfg->n_sb); + if (hopping_cfg->n_sb > 1) { + n_prb_tilde += (hopping_cfg->hopping_offset - 1) / 2 + 1; + } + } + grant->n_prb_tilde[slot] = n_prb_tilde; + } +} + +static int ra_ul_grant_to_grant_prb_allocation(srslte_dci_ul_t* dci, + srslte_pusch_grant_t* grant, + uint32_t n_rb_ho, + uint32_t nof_prb) +{ + uint32_t n_prb_1 = 0; + uint32_t n_rb_pusch = 0; + + srslte_ra_type2_from_riv(dci->type2_alloc.riv, &grant->L_prb, &n_prb_1, nof_prb, nof_prb); + if (n_rb_ho % 2) { + n_rb_ho++; + } + + if (dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED || dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_TYPE2) { + /* For no freq hopping or type2 freq hopping, n_prb is the same + * n_prb_tilde is calculated during resource mapping + */ + for (uint32_t i = 0; i < 2; i++) { + grant->n_prb[i] = n_prb_1; + } + if (dci->freq_hop_fl == SRSLTE_RA_PUSCH_HOP_DISABLED) { + grant->freq_hopping = 0; + } else { + grant->freq_hopping = 2; + } + INFO("prb1: %d, prb2: %d, L: %d\n", grant->n_prb[0], grant->n_prb[1], grant->L_prb); + } else { + /* Type1 frequency hopping as defined in 8.4.1 of 36.213 + * frequency offset between 1st and 2nd slot is fixed. + */ + n_rb_pusch = nof_prb - n_rb_ho - (nof_prb % 2); + + // starting prb idx for slot 0 is as given by resource dci + grant->n_prb[0] = n_prb_1; + if (n_prb_1 < n_rb_ho / 2) { + INFO("Invalid Frequency Hopping parameters. Offset: %d, n_prb_1: %d\n", n_rb_ho, n_prb_1); + return SRSLTE_ERROR; + } + uint32_t n_prb_1_tilde = n_prb_1; + + // prb idx for slot 1 + switch (dci->freq_hop_fl) { + case SRSLTE_RA_PUSCH_HOP_QUART: + grant->n_prb[1] = (n_rb_pusch / 4 + n_prb_1_tilde) % n_rb_pusch; + break; + case SRSLTE_RA_PUSCH_HOP_QUART_NEG: + if (n_prb_1 < n_rb_pusch / 4) { + grant->n_prb[1] = (n_rb_pusch + n_prb_1_tilde - n_rb_pusch / 4); + } else { + grant->n_prb[1] = (n_prb_1_tilde - n_rb_pusch / 4); + } + break; + case SRSLTE_RA_PUSCH_HOP_HALF: + grant->n_prb[1] = (n_rb_pusch / 2 + n_prb_1_tilde) % n_rb_pusch; + break; + default: + break; + } + INFO("n_rb_pusch: %d, prb1: %d, prb2: %d, L: %d\n", n_rb_pusch, grant->n_prb[0], grant->n_prb[1], grant->L_prb); + grant->freq_hopping = 1; + } + + if (grant->n_prb[0] + grant->L_prb <= nof_prb && grant->n_prb[1] + grant->L_prb <= nof_prb) { + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR; + } +} + +static void ul_fill_ra_mcs(srslte_ra_tb_t* tb, srslte_ra_tb_t* last_tb, uint32_t L_prb, bool cqi_request) +{ + // 8.6.2 First paragraph + if (tb->mcs_idx <= 28) { + /* Table 8.6.1-1 on 36.213 */ + if (tb->mcs_idx < 11) { + tb->mod = SRSLTE_MOD_QPSK; + tb->tbs = srslte_ra_tbs_from_idx(tb->mcs_idx, L_prb); + } else if (tb->mcs_idx < 21) { + tb->mod = SRSLTE_MOD_16QAM; + tb->tbs = srslte_ra_tbs_from_idx(tb->mcs_idx - 1, L_prb); + } else if (tb->mcs_idx < 29) { + tb->mod = SRSLTE_MOD_64QAM; + tb->tbs = srslte_ra_tbs_from_idx(tb->mcs_idx - 2, L_prb); + } else { + ERROR("Invalid MCS index %d\n", tb->mcs_idx); + } + } else if (tb->mcs_idx == 29 && cqi_request && L_prb <= 4) { + // 8.6.1 and 8.6.2 36.213 second paragraph + tb->mod = SRSLTE_MOD_QPSK; + tb->tbs = 0; + tb->rv = 1; + } else if (tb->mcs_idx >= 29) { + // Else use last TBS/Modulation and use mcs to obtain rv_idx + tb->tbs = last_tb->tbs; + tb->mod = last_tb->mod; + tb->rv = tb->mcs_idx - 28; + } +} + +static void compute_nof_re(srslte_pusch_grant_t* grant, srslte_cp_t cp, uint32_t N_srs) +{ + grant->nof_symb = 2 * (SRSLTE_CP_NSYMB(cp) - 1) - N_srs; + grant->nof_re = grant->nof_symb * grant->L_prb * SRSLTE_NRE; + grant->tb.nof_bits = grant->nof_re * srslte_mod_bits_x_symbol(grant->tb.mod); +} + +/********** + * NON-STATIC FUNCTIONS + * + **********/ + +/* Initializes the Pseudo-Random sequence to the provided cell id. Can be called multiple times without allocating new + * memory + */ +int srslte_ra_ul_pusch_hopping_init(srslte_ra_ul_pusch_hopping_t* q, srslte_cell_t cell) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q) { + if (cell.id != q->cell.id || !q->initialized) { + q->cell = cell; + q->initialized = true; + /* Precompute sequence for type2 frequency hopping */ + if (srslte_sequence_LTE_pr(&q->seq_type2_fo, 210, q->cell.id)) { + ERROR("Error initiating type2 frequency hopping sequence\n"); + return SRSLTE_ERROR; + } + ret = SRSLTE_SUCCESS; + } + } + return ret; +} + +void srslte_ra_ul_pusch_hopping_free(srslte_ra_ul_pusch_hopping_t* q) +{ + srslte_sequence_free(&q->seq_type2_fo); +} + +void srslte_ra_ul_pusch_hopping(srslte_ra_ul_pusch_hopping_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_hopping_cfg_t* hopping_cfg, + srslte_pusch_grant_t* grant) +{ + /* Compute PUSCH frequency hopping */ + if (hopping_cfg->hopping_enabled) { + compute_freq_hopping(q, sf, hopping_cfg, grant); + } else { + grant->n_prb_tilde[0] = grant->n_prb[0]; + grant->n_prb_tilde[1] = grant->n_prb[1]; + } +} + +/** Compute PRB allocation for Uplink as defined in 8.1 and 8.4 of 36.213 */ +int srslte_ra_ul_dci_to_grant(srslte_cell_t* cell, + srslte_ul_sf_cfg_t* sf, + srslte_pusch_hopping_cfg_t* hopping_cfg, + srslte_dci_ul_t* dci, + srslte_pusch_grant_t* grant) +{ + + // Compute PRB allocation + if (!ra_ul_grant_to_grant_prb_allocation(dci, grant, hopping_cfg->n_rb_ho, cell->nof_prb)) { + + // Compute MCS + grant->tb.mcs_idx = dci->tb.mcs_idx; + ul_fill_ra_mcs(&grant->tb, &grant->last_tb, grant->L_prb, dci->cqi_request); + + // copy RV + grant->tb.rv = dci->tb.rv; + + /* Compute final number of bits and RE */ + compute_nof_re(grant, cell->cp, sf->shortened ? 1 : 0); + + // Assume hopping is the same + for (uint32_t i = 0; i < 2; i++) { + grant->n_prb_tilde[i] = grant->n_prb[i]; + } + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR; + } +} + +uint32_t srslte_ra_ul_info(srslte_pusch_grant_t *grant, char *info_str, uint32_t len) +{ + return srslte_print_check(info_str, len, 0, ", rb=(%d,%d), nof_re=%d, tbs=%d, mod=%d, rv=%d", grant->n_prb_tilde[0], + grant->n_prb_tilde[0] + grant->L_prb - 1, grant->nof_re, grant->tb.tbs / 8, + srslte_mod_bits_x_symbol(grant->tb.mod), grant->tb.rv); +} \ No newline at end of file diff --git a/lib/src/phy/phch/regs.c b/lib/src/phy/phch/regs.c index a89e0a565..4f712f89e 100644 --- a/lib/src/phy/phch/regs.c +++ b/lib/src/phy/phch/regs.c @@ -160,7 +160,7 @@ clean_and_exit: int srslte_regs_pdcch_nregs(srslte_regs_t *h, uint32_t cfi) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI=%d\n", cfi); + ERROR("Invalid CFI=%d\n", cfi); return SRSLTE_ERROR; } else { return (int) h->pdcch[cfi-1].nof_regs; @@ -182,7 +182,7 @@ int srslte_regs_pdcch_ncce(srslte_regs_t *h, uint32_t cfi) { int srslte_regs_pdcch_put_offset(srslte_regs_t *h, uint32_t cfi, cf_t *d, cf_t *slot_symbols, uint32_t start_reg, uint32_t nof_regs) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI=%d\n", cfi); + ERROR("Invalid CFI=%d\n", cfi); return SRSLTE_ERROR; } if (start_reg + nof_regs <= h->pdcch[cfi-1].nof_regs) { @@ -194,14 +194,14 @@ int srslte_regs_pdcch_put_offset(srslte_regs_t *h, uint32_t cfi, cf_t *d, cf_t * } return k; } else { - fprintf(stderr, "Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[cfi-1].nof_regs); + ERROR("Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[cfi - 1].nof_regs); return SRSLTE_ERROR; } } int srslte_regs_pdcch_put(srslte_regs_t *h, uint32_t cfi, cf_t *d, cf_t *slot_symbols) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI=%d\n", cfi); + ERROR("Invalid CFI=%d\n", cfi); return SRSLTE_ERROR; } return srslte_regs_pdcch_put_offset(h, cfi, d, slot_symbols, 0, h->pdcch[cfi-1].nof_regs); @@ -209,7 +209,7 @@ int srslte_regs_pdcch_put(srslte_regs_t *h, uint32_t cfi, cf_t *d, cf_t *slot_sy int srslte_regs_pdcch_get_offset(srslte_regs_t *h, uint32_t cfi, cf_t *slot_symbols, cf_t *d, uint32_t start_reg, uint32_t nof_regs) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI=%d\n", cfi); + ERROR("Invalid CFI=%d\n", cfi); return SRSLTE_ERROR; } if (start_reg + nof_regs <= h->pdcch[cfi-1].nof_regs) { @@ -221,7 +221,7 @@ int srslte_regs_pdcch_get_offset(srslte_regs_t *h, uint32_t cfi, cf_t *slot_symb } return k; } else { - fprintf(stderr, "Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[cfi-1].nof_regs); + ERROR("Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[cfi - 1].nof_regs); return SRSLTE_ERROR; } } @@ -229,7 +229,7 @@ int srslte_regs_pdcch_get_offset(srslte_regs_t *h, uint32_t cfi, cf_t *slot_symb int srslte_regs_pdcch_get(srslte_regs_t *h, uint32_t cfi, cf_t *slot_symbols, cf_t *d) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI=%d\n", cfi); + ERROR("Invalid CFI=%d\n", cfi); return SRSLTE_ERROR; } return srslte_regs_pdcch_get_offset(h, cfi, slot_symbols, d, 0, h->pdcch[cfi-1].nof_regs); @@ -247,7 +247,8 @@ int srslte_regs_pdcch_get(srslte_regs_t *h, uint32_t cfi, cf_t *slot_symbols, cf /** Initialize REGs for PHICH * 36.211 10.3 section 6.9.3 */ -int regs_phich_init(srslte_regs_t *h) { +int regs_phich_init(srslte_regs_t* h, uint32_t phich_mi, bool mbsfn_or_sf1_6_tdd) +{ float ng; uint32_t i, ni, li, n[3], nreg, mi; srslte_regs_reg_t **regs_phich[3]; @@ -274,7 +275,7 @@ int regs_phich_init(srslte_regs_t *h) { ng = 0; break; } - h->ngroups_phich = (int) ceilf(ng * ((float) h->cell.nof_prb/8)); + h->ngroups_phich = (int)phich_mi * ceilf(ng * ((float)h->cell.nof_prb / 8)); h->phich = malloc(sizeof(srslte_regs_ch_t) * h->ngroups_phich); if (!h->phich) { perror("malloc"); @@ -321,9 +322,21 @@ int regs_phich_init(srslte_regs_t *h) { nreg=0; for (mi=0;mingroups_phich;mi++) { // here ngroups is the number of mapping units - for (i=0;i<3;i++) { - li=h->phich_len==SRSLTE_PHICH_EXT?i:0; // Step 7 - ni=((h->cell.id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 + for (i = 0; i < 3; i++) { + // Step 7 + if (h->phich_len == SRSLTE_PHICH_NORM) { + li = 0; + } else if (h->phich_len == SRSLTE_PHICH_EXT && mbsfn_or_sf1_6_tdd) { + li = (mi / 2 + i + 1) % 2; + } else { + li = i; + } + // Step 8 + if (h->phich_len == SRSLTE_PHICH_EXT && mbsfn_or_sf1_6_tdd) { + ni = ((h->cell.id * n[li] / n[1]) + mi + i * n[li] / 3) % n[li]; + } else { + ni = ((h->cell.id * n[li] / n[0]) + mi + i * n[li] / 3) % n[li]; + } h->phich[mi].regs[i] = regs_phich[li][ni]; h->phich[mi].regs[i]->assigned = true; DEBUG("Assigned PHICH REG#%d (%d,%d)\n",nreg,h->phich[mi].regs[i]->k0,li); @@ -399,7 +412,7 @@ uint32_t srslte_regs_phich_ngroups(srslte_regs_t *h) { int srslte_regs_phich_add(srslte_regs_t *h, cf_t symbols[REGS_PHICH_NSYM], uint32_t ngroup, cf_t *slot_symbols) { uint32_t i; if (ngroup >= h->ngroups_phich) { - fprintf(stderr, "Error invalid ngroup %d\n", ngroup); + ERROR("Error invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(h->cell.cp)) { @@ -442,7 +455,7 @@ int srslte_regs_phich_reset(srslte_regs_t *h, cf_t *slot_symbols) { int srslte_regs_phich_get(srslte_regs_t *h, cf_t *slot_symbols, cf_t symbols[REGS_PHICH_NSYM], uint32_t ngroup) { uint32_t i; if (ngroup >= h->ngroups_phich) { - fprintf(stderr, "Error invalid ngroup %d\n", ngroup); + ERROR("Error invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(h->cell.cp)) { @@ -495,13 +508,10 @@ int regs_pcfich_init(srslte_regs_t *h) { % (h->cell.nof_prb * SRSLTE_NRE); ch->regs[i] = regs_find_reg(h, k, 0); if (!ch->regs[i]) { - fprintf(stderr, "Error allocating PCFICH: REG (%d,0) not found\n", - k); + ERROR("Error allocating PCFICH: REG (%d,0) not found\n", k); return SRSLTE_ERROR; } else if (ch->regs[i]->assigned) { - fprintf(stderr, - "Error allocating PCFICH: REG (%d,0) already allocated\n", - k); + ERROR("Error allocating PCFICH: REG (%d,0) already allocated\n", k); return SRSLTE_ERROR; } else { ch->regs[i]->assigned = true; @@ -597,7 +607,7 @@ int regs_num_x_symbol(uint32_t symbol, uint32_t nof_port, srslte_cp_t cp) { case 4: return 2; default: - fprintf(stderr, "Invalid number of ports %d\n", nof_port); + ERROR("Invalid number of ports %d\n", nof_port); return SRSLTE_ERROR; } break; @@ -610,7 +620,7 @@ int regs_num_x_symbol(uint32_t symbol, uint32_t nof_port, srslte_cp_t cp) { return 2; } default: - fprintf(stderr, "Invalid symbol %d\n", symbol); + ERROR("Invalid symbol %d\n", symbol); return SRSLTE_ERROR; } } @@ -644,7 +654,7 @@ int regs_reg_init(srslte_regs_reg_t *reg, uint32_t symbol, uint32_t nreg, uint32 j++; } if (j != 4) { - fprintf(stderr, "Something went wrong: expected 2 references\n"); + ERROR("Something went wrong: expected 2 references\n"); return SRSLTE_ERROR; } break; @@ -657,7 +667,7 @@ int regs_reg_init(srslte_regs_reg_t *reg, uint32_t symbol, uint32_t nreg, uint32 } break; default: - fprintf(stderr, "Invalid number of REGs per PRB: %d\n", maxreg); + ERROR("Invalid number of REGs per PRB: %d\n", maxreg); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; @@ -674,13 +684,19 @@ void srslte_regs_free(srslte_regs_t *h) { bzero(h, sizeof(srslte_regs_t)); } +int srslte_regs_init(srslte_regs_t* h, srslte_cell_t cell) +{ + return srslte_regs_init_opts(h, cell, 1, false); +} + /** * Initializes REGs structure. * Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs * Returns 0 if OK, -1 on error */ -int srslte_regs_init(srslte_regs_t *h, srslte_cell_t cell) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; +int srslte_regs_init_opts(srslte_regs_t* h, srslte_cell_t cell, uint32_t phich_mi, bool mbsfn_or_sf1_6_tdd) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; uint32_t i, k; uint32_t j[4], jmax, prb; uint32_t n[4], vo; @@ -721,7 +737,7 @@ int srslte_regs_init(srslte_regs_t *h, srslte_cell_t cell) { while (k < h->nof_regs) { if (n[i] == 3 || (n[i] == 2 && jmax != 1)) { if (regs_reg_init(&h->regs[k], i, j[i], prb * SRSLTE_NRE, n[i], vo)) { - fprintf(stderr, "Error initializing REGs\n"); + ERROR("Error initializing REGs\n"); goto clean_and_exit; } /*DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], @@ -742,16 +758,18 @@ int srslte_regs_init(srslte_regs_t *h, srslte_cell_t cell) { } } if (regs_pcfich_init(h)) { - fprintf(stderr, "Error initializing PCFICH REGs\n"); + ERROR("Error initializing PCFICH REGs\n"); goto clean_and_exit; } - - if (regs_phich_init(h)) { - fprintf(stderr, "Error initializing PHICH REGs\n"); - goto clean_and_exit; + h->phich_mi = phich_mi; + if (phich_mi > 0) { + if (regs_phich_init(h, phich_mi, mbsfn_or_sf1_6_tdd)) { + ERROR("Error initializing PHICH REGs\n"); + goto clean_and_exit; + } } if (regs_pdcch_init(h)) { - fprintf(stderr, "Error initializing PDCCH REGs\n"); + ERROR("Error initializing PDCCH REGs\n"); goto clean_and_exit; } diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index 8fab5198b..4be298f92 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -24,19 +24,18 @@ * */ +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" +#include "srslte/srslte.h" +#include +#include +#include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include "srslte/phy/phch/pdsch.h" -#include "srslte/phy/utils/bit.h" -#include "srslte/phy/utils/debug.h" -#include "srslte/phy/utils/vector.h" #define SRSLTE_PDSCH_MAX_TDEC_ITERS 10 @@ -100,20 +99,20 @@ int srslte_sch_init(srslte_sch_t *q) { bzero(q, sizeof(srslte_sch_t)); if (srslte_crc_init(&q->crc_tb, SRSLTE_LTE_CRC24A, 24)) { - fprintf(stderr, "Error initiating CRC\n"); + ERROR("Error initiating CRC\n"); goto clean; } if (srslte_crc_init(&q->crc_cb, SRSLTE_LTE_CRC24B, 24)) { - fprintf(stderr, "Error initiating CRC\n"); + ERROR("Error initiating CRC\n"); goto clean; } if (srslte_tcod_init(&q->encoder, SRSLTE_TCOD_MAX_LEN_CB)) { - fprintf(stderr, "Error initiating Turbo Coder\n"); + ERROR("Error initiating Turbo Coder\n"); goto clean; } if (srslte_tdec_init(&q->decoder, SRSLTE_TCOD_MAX_LEN_CB)) { - fprintf(stderr, "Error initiating Turbo Decoder\n"); + ERROR("Error initiating Turbo Decoder\n"); goto clean; } @@ -178,8 +177,9 @@ void srslte_sch_set_max_noi(srslte_sch_t *q, uint32_t max_iterations) { q->max_iterations = max_iterations; } -uint32_t srslte_sch_last_noi(srslte_sch_t *q) { - return q->nof_iterations; +float srslte_sch_last_noi(srslte_sch_t* q) +{ + return q->avg_iterations; } /* Encode a transport block according to 36.212 5.3.2 @@ -192,22 +192,17 @@ static int encode_tb_off(srslte_sch_t *q, { uint32_t i; uint32_t cb_len=0, rp=0, wp=0, rlen=0, n_e=0; - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - e_bits != NULL && - cb_segm != NULL && - softbuffer != NULL) - { - + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && e_bits != NULL && cb_segm != NULL && softbuffer != NULL) { + if (cb_segm->F) { - fprintf(stderr, "Error filler bits are not supported. Use standard TBS\n"); - return SRSLTE_ERROR; + ERROR("Error filler bits are not supported. Use standard TBS\n"); + return SRSLTE_ERROR; } if (cb_segm->C > softbuffer->max_cb) { - fprintf(stderr, "Error number of CB to encode (%d) exceeds soft buffer size (%d CBs)\n", cb_segm->C, - softbuffer->max_cb); + ERROR("Error number of CB to encode (%d) exceeds soft buffer size (%d CBs)\n", cb_segm->C, softbuffer->max_cb); return -1; } @@ -281,22 +276,23 @@ static int encode_tb_off(srslte_sch_t *q, if (srslte_rm_turbo_tx_lut(softbuffer->buffer_b[i], q->cb_in, q->parity_bits, &e_bits[(wp+w_offset)/8], cblen_idx, n_e, (wp+w_offset)%8, rv)) { - fprintf(stderr, "Error in rate matching\n"); + ERROR("Error in rate matching\n"); return SRSLTE_ERROR; } - + /* Set read/write pointers */ rp += rlen; wp += n_e; } INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); - ret = SRSLTE_SUCCESS; - } - return ret; + ret = SRSLTE_SUCCESS; + } else { + ERROR("Invalid parameters: e_bits=%d, cb_segm=%d, softbuffer=%d\n", e_bits != 0, cb_segm != 0, softbuffer != 0); + } + return ret; } - static int encode_tb(srslte_sch_t *q, srslte_softbuffer_tx_t *soft_buffer, srslte_cbsegm_t *cb_segm, uint32_t Qm, uint32_t rv, uint32_t nof_e_bits, @@ -315,11 +311,11 @@ bool decode_tb_cb(srslte_sch_t *q, int16_t *e_bits_s = e_bits; if (cb_segm->C > SRSLTE_MAX_CODEBLOCKS) { - fprintf(stderr, "Error SRSLTE_MAX_CODEBLOCKS=%d\n", SRSLTE_MAX_CODEBLOCKS); + ERROR("Error SRSLTE_MAX_CODEBLOCKS=%d\n", SRSLTE_MAX_CODEBLOCKS); return false; } - q->nof_iterations = 0; + q->avg_iterations = 0; for (int cb_idx=0;cb_idxC;cb_idx++) { @@ -344,12 +340,12 @@ bool decode_tb_cb(srslte_sch_t *q, if (q->llr_is_8bit) { if (srslte_rm_turbo_rx_lut_8bit(&e_bits_b[rp], (int8_t*) softbuffer->buffer_f[cb_idx], n_e2, cb_len_idx, rv)) { - fprintf(stderr, "Error in rate matching\n"); + ERROR("Error in rate matching\n"); return SRSLTE_ERROR; } } else { if (srslte_rm_turbo_rx_lut(&e_bits_s[rp], softbuffer->buffer_f[cb_idx], n_e2, cb_len_idx, rv)) { - fprintf(stderr, "Error in rate matching\n"); + ERROR("Error in rate matching\n"); return SRSLTE_ERROR; } } @@ -365,11 +361,11 @@ bool decode_tb_cb(srslte_sch_t *q, } else { srslte_tdec_iteration(&q->decoder, softbuffer->buffer_f[cb_idx], &data[cb_idx*rlen/8]); } - q->nof_iterations++; + q->avg_iterations++; cb_noi++; uint32_t len_crc; - srslte_crc_t *crc_ptr; + srslte_crc_t* crc_ptr; if (cb_segm->C > 1) { len_crc = cb_len; @@ -418,7 +414,7 @@ bool decode_tb_cb(srslte_sch_t *q, } } - q->nof_iterations /= cb_segm->C; + q->avg_iterations /= (float)cb_segm->C; return softbuffer->tb_crc; } @@ -435,10 +431,14 @@ bool decode_tb_cb(srslte_sch_t *q, * @param[out] data Decoded transport block * @return negative if error in parameters or CRC error in decoding */ -static int decode_tb(srslte_sch_t *q, - srslte_softbuffer_rx_t *softbuffer, srslte_cbsegm_t *cb_segm, - uint32_t Qm, uint32_t rv, uint32_t nof_e_bits, - int16_t *e_bits, uint8_t *data) +static int decode_tb(srslte_sch_t* q, + srslte_softbuffer_rx_t* softbuffer, + srslte_cbsegm_t* cb_segm, + uint32_t Qm, + uint32_t rv, + uint32_t nof_e_bits, + int16_t* e_bits, + uint8_t* data) { if (q != NULL && @@ -495,59 +495,92 @@ static int decode_tb(srslte_sch_t *q, return SRSLTE_ERROR; } } else { + ERROR("Missing inputs: data=%d, softbuffer=%d, e_bits=%d, cb_segm=%d\n", + data != 0, + softbuffer != 0, + e_bits != 0, + cb_segm != 0); return SRSLTE_ERROR_INVALID_INPUTS; } } -int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, uint8_t *data) { - return srslte_dlsch_decode2(q, cfg, softbuffer, e_bits, data, 0); +int srslte_dlsch_decode(srslte_sch_t* q, srslte_pdsch_cfg_t* cfg, int16_t* e_bits, uint8_t* data) +{ + return srslte_dlsch_decode2(q, cfg, e_bits, data, 0, 1); } - -int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - int16_t *e_bits, uint8_t *data, int tb_idx) { +int srslte_dlsch_decode2( + srslte_sch_t* q, srslte_pdsch_cfg_t* cfg, int16_t* e_bits, uint8_t* data, int tb_idx, uint32_t nof_layers) +{ uint32_t Nl = 1; - if (cfg->nof_layers != SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)) { + if (nof_layers != cfg->grant.nof_tb) { Nl = 2; } + // Prepare cbsegm + srslte_cbsegm_t cb_segm; + if (srslte_cbsegm(&cb_segm, (uint32_t)cfg->grant.tb[tb_idx].tbs)) { + ERROR("Error computing Codeword (%d) segmentation for TBS=%d\n", tb_idx, cfg->grant.tb[tb_idx].tbs); + return SRSLTE_ERROR; + } - return decode_tb(q, softbuffer, &cfg->cb_segm[tb_idx], - cfg->grant.Qm[tb_idx] * Nl, cfg->rv[tb_idx], cfg->nbits[tb_idx].nof_bits, - e_bits, data); + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb[tb_idx].mod); + + return decode_tb(q, + cfg->softbuffers.rx[tb_idx], + &cb_segm, + Qm * Nl, + cfg->grant.tb[tb_idx].rv, + cfg->grant.tb[tb_idx].nof_bits, + e_bits, + data); } /** * Encode transport block. Segments into code blocks, adds channel coding, and does rate matching. * - * @param[in] q Initialized + * @param[in] q Initialized * @param[in] cfg Encoding parameters * @param[inout] softbuffer Initialized softbuffer - * @param[in] data Byte array of data. Size is implicit in cfg->cb_segm + * @param[in] data Byte array of data. Size is implicit in cb_segm * @param e_bits * @return Error code */ -int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint8_t *e_bits) +int srslte_dlsch_encode(srslte_sch_t* q, srslte_pdsch_cfg_t* cfg, uint8_t* data, uint8_t* e_bits) { - return srslte_dlsch_encode2(q, cfg, softbuffer, data, e_bits, 0); + return srslte_dlsch_encode2(q, cfg, data, e_bits, 0, 1); } -int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint8_t *e_bits, int tb_idx) { +int srslte_dlsch_encode2( + srslte_sch_t* q, srslte_pdsch_cfg_t* cfg, uint8_t* data, uint8_t* e_bits, int tb_idx, uint32_t nof_layers) +{ uint32_t Nl = 1; - if (cfg->nof_layers != SRSLTE_RA_DL_GRANT_NOF_TB(&cfg->grant)) { + if (nof_layers != cfg->grant.nof_tb) { Nl = 2; } - return encode_tb(q, softbuffer, &cfg->cb_segm[tb_idx], cfg->grant.Qm[tb_idx]*Nl, cfg->rv[tb_idx], - cfg->nbits[tb_idx].nof_bits, data, e_bits); + // Prepare cbsegm + srslte_cbsegm_t cb_segm; + if (srslte_cbsegm(&cb_segm, (uint32_t)cfg->grant.tb[tb_idx].tbs)) { + ERROR("Error computing Codeword (%d) segmentation for TBS=%d\n", tb_idx, cfg->grant.tb[tb_idx].tbs); + return SRSLTE_ERROR; + } + + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb[tb_idx].mod); + + return encode_tb(q, + cfg->softbuffers.tx[tb_idx], + &cb_segm, + Qm * Nl, + cfg->grant.tb[tb_idx].rv, + cfg->grant.tb[tb_idx].nof_bits, + data, + e_bits); } /* Compute the interleaving function on-the-fly, because it depends on number of RI bits - * Profiling show that the computation of this matrix is neglegible. + * Profiling show that the computation of this matrix is neglegible. */ static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm, uint8_t *ri_present, uint32_t *interleaver_lut) @@ -598,7 +631,7 @@ static void ulsch_interleave_qm2(const uint8_t *g_bits, uint32_t rows, uint32_t uint32_t read_bit_idx = bit_read_idx % 8; uint32_t write_byte_idx = k / 8; uint32_t write_bit_idx = k % 8; - uint8_t w = (g_bits[read_byte_idx] >> (6 - read_bit_idx)) & (uint8_t) 0x03; + uint8_t w = (g_bits[read_byte_idx] >> (6 - read_bit_idx)) & (uint8_t)0x03; q_bits[write_byte_idx] |= w << (6 - write_bit_idx); bit_read_idx += 2; @@ -613,8 +646,8 @@ static void ulsch_interleave_qm4(uint8_t *g_bits, uint32_t rows, uint32_t cols, for (uint32_t j = 0; j < ri_min_row; j++) { int32_t i = 0; -#ifndef LV_HAVE_SSE - #ifndef HAVE_NEON +#ifdef DOES_NOT_WORK +#ifndef HAVE_NEON __m128i _counter = _mm_slli_epi32(_mm_add_epi32(_mm_mullo_epi32(_counter0,_rows),_mm_set1_epi32(j)), 2); uint8_t *_g_bits = &g_bits[bit_read_idx/8]; @@ -807,9 +840,14 @@ static void ulsch_interleave_qm6(const uint8_t *g_bits, } /* UL-SCH channel interleaver according to 5.2.2.8 of 36.212 */ -void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total, - uint32_t N_pusch_symbs, uint8_t *q_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits, - uint8_t *ri_present, uint32_t *inteleaver_lut) +static void ulsch_interleave(uint8_t* g_bits, + uint32_t Qm, + uint32_t H_prime_total, + uint32_t N_pusch_symbs, + uint8_t* q_bits, + srslte_uci_bit_t* ri_bits, + uint32_t nof_ri_bits, + uint8_t* ri_present) { const uint32_t nof_bits = H_prime_total * Qm; @@ -830,7 +868,6 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total, } } -#if 1 bzero(q_bits, nof_bits / 8); switch (Qm) { case 2: @@ -844,13 +881,8 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total, break; default: /* This line should never be reached */ - fprintf(stderr, "Wrong Qm (%d)\n", Qm); + ERROR("Wrong Qm (%d)\n", Qm); } -#else - // Genearate interleaver table and interleave bits - ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut); - srslte_bit_interleave_i(g_bits, q_bits, inteleaver_lut, H_prime_total*Qm); -#endif // Reset temp_buffer because will be reused next time if (nof_ri_bits > 0) { @@ -861,224 +893,310 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total, } /* UL-SCH channel deinterleaver according to 5.2.2.8 of 36.212 */ -void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total, - uint32_t N_pusch_symbs, int16_t *g_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits, - uint8_t *ri_present, uint32_t *inteleaver_lut) -{ +void ulsch_deinterleave(int16_t* q_bits, + uint32_t Qm, + uint32_t H_prime_total, + uint32_t N_pusch_symbs, + int16_t* g_bits, + srslte_uci_bit_t* ri_bits, + uint32_t nof_ri_bits, + uint8_t* ri_present, + uint32_t* inteleaver_lut) +{ // Prepare ri_bits for fast search using temp_buffer if (nof_ri_bits > 0) { - for (uint32_t i=0;i 0) { - for (uint32_t i=0;inbits.nof_bits; - uint32_t Qm = cfg->grant.Qm; + uint32_t Q_prime_ri = 0; + + uint32_t nb_q = cfg->grant.tb.nof_bits; + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); + + // If there is RI and CQI, assume RI = 1 for the purpose of RI/ACK decoding (3GPP 36.212 Clause 5.2.4.1. ) + if (cfg->uci_cfg.cqi.data_enable) { + if (cfg->uci_cfg.cqi.type == SRSLTE_CQI_TYPE_SUBBAND_HL && cfg->uci_cfg.cqi.ri_present) { + cfg->uci_cfg.cqi.rank_is_not_one = false; + } + } + + uint32_t cqi_len = srslte_cqi_size(&cfg->uci_cfg.cqi); - cfg->last_O_cqi = uci_data->uci_cqi_len; - // Deinterleave and decode HARQ bits - if (uci_data->uci_ack_len > 0) { - uint8_t acks[2] = {0, 0}; - float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; - if (cfg->cb_segm.tbs == 0) { - beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; + if (cfg->uci_cfg.ack.nof_acks > 0) { + float beta = beta_harq_offset[cfg->uci_offset.I_offset_ack]; + if (cfg->grant.tb.tbs == 0) { + beta /= beta_cqi_offset[cfg->uci_offset.I_offset_cqi]; } - ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len, false); + ret = srslte_uci_decode_ack_ri(cfg, + q_bits, + c_seq, + beta, + nb_q / Qm, + cqi_len, + q->ack_ri_bits, + uci_data->ack.ack_value, + cfg->uci_cfg.ack.nof_acks, + false); if (ret < 0) { - return ret; + return ret; } - uci_data->uci_ack = acks[0]; - uci_data->uci_ack_2 = acks[1]; - Q_prime_ack = (uint32_t) ret; + Q_prime_ack = (uint32_t)ret; // Set zeros to HARQ bits for (uint32_t i = 0; i < Q_prime_ack * Qm; i++) { q_bits[q->ack_ri_bits[i].position] = 0; } } - + // Deinterleave and decode RI bits - if (uci_data->uci_ri_len > 0) { - float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; - if (cfg->cb_segm.tbs == 0) { - beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; + if (cfg->uci_cfg.cqi.ri_len > 0) { + float beta = beta_ri_offset[cfg->uci_offset.I_offset_ri]; + if (cfg->grant.tb.tbs == 0) { + beta /= beta_cqi_offset[cfg->uci_offset.I_offset_cqi]; } - ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri, uci_data->uci_ri_len, true); + ret = srslte_uci_decode_ack_ri( + cfg, q_bits, c_seq, beta, nb_q / Qm, cqi_len, q->ack_ri_bits, &uci_data->ri, cfg->uci_cfg.cqi.ri_len, true); if (ret < 0) { - return ret; + return ret; } - Q_prime_ri = (uint32_t) ret; + Q_prime_ri = (uint32_t)ret; } - - q->nof_ri_ack_bits = Q_prime_ri; - - return SRSLTE_SUCCESS; + + // Now set correct RI + if (cfg->uci_cfg.cqi.data_enable) { + if (cfg->uci_cfg.cqi.type == SRSLTE_CQI_TYPE_SUBBAND_HL && cfg->uci_cfg.cqi.ri_present) { + cfg->uci_cfg.cqi.rank_is_not_one = uci_data->ri > 0; + } + } + + return Q_prime_ri; } -int srslte_ulsch_uci_decode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, - int16_t *q_bits, int16_t *g_bits, uint8_t *data, srslte_uci_data_t *uci_data) +int srslte_ulsch_decode(srslte_sch_t* q, + srslte_pusch_cfg_t* cfg, + int16_t* q_bits, + int16_t* g_bits, + uint8_t* c_seq, + uint8_t* data, + srslte_uci_value_t* uci_data) { - int ret = 0; - - uint32_t Q_prime_ri = q->nof_ri_ack_bits; - uint32_t Q_prime_cqi = 0; - uint32_t e_offset = 0; + int ret = SRSLTE_ERROR_INVALID_INPUTS; - uint32_t nb_q = cfg->nbits.nof_bits; - uint32_t Qm = cfg->grant.Qm; + // Prepare cbsegm + srslte_cbsegm_t cb_segm; + if (srslte_cbsegm(&cb_segm, (uint32_t)cfg->grant.tb.tbs)) { + ERROR("Error computing segmentation for TBS=%d\n", cfg->grant.tb.tbs); + return SRSLTE_ERROR; + } + + uint32_t nb_q = cfg->grant.tb.nof_bits; + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); + + cfg->K_segm = cb_segm.C1 * cb_segm.K1 + cb_segm.C2 * cb_segm.K2; + + // Decode RI/HARQ values + if ((ret = uci_decode_ri_ack(q, cfg, q_bits, c_seq, uci_data)) < 0) { + ERROR("Error decoding RI/HARQ bits\n"); + return SRSLTE_ERROR; + } + + uint32_t Q_prime_ri = (uint32_t)ret; + + /* + if (cfg->uci_cfg.cqi.data_enable) { + printf("deinter_input: Qm=%d, nb_q=%d, nof_symb=%d, Q_prime_ri=%d\n", Qm, nb_q, cfg->grant.nof_symb, Q_prime_ri); + }*/ + // Deinterleave data and CQI in ULSCH + ulsch_deinterleave(q_bits, + Qm, + nb_q / Qm, + cfg->grant.nof_symb, + g_bits, + q->ack_ri_bits, + Q_prime_ri * Qm, + q->temp_g_bits, + q->ul_interleaver); - // Deinterleave data and CQI in ULSCH - ulsch_deinterleave(q_bits, Qm, nb_q/Qm, cfg->nbits.nof_symb, g_bits, q->ack_ri_bits, Q_prime_ri*Qm, - q->temp_g_bits, q->ul_interleaver); - // Decode CQI (multiplexed at the front of ULSCH) - if (uci_data->uci_cqi_len > 0) { - ret = srslte_uci_decode_cqi_pusch(&q->uci_cqi, cfg, g_bits, - beta_cqi_offset[cfg->uci_cfg.I_offset_cqi], - Q_prime_ri, uci_data->uci_cqi_len, - uci_data->uci_cqi, &uci_data->cqi_ack); + uint32_t Q_prime_cqi = 0; + uint32_t e_offset = 0; + if (cfg->uci_cfg.cqi.data_enable) { + uint32_t cqi_len = srslte_cqi_size(&cfg->uci_cfg.cqi); + uint8_t cqi_buff[SRSLTE_CQI_MAX_BITS]; + ZERO_OBJECT(cqi_buff); + ret = srslte_uci_decode_cqi_pusch(&q->uci_cqi, + cfg, + g_bits, + beta_cqi_offset[cfg->uci_offset.I_offset_cqi], + Q_prime_ri, + cqi_len, + cqi_buff, + &uci_data->cqi.data_crc); if (ret < 0) { - return ret; + return ret; } - Q_prime_cqi = (uint32_t) ret; + srslte_cqi_value_unpack(&cfg->uci_cfg.cqi, cqi_buff, &uci_data->cqi); + Q_prime_cqi = (uint32_t)ret; } - - e_offset += Q_prime_cqi*Qm; - + + e_offset += Q_prime_cqi * Qm; + // Decode ULSCH - if (cfg->cb_segm.tbs > 0) { - uint32_t G = nb_q/Qm - Q_prime_ri - Q_prime_cqi; - ret = decode_tb(q, softbuffer, &cfg->cb_segm, - Qm, cfg->rv, G*Qm, - &g_bits[e_offset], data); - if (ret) { - return ret; - } + if (cb_segm.tbs > 0) { + uint32_t G = nb_q / Qm - Q_prime_ri - Q_prime_cqi; + ret = decode_tb(q, cfg->softbuffers.rx, &cb_segm, Qm, cfg->grant.tb.rv, G * Qm, &g_bits[e_offset], data); } - return SRSLTE_SUCCESS; + return ret; } -int srslte_ulsch_encode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, uint8_t *g_bits, uint8_t *q_bits) +int srslte_ulsch_encode(srslte_sch_t* q, + srslte_pusch_cfg_t* cfg, + uint8_t* data, + srslte_uci_value_t* uci_data, + uint8_t* g_bits, + uint8_t* q_bits) { - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - return srslte_ulsch_uci_encode(q, cfg, softbuffer, data, uci_data, g_bits, q_bits); -} + int ret; -int srslte_ulsch_uci_encode(srslte_sch_t *q, - srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, - uint8_t *data, srslte_uci_data_t uci_data, - uint8_t *g_bits, uint8_t *q_bits) -{ - int ret; - uint32_t e_offset = 0; uint32_t Q_prime_cqi = 0; uint32_t Q_prime_ack = 0; uint32_t Q_prime_ri = 0; - uint32_t nb_q = cfg->nbits.nof_bits; - uint32_t Qm = cfg->grant.Qm; + uint32_t nb_q = cfg->grant.tb.nof_bits; + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); if (Qm == 0) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (uci_data.uci_ri_len > 0) { - float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri]; - if (cfg->cb_segm.tbs == 0) { - beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; + // Prepare cbsegm + srslte_cbsegm_t cb_segm; + if (srslte_cbsegm(&cb_segm, (uint32_t)cfg->grant.tb.tbs)) { + ERROR("Error computing segmentation for TBS=%d\n", cfg->grant.tb.tbs); + return SRSLTE_ERROR; + } + + cfg->K_segm = cb_segm.C1 * cb_segm.K1 + cb_segm.C2 * cb_segm.K2; + + int uci_cqi_len = 0; + uint8_t cqi_buff[SRSLTE_CQI_MAX_BITS]; + ZERO_OBJECT(cqi_buff); + + if (cfg->uci_cfg.cqi.data_enable) { + uci_cqi_len = (uint32_t)srslte_cqi_value_pack(&cfg->uci_cfg.cqi, &uci_data->cqi, cqi_buff); + if (uci_cqi_len < 0) { + ERROR("Error encoding CQI bits\n"); + return SRSLTE_ERROR; + } + } + + if (cfg->uci_cfg.cqi.ri_len > 0) { + float beta = beta_ri_offset[cfg->uci_offset.I_offset_ri]; + if (cb_segm.tbs == 0) { + beta /= beta_cqi_offset[cfg->uci_offset.I_offset_cqi]; } - uint8_t ri[2] = {uci_data.uci_ri, 0}; - ret = srslte_uci_encode_ack_ri(cfg, ri, uci_data.uci_ri_len, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits, true); + uint8_t ri[2] = {uci_data->ri, 0}; + ret = srslte_uci_encode_ack_ri(cfg, + ri, + cfg->uci_cfg.cqi.ri_len, + (uint32_t)uci_cqi_len, + beta, + nb_q / Qm, + true, + cfg->uci_cfg.ack.N_bundle, + q->ack_ri_bits); if (ret < 0) { - return ret; + return ret; } - Q_prime_ri = (uint32_t) ret; + Q_prime_ri = (uint32_t)ret; } // Encode CQI - cfg->last_O_cqi = uci_data.uci_cqi_len; - if (uci_data.uci_cqi_len > 0) { - ret = srslte_uci_encode_cqi_pusch(&q->uci_cqi, cfg, - uci_data.uci_cqi, uci_data.uci_cqi_len, - beta_cqi_offset[cfg->uci_cfg.I_offset_cqi], - Q_prime_ri, q->temp_g_bits); + if (uci_cqi_len > 0) { + ret = srslte_uci_encode_cqi_pusch(&q->uci_cqi, + cfg, + cqi_buff, + (uint32_t)uci_cqi_len, + beta_cqi_offset[cfg->uci_offset.I_offset_cqi], + Q_prime_ri, + q->temp_g_bits); if (ret < 0) { return ret; } - Q_prime_cqi = (uint32_t) ret; + Q_prime_cqi = (uint32_t)ret; + + /* + if (Q_prime_cqi) { + printf("Encoding cqi Q=%d: ", Q_prime_cqi*Qm); + srslte_vec_fprint_b(stdout, q->temp_g_bits, Q_prime_cqi*Qm); + }*/ + srslte_bit_pack_vector(q->temp_g_bits, g_bits, Q_prime_cqi*Qm); // Reset the buffer because will be reused in ulsch_interleave - bzero(q->temp_g_bits, Q_prime_cqi*Qm); + bzero(q->temp_g_bits, Q_prime_cqi * Qm); } e_offset += Q_prime_cqi*Qm; // Encode UL-SCH - if (cfg->cb_segm.tbs > 0) { - uint32_t G = nb_q/Qm - Q_prime_ri - Q_prime_cqi; - ret = encode_tb_off(q, softbuffer, &cfg->cb_segm, - Qm, cfg->rv, G*Qm, - data, &g_bits[e_offset/8], e_offset%8); + if (cb_segm.tbs > 0) { + uint32_t G = nb_q / Qm - Q_prime_ri - Q_prime_cqi; + ret = encode_tb_off( + q, cfg->softbuffers.tx, &cb_segm, Qm, cfg->grant.tb.rv, G * Qm, data, &g_bits[e_offset / 8], e_offset % 8); if (ret) { return ret; } } // Interleave UL-SCH (and RI and CQI) - ulsch_interleave(g_bits, Qm, nb_q/Qm, cfg->nbits.nof_symb, q_bits, q->ack_ri_bits, Q_prime_ri*Qm, - q->temp_g_bits, q->ul_interleaver); - + ulsch_interleave(g_bits, Qm, nb_q / Qm, cfg->grant.nof_symb, q_bits, q->ack_ri_bits, Q_prime_ri * Qm, q->temp_g_bits); + // Encode (and interleave) ACK - if (uci_data.uci_ack_len > 0) { - uint8_t acks [2] = {uci_data.uci_ack, uci_data.uci_ack_2}; - float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack]; - if (cfg->cb_segm.tbs == 0) { - beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; + if (cfg->uci_cfg.ack.nof_acks > 0) { + float beta = beta_harq_offset[cfg->uci_offset.I_offset_ack]; + if (cb_segm.tbs == 0) { + beta /= beta_cqi_offset[cfg->uci_offset.I_offset_cqi]; } - ret = srslte_uci_encode_ack_ri(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len, - beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false); + ret = srslte_uci_encode_ack_ri(cfg, + uci_data->ack.ack_value, + cfg->uci_cfg.ack.nof_acks, + (uint32_t)uci_cqi_len, + beta, + nb_q / Qm, + false, + cfg->uci_cfg.ack.N_bundle, + &q->ack_ri_bits[Q_prime_ri * Qm]); if (ret < 0) { return ret; } Q_prime_ack = (uint32_t) ret; } - - q->nof_ri_ack_bits = (Q_prime_ack+Q_prime_ri)*Qm; - - for (uint32_t i=0;inof_ri_ack_bits;i++) { + + uint32_t nof_ri_ack_bits = (Q_prime_ack + Q_prime_ri) * Qm; + + for (uint32_t i = 0; i < nof_ri_ack_bits; i++) { uint32_t p = q->ack_ri_bits[i].position; if (p < nb_q) { if (q->ack_ri_bits[i].type == UCI_BIT_1) { @@ -1087,13 +1205,12 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q, q_bits[p/8] &= ~(1<<(7-p%8)); } } else { - fprintf(stderr, "Invalid RI/ACK bit position %d. Max bits=%d\n", p, nb_q); - } + ERROR("Invalid RI/ACK bit %d/%d, position %d. Max bits=%d, Qm=%d\n", i, nof_ri_ack_bits, p, nb_q, Qm); + } } - - - INFO("Q_prime_ack=%d, Q_prime_cqi=%d, Q_prime_ri=%d\n",Q_prime_ack, Q_prime_cqi, Q_prime_ri); - return SRSLTE_SUCCESS; + INFO("Q_prime_ack=%d, Q_prime_cqi=%d, Q_prime_ri=%d\n", Q_prime_ack, Q_prime_cqi, Q_prime_ri); + + return nof_ri_ack_bits; } diff --git a/lib/src/phy/phch/sequences.c b/lib/src/phy/phch/sequences.c index dc9e45a7f..aa6970555 100644 --- a/lib/src/phy/phch/sequences.c +++ b/lib/src/phy/phch/sequences.c @@ -76,7 +76,7 @@ int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, * 36.211 5.4.2 */ int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id) { - return srslte_sequence_LTE_pr(seq, 20, ((((nslot/2)+1)*(2*cell_id+1))<<16)+rnti); + return srslte_sequence_LTE_pr(seq, 12 * 4, ((((nslot / 2) + 1) * (2 * cell_id + 1)) << 16) + rnti); } int srslte_sequence_pmch(srslte_sequence_t *seq, uint32_t nslot, uint32_t mbsfn_id , uint32_t len){ diff --git a/lib/src/phy/phch/tbs_tables.h b/lib/src/phy/phch/tbs_tables.h index 40a9298e1..2f356c371 100644 --- a/lib/src/phy/phch/tbs_tables.h +++ b/lib/src/phy/phch/tbs_tables.h @@ -24,11 +24,6 @@ * */ -const int tbs_format1c_table[32] = { - 40, 56, 72, 120, 136, 144, 176, 208, 224, 256, 280, 296, 328, 336, 392, 488, - 552, 600, 632, 696, 776, 840, 904, 1000, 1064, 1128, 1224, 1288, 1384, 1480, 1608, 1736 -}; - /* Modulation and TBS index table for PDSCH from 3GPP TS 36.213 v10.3.0 table 7.1.7.1-1 */ const int dl_mcs_tbs_idx_table[29] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}; diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index c93770a84..15d945238 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -73,7 +73,19 @@ add_test(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) add_executable(pdcch_test pdcch_test.c) target_link_libraries(pdcch_test srslte_phy) -add_test(pdcch_test pdcch_test) +add_test(pdcch_test_6 pdcch_test -n 6) +add_test(pdcch_test_15 pdcch_test -n 15) +add_test(pdcch_test_25 pdcch_test -n 25) +add_test(pdcch_test_50 pdcch_test -n 50) +add_test(pdcch_test_75 pdcch_test -n 75) +add_test(pdcch_test_100 pdcch_test -n 100) +add_test(pdcch_test_6_mimo pdcch_test -n 6 -p 2) +add_test(pdcch_test_15_mimo pdcch_test -n 15 -p 2) +add_test(pdcch_test_25_mimo pdcch_test -n 25 -p 2) +add_test(pdcch_test_50_mimo pdcch_test -n 50 -p 2) +add_test(pdcch_test_75_mimo pdcch_test -n 75 -p 2) +add_test(pdcch_test_100_mimo pdcch_test -n 100 -p 2) +#add_test(pdcch_test_crosscarrier pdcch_test -x) ######################################################################## # PDSCH TEST @@ -87,93 +99,93 @@ add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100) add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100 -r 2) add_test(pdsch_test_qam64 pdsch_test -n 100) -# PDSCH test for single transmision mode and 2 Rx antennas -add_test(pdsch_test_sin_6 pdsch_test -x single -a 2 -n 6) -add_test(pdsch_test_sin_12 pdsch_test -x single -a 2 -n 12) -add_test(pdsch_test_sin_25 pdsch_test -x single -a 2 -n 25) -add_test(pdsch_test_sin_50 pdsch_test -x single -a 2 -n 50) -add_test(pdsch_test_sin_75 pdsch_test -x single -a 2 -n 75) -add_test(pdsch_test_sin_100 pdsch_test -x single -a 2 -n 100) - -# PDSCH test for transmit diversity transmision mode (1 codeword) -add_test(pdsch_test_div_6 pdsch_test -x diversity -a 2 -n 6) -add_test(pdsch_test_div_12 pdsch_test -x diversity -a 2 -n 12) -add_test(pdsch_test_div_25 pdsch_test -x diversity -a 2 -n 25) -add_test(pdsch_test_div_50 pdsch_test -x diversity -a 2 -n 50) -add_test(pdsch_test_div_75 pdsch_test -x diversity -a 2 -n 75) -add_test(pdsch_test_div_100 pdsch_test -x diversity -a 2 -n 100) +# PDSCH test for 1 transmision mode and 2 Rx antennas +add_test(pdsch_test_sin_6 pdsch_test -x 1 -a 2 -n 6) +add_test(pdsch_test_sin_12 pdsch_test -x 1 -a 2 -n 12) +add_test(pdsch_test_sin_25 pdsch_test -x 1 -a 2 -n 25) +add_test(pdsch_test_sin_50 pdsch_test -x 1 -a 2 -n 50) +add_test(pdsch_test_sin_75 pdsch_test -x 1 -a 2 -n 75) +add_test(pdsch_test_sin_100 pdsch_test -x 1 -a 2 -n 100) + +# PDSCH test for transmit 2 transmision mode (1 codeword) +add_test(pdsch_test_div_6 pdsch_test -x 2 -a 2 -n 6) +add_test(pdsch_test_div_12 pdsch_test -x 2 -a 2 -n 12) +add_test(pdsch_test_div_25 pdsch_test -x 2 -a 2 -n 25) +add_test(pdsch_test_div_50 pdsch_test -x 2 -a 2 -n 50) +add_test(pdsch_test_div_75 pdsch_test -x 2 -a 2 -n 75) +add_test(pdsch_test_div_100 pdsch_test -x 2 -a 2 -n 100) # PDSCH test for CDD transmision mode (2 codeword) -add_test(pdsch_test_cdd_6 pdsch_test -x cdd -a 2 -t 0 -n 6) -add_test(pdsch_test_cdd_12 pdsch_test -x cdd -a 2 -t 0 -n 12) -add_test(pdsch_test_cdd_25 pdsch_test -x cdd -a 2 -t 0 -n 25) -add_test(pdsch_test_cdd_50 pdsch_test -x cdd -a 2 -t 0 -n 50) -add_test(pdsch_test_cdd_75 pdsch_test -x cdd -a 2 -t 0 -n 75) -add_test(pdsch_test_cdd_100 pdsch_test -x cdd -a 2 -t 0 -n 100) +add_test(pdsch_test_cdd_6 pdsch_test -x 3 -a 2 -t 0 -n 6) +add_test(pdsch_test_cdd_12 pdsch_test -x 3 -a 2 -t 0 -n 12) +add_test(pdsch_test_cdd_25 pdsch_test -x 3 -a 2 -t 0 -n 25) +add_test(pdsch_test_cdd_50 pdsch_test -x 3 -a 2 -t 0 -n 50) +add_test(pdsch_test_cdd_75 pdsch_test -x 3 -a 2 -t 0 -n 75) +add_test(pdsch_test_cdd_100 pdsch_test -x 3 -a 2 -t 0 -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword) -add_test(pdsch_test_multiplex1cw_p0_6 pdsch_test -x multiplex -a 2 -p 0 -n 6) -add_test(pdsch_test_multiplex1cw_p0_12 pdsch_test -x multiplex -a 2 -p 0 -n 12) -add_test(pdsch_test_multiplex1cw_p0_25 pdsch_test -x multiplex -a 2 -p 0 -n 25) -add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x multiplex -a 2 -p 0 -n 50) -add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x multiplex -a 2 -p 0 -n 75) -add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x multiplex -a 2 -p 0 -n 100) +add_test(pdsch_test_multiplex1cw_p0_6 pdsch_test -x 4 -a 2 -p 0 -n 6) +add_test(pdsch_test_multiplex1cw_p0_12 pdsch_test -x 4 -a 2 -p 0 -n 12) +add_test(pdsch_test_multiplex1cw_p0_25 pdsch_test -x 4 -a 2 -p 0 -n 25) +add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x 4 -a 2 -p 0 -n 50) +add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x 4 -a 2 -p 0 -n 75) +add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x 4 -a 2 -p 0 -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword, swapped) -add_test(pdsch_test_multiplex1cw_p0_6_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 6 -F 1) -add_test(pdsch_test_multiplex1cw_p0_15_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 15) -add_test(pdsch_test_multiplex1cw_p0_25_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 25) -add_test(pdsch_test_multiplex1cw_p0_50_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 50) -add_test(pdsch_test_multiplex1cw_p0_75_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 75) -add_test(pdsch_test_multiplex1cw_p0_100_swap pdsch_test -x multiplex -a 2 -p 0 -m 0 -r 1 -M 28 -t 0 -n 100) +add_test(pdsch_test_multiplex1cw_p0_swap_6 pdsch_test -x 4 -a 2 -p 0 -w -n 6) +add_test(pdsch_test_multiplex1cw_p0_swap_12 pdsch_test -x 4 -a 2 -p 0 -w -n 12) +add_test(pdsch_test_multiplex1cw_p0_swap_25 pdsch_test -x 4 -a 2 -p 0 -w -n 25) +add_test(pdsch_test_multiplex1cw_p0_swap_50 pdsch_test -x 4 -a 2 -p 0 -w -n 50) +add_test(pdsch_test_multiplex1cw_p0_swap_75 pdsch_test -x 4 -a 2 -p 0 -w -n 75) +add_test(pdsch_test_multiplex1cw_p0_swap_100 pdsch_test -x 4 -a 2 -p 0 -w -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (1 codeword) -add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x multiplex -a 2 -p 1 -n 6) -add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x multiplex -a 2 -p 1 -n 12) -add_test(pdsch_test_multiplex1cw_p1_25 pdsch_test -x multiplex -a 2 -p 1 -n 25) -add_test(pdsch_test_multiplex1cw_p1_50 pdsch_test -x multiplex -a 2 -p 1 -n 50) -add_test(pdsch_test_multiplex1cw_p1_75 pdsch_test -x multiplex -a 2 -p 1 -n 75) -add_test(pdsch_test_multiplex1cw_p1_100 pdsch_test -x multiplex -a 2 -p 1 -n 100) +add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x 4 -a 2 -p 1 -n 6) +add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x 4 -a 2 -p 1 -n 12) +add_test(pdsch_test_multiplex1cw_p1_25 pdsch_test -x 4 -a 2 -p 1 -n 25) +add_test(pdsch_test_multiplex1cw_p1_50 pdsch_test -x 4 -a 2 -p 1 -n 50) +add_test(pdsch_test_multiplex1cw_p1_75 pdsch_test -x 4 -a 2 -p 1 -n 75) +add_test(pdsch_test_multiplex1cw_p1_100 pdsch_test -x 4 -a 2 -p 1 -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 2 (1 codeword) -add_test(pdsch_test_multiplex1cw_p2_6 pdsch_test -x multiplex -a 2 -p 2 -n 6) -add_test(pdsch_test_multiplex1cw_p2_12 pdsch_test -x multiplex -a 2 -p 2 -n 12) -add_test(pdsch_test_multiplex1cw_p2_25 pdsch_test -x multiplex -a 2 -p 2 -n 25) -add_test(pdsch_test_multiplex1cw_p2_50 pdsch_test -x multiplex -a 2 -p 2 -n 50) -add_test(pdsch_test_multiplex1cw_p2_75 pdsch_test -x multiplex -a 2 -p 2 -n 75) -add_test(pdsch_test_multiplex1cw_p2_100 pdsch_test -x multiplex -a 2 -p 2 -n 100) +add_test(pdsch_test_multiplex1cw_p2_6 pdsch_test -x 4 -a 2 -p 2 -n 6) +add_test(pdsch_test_multiplex1cw_p2_12 pdsch_test -x 4 -a 2 -p 2 -n 12) +add_test(pdsch_test_multiplex1cw_p2_25 pdsch_test -x 4 -a 2 -p 2 -n 25) +add_test(pdsch_test_multiplex1cw_p2_50 pdsch_test -x 4 -a 2 -p 2 -n 50) +add_test(pdsch_test_multiplex1cw_p2_75 pdsch_test -x 4 -a 2 -p 2 -n 75) +add_test(pdsch_test_multiplex1cw_p2_100 pdsch_test -x 4 -a 2 -p 2 -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 3 (1 codeword) -add_test(pdsch_test_multiplex1cw_p3_6 pdsch_test -x multiplex -a 2 -p 3 -n 6) -add_test(pdsch_test_multiplex1cw_p3_12 pdsch_test -x multiplex -a 2 -p 3 -n 12) -add_test(pdsch_test_multiplex1cw_p3_25 pdsch_test -x multiplex -a 2 -p 3 -n 25) -add_test(pdsch_test_multiplex1cw_p3_50 pdsch_test -x multiplex -a 2 -p 3 -n 50) -add_test(pdsch_test_multiplex1cw_p3_75 pdsch_test -x multiplex -a 2 -p 3 -n 75) -add_test(pdsch_test_multiplex1cw_p3_100 pdsch_test -x multiplex -a 2 -p 3 -n 100) +add_test(pdsch_test_multiplex1cw_p3_6 pdsch_test -x 4 -a 2 -p 3 -n 6) +add_test(pdsch_test_multiplex1cw_p3_12 pdsch_test -x 4 -a 2 -p 3 -n 12) +add_test(pdsch_test_multiplex1cw_p3_25 pdsch_test -x 4 -a 2 -p 3 -n 25) +add_test(pdsch_test_multiplex1cw_p3_50 pdsch_test -x 4 -a 2 -p 3 -n 50) +add_test(pdsch_test_multiplex1cw_p3_75 pdsch_test -x 4 -a 2 -p 3 -n 75) +add_test(pdsch_test_multiplex1cw_p3_100 pdsch_test -x 4 -a 2 -p 3 -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword) -add_test(pdsch_test_multiplex2cw_p0_6 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 6) -add_test(pdsch_test_multiplex2cw_p0_12 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 12) -add_test(pdsch_test_multiplex2cw_p0_25 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 25) -add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 50) -add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 75) -add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 100) +add_test(pdsch_test_multiplex2cw_p0_6 pdsch_test -x 4 -a 2 -t 0 -p 0 -n 6) +add_test(pdsch_test_multiplex2cw_p0_12 pdsch_test -x 4 -a 2 -t 0 -p 0 -n 12) +add_test(pdsch_test_multiplex2cw_p0_25 pdsch_test -x 4 -a 2 -t 0 -p 0 -n 25) +add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x 4 -a 2 -t 0 -p 0 -n 50) +add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x 4 -a 2 -t 0 -p 0 -n 75) +add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x 4 -a 2 -t 0 -p 0 -n 100) # PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword, swapped) -add_test(pdsch_test_multiplex2cw_p0_6_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -M 28 -n 6 -w -F 1) -add_test(pdsch_test_multiplex2cw_p0_12_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -m 28 -n 12 -w) -add_test(pdsch_test_multiplex2cw_p0_25_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -M 28 -n 25 -w) -add_test(pdsch_test_multiplex2cw_p0_50_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -m 28 -n 50 -w) -add_test(pdsch_test_multiplex2cw_p0_75_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -M 28 -n 75 -w) -add_test(pdsch_test_multiplex2cw_p0_100_swap pdsch_test -x multiplex -a 2 -t 0 -p 0 -m 28 -n 100 -w) +add_test(pdsch_test_multiplex2cw_p0_6_swap pdsch_test -x 4 -a 2 -t 0 -p 0 -M 28 -n 6 -w -F 1) +add_test(pdsch_test_multiplex2cw_p0_12_swap pdsch_test -x 4 -a 2 -t 0 -p 0 -m 28 -n 12 -w) +add_test(pdsch_test_multiplex2cw_p0_25_swap pdsch_test -x 4 -a 2 -t 0 -p 0 -M 28 -n 25 -w) +add_test(pdsch_test_multiplex2cw_p0_50_swap pdsch_test -x 4 -a 2 -t 0 -p 0 -m 28 -n 50 -w) +add_test(pdsch_test_multiplex2cw_p0_75_swap pdsch_test -x 4 -a 2 -t 0 -p 0 -M 28 -n 75 -w) +add_test(pdsch_test_multiplex2cw_p0_100_swap pdsch_test -x 4 -a 2 -t 0 -p 0 -m 28 -n 100 -w) # PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (2 codeword) -add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 6) -add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 12) -add_test(pdsch_test_multiplex2cw_p1_25 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 25) -add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 50) -add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75) -add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100) +add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x 4 -a 2 -t 0 -p 1 -n 6) +add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x 4 -a 2 -t 0 -p 1 -n 12) +add_test(pdsch_test_multiplex2cw_p1_25 pdsch_test -x 4 -a 2 -t 0 -p 1 -n 25) +add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x 4 -a 2 -t 0 -p 1 -n 50) +add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x 4 -a 2 -t 0 -p 1 -n 75) +add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x 4 -a 2 -t 0 -p 1 -n 100) ######################################################################## # PMCH TEST @@ -241,7 +253,7 @@ if (TEST_EXTENSION STREQUAL Paranoid) set(pusch_cqi none wideband) else (TEST_EXTENSION STREQUAL Paranoid) - set(cell_n_prb_valid 6 15 25 50 100) + set(cell_n_prb_valid 50) set(pusch_min_mcs 0) set(pusch_max_mcs 28) @@ -278,7 +290,7 @@ foreach (cell_n_prb 6 15 25 50 75 100) endif (NOT (${ack} EQUAL -1)) if (NOT (${cqi} STREQUAL none)) - set(pusch_test_args ${pusch_test_args} -p uci_cqi ${cqi}) + set(pusch_test_args ${pusch_test_args} -p cqi ${cqi}) #if (mcs EQUAL 28) # set(mcs 27) #endif (mcs EQUAL 28) @@ -314,11 +326,11 @@ target_link_libraries(prach_test srslte_phy) add_test(prach prach_test) -add_test(prach_256 prach_test -N 256) -add_test(prach_512 prach_test -N 512) -add_test(prach_1024 prach_test -N 1024) -add_test(prach_1536 prach_test -N 1536) -add_test(prach_2048 prach_test -N 2048) +add_test(prach_256 prach_test -n 15) +add_test(prach_512 prach_test -n 25) +add_test(prach_1024 prach_test -n 50) +add_test(prach_1536 prach_test -n 75) +add_test(prach_2048 prach_test -n 100) add_test(prach_f0 prach_test -f 0) add_test(prach_f1 prach_test -f 1) diff --git a/lib/src/phy/phch/test/dlsch_encode_test_mex.c b/lib/src/phy/phch/test/dlsch_encode_test_mex.c deleted file mode 100644 index c6181d9c5..000000000 --- a/lib/src/phy/phch/test/dlsch_encode_test_mex.c +++ /dev/null @@ -1,157 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -#define UECFG prhs[0] -#define PUSCHCFG prhs[1] -#define OUTLEN prhs[2] -#define TRBLKIN prhs[3] -#define NOF_INPUTS 4 - -void help() -{ - mexErrMsgTxt - ("[cwout] = srslte_dlsch_encode(ue, chs, outlen, trblkin)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - int i; - srslte_sch_t dlsch; - srslte_pdsch_cfg_t cfg; - srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS]; - uint32_t nof_codewords = 1; - - memset(&dlsch, 0, sizeof(srslte_sch_t)); - memset(&cfg, 0, sizeof(srslte_pdsch_cfg_t)); - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (srslte_sch_init(&dlsch)) { - mexErrMsgTxt("Error initiating DL-SCH\n"); - return; - } - srslte_cell_t cell; - cell.nof_prb = 100; - cell.id=1; - srslte_verbose = SRSLTE_VERBOSE_NONE; - - uint8_t *trblkin_bits = NULL; - cfg.grant.nof_tb = 1; - cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits); - if (cfg.grant.mcs.tbs == 0) { - mexErrMsgTxt("Error trblklen is zero\n"); - return; - } - uint8_t *trblkin = srslte_vec_malloc(cfg.grant.mcs.tbs/8); - srslte_bit_pack_vector(trblkin_bits, trblkin, cfg.grant.mcs.tbs); - free(trblkin_bits); - - if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &cfg.rv)) { - mexErrMsgTxt("Field RV not found in dlsch config\n"); - return; - } - - if (mexutils_read_uint32_struct(PUSCHCFG, "NLayers", &cfg.nof_layers)) { - mexErrMsgTxt("Field NLayers not found in dlsch config\n"); - return; - } - - char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); - - if (!strcmp(mod_str, "QPSK")) { - cfg.grant.mcs.mod = SRSLTE_MOD_QPSK; - cfg.grant.Qm = 2; - } else if (!strcmp(mod_str, "16QAM")) { - cfg.grant.mcs.mod = SRSLTE_MOD_16QAM; - cfg.grant.Qm = 4; - } else if (!strcmp(mod_str, "64QAM")) { - cfg.grant.mcs.mod = SRSLTE_MOD_64QAM; - cfg.grant.Qm = 6; - } else { - mexErrMsgTxt("Unknown modulation\n"); - return; - } - - mxFree(mod_str); - - /* Initialise buffers */ - for (i = 0; i < nof_codewords; i++) { - if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) { - mexErrMsgTxt("Error initiating DL-SCH soft buffer\n"); - return; - } - } - - cfg.nbits.nof_bits = mxGetScalar(OUTLEN); - uint8_t *e_bits = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)); - if (!e_bits) { - return; - } - if (srslte_cbsegm(&cfg.cb_segm, cfg.grant.mcs.tbs)) { - mexErrMsgTxt("Error computing CB segmentation\n"); - return; - } - uint32_t tmp_rv=cfg.rv; - if (tmp_rv) { - cfg.rv = 0; - if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) { - mexErrMsgTxt("Error encoding TB\n"); - return; - } - cfg.rv = tmp_rv; - } - if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) { - mexErrMsgTxt("Error encoding TB\n"); - return; - } - uint8_t *e_bits_unpacked = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)); - if (!e_bits_unpacked) { - return; - } - srslte_bit_unpack_vector(e_bits, e_bits_unpacked, cfg.nbits.nof_bits); - if (nlhs >= 1) { - mexutils_write_uint8(e_bits_unpacked, &plhs[0], cfg.nbits.nof_bits, 1); - } - - srslte_sch_free(&dlsch); - - free(trblkin); - free(e_bits); - free(e_bits_unpacked); - for (i = 0; i < nof_codewords; i++) { - srslte_softbuffer_tx_free(&softbuffers[i]); - } - return; -} - diff --git a/lib/src/phy/phch/test/pbch_file_test.c b/lib/src/phy/phch/test/pbch_file_test.c index 2f750f1cc..cedf9d931 100644 --- a/lib/src/phy/phch/test/pbch_file_test.c +++ b/lib/src/phy/phch/test/pbch_file_test.c @@ -35,12 +35,14 @@ char *input_file_name = NULL; srslte_cell_t cell = { - 6, // nof_prb - 2, // nof_ports - 150, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 6, // nof_prb + 2, // nof_ports + 150, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1, // PHICH resources + SRSLTE_FDD, + }; int nof_frames = 1; @@ -50,10 +52,11 @@ uint8_t bch_payload_file[SRSLTE_BCH_PAYLOAD_LEN] = {0, 1, 1, 0, 1, 0, 0, 0, 0, 0 #define FLEN (10*SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))) srslte_filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[SRSLTE_MAX_PORTS]; +cf_t * input_buffer, *fft_buffer[SRSLTE_MAX_CODEWORDS]; srslte_pbch_t pbch; srslte_ofdm_t fft; srslte_chest_dl_t chest; +srslte_chest_dl_res_t chest_res; void usage(char *prog) { printf("Usage: %s [vcoe] -i input_file\n", prog); @@ -99,10 +102,9 @@ void parse_args(int argc, char **argv) { } int base_init() { - int i; if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); + ERROR("Error opening file %s\n", input_file_name); exit(-1); } @@ -112,45 +114,47 @@ int base_init() { exit(-1); } - fft_buffer = malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - if (!fft_buffer) { + fft_buffer[0] = malloc(SRSLTE_NOF_RE(cell) * sizeof(cf_t)); + if (!fft_buffer[0]) { perror("malloc"); return -1; } - for (i=0;i 0 && frame_cnt < nof_frames); diff --git a/lib/src/phy/phch/test/pbch_test.c b/lib/src/phy/phch/test/pbch_test.c index dd2e4106e..039e23657 100644 --- a/lib/src/phy/phch/test/pbch_test.c +++ b/lib/src/phy/phch/test/pbch_test.c @@ -34,12 +34,14 @@ #include "srslte/srslte.h" srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 6, // nof_prb + 1, // nof_ports + 1, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1, // PHICH resources + SRSLTE_FDD, + }; void usage(char *prog) { @@ -73,43 +75,41 @@ void parse_args(int argc, char **argv) { } } - -int main(int argc, char **argv) { - srslte_pbch_t pbch; +int main(int argc, char** argv) +{ + srslte_chest_dl_res_t chest_dl_res; + srslte_pbch_t pbch; uint8_t bch_payload_tx[SRSLTE_BCH_PAYLOAD_LEN], bch_payload_rx[SRSLTE_BCH_PAYLOAD_LEN]; - int i, j; - cf_t *ce[SRSLTE_MAX_PORTS]; - int nof_re; - cf_t *slot1_symbols[SRSLTE_MAX_PORTS]; - uint32_t nof_rx_ports; + int i, j, k; + int nof_re; + cf_t* sf_symbols[SRSLTE_MAX_PORTS]; + uint32_t nof_rx_ports; parse_args(argc,argv); - nof_re = SRSLTE_SLOT_LEN_RE(cell.nof_prb, SRSLTE_CP_NORM); + nof_re = SRSLTE_SF_LEN_RE(cell.nof_prb, SRSLTE_CP_NORM); /* init memory */ - for (i=0;i -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define INPUT prhs[1] -#define NOF_INPUTS 2 - -void help() -{ - mexErrMsgTxt - ("[decoded_ok, symbols, bits] = srslte_pbch(enbConfig, rxWaveform)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - int i; - srslte_cell_t cell; - srslte_pbch_t pbch; - srslte_chest_dl_t chest; - srslte_ofdm_t ofdm_rx; - cf_t *input_fft = NULL; - cf_t *ce[SRSLTE_MAX_PORTS], *ce_slot[SRSLTE_MAX_PORTS]; - - srslte_verbose = SRSLTE_VERBOSE_DEBUG; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - // Allocate memory - for (i=0;i NOF_INPUTS) { - cf_t *cearray = NULL; - mexutils_read_cf(prhs[NOF_INPUTS], &cearray); - cf_t *cearray_ptr = cearray; - for (i=0;i NOF_INPUTS + 1) { - noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); - } else if (nrhs > NOF_INPUTS) { - noise_power = 0; - } else { - noise_power = srslte_chest_dl_get_noise_estimate(&chest); - } - - n = srslte_pbch_decode(&pbch, &input_fft[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)], - ce_slot, noise_power, - NULL, &nof_ports, &sfn_offset); - } - - if (nlhs >= 1) { - if (n == 1) { - plhs[0] = mxCreateDoubleScalar(nof_ports); - } else { - plhs[0] = mxCreateDoubleScalar(0); - } - } - if (nlhs >= 2) { - mexutils_write_cf(pbch.d, &plhs[1], pbch.nof_symbols, 1); - } - if (nlhs >= 3) { - mexutils_write_f(pbch.temp, &plhs[2], 4*2*pbch.nof_symbols, 1); - } - if (nlhs >= 4) { - mexutils_write_cf(ce[0], &plhs[3], SRSLTE_SF_LEN_RE(cell.nof_prb,cell.cp)/14, 14); - } - if (nlhs >= 5) { - mexutils_write_cf(ce[1], &plhs[4], SRSLTE_SF_LEN_RE(cell.nof_prb,cell.cp)/14, 14); - } - if (nlhs >= 6) { - mexutils_write_cf(pbch.symbols[0], &plhs[5], pbch.nof_symbols, 1); - } - if (nlhs >= 7) { - mexutils_write_cf(pbch.ce[0], &plhs[6], pbch.nof_symbols, 1); - } - if (nlhs >= 8) { - plhs[7] = mxCreateDoubleScalar(sfn_offset); - } - if (nlhs >= 9) { - mexutils_write_f(pbch.rm_f, &plhs[8], 120, 1); - } - - srslte_chest_dl_free(&chest); - srslte_ofdm_rx_free(&ofdm_rx); - srslte_pbch_free(&pbch); - - for (i=0;i 2.8 && cfi == 1) { + if (cfi_corr > 2.8 && dl_sf.cfi == 2) { exit(0); } else { exit(-1); diff --git a/lib/src/phy/phch/test/pcfich_test.c b/lib/src/phy/phch/test/pcfich_test.c index ea821a8d0..1a428972f 100644 --- a/lib/src/phy/phch/test/pcfich_test.c +++ b/lib/src/phy/phch/test/pcfich_test.c @@ -32,14 +32,15 @@ #include "srslte/srslte.h" - srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1000, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 6, // nof_prb + 1, // nof_ports + 1000, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1, // PHICH resources + SRSLTE_FDD, + }; void usage(char *prog) { @@ -73,32 +74,28 @@ void parse_args(int argc, char **argv) { } } - -int main(int argc, char **argv) { - srslte_pcfich_t pcfich; - srslte_regs_t regs; +int main(int argc, char** argv) +{ + srslte_chest_dl_res_t chest_res; + srslte_pcfich_t pcfich; + srslte_regs_t regs; int i, j; - cf_t *ce[SRSLTE_MAX_PORTS]; int nof_re; cf_t *slot_symbols[SRSLTE_MAX_PORTS]; - uint32_t cfi, cfi_rx, nsf; + uint32_t cfi, nsf; int cid, max_cid; - float corr_res; + float corr_res; parse_args(argc,argv); nof_re = SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE; /* init memory */ - for (i=0;i -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define INPUT prhs[1] -#define NOF_INPUTS 2 - -void help() -{ - mexErrMsgTxt - ("[cfi] = srslte_pcfich(enbConfig, rxWaveform)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - int i; - srslte_cell_t cell; - srslte_pcfich_t pcfich; - srslte_chest_dl_t chest; - srslte_ofdm_t ofdm_rx; - srslte_regs_t regs; - uint32_t sf_idx; - cf_t *input_fft, *input_signal; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &sf_idx)) { - help(); - return; - } - - if (srslte_chest_dl_init(&chest, cell)) { - mexErrMsgTxt("Error initializing equalizer\n"); - return; - } - - if (srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb)) { - mexErrMsgTxt("Error initializing FFT\n"); - return; - } - - if (srslte_regs_init(®s, cell)) { - mexErrMsgTxt("Error initiating regs\n"); - return; - } - - if (srslte_pcfich_init(&pcfich, ®s, cell)) { - mexErrMsgTxt("Error creating PBCH object\n"); - return; - } - -// Read input signal - input_signal = NULL; - int insignal_len = mexutils_read_cf(INPUT, &input_signal); - if (insignal_len < 0) { - mexErrMsgTxt("Error reading input signal\n"); - return; - } - if (insignal_len == SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)) { - input_fft = input_signal; - } else { - input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - srslte_ofdm_rx_sf(&ofdm_rx, input_signal, input_fft); - free(input_signal); - } - - cf_t *ce[SRSLTE_MAX_PORTS]; - for (i=0;i NOF_INPUTS) { - cf_t *cearray = NULL; - mexutils_read_cf(prhs[NOF_INPUTS], &cearray); - cf_t *cearray_ptr = cearray; - for (i=0;i NOF_INPUTS + 1) { - noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); - } else if (nrhs > NOF_INPUTS) { - noise_power = 0; - } else { - noise_power = srslte_chest_dl_get_noise_estimate(&chest); - } - - - uint32_t cfi; - float corr_res; - int n = srslte_pcfich_decode(&pcfich, input_fft, ce, noise_power, sf_idx, &cfi, &corr_res); - - if (nlhs >= 1) { - if (n < 0) { - plhs[0] = mxCreateDoubleScalar(-1); - } else { - plhs[0] = mxCreateDoubleScalar(cfi); - } - } - if (nlhs >= 2) { - mexutils_write_cf(pcfich.d, &plhs[1], 16, 1); - } - if (nlhs >= 3) { - mexutils_write_cf(pcfich.symbols[0], &plhs[2], 16, 1); - } - if (nlhs >= 4) { - mexutils_write_cf(ce[0], &plhs[3], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); - } - - srslte_chest_dl_free(&chest); - srslte_ofdm_rx_free(&ofdm_rx); - srslte_pcfich_free(&pcfich); - srslte_regs_free(®s); - - for (i=0;i #include #include -#include -#include -#include -#include #include "srslte/srslte.h" @@ -47,21 +43,23 @@ srslte_cell_t cell = { uint32_t cfi = 1; uint32_t nof_rx_ant = 1; bool print_dci_table; +srslte_dci_cfg_t dci_cfg = {}; void usage(char *prog) { - printf("Usage: %s [cfpndv]\n", prog); + printf("Usage: %s [cfpndxv]\n", prog); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-f cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); printf("\t-A nof_rx_ant [Default %d]\n", nof_rx_ant); printf("\t-d Print DCI table [Default %s]\n", print_dci_table?"yes":"no"); + printf("\t-x Enable/Disable Cross-scheduling [Default %s]\n", dci_cfg.cif_enabled ? "enabled" : "disabled"); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "cfpndvA")) != -1) { + while ((opt = getopt(argc, argv, "cfpndvAx")) != -1) { switch (opt) { case 'p': cell.nof_ports = (uint32_t) atoi(argv[optind]); @@ -81,6 +79,9 @@ void parse_args(int argc, char **argv) { case 'd': print_dci_table = true; break; + case 'x': + dci_cfg.cif_enabled ^= true; + break; case 'v': srslte_verbose++; break; @@ -99,16 +100,29 @@ int test_dci_payload_size() { const int dci_sz[6][5] = { { 21, 19, 21, 8, 28 }, { 22, 23, 22, 10 , 31}, { 25, 27, 25, 12 , 36}, { 27, 31, 27, 13 , 41}, { 27, 33, 27, 14 , 42}, { 28, 39, 28, 15, 48 }}; + srslte_dl_sf_cfg_t dl_sf; + ZERO_OBJECT(dl_sf); + + srslte_cell_t cell_test; + ZERO_OBJECT(cell_test); + cell_test.nof_ports = 1; + + ZERO_OBJECT(dci_cfg); printf("Testing DCI payload sizes...\n"); printf(" PRB\t0\t1\t1A\t1C\t2A\n"); for (i = 0; i < 6; i++) { int n = prb[i]; + cell_test.nof_prb = n; + for (j = 0; j < 5; j++) { - x[j] = srslte_dci_format_sizeof(formats[j], (uint32_t) n, 1); + x[j] = srslte_dci_format_sizeof(&cell_test, &dl_sf, &dci_cfg, formats[j]); if (x[j] != dci_sz[i][j]) { - fprintf(stderr, "Invalid DCI payload size for %s\n", - srslte_dci_format_string(formats[j])); + ERROR("Invalid DCI payload size for %s and %d PRB. Is %d and should be %d\n", + srslte_dci_format_string(formats[j]), + n, + x[j], + dci_sz[i][j]); return -1; } } @@ -120,8 +134,9 @@ int test_dci_payload_size() { printf("dci_sz_table[101][4] = {\n"); for (i=0;i<=100;i++) { printf(" {"); - for (j=0;j<4;j++) { - printf("%d",srslte_dci_format_sizeof(formats[j], (uint32_t) i, 1)); + for (j = 0; j < 4; j++) { + cell_test.nof_prb = i; + printf("%d", srslte_dci_format_sizeof(&cell, &dl_sf, &dci_cfg, formats[j])); if (j<3) { printf(", "); } @@ -140,20 +155,21 @@ int test_dci_payload_size() { typedef struct { srslte_dci_msg_t dci_tx, dci_rx; srslte_dci_location_t dci_location; - srslte_dci_format_t dci_format; - srslte_ra_dl_dci_t ra_dl_tx; - srslte_ra_dl_dci_t ra_dl_rx; + srslte_dci_format_t dci_format; + srslte_dci_dl_t ra_dl_tx; + srslte_dci_dl_t ra_dl_rx; } testcase_dci_t; -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ + + srslte_chest_dl_res_t chest_dl_res; srslte_pdcch_t pdcch_tx, pdcch_rx; testcase_dci_t testcases[10]; - srslte_ra_dl_dci_t ra_dl; srslte_regs_t regs; - int i, j, k; - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + int i; int nof_re; - cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS]; + cf_t *slot_symbols[SRSLTE_MAX_PORTS]; int nof_dcis; bzero(&testcases, sizeof(testcase_dci_t)*10); @@ -169,175 +185,210 @@ int main(int argc, char **argv) { } /* init memory */ - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - for (j = 0; j < SRSLTE_MAX_PORTS; j++) { - ce[i][j] = malloc(sizeof(cf_t) * nof_re); - if (!ce[i][j]) { - perror("malloc"); - exit(-1); - } - for (k = 0; k < nof_re; k++) { - //ce[i][j][k] = (i == j) ? 1 : 0; - ce[i][j][k] = ((float)rand()/(float)RAND_MAX) + _Complex_I*((float)rand()/(float)RAND_MAX); - } - } - tx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); - if (!tx_slot_symbols[i]) { - perror("malloc"); - exit(-1); - } - bzero(tx_slot_symbols[i], sizeof(cf_t) * nof_re); - rx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); - if (!rx_slot_symbols[i]) { + srslte_chest_dl_res_init(&chest_dl_res, cell.nof_prb); + srslte_chest_dl_res_set_identity(&chest_dl_res); + + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); + if (!slot_symbols[i]) { perror("malloc"); exit(-1); } - bzero(rx_slot_symbols[i], sizeof(cf_t) * nof_re); + bzero(slot_symbols[i], sizeof(cf_t) * nof_re); } if (srslte_regs_init(®s, cell)) { - fprintf(stderr, "Error initiating regs\n"); + ERROR("Error initiating regs\n"); exit(-1); } if (srslte_pdcch_init_enb(&pdcch_tx, cell.nof_prb)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); exit(-1); } if (srslte_pdcch_set_cell(&pdcch_tx, ®s, cell)) { - fprintf(stderr, "Error setting cell in PDCCH object\n"); + ERROR("Error setting cell in PDCCH object\n"); exit(-1); } if (srslte_pdcch_init_ue(&pdcch_rx, cell.nof_prb, nof_rx_ant)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); exit(-1); } if (srslte_pdcch_set_cell(&pdcch_rx, ®s, cell)) { - fprintf(stderr, "Error setting cell in PDCCH object\n"); + ERROR("Error setting cell in PDCCH object\n"); exit(-1); } /* Resource allocate init */ nof_dcis = 0; - bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); - ra_dl.harq_process = 0; - ra_dl.mcs_idx = 5; - ra_dl.ndi = 0; - ra_dl.rv_idx = 0; - ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; - ra_dl.type0_alloc.rbg_bitmask = 0x5; - ra_dl.tb_en[0] = true; + srslte_dci_dl_t dci; + ZERO_OBJECT(dci); + dci.pid = 5; + dci.tb[0].mcs_idx = 5; + dci.tb[0].ndi = 0; + dci.tb[0].rv = 1; + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci.type0_alloc.rbg_bitmask = 0x5; + dci.cif_present = dci_cfg.cif_enabled; + if (dci_cfg.cif_enabled) { + dci.cif = (uint32_t)(random() & 0x7); + } /* Format 1 Test case */ - testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; - testcases[nof_dcis].ra_dl_tx = ra_dl; - nof_dcis++; + if (cell.nof_ports == 1) { + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; + if (dci_cfg.cif_enabled) { + dci.cif = (uint32_t)(random() & 0x7); + } + testcases[nof_dcis].ra_dl_tx = dci; + nof_dcis++; - /* Format 1 Test case */ - ra_dl.mcs_idx = 15; - testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; - testcases[nof_dcis].ra_dl_tx = ra_dl; - nof_dcis++; + /* Format 1 Test case */ + dci.tb[0].mcs_idx = 15; + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; + if (dci_cfg.cif_enabled) { + dci.cif = (uint32_t)(random() & 0x7); + } + testcases[nof_dcis].ra_dl_tx = dci; + nof_dcis++; + } /* Tx Diversity Test case */ if (cell.nof_ports > 1) { - ra_dl.mcs_idx_1 = 0; - ra_dl.rv_idx_1 = 0; - ra_dl.ndi_1 = false; - ra_dl.tb_en[1] = false; + dci.tb[1].mcs_idx = 13; + dci.tb[1].rv = 3; + dci.tb[1].ndi = true; testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A; - testcases[nof_dcis].ra_dl_tx = ra_dl; + if (dci_cfg.cif_enabled) { + dci.cif = (uint32_t)(random() & 0x7); + } + testcases[nof_dcis].ra_dl_tx = dci; nof_dcis++; } /* CDD Spatial Multiplexing Test case */ if (cell.nof_ports > 1) { - ra_dl.mcs_idx_1 = 28; - ra_dl.rv_idx_1 = 1; - ra_dl.ndi_1 = false; - ra_dl.tb_en[1] = true; - testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A; - testcases[nof_dcis].ra_dl_tx = ra_dl; + dci.tb[1].mcs_idx = 28; + dci.tb[1].rv = 1; + dci.tb[1].ndi = false; + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2; + if (dci_cfg.cif_enabled) { + dci.cif = (uint32_t)(random() & 0x7); + } + testcases[nof_dcis].ra_dl_tx = dci; nof_dcis++; } - /* Execute Rx */ - for (i=0;i= 1234 && crc_rem < 1234 + nof_dcis) { - crc_rem -= 1234; - } else { - printf("Received invalid DCI CRC 0x%x\n", crc_rem); + + /* Execute 'Rx' */ + if (srslte_pdcch_extract_llr(&pdcch_rx, &dl_sf, &chest_dl_res, slot_symbols)) { + ERROR("Error extracting LLRs\n"); goto quit; } - } - /* Compare Tx and Rx */ - for (i = 0; i < nof_dcis; i++) { - if (memcmp(testcases[i].dci_tx.data, testcases[i].dci_rx.data, testcases[i].dci_tx.nof_bits)) { - printf("Error in DCI %d: Received data does not match\n", i); - goto quit; + /* Decode DCIs */ + for (i=0;i= 1234 && testcases[i].dci_rx.rnti < 1234 + nof_dcis) { + testcases[i].dci_rx.rnti -= 1234; + } else { + printf("Received invalid DCI CRC %d\n", testcases[i].dci_rx.rnti); + goto quit; + } } - if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srslte_ra_dl_dci_t))) { - printf("Error in RA %d: Received data does not match\n", i); - printf(" Field | Tx | Rx \n"); - printf("--------------+----------+----------\n"); - printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.harq_process, testcases[i].ra_dl_rx.harq_process); - printf(" mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx, testcases[i].ra_dl_rx.mcs_idx); - printf(" rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx, testcases[i].ra_dl_rx.rv_idx); - printf(" ndi | %8d | %8d\n", testcases[i].ra_dl_tx.ndi, testcases[i].ra_dl_rx.ndi); - printf(" mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx_1, testcases[i].ra_dl_rx.mcs_idx_1); - printf(" rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx_1, testcases[i].ra_dl_rx.rv_idx_1); - printf(" ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.ndi_1, testcases[i].ra_dl_rx.ndi_1); - printf(" tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap); - printf(" sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id); - printf(" pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo); - printf(" pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf); - printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset); - printf(" tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch); - printf(" tb_en[0] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[0], testcases[i].ra_dl_rx.tb_en[0]); - printf(" tb_en[1] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[1], testcases[i].ra_dl_rx.tb_en[1]); - printf(" dci_is_1a | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1a, testcases[i].ra_dl_rx.dci_is_1a); - printf(" dci_is_1c | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1c, testcases[i].ra_dl_rx.dci_is_1c); - goto quit; + + /* Compare Tx and Rx */ + for (i = 0; i < nof_dcis; i++) { + if (memcmp(testcases[i].dci_tx.payload, testcases[i].dci_rx.payload, testcases[i].dci_tx.nof_bits)) { + printf("Error in DCI %d: Received data does not match\n", i); + goto quit; + } +#if SRSLTE_DCI_HEXDEBUG + // Ignore Hex str + bzero(testcases[i].ra_dl_rx.hex_str, sizeof(testcases[i].ra_dl_rx.hex_str)); + testcases[i].ra_dl_rx.nof_bits = 0; +#endif + // Ignore DCI location + testcases[i].ra_dl_rx.location = testcases[i].ra_dl_tx.location; + // Ignore cw_idx + for (int j=0;j -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define RNTI prhs[1] -#define AMP prhs[2] -#define INPUT prhs[3] -#define NOF_INPUTS 4 - - - -srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1,SRSLTE_DCI_FORMAT2B}; // SRSLTE_DCI_FORMAT1B should go here also -const uint32_t nof_ue_formats = 3; - -srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; -const uint32_t nof_common_formats = 2; - - -void help() -{ - mexErrMsgTxt - ("[decoded_ok, llr, rm, bits, symbols] = srslte_pdcch(enbConfig, RNTI, rxWaveform)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - int i; - srslte_cell_t cell; - srslte_pdcch_t pdcch; - srslte_chest_dl_t chest; - srslte_ofdm_t ofdm_rx; - srslte_regs_t regs; - srslte_dci_location_t locations[MAX_CANDIDATES]; - uint32_t cfi, sf_idx; - uint16_t rnti; - cf_t *input_fft, *input_signal; - int nof_re; - uint32_t nof_formats; - srslte_dci_format_t *formats = NULL; - - srslte_verbose = SRSLTE_VERBOSE_DEBUG; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - if (mexutils_read_uint32_struct(ENBCFG, "CFI", &cfi)) { - help(); - return; - } - if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &sf_idx)) { - help(); - return; - } - - if (srslte_chest_dl_init(&chest, cell)) { - fprintf(stderr, "Error initializing equalizer\n"); - return; - } - - if (srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); - return; - } - - rnti = (uint16_t) mxGetScalar(RNTI); - - if (srslte_regs_init(®s, cell)) { - mexErrMsgTxt("Error initiating regs\n"); - return; - } - - if (srslte_regs_set_cfi(®s, cfi)) { - fprintf(stderr, "Error setting CFI\n"); - exit(-1); - } - - if (srslte_pdcch_init(&pdcch, ®s, cell)) { - mexErrMsgTxt("Error initiating channel estimator\n"); - return; - } - - // Read input signal - int insignal_len = mexutils_read_cf(INPUT, &input_signal); - if (insignal_len < 0) { - mexErrMsgTxt("Error reading input signal\n"); - return; - } - if (insignal_len == SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)) { - input_fft = input_signal; - mexPrintf("Input is freq domain\n"); - } else { - input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - srslte_ofdm_rx_sf(&ofdm_rx, input_signal, input_fft); - free(input_signal); - mexPrintf("Input is time domain\n"); - } - - cf_t *ce[SRSLTE_MAX_PORTS]; - for (i=0;i NOF_INPUTS) { - cf_t *cearray = NULL; - nof_re = mexutils_read_cf(prhs[NOF_INPUTS], &cearray); - cf_t *cearray_ptr = cearray; - for (i=0;i NOF_INPUTS + 1) { - noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); - } else if (nrhs > NOF_INPUTS) { - noise_power = 0; - } else { - noise_power = srslte_chest_dl_get_noise_estimate(&chest); - } - - float amplitude = mxGetScalar(AMP); - - srslte_viterbi_set_gain_quant(&pdcch.decoder, amplitude); - - srslte_pdcch_extract_llr(&pdcch, input_fft, ce, noise_power, sf_idx, cfi); - - uint32_t nof_locations; - if (rnti == SRSLTE_SIRNTI) { - nof_locations = srslte_pdcch_common_locations(&pdcch, locations, MAX_CANDIDATES, cfi); - formats = common_formats; - nof_formats = nof_common_formats; - } else { - nof_locations = srslte_pdcch_ue_locations(&pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, rnti); - formats = ue_formats; - nof_formats = nof_ue_formats; - } - uint16_t crc_rem=0; - srslte_dci_msg_t dci_msg; - bzero(&dci_msg, sizeof(srslte_dci_msg_t)); - - for (int f=0;f= 1) { - plhs[0] = mxCreateLogicalScalar(crc_rem == rnti); - } - int nof_bits = (srslte_regs_pdcch_nregs(®s, cfi) / 9) * 72; - if (nlhs >= 2) { - mexutils_write_f(pdcch.llr, &plhs[1], nof_bits, 1); - } - if (nlhs >= 3) { - mexutils_write_cf(pdcch.symbols[0], &plhs[2], 36*pdcch.nof_cce, 1); - } - if (nlhs >= 4) { - mexutils_write_cf(pdcch.d, &plhs[3], 36*pdcch.nof_cce, 1); - } - if (nlhs >= 5) { - mexutils_write_cf(ce[0], &plhs[4], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); - } - - srslte_chest_dl_free(&chest); - srslte_ofdm_rx_free(&ofdm_rx); - srslte_pdcch_free(&pdcch); - srslte_regs_free(®s); - - for (i=0;i 0) { printf("PDSCH Decoded OK!\n"); } else if (ret == 0) { - printf("No DCI grant found\n"); + printf("No DCI dci found\n"); } else if (ret < 0) { printf("Error decoding PDSCH\n"); } diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index e75f1b2e6..fef074b8f 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -29,43 +29,37 @@ #include #include #include -#include #include "srslte/srslte.h" // Enable to measure execution time -#define DO_OFDM - -#ifdef DO_OFDM -#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb) -#else -#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) -#endif - -srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 0, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_NORM, // PHICH length - SRSLTE_PHICH_R_1_6 // PHICH resources +#define NOF_CE_SYMBOLS SRSLTE_NOF_RE(cell) + +static srslte_cell_t cell = { + 6, // nof_prb + 1, // nof_ports + 0, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1_6, // PHICH resources + SRSLTE_FDD, + }; -char mimo_type_str[32] = "single"; -srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; -uint32_t cfi = 1; -uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0}; -uint32_t subframe = 1; -int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; -uint16_t rnti = 1234; -uint32_t nof_rx_antennas = 1; -bool tb_cw_swap = false; -bool enable_coworker = false; -uint32_t pmi = 0; -char *input_file = NULL; -int M=1; - -bool use_8_bit = false; +static srslte_tm_t tm = SRSLTE_TM1; +static uint32_t cfi = 1; +static uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0}; +static uint32_t subframe = 1; +static int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; +static uint16_t rnti = 1234; +static uint32_t nof_rx_antennas = 1; +static bool tb_cw_swap = false; +static bool enable_coworker = false; +static uint32_t pmi = 0; +static char* input_file = NULL; +static int M = 1; + +static bool use_8_bit = false; void usage(char *prog) { printf("Usage: %s [fmMbcsrtRFpnwav] \n", prog); @@ -80,7 +74,7 @@ void usage(char *prog) { printf("\t-R rnti [Default %d]\n", rnti); printf("\t-F cfi [Default %d]\n", cfi); printf("\t-X Number of repetitions for time measurement [Default %d]\n", M); - printf("\t-x Transmission mode [single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); + printf("\t-x Transmission mode [1 to 4] [Default %d]\n", tm + 1); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-p pmi (multiplex only) [Default %d]\n", pmi); @@ -124,8 +118,7 @@ void parse_args(int argc, char **argv) { cfi = atoi(argv[optind]); break; case 'x': - strncpy(mimo_type_str, argv[optind], sizeof(mimo_type_str)-1); - mimo_type_str[sizeof(mimo_type_str)-1] = 0; + tm = (srslte_tm_t)atoi(argv[optind]) - 1; break; case 'p': pmi = (uint32_t) atoi(argv[optind]); @@ -155,164 +148,138 @@ void parse_args(int argc, char **argv) { } } -static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL}; -static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL}; -cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; -cf_t *ce_dummy[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; -srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS]; -srslte_ra_dl_grant_t grant; -srslte_pdsch_cfg_t pdsch_cfg; -#ifdef DO_OFDM -cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS]; -cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS]; -#endif /* DO_OFDM */ -cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS]; -cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS]; -srslte_pdsch_t pdsch_tx, pdsch_rx; -srslte_ofdm_t ofdm_tx[SRSLTE_MAX_PORTS], ofdm_rx[SRSLTE_MAX_PORTS]; -srslte_chest_dl_t chest_dl; - int main(int argc, char **argv) { - uint32_t i, j, k; int ret = -1; - struct timeval t[3]; + struct timeval t[3] = {}; srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS]; bool acks[SRSLTE_MAX_CODEWORDS] = {false}; - parse_args(argc,argv); + uint8_t* data_tx[SRSLTE_MAX_CODEWORDS] = {NULL}; + uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {NULL}; + srslte_softbuffer_rx_t* softbuffers_rx[SRSLTE_MAX_CODEWORDS]; + srslte_pdsch_cfg_t pdsch_cfg; + srslte_dl_sf_cfg_t dl_sf; + cf_t* tx_slot_symbols[SRSLTE_MAX_PORTS]; + cf_t* rx_slot_symbols[SRSLTE_MAX_PORTS]; + srslte_pdsch_t pdsch_tx, pdsch_rx; + srslte_ofdm_t ofdm_tx[SRSLTE_MAX_PORTS]; + srslte_ofdm_t ofdm_rx[SRSLTE_MAX_PORTS]; + srslte_chest_dl_t chest; + srslte_chest_dl_res_t chest_res; + srslte_pdsch_res_t pdsch_res[SRSLTE_MAX_CODEWORDS]; /* Initialise to zeros */ - bzero(&pdsch_tx, sizeof(srslte_pdsch_t)); - bzero(&pdsch_rx, sizeof(srslte_pdsch_t)); - bzero(&pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); - bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(ce_dummy, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - - /* Parse transmission mode */ - if (srslte_str2mimotype(mimo_type_str, &mimo_type)) { - ERROR("Wrong transmission mode."); - goto quit; - } - - if (mimo_type == SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { + ZERO_OBJECT(softbuffers_tx); + ZERO_OBJECT(data_tx); + ZERO_OBJECT(data_rx); + ZERO_OBJECT(softbuffers_rx); + ZERO_OBJECT(pdsch_cfg); + ZERO_OBJECT(dl_sf); + ZERO_OBJECT(tx_slot_symbols); + ZERO_OBJECT(rx_slot_symbols); + ZERO_OBJECT(pdsch_tx); + ZERO_OBJECT(pdsch_rx); + ZERO_OBJECT(ofdm_tx); + ZERO_OBJECT(ofdm_rx); + ZERO_OBJECT(chest); + ZERO_OBJECT(chest_res); + ZERO_OBJECT(pdsch_res); + + parse_args(argc, argv); + + if (tm == SRSLTE_TM1) { cell.nof_ports = 1; + mcs[1] = 0; + rv_idx[1] = 1; } else { cell.nof_ports = 2; } - srslte_ra_dl_dci_t dci; - bzero(&dci, sizeof(srslte_ra_dl_dci_t)); + srslte_dci_dl_t dci; + ZERO_OBJECT(dci); + + switch (tm) { + case SRSLTE_TM1: + case SRSLTE_TM2: + dci.format = SRSLTE_DCI_FORMAT1A; + break; + case SRSLTE_TM3: + dci.format = SRSLTE_DCI_FORMAT2A; + break; + case SRSLTE_TM4: + dci.format = SRSLTE_DCI_FORMAT2; + break; + default: + fprintf(stderr, "Error unsupported tm=%d\n", tm); + exit(-1); + } + dci.rnti = rnti; dci.type0_alloc.rbg_bitmask = 0xffffffff; /* If transport block 0 is enabled */ - if (mcs[0] != 0 || rv_idx[0] != 1) { - dci.mcs_idx = mcs[0]; - dci.rv_idx = rv_idx[0]; - dci.tb_en[0] = true; + uint32_t nof_tb = 0; + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + dci.tb[i].mcs_idx = mcs[i]; + dci.tb[i].rv = rv_idx[i]; + if (SRSLTE_DCI_IS_TB_EN(dci.tb[i])) { + nof_tb++; + } } - /* If transport block 0 is disabled */ - if (mcs[1] != 0 || rv_idx[1] != 1) { - dci.mcs_idx_1 = mcs[1]; - dci.rv_idx_1 = rv_idx[1]; - dci.tb_en[1] = true; + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + dci.tb[i].cw_idx = (((tb_cw_swap) ? 1 : 0) + i) % nof_tb; } - /* Enable swap */ - if (SRSLTE_RA_DL_GRANT_NOF_TB(&dci) == SRSLTE_MAX_TB && tb_cw_swap) { - dci.tb_cw_swap = tb_cw_swap; - } + ZERO_OBJECT(dl_sf); + dl_sf.tti = subframe; + dl_sf.cfi = cfi; - /* Generate grant from DCI */ - if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) { - fprintf(stderr, "Error computing resource allocation\n"); + // Enable power allocation + pdsch_cfg.power_scale = true; + pdsch_cfg.p_a = 0.0f; // 0 dB + pdsch_cfg.p_b = (tm > SRSLTE_TM1) ? 1 : 0; // 0 dB + + /* Generate dci from DCI */ + if (srslte_ra_dl_dci_to_grant(&cell, &dl_sf, tm, &dci, &pdsch_cfg.grant)) { + ERROR("Error computing resource allocation\n"); return ret; } - /* Configure PDSCH */ - if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, mimo_type, pmi)) { - fprintf(stderr, "Error configuring PDSCH\n"); - goto quit; - } + srslte_chest_dl_res_init(&chest_res, cell.nof_prb); + srslte_chest_dl_res_set_identity(&chest_res); /* init memory */ - for (i=0;i -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define PDSCHCFG prhs[1] -#define TBS prhs[2] -#define INPUT prhs[3] -#define NOF_INPUTS 4 - -void help() -{ - mexErrMsgTxt - ("[decoded_ok, llr, rm, bits, symbols] = srslte_pdsch(enbConfig, pdschConfig, trblklen, rxWaveform)\n\n"); -} - -extern int indices[2048]; - -int rv_seq[4] = {0, 2, 3, 1}; - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - int i; - srslte_cell_t cell; - srslte_ofdm_t ofdm_rx; - srslte_pdsch_t pdsch; - srslte_chest_dl_t chest; - cf_t *input_fft[SRSLTE_MAX_PORTS]; - srslte_pdsch_cfg_t cfg; - srslte_softbuffer_rx_t softbuffer; - uint32_t rnti32; - uint32_t cfi; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - srslte_verbose = SRSLTE_VERBOSE_DEBUG; - bzero(&cfg, sizeof(srslte_pdsch_cfg_t)); - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - if (mexutils_read_uint32_struct(PDSCHCFG, "RNTI", &rnti32)) { - mexErrMsgTxt("Field RNTI not found in pdsch config\n"); - return; - } - - if (mexutils_read_uint32_struct(ENBCFG, "CFI", &cfi)) { - help(); - return; - } - if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &cfg.sf_idx)) { - help(); - return; - } - - if (srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); - return; - } - - - const size_t ndims = mxGetNumberOfDimensions(INPUT); - uint32_t nof_antennas = 1; - if (ndims >= 3) { - const mwSize *dims = mxGetDimensions(INPUT); - nof_antennas = dims[2]; - } - - if (srslte_pdsch_init_rx_multi(&pdsch, cell, nof_antennas)) { - mexErrMsgTxt("Error initiating PDSCH\n"); - return; - } - uint16_t rnti = (uint16_t) (rnti32 & 0xffff); - srslte_pdsch_set_rnti(&pdsch, rnti); - - if (srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb)) { - mexErrMsgTxt("Error initiating soft buffer\n"); - return; - } - - if (srslte_chest_dl_init(&chest, cell)) { - mexErrMsgTxt("Error initializing equalizer\n"); - return; - } - - srslte_ra_dl_grant_t grant; - grant.mcs.tbs = mxGetScalar(TBS); - if (grant.mcs.tbs == 0) { - mexErrMsgTxt("Error trblklen is zero\n"); - return; - } - if (srslte_cbsegm(&cfg.cb_segm, grant.mcs.tbs)) { - mexErrMsgTxt("Error computing CB segmentation\n"); - return; - } - - if (mexutils_read_uint32_struct(PDSCHCFG, "RV", &cfg.rv)) { - mexErrMsgTxt("Field RV not found in pdsch config\n"); - return; - } - - uint32_t max_iterations = 5; - mexutils_read_uint32_struct(PDSCHCFG, "NTurboDecIts", &max_iterations); - - char *mod_str = mexutils_get_char_struct(PDSCHCFG, "Modulation"); - - if (!strcmp(mod_str, "QPSK")) { - grant.mcs.mod = SRSLTE_MOD_QPSK; - } else if (!strcmp(mod_str, "16QAM")) { - grant.mcs.mod = SRSLTE_MOD_16QAM; - } else if (!strcmp(mod_str, "64QAM")) { - grant.mcs.mod = SRSLTE_MOD_64QAM; - } else { - mexErrMsgTxt("Unknown modulation\n"); - return; - } - - mxFree(mod_str); - - mxArray *p; - p = mxGetField(PDSCHCFG, 0, "PRBSet"); - if (!p) { - mexErrMsgTxt("Error field PRBSet not found\n"); - return; - } - - float *prbset_f; - uint64_t *prbset; - if (mxGetClassID(p) == mxDOUBLE_CLASS) { - grant.nof_prb = mexutils_read_f(p, &prbset_f); - prbset = malloc(sizeof(uint64_t)*grant.nof_prb); - for (i=0;i 1) { - cfg.rv = rv_seq[rvIdx%4]; - } - } - - // Read input signal - cf_t *input_signal = NULL; - int insignal_len = mexutils_read_cf(tmp, &input_signal); - if (insignal_len < 0) { - mexErrMsgTxt("Error reading input signal\n"); - return; - } - if (!(insignal_len % SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp))) { - for (int i=0;i NOF_INPUTS) { - cf_t *cearray = NULL; - mexutils_read_cf(prhs[NOF_INPUTS], &cearray); - cf_t *cearray_ptr = cearray; - for (int k=0;k NOF_INPUTS + 1) { - noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); - } else if (nrhs > NOF_INPUTS) { - noise_power = 0; - } else { - noise_power = srslte_chest_dl_get_noise_estimate(&chest); - } - - r = srslte_pdsch_decode_multi(&pdsch, &cfg, &softbuffer, input_fft, ce, noise_power, rnti, data_bytes); - } - - uint8_t *data = malloc(grant.mcs.tbs); - srslte_bit_unpack_vector(data_bytes[0], data, grant.mcs.tbs); - - if (nlhs >= 1) { - plhs[0] = mxCreateLogicalScalar(r == 0); - } - if (nlhs >= 2) { - mexutils_write_uint8(data, &plhs[1], grant.mcs.tbs, 1); - } - if (nlhs >= 3) { - mexutils_write_cf(pdsch.symbols[0], &plhs[2], cfg.nbits.nof_re, 1); - } - if (nlhs >= 4) { - mexutils_write_cf(pdsch.d[0], &plhs[3], cfg.nbits.nof_re, 1); - } - if (nlhs >= 5) { - mexutils_write_s(pdsch.e[0], &plhs[4], cfg.nbits.nof_bits, 1); - } - if (nlhs >= 6) { - uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); - cf_t *cearray_ptr = srslte_vec_malloc(len*sizeof(cf_t)); - int n=0; - for (i=0;i #include #include -#include #include "srslte/srslte.h" @@ -37,12 +36,14 @@ char *input_file_name = NULL; char *matlab_file_name = NULL; srslte_cell_t cell = { - 50, // cell.nof_prb - 2, // cell.nof_ports - 150, // cell.id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 50, // cell.nof_prb + 2, // cell.nof_ports + 150, // cell.id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1, // PHICH resources + SRSLTE_FDD, + }; int flen; @@ -52,11 +53,12 @@ int numsubframe = 0; FILE *fmatlab = NULL; srslte_filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[SRSLTE_MAX_PORTS]; +cf_t * input_buffer, *fft_buffer[SRSLTE_MAX_CODEWORDS]; srslte_phich_t phich; srslte_regs_t regs; srslte_ofdm_t fft; srslte_chest_dl_t chest; +srslte_chest_dl_res_t chest_res; void usage(char *prog) { printf("Usage: %s [vcoe] -i input_file\n", prog); @@ -97,7 +99,7 @@ void parse_args(int argc, char **argv) { } else if (!strcmp(argv[optind], "2")) { cell.phich_resources = SRSLTE_PHICH_R_2; } else { - fprintf(stderr, "Invalid phich ng factor %s. Setting to default.\n", argv[optind]); + ERROR("Invalid phich ng factor %s. Setting to default.\n", argv[optind]); } break; case 'e': @@ -127,10 +129,9 @@ void parse_args(int argc, char **argv) { } int base_init() { - int i; if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); + ERROR("Error opening file %s\n", input_file_name); exit(-1); } @@ -144,7 +145,7 @@ int base_init() { fmatlab = NULL; } - flen = SRSLTE_SF_LEN(srslte_symbol_sz_power2(cell.nof_prb)); + flen = SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb)); input_buffer = malloc(flen * sizeof(cf_t)); if (!input_buffer) { @@ -152,45 +153,47 @@ int base_init() { exit(-1); } - fft_buffer = malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - if (!fft_buffer) { + fft_buffer[0] = malloc(SRSLTE_NOF_RE(cell) * sizeof(cf_t)); + if (!fft_buffer[0]) { perror("malloc"); return -1; } - for (i=0;i -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define HIRES prhs[1] -#define INPUT prhs[2] -#define NOF_INPUTS 3 - -void help() -{ - mexErrMsgTxt - ("[hi, symbols] = srslte_phich(enbConfig, hires, input_signal, [hest, nest])\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - int i; - srslte_cell_t cell; - srslte_phich_t phich; - srslte_chest_dl_t chest; - srslte_ofdm_t ofdm_rx; - srslte_regs_t regs; - uint32_t sf_idx; - cf_t *input_fft, *input_signal; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &sf_idx)) { - help(); - return; - } - - if (srslte_chest_dl_init(&chest, cell)) { - mexErrMsgTxt("Error initializing equalizer\n"); - return; - } - - if (srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb)) { - mexErrMsgTxt("Error initializing FFT\n"); - return; - } - - if (srslte_regs_init(®s, cell)) { - mexErrMsgTxt("Error initiating regs\n"); - return; - } - - if (srslte_phich_init(&phich, ®s, cell)) { - mexErrMsgTxt("Error creating PHICH object\n"); - return; - } - -// Read input signal - input_signal = NULL; - int insignal_len = mexutils_read_cf(INPUT, &input_signal); - if (insignal_len < 0) { - mexErrMsgTxt("Error reading input signal\n"); - return; - } - if (insignal_len == SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)) { - input_fft = input_signal; - } else { - input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - srslte_ofdm_rx_sf(&ofdm_rx, input_signal, input_fft); - free(input_signal); - } - - cf_t *ce[SRSLTE_MAX_PORTS]; - for (i=0;i NOF_INPUTS) { - cf_t *cearray = NULL; - mexutils_read_cf(prhs[NOF_INPUTS], &cearray); - cf_t *cearray_ptr = cearray; - for (i=0;i NOF_INPUTS + 1) { - noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); - } else if (nrhs > NOF_INPUTS) { - noise_power = 0; - } else { - noise_power = srslte_chest_dl_get_noise_estimate(&chest); - } - - // Read hires values - float *hires = NULL; - int nhires = mexutils_read_f(HIRES, &hires); - if (nhires != 2) { - mexErrMsgTxt("Expecting 2 values for hires parameter\n"); - return; - } - uint32_t ngroup = (uint32_t) hires[0]; - uint32_t nseq = (uint32_t) hires[1]; - uint8_t ack; - float corr_res; - int n = srslte_phich_decode(&phich, input_fft, ce, noise_power, ngroup, nseq, sf_idx, &ack, &corr_res); - - if (nlhs >= 1) { - if (n < 0) { - plhs[0] = mxCreateDoubleScalar(-1); - } else { - plhs[0] = mxCreateDoubleScalar(ack); - } - } - if (nlhs >= 2) { - mexutils_write_cf(phich.z, &plhs[1], 1, SRSLTE_PHICH_NBITS); - } - - srslte_chest_dl_free(&chest); - srslte_ofdm_rx_free(&ofdm_rx); - srslte_phich_free(&phich); - srslte_regs_free(®s); - - for (i=0;i 0) { + + srslte_dl_sf_cfg_t dl_sf; + ZERO_OBJECT(dl_sf); + + dl_sf.cfi = cfi; + dl_sf.tti = sf_idx; + dl_sf.sf_type = SRSLTE_SF_MBSFN; + + srslte_ue_dl_cfg_t ue_dl_cfg; + ZERO_OBJECT(ue_dl_cfg); + ue_dl_cfg.chest_cfg.mbsfn_area_id = mbsfn_area_id; + + // Special configuration for MBSFN channel estimation + ue_dl_cfg.chest_cfg.filter_type = SRSLTE_CHEST_FILTER_TRIANGLE; + ue_dl_cfg.chest_cfg.filter_coef[0] = 0.1; + ue_dl_cfg.chest_cfg.interpolate_subframe = true; + ue_dl_cfg.chest_cfg.noise_alg = SRSLTE_NOISE_ALG_PSS; + + if ((ret = srslte_ue_dl_decode_fft_estimate(&ue_dl, &dl_sf, &ue_dl_cfg)) < 0) { + return ret; + } + dl_sf.cfi = cfi; + srslte_pmch_cfg_t pmch_cfg; + ZERO_OBJECT(pmch_cfg); + pmch_cfg.area_id = mbsfn_area_id; + pmch_cfg.pdsch_cfg.softbuffers.rx[0] = &softbuffer_rx; + + srslte_dci_dl_t dci; + ZERO_OBJECT(dci); + dci.rnti = SRSLTE_MRNTI; + dci.format = SRSLTE_DCI_FORMAT1; + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci.type0_alloc.rbg_bitmask = 0xffffffff; + dci.tb[0].mcs_idx = 2; + SRSLTE_DCI_TB_DISABLE(dci.tb[1]); + srslte_ra_dl_dci_to_grant(&cell, &dl_sf, SRSLTE_TM1, &dci, &pmch_cfg.pdsch_cfg.grant); + + srslte_pdsch_res_t pdsch_res; + pdsch_res.payload = data; + ret = srslte_ue_dl_decode_pmch(&ue_dl, &dl_sf, &pmch_cfg, &pdsch_res); + if (ret >= 0) { printf("PMCH Decoded OK!\n"); } else if (ret < 0) { printf("Error decoding PMCH\n"); @@ -203,7 +231,7 @@ int main(int argc, char **argv) { free(data); } srslte_dft_exit(); - if (ret > 0) { + if (ret >= 0) { exit(0); } else { exit(-1); diff --git a/lib/src/phy/phch/test/pmch_test.c b/lib/src/phy/phch/test/pmch_test.c index e4871a594..af7117f9f 100644 --- a/lib/src/phy/phch/test/pmch_test.c +++ b/lib/src/phy/phch/test/pmch_test.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "srslte/srslte.h" @@ -39,20 +38,20 @@ #ifdef DO_OFDM #define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb) #else -#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) +#define NOF_CE_SYMBOLS SRSLTE_NOF_RE(cell) #endif srslte_cell_t cell = { - 100, // nof_prb - 1, // nof_ports - 1, // cell_id - SRSLTE_CP_EXT, // cyclic prefix - SRSLTE_PHICH_NORM, // PHICH length - SRSLTE_PHICH_R_1_6 // PHICH resources + 100, // nof_prb + 1, // nof_ports + 1, // cell_id + SRSLTE_CP_EXT, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1_6, // PHICH resources + SRSLTE_FDD, + }; -char mimo_type_str [32] = "single"; -srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; uint32_t cfi = 2; uint32_t mcs_idx = 2; uint32_t subframe = 1; @@ -63,6 +62,7 @@ uint32_t pmi = 0; char *input_file = NULL; uint32_t mbsfn_area_id = 1; uint32_t non_mbsfn_region = 2; + void usage(char *prog) { printf("Usage: %s [fmMcsrtRFpnwav] \n", prog); printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n"); @@ -81,7 +81,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) { + while ((opt = getopt(argc, argv, "fmMcsrtRFpnav")) != -1) { switch(opt) { case 'f': input_file = argv[optind]; @@ -101,10 +101,6 @@ void parse_args(int argc, char **argv) { case 'F': cfi = atoi(argv[optind]); break; - case 'x': - strncpy(mimo_type_str, argv[optind], 31); - mimo_type_str[31] = 0; - break; case 'p': pmi = (uint32_t) atoi(argv[optind]); break; @@ -127,74 +123,43 @@ void parse_args(int argc, char **argv) { } } -static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL}; -static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL}; -cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; -srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS]; -srslte_ra_dl_grant_t grant; -#ifdef DO_OFDM -cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS]; -cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS]; -#endif /* DO_OFDM */ -cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS]; -cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS]; -srslte_pmch_t pmch_tx, pmch_rx; -srslte_pdsch_cfg_t pmch_cfg; -srslte_ofdm_t ifft_mbsfn[SRSLTE_MAX_PORTS], fft_mbsfn[SRSLTE_MAX_PORTS]; - int main(int argc, char **argv) { uint32_t i, j, k; int ret = -1; struct timeval t[3]; - srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS]; int M=1; - + + static uint8_t* data_tx[SRSLTE_MAX_CODEWORDS] = {NULL}; + static uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {NULL}; + srslte_softbuffer_rx_t* softbuffers_rx[SRSLTE_MAX_CODEWORDS]; + srslte_softbuffer_tx_t* softbuffers_tx[SRSLTE_MAX_CODEWORDS]; +#ifdef DO_OFDM + cf_t* tx_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t* rx_sf_symbols[SRSLTE_MAX_PORTS]; +#endif /* DO_OFDM */ + cf_t* tx_slot_symbols[SRSLTE_MAX_PORTS]; + cf_t* rx_slot_symbols[SRSLTE_MAX_PORTS]; + + srslte_chest_dl_res_t chest_dl_res; + srslte_pmch_t pmch; + srslte_pmch_cfg_t pmch_cfg; + srslte_ofdm_t ifft_mbsfn[SRSLTE_MAX_PORTS], fft_mbsfn[SRSLTE_MAX_PORTS]; + parse_args(argc,argv); /* Initialise to zeros */ - bzero(&pmch_tx, sizeof(srslte_pmch_t)); - bzero(&pmch_rx, sizeof(srslte_pmch_t)); - bzero(&pmch_cfg, sizeof(srslte_pdsch_cfg_t)); - bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + bzero(&pmch, sizeof(srslte_pmch_t)); bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(t, 3 * sizeof(struct timeval)); cell.nof_ports = 1; - - srslte_ra_dl_dci_t dci; - bzero(&dci, sizeof(srslte_ra_dl_dci_t)); - dci.type0_alloc.rbg_bitmask = 0xffffffff; - - /* If transport block 0 is enabled */ - grant.tb_en[0] = true; - grant.tb_en[1] = false; - grant.mcs[0].idx = mcs_idx; - - grant.nof_prb = cell.nof_prb; - grant.sf_type = SRSLTE_SF_MBSFN; - - srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb); - grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); - for(int i = 0; i < 2; i++){ - for(int j = 0; j < grant.nof_prb; j++){ - grant.prb_idx[i][j] = true; - } - } - /* init memory */ + srslte_chest_dl_res_init(&chest_dl_res, cell.nof_prb); + srslte_chest_dl_res_set_identity(&chest_dl_res); + for (i=0;i -#define FORCE_POWER2_FFT -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -extern float save_corr[4096]; - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PRACHCFG prhs[1] -#define INPUT prhs[2] -#define NOF_INPUTS 3 - -void help() -{ - mexErrMsgTxt - ("[preamble, offset] = srslte_prach(ueConfig, prachConfig, signal)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - srslte_use_standard_symbol_size(true); - - uint32_t n_ul_rb = 0; - if (mexutils_read_uint32_struct(UECFG, "NULRB", &n_ul_rb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - int r = srslte_symbol_sz(n_ul_rb); - if (r < 0) { - mexErrMsgTxt("Invalid NULRB\n"); - return; - } - uint32_t N_ifft_ul = (uint32_t) r; - - uint32_t sf_idx = 0; - mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx); - uint32_t nframe = 0; - mexutils_read_uint32_struct(UECFG, "NFrame", &nframe); - - uint32_t preamble_format = 0; - mexutils_read_uint32_struct(PRACHCFG, "Format", &preamble_format); - uint32_t root_seq_idx = 0; - mexutils_read_uint32_struct(PRACHCFG, "SeqIdx", &root_seq_idx); - uint32_t seq_idx = 0; - mexutils_read_uint32_struct(PRACHCFG, "PreambleIdx", &seq_idx); - uint32_t zero_corr_zone = 0; - mexutils_read_uint32_struct(PRACHCFG, "CyclicShiftIdx", &zero_corr_zone); - uint32_t high_speed_flag = 0; - mexutils_read_uint32_struct(PRACHCFG, "HighSpeed", &high_speed_flag); - uint32_t frequency_offset = 0; - mexutils_read_uint32_struct(PRACHCFG, "FreqOffset", &frequency_offset); - - srslte_prach_t prach; - if (srslte_prach_init(&prach, N_ifft_ul, preamble_format*16, root_seq_idx, high_speed_flag, zero_corr_zone)) { - mexErrMsgTxt("Error initiating PRACH\n"); - return; - } - - cf_t *input_signal = NULL; - int nof_samples = mexutils_read_cf(INPUT, &input_signal); - - uint32_t preambles[64]; - float offsets[64]; - uint32_t nof_detected = 0; - - if (nrhs > NOF_INPUTS) { - float factor = mxGetScalar(prhs[NOF_INPUTS]); - srslte_prach_set_detect_factor(&prach, factor); - } - - mexPrintf("format=%d config=%d, N_cp=%d, ifft=%d\n", prach.f, prach.config_idx, prach.N_cp, prach.N_ifft_ul); - - if (srslte_prach_detect_offset(&prach, frequency_offset, &input_signal[prach.N_cp], nof_samples, preambles, offsets, NULL, &nof_detected)) { - mexErrMsgTxt("Error detecting PRACH\n"); - return; - } - - if (nlhs >= 1) { - mexutils_write_int((int*) preambles, &plhs[0], nof_detected, 1); - } - if (nlhs >= 2) { - mexutils_write_f(offsets, &plhs[1], nof_detected, 1); - } - if (nlhs >= 3) { - mexutils_write_f(save_corr, &plhs[2], prach.N_zc, 1); - } - - free(input_signal); - srslte_prach_free(&prach); - - return; -} - diff --git a/lib/src/phy/phch/test/prach_test.c b/lib/src/phy/phch/test/prach_test.c index 29b80a525..cb14c1510 100644 --- a/lib/src/phy/phch/test/prach_test.c +++ b/lib/src/phy/phch/test/prach_test.c @@ -38,15 +38,14 @@ #define MAX_LEN 70176 - -uint32_t N_ifft_ul = 1536; +uint32_t nof_prb = 50; uint32_t config_idx = 3; uint32_t root_seq_idx = 0; uint32_t zero_corr_zone = 15; void usage(char *prog) { printf("Usage: %s\n", prog); - printf("\t-N Uplink IFFT size [Default %d]\n", N_ifft_ul); + printf("\t-n Uplink number of PRB [Default %d]\n", nof_prb); printf("\t-f Preamble format [Default 0]\n"); printf("\t-r Root sequence index [Default 0]\n"); printf("\t-z Zero correlation zone config [Default 1]\n"); @@ -54,49 +53,54 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "Nfrz")) != -1) { + while ((opt = getopt(argc, argv, "nfrz")) != -1) { switch (opt) { - case 'N': - N_ifft_ul = atoi(argv[optind]); - break; - case 'f': - config_idx = atoi(argv[optind]); - break; - case 'r': - root_seq_idx = atoi(argv[optind]); - break; - case 'z': - zero_corr_zone = atoi(argv[optind]); - break; - default: - usage(argv[0]); - exit(-1); + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'f': + config_idx = atoi(argv[optind]); + break; + case 'r': + root_seq_idx = atoi(argv[optind]); + break; + case 'z': + zero_corr_zone = atoi(argv[optind]); + break; + default: + usage(argv[0]); + exit(-1); } } } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ parse_args(argc, argv); - - srslte_prach_t *p = (srslte_prach_t*)malloc(sizeof(srslte_prach_t)); + srslte_prach_t prach; bool high_speed_flag = false; cf_t preamble[MAX_LEN]; memset(preamble, 0, sizeof(cf_t)*MAX_LEN); - srslte_prach_init(p, N_ifft_ul); + srslte_prach_cfg_t prach_cfg; + ZERO_OBJECT(prach_cfg); + prach_cfg.config_idx = config_idx; + prach_cfg.hs_flag = high_speed_flag; + prach_cfg.freq_offset = 0; + prach_cfg.root_seq_idx = root_seq_idx; + prach_cfg.zero_corr_zone = zero_corr_zone; - srslte_prach_set_cell( p, - N_ifft_ul, - config_idx, - root_seq_idx, - high_speed_flag, - zero_corr_zone); + if (srslte_prach_init(&prach, srslte_symbol_sz(nof_prb))) { + return -1; + } + if (srslte_prach_set_cfg(&prach, &prach_cfg, nof_prb)) { + ERROR("Error initiating PRACH object\n"); + return -1; + } uint32_t seq_index = 0; - uint32_t frequency_offset = 0; - uint32_t indices[64]; uint32_t n_indices = 0; for(int i=0;i<64;i++) @@ -104,16 +108,13 @@ int main(int argc, char **argv) { for(seq_index=0;seq_index<64;seq_index++) { - srslte_prach_gen(p, - seq_index, - frequency_offset, - preamble); + srslte_prach_gen(&prach, seq_index, 0, preamble); + + uint32_t prach_len = prach.N_seq; - uint32_t prach_len = p->N_seq; - struct timeval t[3]; gettimeofday(&t[1], NULL); - srslte_prach_detect(p, frequency_offset, &preamble[p->N_cp], prach_len, indices, &n_indices); + srslte_prach_detect(&prach, 0, &preamble[prach.N_cp], prach_len, indices, &n_indices); gettimeofday(&t[2], NULL); get_time_interval(t); printf("texec=%ld us\n", t[0].tv_usec); @@ -121,8 +122,7 @@ int main(int argc, char **argv) { return -1; } - srslte_prach_free(p); - free(p); + srslte_prach_free(&prach); srslte_dft_exit(); printf("Done\n"); diff --git a/lib/src/phy/phch/test/prach_test_mex.c b/lib/src/phy/phch/test/prach_test_mex.c deleted file mode 100644 index 54af0ab60..000000000 --- a/lib/src/phy/phch/test/prach_test_mex.c +++ /dev/null @@ -1,115 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 -#define FORCE_POWER2_FFT -#include "srslte/srslte.h" -#include "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PRACHCFG prhs[1] -#define NOF_INPUTS 2 - -void help() -{ - mexErrMsgTxt - ("waveform = srslte_prach(ueConfig, prachConfig)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - - uint32_t n_ul_rb = 0; - if (mexutils_read_uint32_struct(UECFG, "NULRB", &n_ul_rb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - int r = srslte_symbol_sz(n_ul_rb); - if (r < 0) { - mexErrMsgTxt("Invalid NULRB\n"); - return; - } - uint32_t N_ifft_ul = (uint32_t) r; - - uint32_t sf_idx = 0; - mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx); - uint32_t nframe = 0; - mexutils_read_uint32_struct(UECFG, "NFrame", &nframe); - - uint32_t preamble_format = 0; - mexutils_read_uint32_struct(PRACHCFG, "Format", &preamble_format); - uint32_t root_seq_idx = 0; - mexutils_read_uint32_struct(PRACHCFG, "SeqIdx", &root_seq_idx); - uint32_t seq_idx = 0; - mexutils_read_uint32_struct(PRACHCFG, "PreambleIdx", &seq_idx); - uint32_t zero_corr_zone = 0; - mexutils_read_uint32_struct(PRACHCFG, "CyclicShiftIdx", &zero_corr_zone); - uint32_t high_speed_flag = 0; - mexutils_read_uint32_struct(PRACHCFG, "HighSpeed", &high_speed_flag); - uint32_t frequency_offset = 0; - mexutils_read_uint32_struct(PRACHCFG, "FreqOffset", &frequency_offset); - - srslte_prach_t prach; - if (srslte_prach_init(&prach, N_ifft_ul, preamble_format*16, root_seq_idx, high_speed_flag, zero_corr_zone)) { - mexErrMsgTxt("Error initiating PRACH\n"); - return; - } - - uint32_t nof_samples = srslte_sampling_freq_hz(n_ul_rb) * 0.001; - - cf_t *signal = srslte_vec_malloc(sizeof(cf_t) * nof_samples); - if (!signal) { - mexErrMsgTxt("malloc"); - return; - } - bzero(signal, sizeof(cf_t) * nof_samples); - if (srslte_prach_gen(&prach, seq_idx, frequency_offset, signal)) { - mexErrMsgTxt("Error generating PRACH\n"); - return; - } - - srslte_vec_sc_prod_cfc(signal, 1.0/sqrtf(N_ifft_ul), signal, nof_samples); - - if (nlhs >= 0) { - mexutils_write_cf(signal, &plhs[0], nof_samples, 1); - } - - free(signal); - - srslte_prach_free(&prach); - - return; -} - diff --git a/lib/src/phy/phch/test/prach_test_multi.c b/lib/src/phy/phch/test/prach_test_multi.c index 7ef6f2354..7313cf7e4 100644 --- a/lib/src/phy/phch/test/prach_test_multi.c +++ b/lib/src/phy/phch/test/prach_test_multi.c @@ -33,11 +33,11 @@ #include #include "srslte/phy/phch/prach.h" +#include "srslte/phy/utils/debug.h" #define MAX_LEN 70176 - -uint32_t N_ifft_ul = 128; +uint32_t nof_prb = 6; uint32_t preamble_format = 0; uint32_t root_seq_idx = 0; uint32_t zero_corr_zone = 1; @@ -45,7 +45,7 @@ uint32_t n_seqs = 64; void usage(char *prog) { printf("Usage: %s\n", prog); - printf("\t-N Uplink IFFT size [Default 128]\n"); + printf("\t-N Uplink number of PRB [Default %d]\n", nof_prb); printf("\t-f Preamble format [Default 0]\n"); printf("\t-r Root sequence index [Default 0]\n"); printf("\t-z Zero correlation zone config [Default 1]\n"); @@ -57,7 +57,7 @@ void parse_args(int argc, char **argv) { while ((opt = getopt(argc, argv, "Nfrzn")) != -1) { switch (opt) { case 'N': - N_ifft_ul = atoi(argv[optind]); + nof_prb = atoi(argv[optind]); break; case 'f': preamble_format = atoi(argv[optind]); @@ -78,10 +78,10 @@ void parse_args(int argc, char **argv) { } } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ parse_args(argc, argv); - - srslte_prach_t *p = (srslte_prach_t*)malloc(sizeof(srslte_prach_t)); + srslte_prach_t prach; bool high_speed_flag = false; @@ -90,14 +90,22 @@ int main(int argc, char **argv) { cf_t preamble_sum[MAX_LEN]; memset(preamble_sum, 0, sizeof(cf_t)*MAX_LEN); - srslte_prach_init(p, N_ifft_ul); + srslte_prach_cfg_t prach_cfg; + ZERO_OBJECT(prach_cfg); + prach_cfg.config_idx = preamble_format; + prach_cfg.hs_flag = high_speed_flag; + prach_cfg.freq_offset = 0; + prach_cfg.root_seq_idx = root_seq_idx; + prach_cfg.zero_corr_zone = zero_corr_zone; + + if (srslte_prach_init(&prach, srslte_symbol_sz(nof_prb))) { + return -1; + } - srslte_prach_set_cell( p, - N_ifft_ul, - preamble_format, - root_seq_idx, - high_speed_flag, - zero_corr_zone); + if (srslte_prach_set_cfg(&prach, &prach_cfg, nof_prb)) { + ERROR("Error initiating PRACH object\n"); + return -1; + } uint32_t seq_index = 0; uint32_t frequency_offset = 0; @@ -107,37 +115,34 @@ int main(int argc, char **argv) { for(int i=0;i<64;i++) indices[i] = 0; - srslte_prach_set_detect_factor(p, 10); - + srslte_prach_set_detect_factor(&prach, 10); + for(seq_index=0;seq_indexN_cp+p->N_seq;i++) - { + for (int i = 0; i < prach.N_cp + prach.N_seq; i++) { preamble_sum[i] += preamble[i]; } } - uint32_t prach_len = p->N_seq; - if(preamble_format == 2 || preamble_format == 3) + uint32_t prach_len = prach.N_seq; + if (preamble_format == 2 || preamble_format == 3) { prach_len /= 2; - srslte_prach_detect(p, 0, &preamble_sum[p->N_cp], prach_len, indices, &n_indices); + } + srslte_prach_detect(&prach, 0, &preamble_sum[prach.N_cp], prach_len, indices, &n_indices); - if(n_indices != n_seqs) + if (n_indices != n_seqs) { return -1; + } - for(int i=0;iN_seq+p->N_cp; - - srslte_vec_save_file("generated",preamble,prach_len*sizeof(cf_t)); - + srslte_prach_gen(&prach, seq_idx, frequency_offset, preamble); + + uint32_t prach_len = prach.N_seq + prach.N_cp; + + srslte_vec_save_file("generated", preamble, prach_len * sizeof(cf_t)); + cf_t *buffer = malloc(sizeof(cf_t)*flen*nof_frames); // Send through UHD srslte_rf_t rf; printf("Opening RF device...\n"); if (srslte_rf_open(&rf, uhd_args)) { - fprintf(stderr, "Error opening &uhd\n"); + ERROR("Error opening &uhd\n"); exit(-1); } printf("Subframe len: %d samples\n", flen); @@ -173,10 +176,10 @@ int main(int argc, char **argv) { srslte_rf_set_rx_gain(&rf, uhd_rx_gain); srslte_rf_set_tx_gain(&rf, uhd_tx_gain); - srslte_rf_set_rx_freq(&rf, uhd_freq); - srslte_rf_set_tx_freq(&rf, uhd_freq); - - if (srate > 1e6 && (srate/1000) > 0) { + srslte_rf_set_rx_freq(&rf, 0, uhd_freq); + srslte_rf_set_tx_freq(&rf, 0, uhd_freq); + + if (srate > 1e6 && (srate / 1000) > 0) { if (30720%(srate/1000) == 0) { srslte_rf_set_master_clock_rate(&rf, 30.72e6); } else { @@ -189,7 +192,7 @@ int main(int argc, char **argv) { printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000); float srate_rf = srslte_rf_set_rx_srate(&rf, (double) srate); if (srate_rf != srate) { - fprintf(stderr, "Could not set sampling rate\n"); + ERROR("Could not set sampling rate\n"); exit(-1); } srslte_rf_set_tx_srate(&rf, (double) srate); @@ -220,8 +223,9 @@ int main(int argc, char **argv) { uint32_t indices[1024]; float offsets[1024]; - uint32_t nof_detected; - if (srslte_prach_detect_offset(p, frequency_offset, &buffer[flen*10+p->N_cp], flen, indices, offsets, NULL, &nof_detected)) { + uint32_t nof_detected; + if (srslte_prach_detect_offset( + &prach, frequency_offset, &buffer[flen * 10 + prach.N_cp], flen, indices, offsets, NULL, &nof_detected)) { printf("Error detecting prach\n"); } printf("Nof detected PRACHs: %d\n", nof_detected); @@ -233,8 +237,7 @@ int main(int argc, char **argv) { srslte_vec_save_file(output_filename,buffer,11*flen*sizeof(cf_t)); srslte_rf_close(&rf); - srslte_prach_free(p); - free(p); + srslte_prach_free(&prach); srslte_dft_exit(); printf("Done\n"); diff --git a/lib/src/phy/phch/test/pucch_encode_test_mex.c b/lib/src/phy/phch/test/pucch_encode_test_mex.c deleted file mode 100644 index a32b0b00b..000000000 --- a/lib/src/phy/phch/test/pucch_encode_test_mex.c +++ /dev/null @@ -1,229 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PUCCHCFG prhs[1] -#define ACK prhs[2] -#define NOF_INPUTS 3 - -void help() -{ - mexErrMsgTxt - ("[sym, sym_with_dmrs, subframe_all]=srslte_pucch_encode(ue, chs, ack)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - srslte_verbose = SRSLTE_VERBOSE_DEBUG; - - srslte_cell_t cell; - bzero(&cell, sizeof(srslte_cell_t)); - cell.nof_ports = 1; - cell.cp = SRSLTE_CP_NORM; - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - srslte_pucch_t pucch; - if (srslte_pucch_init_ue(&pucch, cell)) { - mexErrMsgTxt("Error initiating PUSCH\n"); - return; - } - - uint32_t sf_idx = 0; - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - uint32_t rnti; - if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - if (srslte_pucch_set_crnti(&pucch, (uint16_t) rnti&0xffff)) { - mexErrMsgTxt("Error setting C-RNTI\n"); - return; - } - uint32_t n_pucch; - if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceIdx", &n_pucch)) { - mexErrMsgTxt("Field ResourceIdx not found in PUCCHCFG\n"); - return; - } - srslte_pucch_cfg_t pucch_cfg; - bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); - - if (mexutils_read_uint32_struct(PUCCHCFG, "DeltaShift", &pucch_cfg.delta_pucch_shift)) { - mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n"); - return; - } - if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceSize", &pucch_cfg.n_rb_2)) { - mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n"); - return; - } - if (mexutils_read_uint32_struct(PUCCHCFG, "CyclicShifts", &pucch_cfg.N_cs)) { - mexErrMsgTxt("Field CyclicShifts not found in PUCCHCFG\n"); - return; - } - bool group_hopping_en = false; - char *hop = mexutils_get_char_struct(UECFG, "Hopping"); - if (hop) { - if (!strcmp(hop, "Group")) { - group_hopping_en = true; - } - mxFree(hop); - } - - pucch.shortened = false; - uint32_t sh = 0; - mexutils_read_uint32_struct(PUCCHCFG, "Shortened", &sh); - if (sh == 1) { - pucch.shortened = true; - } - - uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; - uint8_t pucch2_bits[2]; - float *bits_ptr; - int n = mexutils_read_f(ACK, &bits_ptr); - - srslte_pucch_format_t format; - switch(n) { - case 0: - format = SRSLTE_PUCCH_FORMAT_1; - break; - case 1: - format = SRSLTE_PUCCH_FORMAT_1A; - break; - case 2: - format = SRSLTE_PUCCH_FORMAT_1B; - break; - case 20: - format = SRSLTE_PUCCH_FORMAT_2; - break; - case 21: - format = SRSLTE_PUCCH_FORMAT_2A; - break; - case 22: - format = SRSLTE_PUCCH_FORMAT_2B; - break; - default: - mexErrMsgTxt("Invalid number of bits in parameter ack\n"); - return; - } - if (n > 20) { - n = 20; - } - for (int i=0;i0?1:0; - } - if (format == SRSLTE_PUCCH_FORMAT_2A) { - pucch2_bits[0] = bits_ptr[20]; - } - if (format == SRSLTE_PUCCH_FORMAT_2B) { - pucch2_bits[0] = bits_ptr[20]; - pucch2_bits[1] = bits_ptr[21]; - } - free(bits_ptr); - - cf_t *sf_symbols = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); - if (!sf_symbols) { - return; - } - bzero(sf_symbols, SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - - srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en); - - if (srslte_pucch_encode(&pucch, format, n_pucch, sf_idx, (uint16_t) rnti, bits, sf_symbols)) { - mexErrMsgTxt("Error encoding PUCCH\n"); - return; - } - - if (nlhs >= 1) { - uint32_t n_bits = srslte_pucch_nof_symbols(&pucch_cfg, format, pucch.shortened); - mexutils_write_cf(pucch.z, &plhs[0], n_bits, 1); - } - - if (nlhs >= 2) { - srslte_refsignal_ul_t pucch_dmrs; - if (srslte_refsignal_ul_init(&pucch_dmrs, cell)) { - mexErrMsgTxt("Error initiating PUCCH DMRS\n"); - return; - } - cf_t *dmrs_pucch = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_NRE*3*2); - if (!dmrs_pucch) { - return; - } - bzero(dmrs_pucch, sizeof(cf_t)*SRSLTE_NRE*3*2); - - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - pusch_cfg.group_hopping_en = group_hopping_en; - pusch_cfg.sequence_hopping_en = false; - srslte_refsignal_ul_set_cfg(&pucch_dmrs, &pusch_cfg, &pucch_cfg, NULL); - - if (srslte_refsignal_dmrs_pucch_gen(&pucch_dmrs, format, n_pucch, sf_idx, pucch2_bits, dmrs_pucch)) { - mexErrMsgTxt("Error generating PUCCH DMRS\n"); - return; - } - uint32_t n_rs = 3; - if (format >= SRSLTE_PUCCH_FORMAT_2) { - n_rs = 2; - } - mexutils_write_cf(dmrs_pucch, &plhs[1], 2*n_rs*SRSLTE_NRE, 1); - - if (nlhs >= 3) { - if (srslte_refsignal_dmrs_pucch_put(&pucch_dmrs, format, n_pucch, dmrs_pucch, sf_symbols)) { - mexErrMsgTxt("Error generating PUCCH DMRS\n"); - return; - } - mexutils_write_cf(sf_symbols, &plhs[2], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), 1); - } - - srslte_refsignal_ul_free(&pucch_dmrs); - free(dmrs_pucch); - } - - srslte_pucch_free(&pucch); - free(sf_symbols); - - return; -} - diff --git a/lib/src/phy/phch/test/pucch_test.c b/lib/src/phy/phch/test/pucch_test.c index 6635f6876..0125f2b99 100644 --- a/lib/src/phy/phch/test/pucch_test.c +++ b/lib/src/phy/phch/test/pucch_test.c @@ -34,12 +34,14 @@ #include "srslte/srslte.h" srslte_cell_t cell = { - 25, // nof_prb - 1, // nof_ports - 1, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1_6, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 25, // nof_prb + 1, // nof_ports + 1, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1_6, // PHICH resources + SRSLTE_FDD, + }; uint32_t subframe = 0; @@ -137,8 +139,6 @@ int main(int argc, char **argv) { srslte_pucch_t pucch; srslte_pucch_cfg_t pucch_cfg; srslte_refsignal_ul_t dmrs; - uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; - uint8_t pucch2_bits[2]; cf_t *sf_symbols = NULL; cf_t pucch_dmrs[2*SRSLTE_NRE*3]; int ret = -1; @@ -150,78 +150,93 @@ int main(int argc, char **argv) { } if (srslte_pucch_init_ue(&pucch)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); exit(-1); } if (srslte_pucch_set_cell(&pucch, cell)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); exit(-1); } if (srslte_refsignal_ul_init(&dmrs, cell.nof_prb)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); exit(-1); } if (srslte_refsignal_ul_set_cell(&dmrs, cell)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); exit(-1); } bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); - - for (int i=0;i= SRSLTE_PUCCH_FORMAT_2) { + uci_data.cfg.cqi.data_enable = true; } - - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - pusch_cfg.group_hopping_en = group_hopping_en; - pusch_cfg.sequence_hopping_en = false; - srslte_refsignal_ul_set_cfg(&dmrs, &pusch_cfg, &pucch_cfg, NULL); - - if (srslte_refsignal_dmrs_pucch_gen(&dmrs, format, n_pucch, subframe, pucch2_bits, pucch_dmrs)) { - fprintf(stderr, "Error encoding PUCCH\n"); + + gettimeofday(&t[1], NULL); + if (srslte_pucch_encode(&pucch, &ul_sf, &pucch_cfg, &uci_data.value, sf_symbols)) { + ERROR("Error encoding PUCCH\n"); goto quit; } - if (srslte_refsignal_dmrs_pucch_put(&dmrs, format, n_pucch, pucch_dmrs, sf_symbols)) { - fprintf(stderr, "Error encoding PUCCH\n"); - goto quit; + + if (srslte_refsignal_dmrs_pucch_gen(&dmrs, &ul_sf, &pucch_cfg, pucch_dmrs)) { + ERROR("Error encoding PUCCH\n"); + goto quit; + } + if (srslte_refsignal_dmrs_pucch_put(&dmrs, &pucch_cfg, pucch_dmrs, sf_symbols)) { + ERROR("Error encoding PUCCH\n"); + goto quit; } gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lib/src/phy/phch/test/pucch_test_mex.c b/lib/src/phy/phch/test/pucch_test_mex.c deleted file mode 100644 index 1e60a57fa..000000000 --- a/lib/src/phy/phch/test/pucch_test_mex.c +++ /dev/null @@ -1,227 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PUCCHCFG prhs[1] -#define N_BITS prhs[2] -#define INPUT prhs[3] -#define THRESHOLD prhs[4] -#define NOF_INPUTS 4 - -void help() -{ - mexErrMsgTxt - ("[data, symbols, ce]=srslte_pucch(ue, chs, n_bits, input)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - srslte_verbose = SRSLTE_VERBOSE_NONE; - - srslte_cell_t cell; - bzero(&cell, sizeof(srslte_cell_t)); - cell.nof_ports = 1; - cell.cp = SRSLTE_CP_NORM; - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - srslte_pucch_t pucch; - if (srslte_pucch_init_ue(&pucch, cell)) { - mexErrMsgTxt("Error initiating PUSCH\n"); - return; - } - - uint32_t sf_idx = 0; - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &sf_idx)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - uint32_t rnti; - if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - if (srslte_pucch_set_crnti(&pucch, (uint16_t) rnti&0xffff)) { - mexErrMsgTxt("Error setting C-RNTI\n"); - return; - } - uint32_t n_pucch; - if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceIdx", &n_pucch)) { - mexErrMsgTxt("Field ResourceIdx not found in PUCCHCFG\n"); - return; - } - srslte_pucch_cfg_t pucch_cfg; - bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); - - if (mexutils_read_uint32_struct(PUCCHCFG, "DeltaShift", &pucch_cfg.delta_pucch_shift)) { - mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n"); - return; - } - if (mexutils_read_uint32_struct(PUCCHCFG, "ResourceSize", &pucch_cfg.n_rb_2)) { - mexErrMsgTxt("Field DeltaShift not found in PUCCHCFG\n"); - return; - } - if (mexutils_read_uint32_struct(PUCCHCFG, "CyclicShifts", &pucch_cfg.N_cs)) { - mexErrMsgTxt("Field CyclicShifts not found in PUCCHCFG\n"); - return; - } - bool group_hopping_en = false; - char *hop = mexutils_get_char_struct(UECFG, "Hopping"); - if (hop) { - if (!strcmp(hop, "Group")) { - group_hopping_en = true; - } - mxFree(hop); - } - - pucch.shortened = false; - uint32_t sh = 0; - mexutils_read_uint32_struct(PUCCHCFG, "Shortened", &sh); - if (sh == 1) { - pucch.shortened = true; - } - - float *thresholds; - int th_len = 0; - - if (nrhs > NOF_INPUTS) { - th_len = mexutils_read_f(THRESHOLD, &thresholds); - if (th_len == 2) { - srslte_pucch_set_threshold(&pucch, thresholds[0], thresholds[1]); - } - } - - uint8_t bits[SRSLTE_PUCCH_MAX_BITS]; - int nof_bits = (int) mxGetScalar(N_BITS); - - srslte_pucch_format_t format; - switch(nof_bits) { - case 0: - format = SRSLTE_PUCCH_FORMAT_1; - break; - case 1: - format = SRSLTE_PUCCH_FORMAT_1A; - break; - case 2: - format = SRSLTE_PUCCH_FORMAT_1B; - break; - case 20: - format = SRSLTE_PUCCH_FORMAT_2; - break; - case 21: - format = SRSLTE_PUCCH_FORMAT_2A; - break; - case 22: - format = SRSLTE_PUCCH_FORMAT_2B; - break; - default: - mexErrMsgTxt("Invalid number of bits in parameter ack\n"); - return; - } - if (nof_bits > 20) { - nof_bits = 20; - } - - cf_t *sf_symbols = NULL; - int nof_re = mexutils_read_cf(INPUT, &sf_symbols); - if (nof_re < 0) { - mexErrMsgTxt("Error reading input\n"); - return; - } - cf_t *ce = srslte_vec_malloc(nof_re*sizeof(cf_t)); - if (!ce) { - perror("malloc"); - return; - } - bzero(ce, nof_re*sizeof(cf_t)); - srslte_chest_ul_t chest_ul; - if (srslte_chest_ul_init(&chest_ul, cell)) { - mexErrMsgTxt("Error initiating PUCCH DMRS\n"); - return; - } - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - pusch_cfg.group_hopping_en = group_hopping_en; - pusch_cfg.sequence_hopping_en = false; - srslte_chest_ul_set_cfg(&chest_ul, &pusch_cfg, &pucch_cfg, NULL); - - srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en); - - uint8_t pucch2_ack_bits[2] = {0}; - - if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx, &pucch2_ack_bits)) { - mexErrMsgTxt("Error estimating PUCCH DMRS\n"); - return; - } - - if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, (uint16_t) rnti, sf_symbols, ce, 0, bits)<0) { - mexErrMsgTxt("Error decoding PUCCH\n"); - return; - } - - if (nlhs >= 1) { - if (format != SRSLTE_PUCCH_FORMAT_1) { - mexutils_write_uint8(bits, &plhs[0], nof_bits, 1); - } else { - if (bits[0] == 1) { - mexutils_write_uint8(bits, &plhs[0], 0, 1); - } else { - mexutils_write_uint8(bits, &plhs[0], 0, 0); - } - } - } - - if (nlhs >= 2) { - mexutils_write_cf(pucch.z, &plhs[1], 10, 1); - } - - if (nlhs >= 3) { - mexutils_write_cf(pucch.z_tmp, &plhs[2], 120, 1); - } - - srslte_pucch_free(&pucch); - free(sf_symbols); - - return; -} - diff --git a/lib/src/phy/phch/test/pusch_encode_test_mex.c b/lib/src/phy/phch/test/pusch_encode_test_mex.c deleted file mode 100644 index 59c0bbe15..000000000 --- a/lib/src/phy/phch/test/pusch_encode_test_mex.c +++ /dev/null @@ -1,251 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PUSCHCFG prhs[1] -#define TRBLKIN prhs[2] -#define CQI prhs[3] -#define RI prhs[4] -#define ACK prhs[5] -#define NOF_INPUTS 6 - -void help() -{ - mexErrMsgTxt - ("sym=srslte_pusch_encode(ue, chs, trblkin, cqi, ri, ack)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - srslte_verbose = SRSLTE_VERBOSE_NONE; - - srslte_cell_t cell; - bzero(&cell, sizeof(srslte_cell_t)); - cell.nof_ports = 1; - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - srslte_pusch_t pusch; - if (srslte_pusch_init(&pusch, cell)) { - mexErrMsgTxt("Error initiating PUSCH\n"); - return; - } - uint32_t rnti32=0; - if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti32)) { - mexErrMsgTxt("Field RNTI not found in pusch config\n"); - return; - } - - uint16_t rnti = (uint16_t) (rnti32 & 0xffff); - srslte_pusch_set_rnti(&pusch, rnti); - - - srslte_pusch_cfg_t cfg; - bzero(&cfg, sizeof(srslte_pusch_cfg_t)); - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &cfg.sf_idx)) { - mexErrMsgTxt("Field NSubframe not found in UE config\n"); - return; - } - - srslte_ra_ul_grant_t grant; - bzero(&grant, sizeof(srslte_ra_ul_grant_t)); - - char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); - if (!strcmp(mod_str, "QPSK")) { - grant.mcs.mod = SRSLTE_MOD_QPSK; - } else if (!strcmp(mod_str, "16QAM")) { - grant.mcs.mod = SRSLTE_MOD_16QAM; - } else if (!strcmp(mod_str, "64QAM")) { - grant.mcs.mod = SRSLTE_MOD_64QAM; - } else { - mexErrMsgTxt("Unknown modulation\n"); - return; - } - mxFree(mod_str); - - float *prbset = NULL; - mxArray *p; - p = mxGetField(PUSCHCFG, 0, "PRBSet"); - if (!p) { - mexErrMsgTxt("Error field PRBSet not found\n"); - return; - } - - uint32_t N_srs = 0; - mexutils_read_uint32_struct(PUSCHCFG, "Shortened", &N_srs); - if (N_srs == 1) { - pusch.shortened = true; - } - - grant.L_prb = mexutils_read_f(p, &prbset); - grant.n_prb[0] = prbset[0]; - grant.n_prb[1] = prbset[0]; - free(prbset); - - uint8_t *trblkin_bits = NULL; - grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits); - - uint8_t *trblkin = srslte_vec_malloc(grant.mcs.tbs/8); - srslte_bit_pack_vector(trblkin_bits, trblkin, grant.mcs.tbs); - free(trblkin_bits); - - grant.M_sc = grant.L_prb*SRSLTE_NRE; - grant.M_sc_init = grant.M_sc; // FIXME: What should M_sc_init be? - grant.Qm = srslte_mod_bits_x_symbol(grant.mcs.mod); - - if (srslte_pusch_cfg(&pusch, &cfg, &grant, NULL, NULL, NULL, cfg.sf_idx, cfg.rv, 0)) { - fprintf(stderr, "Error configuring PUSCH\n"); - exit(-1); - } - - mexPrintf("L_prb: %d, n_prb: %d\n", grant.L_prb, grant.n_prb[0]); - - srslte_softbuffer_tx_t softbuffer; - if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { - mexErrMsgTxt("Error initiating soft buffer\n"); - return; - } - - uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp); - cf_t *sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re); - if (!sf_symbols) { - mexErrMsgTxt("malloc"); - return; - } - bzero(sf_symbols, sizeof(cf_t) * nof_re); - - - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - uint8_t *tmp; - uci_data.uci_cqi_len = mexutils_read_uint8(CQI, &tmp); - memcpy(&uci_data.uci_cqi, tmp, uci_data.uci_cqi_len); - free(tmp); - uci_data.uci_ri_len = mexutils_read_uint8(RI, &tmp); - if (uci_data.uci_ri_len > 0) { - uci_data.uci_ri = *tmp; - } - free(tmp); - uci_data.uci_ack_len = mexutils_read_uint8(ACK, &tmp); - if (uci_data.uci_ack_len > 0) { - uci_data.uci_ack = *tmp; - } - free(tmp); - - - float beta; - if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &beta)) { - cfg.uci_cfg.I_offset_cqi = 7; - } else { - cfg.uci_cfg.I_offset_cqi = srslte_sch_find_Ioffset_cqi(beta); - } - if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &beta)) { - cfg.uci_cfg.I_offset_ri = 2; - } else { - cfg.uci_cfg.I_offset_ri = srslte_sch_find_Ioffset_ri(beta); - } - if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &beta)) { - cfg.uci_cfg.I_offset_ack = 0; - } else { - cfg.uci_cfg.I_offset_ack = srslte_sch_find_Ioffset_ack(beta); - } - mexPrintf("TRBL_len: %d, CQI_len: %2d, ACK_len: %d (%d), RI_len: %d (%d)\n", grant.mcs.tbs, - uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ack, uci_data.uci_ri_len, uci_data.uci_ri); - - mexPrintf("I_cqi: %2d, I_ri: %2d, I_ack=%2d\n", cfg.uci_cfg.I_offset_cqi, cfg.uci_cfg.I_offset_ri, cfg.uci_cfg.I_offset_ack); - - mexPrintf("NofRE: %3d, NofBits: %3d, TBS: %3d, N_srs=%d\n", cfg.nbits.nof_re, cfg.nbits.nof_bits, grant.mcs.tbs, N_srs); - int r = srslte_pusch_encode(&pusch, &cfg, &softbuffer, trblkin, uci_data, rnti, sf_symbols); - if (r < 0) { - mexErrMsgTxt("Error encoding PUSCH\n"); - return; - } - if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &cfg.rv)) { - mexErrMsgTxt("Field RV not found in pdsch config\n"); - return; - } - if (cfg.rv > 0) { - r = srslte_pusch_encode(&pusch, &cfg, &softbuffer, trblkin, uci_data, rnti, sf_symbols); - if (r < 0) { - mexErrMsgTxt("Error encoding PUSCH\n"); - return; - } - } - - - if (nlhs >= 1) { - - cf_t *scfdma = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - bzero(scfdma, sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - srslte_ofdm_t fft; - srslte_ofdm_tx_init(&fft, SRSLTE_CP_NORM, cell.nof_prb); - srslte_ofdm_set_normalize(&fft, true); - srslte_ofdm_set_freq_shift(&fft, 0.5); - - srslte_ofdm_tx_sf(&fft, sf_symbols, scfdma); - // Matlab toolbox expects further normalization - srslte_vec_sc_prod_cfc(scfdma, 1.0/sqrtf(srslte_symbol_sz(cell.nof_prb)), scfdma, SRSLTE_SF_LEN_PRB(cell.nof_prb)); - - mexutils_write_cf(scfdma, &plhs[0], SRSLTE_SF_LEN_PRB(cell.nof_prb), 1); - - free(scfdma); - - } - if (nlhs >= 2) { - mexutils_write_cf(sf_symbols, &plhs[1], nof_re, 1); - } - if (nlhs >= 3) { - mexutils_write_cf(pusch.z, &plhs[2], cfg.nbits.nof_re, 1); - } - if (nlhs >= 4) { - mexutils_write_uint8(pusch.q, &plhs[3], cfg.nbits.nof_bits, 1); - } - srslte_pusch_free(&pusch); - srslte_softbuffer_tx_free(&softbuffer); - free(trblkin); - free(sf_symbols); - - return; -} - diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index b2b7a263f..0ad1a9b34 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -24,11 +24,13 @@ * */ +#include "srslte/srslte.h" +#include #include #include #include -#include #include +#include #include "srslte/srslte.h" @@ -41,53 +43,36 @@ static srslte_cell_t cell = { .phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources }; -static srslte_uci_cfg_t uci_cfg = { +static srslte_uci_offset_cfg_t uci_cfg = { .I_offset_cqi = 6, - .I_offset_ri = 2, + .I_offset_ri = 2, .I_offset_ack = 9, }; -static srslte_uci_data_t uci_data_tx = { - .uci_cqi = {0}, - .uci_cqi_len = 0, - .uci_ri = 0, - .uci_ri_len = 0, - .uci_ack = 0, - .uci_ack_2 = 0, - .uci_ack_len = 0, - .ri_periodic_report = false, - .scheduling_request = false, - .channel_selection = false, - .cqi_ack = false -}; +static srslte_uci_data_t uci_data_tx; -uint32_t cfi = 2; +uint32_t L_rb = 2; uint32_t tbs = 0; uint32_t subframe = 10; srslte_mod_t modulation = SRSLTE_MOD_QPSK; uint32_t rv_idx = 0; -uint32_t L_prb = 2; -uint32_t n_prb = 0; int freq_hop = -1; int riv = -1; uint32_t mcs_idx = 0; -srslte_cqi_value_t cqi_value; bool enable_64_qam = false; void usage(char *prog) { - printf("Usage: %s [csrnfvmtLNF] \n", prog); + printf("Usage: %s [csrnfvmtF] \n", prog); printf("\n\tCell specific parameters:\n"); printf("\t\t-n number of PRB [Default %d]\n", cell.nof_prb); printf("\t\t-c cell id [Default %d]\n", cell.id); printf("\n\tGrant parameters:\n"); printf("\t\t-m MCS index (0-28) [Default %d]\n", mcs_idx); - printf("\t\t-L L_prb [Default %d]\n", L_prb); - printf("\t\t-N n_prb [Default %d]\n", n_prb); printf("\t\t-F frequency hopping [Default %d]\n", freq_hop); + printf("\t\t-L L_rb [Default %d]\n", L_rb); printf("\t\t-R RIV [Default %d]\n", riv); printf("\t\t-r rv_idx (0-3) [Default %d]\n", rv_idx); - printf("\t\t-f cfi [Default %d]\n", cfi); printf("\n\tCQI/RI/ACK Reporting indexes parameters:\n"); printf("\t\t-p I_offset_cqi (0-15) [Default %d]\n", uci_cfg.I_offset_cqi); @@ -95,10 +80,9 @@ void usage(char *prog) { printf("\t\t-p I_offset_ack (0-15) [Default %d]\n", uci_cfg.I_offset_ack); printf("\n\tCQI/RI/ACK Reporting contents:\n"); - printf("\t\t-p uci_cqi (none, wideband) [Default none]\n"); - printf("\t\t-p uci_ri (0-1) (zeros, ones, random) [Default none]\n"); + printf("\t\t-p cqi (none, wideband) [Default none]\n"); + printf("\t\t-p ri (0-1) (zeros, ones, random) [Default none]\n"); printf("\t\t-p uci_ack [Default none]\n"); - printf("\t\t-p uci_ack_2 [Default none]\n"); printf("\n\tOther parameters:\n"); printf("\t\t-p enable_64qam [Default %s]\n", enable_64_qam ? "enabled":"disabled"); @@ -123,38 +107,25 @@ void parse_extensive_param(char *param, char *arg) { if (uci_cfg.I_offset_ack > 15) { ext_code = SRSLTE_ERROR; } - } else if (!strcmp(param, "uci_cqi")) { + } else if (!strcmp(param, "cqi")) { if (!strcmp(arg, "wideband")) { - cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - cqi_value.wideband.wideband_cqi = (uint8_t) (random() & 0x0f); - uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_value, uci_data_tx.uci_cqi); + uci_data_tx.cfg.cqi.type = SRSLTE_CQI_TYPE_WIDEBAND; + uci_data_tx.value.cqi.wideband.wideband_cqi = (uint8_t)(0x0f); + uci_data_tx.cfg.cqi.data_enable = true; } else if (!strcmp(arg, "none")) { - uci_data_tx.uci_cqi_len = 0; + uci_data_tx.cfg.cqi.data_enable = false; } else { ext_code = SRSLTE_ERROR; } - } else if (!strcmp(param, "uci_ri")) { - uci_data_tx.uci_ri = (uint8_t) strtol(arg, NULL, 10); - if (uci_data_tx.uci_ri > 1) { + } else if (!strcmp(param, "ri")) { + uci_data_tx.value.ri = (uint8_t)strtol(arg, NULL, 10); + if (uci_data_tx.value.ri > 1) { ext_code = SRSLTE_ERROR; } else { - uci_data_tx.uci_ri_len = 1; + uci_data_tx.cfg.cqi.ri_len = 1; } } else if (!strcmp(param, "uci_ack")) { - uci_data_tx.uci_ack_len++; - if (uci_data_tx.uci_ack_len > 2) { - uci_data_tx.uci_ack_len = 2; - } - } else if (!strcmp(param, "uci_ack_2")) { - uci_data_tx.uci_ack_2 = (uint8_t) strtol(arg, NULL, 10); - if (uci_data_tx.uci_ack_2 > 1) { - ext_code = SRSLTE_ERROR; - } else { - uci_data_tx.uci_ack_len++; - if (uci_data_tx.uci_ack_len > 2) { - uci_data_tx.uci_ack_len = 2; - } - } + uci_data_tx.cfg.ack.nof_acks = SRSLTE_MIN(uci_data_tx.cfg.ack.nof_acks + 1, SRSLTE_UCI_MAX_ACK_BITS); } else if (!strcmp(param, "enable_64qam")) { enable_64_qam ^= true; } else { @@ -162,14 +133,14 @@ void parse_extensive_param(char *param, char *arg) { } if (ext_code) { - fprintf(stderr, "Error parsing parameter '%s' and argument '%s'\n", param, arg); + ERROR("Error parsing parameter '%s' and argument '%s'\n", param, arg); exit(ext_code); } } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "msLNRFrncpvf")) != -1) { + while ((opt = getopt(argc, argv, "msLFrncpvf")) != -1) { switch (opt) { case 'm': mcs_idx = (uint32_t) strtol(argv[optind], NULL, 10); @@ -177,18 +148,12 @@ void parse_args(int argc, char **argv) { case 's': subframe = (uint32_t) strtol(argv[optind], NULL, 10); break; - case 'f': - cfi = (uint32_t) strtol(argv[optind], NULL, 10); - break; - case 'L': - L_prb = (uint32_t) strtol(argv[optind], NULL, 10); - break; - case 'N': - n_prb = (uint32_t) strtol(argv[optind], NULL, 10); - break; case 'R': riv = (int) strtol(argv[optind], NULL, 10); break; + case 'L': + L_rb = (int)strtol(argv[optind], NULL, 10); + break; case 'F': freq_hop = (int) strtol(argv[optind], NULL, 10); break; @@ -215,70 +180,80 @@ void parse_args(int argc, char **argv) { } } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ + srslte_chest_ul_res_t chest_res; srslte_pusch_t pusch_tx; srslte_pusch_t pusch_rx; uint8_t *data = NULL; uint8_t *data_rx = NULL; cf_t *sf_symbols = NULL; - cf_t *ce = NULL; int ret = -1; struct timeval t[3]; srslte_pusch_cfg_t cfg; srslte_softbuffer_tx_t softbuffer_tx; srslte_softbuffer_rx_t softbuffer_rx; - parse_args(argc, argv); + ZERO_OBJECT(uci_data_tx); bzero(&cfg, sizeof(srslte_pusch_cfg_t)); srslte_dft_load(); - srslte_ra_ul_dci_t dci; + srslte_dci_ul_t dci; + ZERO_OBJECT(dci); + + srand(time(NULL)); + parse_args(argc, argv); + dci.freq_hop_fl = freq_hop; - if (riv < 0) { - dci.type2_alloc.L_crb = L_prb; - dci.type2_alloc.RB_start = n_prb; - } else { + if (riv >= 0) { dci.type2_alloc.riv = (uint32_t) riv; + } else { + dci.type2_alloc.riv = srslte_ra_type2_to_riv(L_rb, 0, cell.nof_prb); } - dci.mcs_idx = mcs_idx; + dci.tb.mcs_idx = mcs_idx; - srslte_ra_ul_grant_t grant; - if (srslte_ra_ul_dci_to_grant(&dci, cell.nof_prb, 0, &grant)) { - fprintf(stderr, "Error computing resource allocation\n"); - return ret; - } + srslte_ul_sf_cfg_t ul_sf; + ZERO_OBJECT(ul_sf); + ul_sf.tti = 0; srslte_pusch_hopping_cfg_t ul_hopping; ul_hopping.n_sb = 1; ul_hopping.hopping_offset = 0; ul_hopping.hop_mode = 1; + if (srslte_ra_ul_dci_to_grant(&cell, &ul_sf, &ul_hopping, &dci, &cfg.grant)) { + ERROR("Error computing resource allocation\n"); + return ret; + } + + cfg.grant.n_prb_tilde[0] = cfg.grant.n_prb[0]; + cfg.grant.n_prb_tilde[1] = cfg.grant.n_prb[1]; + if (srslte_pusch_init_ue(&pusch_tx, cell.nof_prb)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); goto quit; } if (srslte_pusch_set_cell(&pusch_tx, cell)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); goto quit; } if (srslte_pusch_init_enb(&pusch_rx, cell.nof_prb)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); goto quit; } if (srslte_pusch_set_cell(&pusch_rx, cell)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); goto quit; } - uint16_t rnti = 1234; + uint16_t rnti = 62; + dci.rnti = rnti; + cfg.rnti = rnti; srslte_pusch_set_rnti(&pusch_tx, rnti); srslte_pusch_set_rnti(&pusch_rx, rnti); - srslte_uci_data_t uci_data_rx; - memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); - uint32_t nof_re = SRSLTE_NRE * cell.nof_prb * 2 * SRSLTE_CP_NSYMB(cell.cp); sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re); if (!sf_symbols) { @@ -299,135 +274,109 @@ int main(int argc, char **argv) { } if (srslte_softbuffer_tx_init(&softbuffer_tx, 100)) { - fprintf(stderr, "Error initiating soft buffer\n"); + ERROR("Error initiating soft buffer\n"); goto quit; } if (srslte_softbuffer_rx_init(&softbuffer_rx, 100)) { - fprintf(stderr, "Error initiating soft buffer\n"); + ERROR("Error initiating soft buffer\n"); goto quit; } - ce = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); - if (!ce) { - perror("srslte_vec_malloc"); - goto quit; - } - for (int j = 0; j < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); j++) { - ce[j] = 1; - } + srslte_chest_ul_res_init(&chest_res, cell.nof_prb); + srslte_chest_ul_res_set_identity(&chest_res); - if (!enable_64_qam && grant.mcs.mod == SRSLTE_MOD_64QAM) { - grant.mcs.mod = SRSLTE_MOD_16QAM; - grant.Qm = 4; - } + cfg.enable_64qam = enable_64_qam; for (int n = 0; n < subframe; n++) { ret = SRSLTE_SUCCESS; /* Configure PUSCH */ - if (srslte_pusch_cfg(&pusch_tx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, (uint32_t) n % 10, 0, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, (uint32_t) n % 10, 0, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } + ul_sf.tti = n; + cfg.uci_offset = uci_cfg; srslte_softbuffer_tx_reset(&softbuffer_tx); srslte_softbuffer_rx_reset(&softbuffer_rx); - for (uint32_t i = 0; i < cfg.grant.mcs.tbs / 8; i++) { + for (uint32_t i = 0; i < cfg.grant.tb.tbs / 8; i++) { data[i] = (uint8_t) (random() & 0xff); } - for (uint32_t i = 0; i < uci_data_tx.uci_cqi_len; i++) { - uci_data_tx.uci_cqi[i] = (uint8_t) (random() & 0x1); + for (uint32_t a = 0; a < uci_data_tx.cfg.ack.nof_acks; a++) { + uci_data_tx.value.ack.ack_value[a] = (uint8_t)(random() & 0x1); } - if (uci_data_tx.uci_ack_len > 0) { - uci_data_tx.uci_ack = (uint8_t) (random() & 0x1); - } + srslte_pusch_data_t pdata; + pdata.ptr = data; + pdata.uci = uci_data_tx.value; + cfg.uci_cfg = uci_data_tx.cfg; + cfg.softbuffers.tx = &softbuffer_tx; - if (uci_data_tx.uci_ack_len > 1) { - uci_data_tx.uci_ack_2 = (uint8_t) (random() & 0x1); - } - - if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { - fprintf(stderr, "Error encoding TB\n"); + if (srslte_pusch_encode(&pusch_tx, &ul_sf, &cfg, &pdata, sf_symbols)) { + ERROR("Error encoding TB\n"); exit(-1); } if (rv_idx > 0) { - cfg.rv = rv_idx; - if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { - fprintf(stderr, "Error encoding TB\n"); + + cfg.grant.tb.rv = rv_idx; + if (srslte_pusch_encode(&pusch_tx, &ul_sf, &cfg, &pdata, sf_symbols)) { + ERROR("Error encoding TB\n"); exit(-1); } } + srslte_pusch_res_t pusch_res; + pusch_res.data = data_rx; + cfg.softbuffers.rx = &softbuffer_rx; + memcpy(&cfg.uci_cfg, &uci_data_tx.cfg, sizeof(srslte_uci_cfg_t)); + gettimeofday(&t[1], NULL); - int r = srslte_pusch_decode(&pusch_rx, - &cfg, - &softbuffer_rx, - sf_symbols, - ce, - 0, - rnti, - data_rx, - (uci_data_tx.uci_cqi_len) ? &cqi_value : NULL, - &uci_data_rx); + int r = srslte_pusch_decode(&pusch_rx, &ul_sf, &cfg, &chest_res, sf_symbols, &pusch_res); gettimeofday(&t[2], NULL); if (r) { printf("Error returned while decoding\n"); ret = SRSLTE_ERROR; } - if (memcmp(data_rx, data, (size_t) cfg.grant.mcs.tbs / 8) != 0) { + if (memcmp(data_rx, data, (size_t)cfg.grant.tb.tbs / 8) != 0) { printf("Unmatched data detected\n"); ret = SRSLTE_ERROR; } else { INFO("Rx Data is Ok\n"); } - if (uci_data_tx.uci_ack_len) { - if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) { - printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack); - ret = SRSLTE_ERROR; - } else { - INFO("Rx ACK is Ok\n"); - } - } - - if (uci_data_tx.uci_ack_len > 1) { - if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) { - printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2); + if (uci_data_tx.cfg.ack.nof_acks) { + if (memcmp(uci_data_tx.value.ack.ack_value, pusch_res.uci.ack.ack_value, uci_data_tx.cfg.ack.nof_acks) != 0) { + printf("UCI ACK bit error:\n"); + printf("\tTx: "); + srslte_vec_fprint_byte(stdout, uci_data_tx.value.ack.ack_value, uci_data_tx.cfg.ack.nof_acks); + printf("\tRx: "); + srslte_vec_fprint_byte(stdout, pusch_res.uci.ack.ack_value, cfg.uci_cfg.ack.nof_acks); ret = SRSLTE_ERROR; } else { - INFO("Rx ACK2 is Ok\n"); + INFO("Rx ACK (%d bits) is Ok, %d%d\n", + uci_data_tx.cfg.ack.nof_acks, + uci_data_tx.value.ack.ack_value[0], + uci_data_tx.value.ack.ack_value[1]); } } - if (uci_data_tx.uci_ri_len) { - if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) { - printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri); + if (uci_data_tx.cfg.cqi.ri_len) { + if (uci_data_tx.value.ri != pusch_res.uci.ri) { + printf("UCI RI bit error: %d != %d\n", uci_data_tx.value.ri, pusch_res.uci.ri); ret = SRSLTE_ERROR; } else { INFO("Rx RI is Ok\n"); } } - if (uci_data_tx.uci_cqi_len) { - if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, uci_data_tx.uci_cqi_len) != 0) { + if (uci_data_tx.cfg.cqi.data_enable) { + uci_data_tx.value.cqi.data_crc = pusch_res.uci.cqi.data_crc; + if (memcmp(&uci_data_tx.value.cqi, &pusch_res.uci.cqi, sizeof(pusch_res.uci.cqi)) != 0) { printf("CQI Decode failed at subframe %d\n", n); - printf("cqi_tx="); - srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len); - printf("cqi_rx="); - srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len); ret = SRSLTE_ERROR; } else { - INFO("Rx CQI is Ok\n"); + INFO("Rx CQI is Ok (crc=%d, wb_cqi=%d)\n", pusch_res.uci.cqi.data_crc, pusch_res.uci.cqi.wideband.wideband_cqi); } } @@ -436,22 +385,23 @@ int main(int argc, char **argv) { } get_time_interval(t); - printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec, - (int) t[0].tv_usec, - cfg.grant.mcs.tbs, - (float) cfg.grant.mcs.tbs / 1000, - (float) cfg.grant.mcs.tbs / t[0].tv_usec); - + printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", + (int)t[0].tv_sec, + (int)t[0].tv_usec, + cfg.grant.tb.tbs, + (float)cfg.grant.tb.tbs / 1000, + (float)cfg.grant.tb.tbs / t[0].tv_usec); } quit: - srslte_pusch_free(&pusch_tx); - srslte_pusch_free(&pusch_rx); - srslte_softbuffer_tx_free(&softbuffer_tx); - srslte_softbuffer_rx_free(&softbuffer_rx); - - if (sf_symbols) { - free(sf_symbols); + srslte_chest_ul_res_free(&chest_res); + srslte_pusch_free(&pusch_tx); + srslte_pusch_free(&pusch_rx); + srslte_softbuffer_tx_free(&softbuffer_tx); + srslte_softbuffer_rx_free(&softbuffer_rx); + + if (sf_symbols) { + free(sf_symbols); } if (data) { free(data); @@ -459,9 +409,6 @@ int main(int argc, char **argv) { if (data_rx) { free(data_rx); } - if (ce) { - free(ce); - } if (ret) { printf("Error\n"); } else { diff --git a/lib/src/phy/phch/test/pusch_test_mex.c b/lib/src/phy/phch/test/pusch_test_mex.c deleted file mode 100644 index 7b29075eb..000000000 --- a/lib/src/phy/phch/test/pusch_test_mex.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define UECFG prhs[0] -#define PUSCHCFG prhs[1] -#define TBS prhs[2] -#define INPUT prhs[3] -#define NOF_INPUTS 4 - -void help() -{ - mexErrMsgTxt - ("[decoded_ok, cqi_data, ri_data, ack_data] = srslte_pusch(ueConfig, puschConfig, trblklen, rxWaveform)\n\n"); -} - -extern int indices[2048]; - -int rv_seq[4] = {0, 2, 3, 1}; - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - srslte_ofdm_t ofdm_rx; - srslte_pusch_t pusch; - srslte_chest_ul_t chest; - cf_t *input_fft; - srslte_softbuffer_rx_t softbuffer; - uint32_t rnti32; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - srslte_verbose = SRSLTE_VERBOSE_INFO; - - srslte_cell_t cell; - bzero(&cell, sizeof(srslte_cell_t)); - cell.nof_ports = 1; - if (mexutils_read_uint32_struct(UECFG, "NCellID", &cell.id)) { - mexErrMsgTxt("Field NCellID not found in UE config\n"); - return; - } - if (mexutils_read_uint32_struct(UECFG, "NULRB", &cell.nof_prb)) { - mexErrMsgTxt("Field NULRB not found in UE config\n"); - return; - } - - srslte_pusch_cfg_t cfg; - bzero(&cfg, sizeof(srslte_pusch_cfg_t)); - if (mexutils_read_uint32_struct(UECFG, "RNTI", &rnti32)) { - mexErrMsgTxt("Field RNTI not found in pdsch config\n"); - return; - } - - if (mexutils_read_uint32_struct(UECFG, "NSubframe", &cfg.sf_idx)) { - help(); - return; - } - - if (srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); - return; - } - srslte_ofdm_set_normalize(&ofdm_rx, true); - srslte_ofdm_set_freq_shift(&ofdm_rx, 0.5); - - if (srslte_pusch_init(&pusch, cell)) { - mexErrMsgTxt("Error initiating PDSCH\n"); - return; - } - uint16_t rnti = (uint16_t) (rnti32 & 0xffff); - srslte_pusch_set_rnti(&pusch, rnti); - - if (srslte_softbuffer_rx_init(&softbuffer, cell.nof_prb)) { - mexErrMsgTxt("Error initiating soft buffer\n"); - return; - } - - if (srslte_chest_ul_init(&chest, cell)) { - mexErrMsgTxt("Error initializing equalizer\n"); - return; - } - - srslte_ra_ul_grant_t grant; - bzero(&grant, sizeof(srslte_ra_ul_grant_t)); - - char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); - if (!strcmp(mod_str, "QPSK")) { - grant.mcs.mod = SRSLTE_MOD_QPSK; - } else if (!strcmp(mod_str, "16QAM")) { - grant.mcs.mod = SRSLTE_MOD_16QAM; - } else if (!strcmp(mod_str, "64QAM")) { - grant.mcs.mod = SRSLTE_MOD_64QAM; - } else { - mexErrMsgTxt("Unknown modulation\n"); - return; - } - mxFree(mod_str); - - grant.mcs.tbs = mxGetScalar(TBS); - if (grant.mcs.tbs == 0) { - mexErrMsgTxt("Error trblklen is zero\n"); - return; - } - - uint32_t N_srs = 0; - mexutils_read_uint32_struct(PUSCHCFG, "Shortened", &N_srs); - if (N_srs == 1) { - pusch.shortened = true; - } - - float *prbset = NULL; - mxArray *p; - p = mxGetField(PUSCHCFG, 0, "PRBSet"); - if (!p) { - mexErrMsgTxt("Error field PRBSet not found\n"); - return; - } - - grant.L_prb = mexutils_read_f(p, &prbset); - grant.n_prb[0] = prbset[0]; - grant.n_prb[1] = prbset[0]; - free(prbset); - - grant.M_sc = grant.L_prb*SRSLTE_NRE; - grant.M_sc_init = grant.M_sc; // FIXME: What should M_sc_init be? - grant.Qm = srslte_mod_bits_x_symbol(grant.mcs.mod); - - if (srslte_cbsegm(&cfg.cb_segm, grant.mcs.tbs)) { - mexErrMsgTxt("Error computing CB segmentation\n"); - return; - } - - if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &cfg.rv)) { - mexErrMsgTxt("Field RV not found in pdsch config\n"); - return; - } - - uint32_t max_iterations = 5; - mexutils_read_uint32_struct(PUSCHCFG, "NTurboDecIts", &max_iterations); - - /* Configure rest of pdsch_cfg parameters */ - if (srslte_pusch_cfg(&pusch, &cfg, &grant, NULL, NULL, NULL, cfg.sf_idx, cfg.rv, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - - mexutils_read_uint32_struct(PUSCHCFG, "OCQI", &uci_data.uci_cqi_len); - mexutils_read_uint32_struct(PUSCHCFG, "ORI", &uci_data.uci_ri_len); - mexutils_read_uint32_struct(PUSCHCFG, "OACK", &uci_data.uci_ack_len); - - float beta; - if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &beta)) { - cfg.uci_cfg.I_offset_cqi = 7; - } else { - cfg.uci_cfg.I_offset_cqi = srslte_sch_find_Ioffset_cqi(beta); - } - if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &beta)) { - cfg.uci_cfg.I_offset_ri = 2; - } else { - cfg.uci_cfg.I_offset_ri = srslte_sch_find_Ioffset_ri(beta); - } - if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &beta)) { - cfg.uci_cfg.I_offset_ack = 0; - } else { - cfg.uci_cfg.I_offset_ack = srslte_sch_find_Ioffset_ack(beta); - } - mexPrintf("TRBL_len: %d, CQI_len: %2d, ACK_len: %d (%d), RI_len: %d (%d)\n", grant.mcs.tbs, - uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ack, uci_data.uci_ri_len, uci_data.uci_ri); - - mexPrintf("I_cqi: %2d, I_ri: %2d, I_ack=%2d\n", cfg.uci_cfg.I_offset_cqi, cfg.uci_cfg.I_offset_ri, cfg.uci_cfg.I_offset_ack); - - - mexPrintf("L_prb: %d, n_prb: %d/%d, TBS=%d\n", grant.L_prb, grant.n_prb[0], grant.n_prb[1], grant.mcs.tbs); - - /** Allocate input buffers */ - int nof_retx=1; - if (mexutils_isCell(INPUT)) { - nof_retx = mexutils_getLength(INPUT); - } - - cf_t *ce = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));; - - uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8); - if (!data_bytes) { - return; - } - srslte_sch_set_max_noi(&pusch.ul_sch, max_iterations); - - input_fft = NULL; - int r=-1; - for (int rvIdx=0;rvIdx 1) { - cfg.rv = rv_seq[rvIdx%4]; - } - } - - // Read input signal - cf_t *input_signal = NULL; - int insignal_len = mexutils_read_cf(tmp, &input_signal); - if (insignal_len < 0) { - mexErrMsgTxt("Error reading input signal\n"); - return; - } - if (insignal_len == SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)) { - input_fft = input_signal; - mexPrintf("Input is after fft\n"); - } else { - input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - srslte_ofdm_rx_sf(&ofdm_rx, input_signal, input_fft); - mexPrintf("Input is before fft\n"); - free(input_signal); - } - - if (nrhs > NOF_INPUTS) { - cf_t *cearray = NULL; - mexutils_read_cf(prhs[NOF_INPUTS], &cearray); - cf_t *cearray_ptr = cearray; - for (int j=0;j NOF_INPUTS + 1) { - noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); - } else if (nrhs > NOF_INPUTS) { - noise_power = 0; - } else { - noise_power = srslte_chest_ul_get_noise_estimate(&chest); - } - - r = srslte_pusch_decode(&pusch, &cfg, &softbuffer, input_fft, ce, noise_power, rnti, data_bytes, &uci_data); - } - - uint8_t *data = malloc(grant.mcs.tbs); - srslte_bit_unpack_vector(data_bytes, data, grant.mcs.tbs); - - if (nlhs >= 1) { - plhs[0] = mxCreateLogicalScalar(r == 0); - } - if (nlhs >= 2) { - mexutils_write_uint8(uci_data.uci_cqi, &plhs[1], uci_data.uci_cqi_len, 1); - } - if (nlhs >= 3 && uci_data.uci_ri_len <= 1) { - mexutils_write_uint8(&uci_data.uci_ri, &plhs[2], uci_data.uci_ri_len, 1); - } - if (nlhs >= 4 && uci_data.uci_ack_len <= 1) { - mexutils_write_uint8(&uci_data.uci_ack, &plhs[3], uci_data.uci_ack_len, 1); - } - - srslte_softbuffer_rx_free(&softbuffer); - srslte_chest_ul_free(&chest); - srslte_pusch_free(&pusch); - srslte_ofdm_rx_free(&ofdm_rx); - - free(ce); - free(data_bytes); - free(data); - if (input_fft) { - free(input_fft); - } - - return; -} - diff --git a/lib/src/phy/phch/test/ulsch_encode_test_mex.c b/lib/src/phy/phch/test/ulsch_encode_test_mex.c deleted file mode 100644 index a74496421..000000000 --- a/lib/src/phy/phch/test/ulsch_encode_test_mex.c +++ /dev/null @@ -1,220 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -#define UECFG prhs[0] -#define PUSCHCFG prhs[1] -#define TRBLKIN prhs[2] -#define CQI prhs[3] -#define RI prhs[4] -#define ACK prhs[5] -#define NOF_INPUTS 6 - -void help() -{ - mexErrMsgTxt - ("[cwout] = srslte_pusch_encode(ue, chs, trblkin, cqi, ri, ack)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - srslte_sch_t ulsch; - - srslte_pusch_cfg_t cfg; - srslte_softbuffer_tx_t softbuffer; - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - uint32_t rv; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - bzero(&cfg, sizeof(srslte_pusch_cfg_t)); - - if (srslte_sch_init(&ulsch)) { - mexErrMsgTxt("Error initiating ULSCH\n"); - return; - } - srslte_cell_t cell; - cell.nof_prb = 100; - cell.id=1; - cell.cp=SRSLTE_CP_NORM; - - srslte_verbose = SRSLTE_VERBOSE_NONE; - - if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { - mexErrMsgTxt("Error initiating HARQ\n"); - return; - } - - uint8_t *trblkin_bits = NULL; - cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits); - - uint8_t *trblkin = srslte_vec_malloc(cfg.grant.mcs.tbs/8); - srslte_bit_pack_vector(trblkin_bits, trblkin, cfg.grant.mcs.tbs); - free(trblkin_bits); - - - uint8_t *tmp; - uci_data.uci_cqi_len = mexutils_read_uint8(CQI, &tmp); - memcpy(uci_data.uci_cqi, tmp, uci_data.uci_cqi_len); - free(tmp); - uci_data.uci_ri_len = mexutils_read_uint8(RI, &tmp); - if (uci_data.uci_ri_len > 0) { - uci_data.uci_ri = *tmp; - } - free(tmp); - uci_data.uci_ack_len = mexutils_read_uint8(ACK, &tmp); - if (uci_data.uci_ack_len > 0) { - uci_data.uci_ack = *tmp; - } - free(tmp); - - mexPrintf("TRBL_len: %d, CQI_len: %d, ACK_len: %d, RI_len: %d\n", cfg.grant.mcs.tbs, - uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ri_len); - - if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) { - mexErrMsgTxt("Field RV not found in pdsch config\n"); - return; - } - - float beta; - if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &beta)) { - cfg.uci_cfg.I_offset_cqi = 7; - } else { - cfg.uci_cfg.I_offset_cqi = srslte_sch_find_Ioffset_cqi(beta); - } - if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &beta)) { - cfg.uci_cfg.I_offset_ri = 2; - } else { - cfg.uci_cfg.I_offset_ri = srslte_sch_find_Ioffset_ri(beta); - } - if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &beta)) { - cfg.uci_cfg.I_offset_ack = 0; - } else { - cfg.uci_cfg.I_offset_ack = srslte_sch_find_Ioffset_ack(beta); - } - - char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); - - if (!strcmp(mod_str, "QPSK")) { - cfg.grant.mcs.mod = SRSLTE_MOD_QPSK; - } else if (!strcmp(mod_str, "16QAM")) { - cfg.grant.mcs.mod = SRSLTE_MOD_16QAM; - } else if (!strcmp(mod_str, "64QAM")) { - cfg.grant.mcs.mod = SRSLTE_MOD_64QAM; - } else { - mexErrMsgTxt("Unknown modulation\n"); - return; - } - - mxFree(mod_str); - - float *prbset; - mxArray *p; - p = mxGetField(PUSCHCFG, 0, "PRBSet"); - if (!p) { - mexErrMsgTxt("Error field PRBSet not found\n"); - return; - } - - uint32_t N_srs = 0; - mexutils_read_uint32_struct(PUSCHCFG, "Shortened", &N_srs); - - - cfg.grant.L_prb = mexutils_read_f(p, &prbset); - cfg.grant.n_prb[0] = prbset[0]; - cfg.grant.n_prb[1] = prbset[0]; - free(prbset); - cfg.grant.L_prb = mexutils_read_f(p, &prbset); - cfg.grant.n_prb[0] = prbset[0]; - cfg.grant.n_prb[1] = prbset[0]; - cfg.nbits.lstart = 0; - cfg.nbits.nof_symb = 2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs; - cfg.grant.M_sc = cfg.grant.L_prb*SRSLTE_NRE; - cfg.grant.M_sc_init = cfg.grant.M_sc; // FIXME: What should M_sc_init be? - cfg.nbits.nof_re = cfg.nbits.nof_symb*cfg.grant.M_sc; - cfg.grant.Qm = srslte_mod_bits_x_symbol(cfg.grant.mcs.mod); - cfg.nbits.nof_bits = cfg.nbits.nof_re * cfg.grant.Qm; - - mexPrintf("Q_m: %d, NPRB: %d, RV: %d, Nsrs=%d\n", srslte_mod_bits_x_symbol(cfg.grant.mcs.mod), cfg.grant.L_prb, cfg.rv, N_srs); - - mexPrintf("I_cqi: %d, I_ri: %d, I_ack=%d\n", cfg.uci_cfg.I_offset_cqi, cfg.uci_cfg.I_offset_ri, cfg.uci_cfg.I_offset_ack); - - if (srslte_cbsegm(&cfg.cb_segm, cfg.grant.mcs.tbs)) { - mexErrMsgTxt("Error configuring HARQ process\n"); - return; - } - - uint8_t *q_bits = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)/8); - if (!q_bits) { - return; - } - uint8_t *q_bits_unpacked = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)); - if (!q_bits_unpacked) { - return; - } - uint8_t *g_bits = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)/8); - if (!g_bits) { - return; - } - - if (srslte_ulsch_uci_encode(&ulsch, &cfg, &softbuffer, trblkin, uci_data, g_bits, q_bits)) - { - mexErrMsgTxt("Error encoding TB\n"); - return; - } - if (rv > 0) { - cfg.rv = rv; - if (srslte_ulsch_uci_encode(&ulsch, &cfg, &softbuffer, trblkin, uci_data, g_bits, q_bits)) { - mexErrMsgTxt("Error encoding TB\n"); - return; - } - } - - srslte_bit_unpack_vector(q_bits, q_bits_unpacked, cfg.nbits.nof_bits); - - if (nlhs >= 1) { - mexutils_write_uint8(q_bits_unpacked, &plhs[0], cfg.nbits.nof_bits, 1); - } - - srslte_sch_free(&ulsch); - srslte_softbuffer_tx_free(&softbuffer); - - free(trblkin); - free(g_bits); - free(q_bits_unpacked); - free(q_bits); - - - return; -} - diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 9d783a93d..7fc3945ae 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "srslte/phy/phch/uci.h" #include "srslte/phy/fec/cbsegm.h" @@ -172,7 +171,10 @@ int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint8_t *c /* Decode UCI CQI/PMI over PUCCH */ -int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len) +int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t* q, + int16_t b_bits[SRSLTE_CQI_MAX_BITS], + uint8_t* cqi_data, + uint32_t cqi_len) { if (cqi_len < SRSLTE_UCI_MAX_CQI_LEN_PUCCH && b_bits != NULL && @@ -186,8 +188,8 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32 // Calculate correlation with pregenerated word and select maximum int32_t corr = srslte_vec_dot_prod_sss(q->cqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B); if (corr > max_corr) { - max_corr = corr; - max_w = w; + max_corr = corr; + max_w = w; } } // Convert word to bits again @@ -198,36 +200,35 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32 return max_corr; } else { return SRSLTE_ERROR_INVALID_INPUTS; - } + } } - - - - - - - -void encode_cqi_pusch_block(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t output[32]) { +void encode_cqi_pusch_block(uint8_t* data, uint32_t nof_bits, uint8_t output[32]) +{ for (int i=0;i<32;i++) { output[i] = 0; for (int n=0;ncqi_table[i] = srslte_vec_malloc(sizeof(uint8_t)*nwords*32); - q->cqi_table_s[i] = srslte_vec_malloc(sizeof(int16_t)*nwords*32); + q->cqi_table_s[i] = srslte_vec_malloc(sizeof(int16_t) * nwords * 32); for (uint32_t w=0;wcqi_table[i][32*w]); + encode_cqi_pusch_block(word, i + 1, &q->cqi_table[i][32 * w]); for (int j=0;j<32;j++) { q->cqi_table_s[i][32*w+j] = 2*q->cqi_table[i][32*w+j]-1; } @@ -267,21 +268,20 @@ void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q) cqi_pusch_pregen_free(q); } -static uint32_t Q_prime_cqi(srslte_pusch_cfg_t *cfg, - uint32_t O, float beta, uint32_t Q_prime_ri) +static uint32_t Q_prime_cqi(srslte_pusch_cfg_t* cfg, uint32_t O, float beta, uint32_t Q_prime_ri) { - - uint32_t K = cfg->cb_segm.C1*cfg->cb_segm.K1 + cfg->cb_segm.C2*cfg->cb_segm.K2; - + + uint32_t K = cfg->K_segm; + uint32_t Q_prime = 0; - uint32_t L = (O<11)?0:8; + uint32_t L = (O < 11) ? 0 : 8; uint32_t x = 999999; - + if (K > 0) { - x = (uint32_t) ceilf((float) (O+L)*cfg->grant.M_sc_init*cfg->nbits.nof_symb*beta/K); + x = (uint32_t)ceilf((float)(O + L) * cfg->grant.L_prb * SRSLTE_NRE * cfg->grant.nof_symb * beta / K); } - - Q_prime = SRSLTE_MIN(x, cfg->grant.M_sc * cfg->nbits.nof_symb - Q_prime_ri); + + Q_prime = SRSLTE_MIN(x, cfg->grant.L_prb * SRSLTE_NRE * cfg->grant.nof_symb - Q_prime_ri); return Q_prime; } @@ -425,22 +425,30 @@ int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, /* Encode UCI CQI/PMI */ -int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *cfg, - int16_t *q_bits, - float beta, uint32_t Q_prime_ri, uint32_t cqi_len, - uint8_t *cqi_data, bool *cqi_ack) +int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t* q, + srslte_pusch_cfg_t* cfg, + int16_t* q_bits, + float beta, + uint32_t Q_prime_ri, + uint32_t cqi_len, + uint8_t* cqi_data, + bool* cqi_ack) { if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); + ERROR("Error beta is reserved\n"); return -1; } uint32_t Q_prime = Q_prime_cqi(cfg, cqi_len, beta, Q_prime_ri); + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); int ret = SRSLTE_ERROR; if (cqi_len <= 11) { - ret = decode_cqi_short(q, q_bits, Q_prime*cfg->grant.Qm, cqi_data, cqi_len); + ret = decode_cqi_short(q, q_bits, Q_prime * Qm, cqi_data, cqi_len); + if (cqi_ack) { + *cqi_ack = true; + } } else { - ret = decode_cqi_long(q, q_bits, Q_prime*cfg->grant.Qm, cqi_data, cqi_len); + ret = decode_cqi_long(q, q_bits, Q_prime * Qm, cqi_data, cqi_len); if (ret == 1) { if (cqi_ack) { *cqi_ack = true; @@ -457,72 +465,67 @@ int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *c } else { return (int) Q_prime; } - - return Q_prime; } /* Encode UCI CQI/PMI as described in 5.2.2.6 of 36.212 */ -int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *cfg, - uint8_t *cqi_data, uint32_t cqi_len, - float beta, uint32_t Q_prime_ri, - uint8_t *q_bits) +int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t* q, + srslte_pusch_cfg_t* cfg, + uint8_t* cqi_data, + uint32_t cqi_len, + float beta, + uint32_t Q_prime_ri, + uint8_t* q_bits) { if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; + ERROR("Error beta is reserved\n"); + return -1; } uint32_t Q_prime = Q_prime_cqi(cfg, cqi_len, beta, Q_prime_ri); - + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); + int ret = SRSLTE_ERROR; if (cqi_len <= 11) { - ret = encode_cqi_short(q, cqi_data, cqi_len, q_bits, Q_prime*cfg->grant.Qm); + ret = encode_cqi_short(q, cqi_data, cqi_len, q_bits, Q_prime * Qm); } else { - ret = encode_cqi_long(q, cqi_data, cqi_len, q_bits, Q_prime*cfg->grant.Qm); + ret = encode_cqi_long(q, cqi_data, cqi_len, q_bits, Q_prime * Qm); } if (ret) { return ret; } else { - return (int) Q_prime; + return (int)Q_prime; } } -static void uci_ulsch_interleave_put(srslte_uci_bit_type_t ack_coded_bits[6], uint32_t Qm, srslte_uci_bit_t *ack_bits) -{ - for(uint32_t k=0; k= 1+ack_q_bit_idx/4) { + if (H_prime_total / N_pusch_symbs >= 1 + ack_q_bit_idx / 4) { uint32_t row = H_prime_total/N_pusch_symbs-1-ack_q_bit_idx/4; uint32_t colidx = (3*ack_q_bit_idx)%4; - uint32_t col = SRSLTE_CP_ISNORM(cp)?ack_column_set_norm[colidx]:ack_column_set_ext[colidx]; + uint32_t col = N_pusch_symbs > 10 ? ack_column_set_norm[colidx] : ack_column_set_ext[colidx]; for(uint32_t k=0; k= 1+ri_q_bit_idx/4) { uint32_t row = H_prime_total/N_pusch_symbs-1-ri_q_bit_idx/4; uint32_t colidx = (3*ri_q_bit_idx)%4; - uint32_t col = SRSLTE_CP_ISNORM(cp)?ri_column_set_norm[colidx]:ri_column_set_ext[colidx]; + uint32_t col = N_pusch_symbs > 10 ? ri_column_set_norm[colidx] : ri_column_set_ext[colidx]; for(uint32_t k=0; kcb_segm.C1*cfg->cb_segm.K1 + cfg->cb_segm.C2*cfg->cb_segm.K2; - + uint32_t K = cfg->K_segm; + // If not carrying UL-SCH, get Q_prime according to 5.2.4.1 if (K == 0) { if (O_cqi <= 11) { - K = O_cqi; + K = O_cqi; } else { - K = O_cqi+8; + K = O_cqi + 8; } } - - uint32_t x = (uint32_t) ceilf((float) O*cfg->grant.M_sc_init*cfg->nbits.nof_symb*beta/K); - uint32_t Q_prime = SRSLTE_MIN(x, 4*cfg->grant.M_sc); + uint32_t x = (uint32_t)ceilf((float)O * cfg->grant.L_prb * SRSLTE_NRE * cfg->grant.nof_symb * beta / K); - return Q_prime; + uint32_t Q_prime = SRSLTE_MIN(x, 4 * cfg->grant.L_prb * SRSLTE_NRE); + + return Q_prime; } -static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit_type_t q_encoded_bits[18], uint8_t Qm) +static uint32_t encode_ri_ack(uint8_t data[2], uint32_t O_ack, uint8_t Qm, srslte_uci_bit_t* q_encoded_bits) { uint32_t i = 0; - if (data_len == 1) { - q_encoded_bits[i++] = data[0] ? UCI_BIT_1 : UCI_BIT_0; - q_encoded_bits[i++] = UCI_BIT_REPETITION; + if (O_ack == 1) { + q_encoded_bits[i++].type = data[0] ? UCI_BIT_1 : UCI_BIT_0; + q_encoded_bits[i++].type = UCI_BIT_REPETITION; while(i < Qm) { - q_encoded_bits[i++] = UCI_BIT_PLACEHOLDER; + q_encoded_bits[i++].type = UCI_BIT_PLACEHOLDER; } - } else if (data_len == 2) { - q_encoded_bits[i++] = data[0] ? UCI_BIT_1 : UCI_BIT_0; - q_encoded_bits[i++] = data[1] ? UCI_BIT_1 : UCI_BIT_0; - while(i 10) { + ERROR("Error encoding long ACK bits: O_ack can't be higher than 10\n"); + return 0; + } + + for (uint32_t i = 0; i < Q_ack; i++) { + uint32_t q_i = 0; + for (uint32_t n = 0; n < O_ack; n++) { + q_i = (q_i + (data[n] * M_basis_seq[i % 32][n])) % 2; + } + q_encoded_bits[i].type = q_i ? UCI_BIT_1 : UCI_BIT_0; + } + + return Q_ack; +} -/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit HARQ +/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 */ static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos) { uint32_t p0 = pos[0].position; uint32_t p1 = pos[1].position; - uint32_t q0 = c_seq[p0]?q_bits[p0]:-q_bits[p0]; - uint32_t q1 = c_seq[p0]?q_bits[p1]:-q_bits[p1]; + // Unscramble p1 + q_bits[p1] = c_seq[p1] ? -q_bits[p1] : q_bits[p1]; - return -(q0+q1); + // Scramble with correct position + int16_t q0 = q_bits[p0]; + int16_t q1 = c_seq[p0] ? -q_bits[p1] : q_bits[p1]; + + return (q0 + q1); } static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) @@ -626,157 +653,134 @@ static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_ uint32_t p4 = pos[Qm * 2 + 0].position; uint32_t p5 = pos[Qm * 2 + 1].position; - int32_t q0 = c_seq[p0] ? q_bits[p0] : -q_bits[p0]; - int32_t q1 = c_seq[p1] ? q_bits[p1] : -q_bits[p1]; - int32_t q2 = c_seq[p2] ? q_bits[p2] : -q_bits[p2]; - int32_t q3 = c_seq[p3] ? q_bits[p3] : -q_bits[p3]; - int32_t q4 = c_seq[p4] ? q_bits[p4] : -q_bits[p4]; - int32_t q5 = c_seq[p5] ? q_bits[p5] : -q_bits[p5]; - - data[0] -= q0 + q3; - data[1] -= q1 + q4; - data[2] -= q2 + q5; + data[0] += q_bits[p0] + q_bits[p3]; + data[1] += q_bits[p1] + q_bits[p4]; + data[2] += q_bits[p2] + q_bits[p5]; } -/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit HARQ - */ -int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ack_bits) -{ - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; - } - - uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - - uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm); +// Table 5.2.2.6-A +const static uint8_t w_scram[4][4] = {{1, 1, 1, 1}, {1, 0, 1, 0}, {1, 1, 0, 0}, {1, 0, 0, 1}}; - if (nof_encoded_bits > 0) { - for (uint32_t i = 0; i < Qprime; i++) { - uci_ulsch_interleave_ack_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &ack_bits[cfg->grant.Qm * i]); - uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits], - cfg->grant.Qm, - &ack_bits[cfg->grant.Qm * i]); +static void uci_ack_scramble_tdd(srslte_uci_bit_t* q, uint32_t O_ack, uint32_t Q_ack, uint32_t N_bundle) +{ + if (N_bundle == 0) { + return; + } + + uint32_t wi = (N_bundle - 1) % 4; + + uint32_t m = O_ack == 1 ? 1 : 3; + + srslte_uci_bit_type_t q_m1 = q[0].type; + uint32_t k = 0; + for (uint32_t i = 0; i < Q_ack; i++) { + switch (q[i].type) { + case UCI_BIT_REPETITION: + // A repetition bit always comes after a 1 or 0 so we can do i-1 + if (i > 0) { + q[i].type = ((q_m1 == UCI_BIT_1 ? 1 : 0) + w_scram[wi][k / m]) % 2; + } + k = (k + 1) % (4 * m); + break; + case UCI_BIT_PLACEHOLDER: + // do not change + break; + default: + q_m1 = q[i].type; + q[i].type = ((q[i].type == UCI_BIT_1 ? 1 : 0) + w_scram[wi][k / m]) % 2; + k = (k + 1) % (4 * m); + break; } } - return (int) Qprime; } -/* Encode UCI RI bits as described in 5.2.2.6 of 36.212 +/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit RI */ -int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg, - uint8_t ri, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *ri_bits) +int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t* cfg, + uint8_t* data, + uint32_t O_ack, + uint32_t O_cqi, + float beta, + uint32_t H_prime_total, + bool input_is_ri, + uint32_t N_bundle, + srslte_uci_bit_t* bits) { - // FIXME: It supports RI of 1 bit only - uint8_t data[2] = {ri, 0}; if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); + ERROR("Error beta is reserved\n"); return -1; } - uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - - uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm); - - for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); - uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]); - } + uint32_t Q_prime = Q_prime_ri_ack(cfg, O_ack, O_cqi, beta); - return (int) Qprime; -} + uint32_t Q_ack = 0; + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); -/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit RI - */ -int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg, - uint8_t *data, uint32_t data_len, - uint32_t O_cqi, float beta, uint32_t H_prime_total, - srslte_uci_bit_t *bits, bool ack_ri) { - if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); - return -1; + if (O_ack < 3) { + uint32_t enc_len = encode_ri_ack(data, O_ack, Qm, bits); + // Repeat bits Q_prime times, remainder bits will be ignored later + while (Q_ack < Q_prime * Qm) { + for (uint32_t j = 0; j < enc_len; j++) { + bits[Q_ack++].type = bits[j].type; + } + } + } else { + Q_ack = encode_ack_long(data, O_ack, Qm, Q_prime, bits); } - uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta); - srslte_uci_bit_type_t q_encoded_bits[18]; - uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm); - - if (nof_encoded_bits > 0) { - for (uint32_t i = 0; i < Qprime; i++) { - if (ack_ri) { - uci_ulsch_interleave_ri_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &bits[cfg->grant.Qm * i]); + // Generate interleaver positions + if (Q_ack > 0) { + for (uint32_t i = 0; i < Q_prime; i++) { + if (input_is_ri) { + uci_ulsch_interleave_ri_gen(i, Qm, H_prime_total, cfg->grant.nof_symb, &bits[Qm * i]); } else { - uci_ulsch_interleave_ack_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &bits[cfg->grant.Qm * i]); + uci_ulsch_interleave_ack_gen(i, Qm, H_prime_total, cfg->grant.nof_symb, &bits[Qm * i]); } - uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits], - cfg->grant.Qm, - &bits[cfg->grant.Qm * i]); + } + + // TDD-bundling scrambling + if (!input_is_ri && N_bundle && O_ack > 0) { + uci_ack_scramble_tdd(bits, O_ack, Q_prime * Qm, N_bundle); } } - return (int) Qprime; + return (int)Q_prime; } /* Decode UCI ACK/RI bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit RI */ -int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, - float beta, uint32_t H_prime_total, - uint32_t O_cqi, srslte_uci_bit_t *ack_ri_bits, uint8_t data[2], uint32_t nof_bits, bool is_ri) +int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg, + int16_t* q_bits, + uint8_t* c_seq, + float beta, + uint32_t H_prime_total, + uint32_t O_cqi, + srslte_uci_bit_t* ack_ri_bits, + uint8_t data[2], + uint32_t nof_bits, + bool is_ri) { int32_t sum[3] = {0, 0, 0}; if (beta < 0) { - fprintf(stderr, "Error beta is reserved\n"); + ERROR("Error beta is reserved\n"); return -1; } uint32_t Qprime = Q_prime_ri_ack(cfg, nof_bits, O_cqi, beta); + uint32_t Qm = srslte_mod_bits_x_symbol(cfg->grant.tb.mod); for (uint32_t i = 0; i < Qprime; i++) { if (is_ri) { - uci_ulsch_interleave_ri_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &ack_ri_bits[cfg->grant.Qm * i]); + uci_ulsch_interleave_ri_gen(i, Qm, H_prime_total, cfg->grant.nof_symb, &ack_ri_bits[Qm * i]); } else { - uci_ulsch_interleave_ack_gen(i, - cfg->grant.Qm, - H_prime_total, - cfg->nbits.nof_symb, - cfg->cp, - &ack_ri_bits[cfg->grant.Qm * i]); - + uci_ulsch_interleave_ack_gen(i, Qm, H_prime_total, cfg->grant.nof_symb, &ack_ri_bits[Qm * i]); } if (nof_bits == 2 && (i % 3 == 0) && i > 0) { - decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[cfg->grant.Qm * (i - 3)], cfg->grant.Qm, sum); + decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[Qm * (i - 3)], Qm, sum); } else if (nof_bits == 1) { - sum[0] += (int32_t) decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[cfg->grant.Qm * i]); + sum[0] += (int32_t)decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[Qm * i]); } } @@ -788,3 +792,33 @@ int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t * return (int) Qprime; } +int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len) +{ + int n = 0; + + if (uci_cfg->is_scheduling_request_tti) { + n = srslte_print_check(str, str_len, n, ", sr=%s", uci_data->scheduling_request ? "yes" : "no"); + } + + if (uci_cfg->ack.nof_acks) { + n = srslte_print_check(str, str_len, n, ", ack="); + for (uint32_t i = 0; i < uci_cfg->ack.nof_acks; i++) { + n = srslte_print_check(str, str_len, n, "%d", uci_data->ack.ack_value[i]); + } + if (uci_cfg->ack.N_bundle) { + n = srslte_print_check(str, str_len, n, ", n_bundle=%d", uci_cfg->ack.N_bundle); + } + } + + if (uci_cfg->cqi.ri_len) { + n = srslte_print_check(str, str_len, n, ", ri=%d", uci_data->ri); + } + + char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = ""; + if (uci_cfg->cqi.data_enable) { + srslte_cqi_value_tostring(&uci_cfg->cqi, &uci_data->cqi, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); + n = srslte_print_check(str, str_len, n, "%s", cqi_str); + } + + return n; +} diff --git a/lib/src/phy/resampling/interp.c b/lib/src/phy/resampling/interp.c index 180b3f9fc..00d4e55f4 100644 --- a/lib/src/phy/resampling/interp.c +++ b/lib/src/phy/resampling/interp.c @@ -24,11 +24,11 @@ * */ +#include "srslte/srslte.h" #include #include #include #include -#include #include "srslte/phy/resampling/interp.h" #include "srslte/phy/utils/vector.h" @@ -121,7 +121,7 @@ int srslte_interp_linear_vector_resize(srslte_interp_linsrslte_vec_t *q, uint32_ q->vector_len = vector_len; return SRSLTE_SUCCESS; } else { - fprintf(stderr, "Error resizing interp_linear: vector_len must be lower or equal than initialized\n"); + ERROR("Error resizing interp_linear: vector_len must be lower or equal than initialized\n"); return SRSLTE_ERROR; } } @@ -237,7 +237,7 @@ int srslte_interp_linear_resize(srslte_interp_lin_t *q, uint32_t vector_len, uin q->M = M; return SRSLTE_SUCCESS; } else { - fprintf(stderr, "Error resizing interp_linear: vector_len and M must be lower or equal than initialized\n"); + ERROR("Error resizing interp_linear: vector_len and M must be lower or equal than initialized\n"); return SRSLTE_ERROR; } } diff --git a/lib/src/phy/rf/rf_blade_imp.c b/lib/src/phy/rf/rf_blade_imp.c index 061c5aa92..dc50b0882 100644 --- a/lib/src/phy/rf/rf_blade_imp.c +++ b/lib/src/phy/rf/rf_blade_imp.c @@ -87,12 +87,12 @@ int rf_blade_start_tx_stream(void *h) num_transfers, timeout_ms); if (status != 0) { - fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); + ERROR("Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); return status; } status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, true); if (status != 0) { - fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status)); + ERROR("Failed to enable TX module: %s\n", bladerf_strerror(status)); return status; } handler->tx_stream_enabled = true; @@ -116,7 +116,7 @@ int rf_blade_start_rx_stream(void *h, bool now) num_transfers, timeout_ms); if (status != 0) { - fprintf(stderr, "Failed to configure RX sync interface: %s\n", bladerf_strerror(status)); + ERROR("Failed to configure RX sync interface: %s\n", bladerf_strerror(status)); return status; } status = bladerf_sync_config(handler->dev, @@ -127,17 +127,17 @@ int rf_blade_start_rx_stream(void *h, bool now) num_transfers, timeout_ms); if (status != 0) { - fprintf(stderr, "Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); + ERROR("Failed to configure TX sync interface: %s\n", bladerf_strerror(status)); return status; } status = bladerf_enable_module(handler->dev, BLADERF_MODULE_RX, true); if (status != 0) { - fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); + ERROR("Failed to enable RX module: %s\n", bladerf_strerror(status)); return status; } status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, true); if (status != 0) { - fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status)); + ERROR("Failed to enable TX module: %s\n", bladerf_strerror(status)); return status; } handler->rx_stream_enabled = true; @@ -149,12 +149,12 @@ int rf_blade_stop_rx_stream(void *h) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; int status = bladerf_enable_module(handler->dev, BLADERF_MODULE_RX, false); if (status != 0) { - fprintf(stderr, "Failed to enable RX module: %s\n", bladerf_strerror(status)); + ERROR("Failed to enable RX module: %s\n", bladerf_strerror(status)); return status; } status = bladerf_enable_module(handler->dev, BLADERF_MODULE_TX, false); if (status != 0) { - fprintf(stderr, "Failed to enable TX module: %s\n", bladerf_strerror(status)); + ERROR("Failed to enable TX module: %s\n", bladerf_strerror(status)); return status; } handler->rx_stream_enabled = false; @@ -197,13 +197,13 @@ int rf_blade_open(char *args, void **h) printf("Opening bladeRF...\n"); int status = bladerf_open(&handler->dev, args); if (status) { - fprintf(stderr, "Unable to open device: %s\n", bladerf_strerror(status)); + ERROR("Unable to open device: %s\n", bladerf_strerror(status)); return status; } status = bladerf_set_gain_mode(handler->dev, BLADERF_MODULE_RX, BLADERF_GAIN_MGC); if (status) { - fprintf(stderr, "Unable to open device: %s\n", bladerf_strerror(status)); + ERROR("Unable to open device: %s\n", bladerf_strerror(status)); return status; } @@ -212,19 +212,19 @@ int rf_blade_open(char *args, void **h) /* Get Gain ranges and set Rx to maximum */ status = bladerf_get_gain_range(handler->dev, BLADERF_MODULE_RX, &range_rx); if ((status != 0) | (range_rx == NULL)) { - fprintf(stderr, "Failed to get RX gain range: %s\n", bladerf_strerror(status)); + ERROR("Failed to get RX gain range: %s\n", bladerf_strerror(status)); return status; } bladerf_get_gain_range(handler->dev, BLADERF_MODULE_RX, &range_tx); if ((status != 0) | (range_tx == NULL)) { - fprintf(stderr, "Failed to get TX gain range: %s\n", bladerf_strerror(status)); + ERROR("Failed to get TX gain range: %s\n", bladerf_strerror(status)); return status; } status = bladerf_set_gain(handler->dev, BLADERF_MODULE_RX, (bladerf_gain) range_rx->max); if (status != 0) { - fprintf(stderr, "Failed to set RX LNA gain: %s\n", bladerf_strerror(status)); + ERROR("Failed to set RX LNA gain: %s\n", bladerf_strerror(status)); return status; } handler->rx_stream_enabled = false; @@ -266,19 +266,19 @@ double rf_blade_set_rx_srate(void *h, double freq) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; int status = bladerf_set_sample_rate(handler->dev, BLADERF_MODULE_RX, (uint32_t) freq, &handler->rx_rate); if (status != 0) { - fprintf(stderr, "Failed to set samplerate = %u: %s\n", (uint32_t) freq, bladerf_strerror(status)); + ERROR("Failed to set samplerate = %u: %s\n", (uint32_t)freq, bladerf_strerror(status)); return -1; } if (handler->rx_rate < 2000000) { status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_RX, handler->rx_rate, &bw); if (status != 0) { - fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->rx_rate, bladerf_strerror(status)); + ERROR("Failed to set bandwidth = %u: %s\n", handler->rx_rate, bladerf_strerror(status)); return -1; } } else { status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_RX, (bladerf_bandwidth) (handler->rx_rate * 0.8), &bw); if (status != 0) { - fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->rx_rate, bladerf_strerror(status)); + ERROR("Failed to set bandwidth = %u: %s\n", handler->rx_rate, bladerf_strerror(status)); return -1; } } @@ -292,12 +292,12 @@ double rf_blade_set_tx_srate(void *h, double freq) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; int status = bladerf_set_sample_rate(handler->dev, BLADERF_MODULE_TX, (uint32_t) freq, &handler->tx_rate); if (status != 0) { - fprintf(stderr, "Failed to set samplerate = %u: %s\n", (uint32_t) freq, bladerf_strerror(status)); + ERROR("Failed to set samplerate = %u: %s\n", (uint32_t)freq, bladerf_strerror(status)); return -1; } status = bladerf_set_bandwidth(handler->dev, BLADERF_MODULE_TX, handler->tx_rate, &bw); if (status != 0) { - fprintf(stderr, "Failed to set bandwidth = %u: %s\n", handler->tx_rate, bladerf_strerror(status)); + ERROR("Failed to set bandwidth = %u: %s\n", handler->tx_rate, bladerf_strerror(status)); return -1; } return (double) handler->tx_rate; @@ -309,7 +309,7 @@ double rf_blade_set_rx_gain(void *h, double gain) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; status = bladerf_set_gain(handler->dev, BLADERF_MODULE_RX, (bladerf_gain) gain); if (status != 0) { - fprintf(stderr, "Failed to set RX gain: %s\n", bladerf_strerror(status)); + ERROR("Failed to set RX gain: %s\n", bladerf_strerror(status)); return -1; } return rf_blade_get_rx_gain(h); @@ -321,7 +321,7 @@ double rf_blade_set_tx_gain(void *h, double gain) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; status = bladerf_set_gain(handler->dev, BLADERF_MODULE_TX, (bladerf_gain) gain); if (status != 0) { - fprintf(stderr, "Failed to set TX gain: %s\n", bladerf_strerror(status)); + ERROR("Failed to set TX gain: %s\n", bladerf_strerror(status)); return -1; } return rf_blade_get_tx_gain(h); @@ -334,8 +334,7 @@ double rf_blade_get_rx_gain(void *h) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; status = bladerf_get_gain(handler->dev, BLADERF_MODULE_RX, &gain); if (status != 0) { - fprintf(stderr, "Failed to get RX gain: %s\n", - bladerf_strerror(status)); + ERROR("Failed to get RX gain: %s\n", bladerf_strerror(status)); return -1; } return gain; @@ -348,8 +347,7 @@ double rf_blade_get_tx_gain(void *h) rf_blade_handler_t *handler = (rf_blade_handler_t*) h; status = bladerf_get_gain(handler->dev, BLADERF_MODULE_TX, &gain); if (status != 0) { - fprintf(stderr, "Failed to get TX gain: %s\n", - bladerf_strerror(status)); + ERROR("Failed to get TX gain: %s\n", bladerf_strerror(status)); return -1; } return gain; @@ -368,14 +366,13 @@ srslte_rf_info_t *rf_blade_get_info(void *h) return info; } -double rf_blade_set_rx_freq(void *h, double freq) +double rf_blade_set_rx_freq(void* h, uint32_t ch, double freq) { - rf_blade_handler_t *handler = (rf_blade_handler_t*) h; + rf_blade_handler_t* handler = (rf_blade_handler_t*)h; bladerf_frequency f_int = (uint32_t) round(freq); int status = bladerf_set_frequency(handler->dev, BLADERF_MODULE_RX, f_int); if (status != 0) { - fprintf(stderr, "Failed to set samplerate = %u: %s\n", - (uint32_t) freq, bladerf_strerror(status)); + ERROR("Failed to set samplerate = %u: %s\n", (uint32_t)freq, bladerf_strerror(status)); return -1; } f_int=0; @@ -385,17 +382,16 @@ double rf_blade_set_rx_freq(void *h, double freq) return freq; } -double rf_blade_set_tx_freq(void *h, double freq) +double rf_blade_set_tx_freq(void* h, uint32_t ch, double freq) { rf_blade_handler_t *handler = (rf_blade_handler_t*) h; - bladerf_frequency f_int = (uint32_t) round(freq); + bladerf_frequency f_int = (uint32_t)round(freq); int status = bladerf_set_frequency(handler->dev, BLADERF_MODULE_TX, f_int); if (status != 0) { - fprintf(stderr, "Failed to set samplerate = %u: %s\n", - (uint32_t) freq, bladerf_strerror(status)); + ERROR("Failed to set samplerate = %u: %s\n", (uint32_t)freq, bladerf_strerror(status)); return -1; } - + f_int=0; bladerf_get_frequency(handler->dev, BLADERF_MODULE_TX, &f_int); printf("set TX frequency to %lu\n", f_int); @@ -427,13 +423,11 @@ void rf_blade_get_time(void *h, time_t *secs, double *frac_secs) int status = bladerf_get_timestamp(handler->dev, BLADERF_RX, &meta.timestamp); if (status != 0) { - fprintf(stderr, "Failed to get current RX timestamp: %s\n", - bladerf_strerror(status)); + ERROR("Failed to get current RX timestamp: %s\n", bladerf_strerror(status)); } timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); } - int rf_blade_recv_with_time_multi(void *h, void **data, uint32_t nsamples, @@ -459,25 +453,25 @@ int rf_blade_recv_with_time(void *h, meta.flags = BLADERF_META_FLAG_RX_NOW; if (2*nsamples > CONVERT_BUFFER_SIZE) { - fprintf(stderr, "RX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); + ERROR("RX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); return -1; } status = bladerf_sync_rx(handler->dev, handler->rx_buffer, nsamples, &meta, 2000); if (status) { - fprintf(stderr, "RX failed: %s\n\n", bladerf_strerror(status)); + ERROR("RX failed: %s\n\n", bladerf_strerror(status)); return -1; } else if (meta.status & BLADERF_META_STATUS_OVERRUN) { if (blade_error_handler) { - srslte_rf_error_t error; - error.opt = meta.actual_count; + srslte_rf_error_t error; + error.opt = meta.actual_count; error.type = SRSLTE_RF_ERROR_OVERFLOW; blade_error_handler(error); } else { - /*fprintf(stderr, "Overrun detected in scheduled RX. " + /*ERROR("Overrun detected in scheduled RX. " "%u valid samples were read.\n\n", meta.actual_count);*/ } } - + timestamp_to_secs(handler->rx_rate, meta.timestamp, secs, frac_secs); srslte_vec_convert_if(handler->rx_buffer, 2048, data, 2*nsamples); @@ -517,12 +511,12 @@ int rf_blade_send_timed(void *h, } if (2*nsamples > CONVERT_BUFFER_SIZE) { - fprintf(stderr, "TX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); + ERROR("TX failed: nsamples exceeds buffer size (%d>%d)\n", nsamples, CONVERT_BUFFER_SIZE); return -1; } srslte_vec_convert_fi(data, 2048, handler->tx_buffer, 2*nsamples); - + memset(&meta, 0, sizeof(meta)); if (is_start_of_burst) { if (has_time_spec) { @@ -535,29 +529,28 @@ int rf_blade_send_timed(void *h, if (is_end_of_burst) { meta.flags |= BLADERF_META_FLAG_TX_BURST_END; } - srslte_rf_error_t error; + srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); - + status = bladerf_sync_tx(handler->dev, handler->tx_buffer, nsamples, &meta, 2000); if (status == BLADERF_ERR_TIME_PAST) { if (blade_error_handler) { error.type = SRSLTE_RF_ERROR_LATE; blade_error_handler(error); } else { - fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); + ERROR("TX failed: %s\n", bladerf_strerror(status)); } } else if (status) { - fprintf(stderr, "TX failed: %s\n", bladerf_strerror(status)); + ERROR("TX failed: %s\n", bladerf_strerror(status)); return status; } else if (meta.status == BLADERF_META_STATUS_UNDERRUN) { if (blade_error_handler) { error.type = SRSLTE_RF_ERROR_UNDERFLOW; blade_error_handler(error); } else { - fprintf(stderr, "TX warning: underflow detected.\n"); + ERROR("TX warning: underflow detected.\n"); } } return nsamples; } - diff --git a/lib/src/phy/rf/rf_blade_imp.h b/lib/src/phy/rf/rf_blade_imp.h index 3809a149f..1b546cf85 100644 --- a/lib/src/phy/rf/rf_blade_imp.h +++ b/lib/src/phy/rf/rf_blade_imp.h @@ -79,8 +79,7 @@ SRSLTE_API void rf_blade_suppress_stdout(void *h); SRSLTE_API void rf_blade_register_error_handler(void *h, srslte_rf_error_handler_t error_handler); -SRSLTE_API double rf_blade_set_rx_freq(void *h, - double freq); +SRSLTE_API double rf_blade_set_rx_freq(void* h, uint32_t ch, double freq); SRSLTE_API int rf_blade_recv_with_time_multi(void *h, void **data, @@ -102,8 +101,7 @@ SRSLTE_API double rf_blade_set_tx_srate(void *h, SRSLTE_API double rf_blade_set_tx_gain(void *h, double gain); -SRSLTE_API double rf_blade_set_tx_freq(void *h, - double freq); +SRSLTE_API double rf_blade_set_tx_freq(void* h, uint32_t ch, double freq); SRSLTE_API void rf_blade_get_time(void *h, time_t *secs, diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 79e69d05c..7cf9b5e1e 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -48,10 +48,11 @@ typedef struct { double (*srslte_rf_get_rx_gain)(void *h); double (*srslte_rf_get_tx_gain)(void *h); srslte_rf_info_t *(*srslte_rf_get_info)(void *h); - double (*srslte_rf_set_rx_freq)(void *h, double freq); + double (*srslte_rf_set_rx_freq)(void* h, uint32_t ch, double freq); double (*srslte_rf_set_tx_srate)(void *h, double freq); - double (*srslte_rf_set_tx_freq)(void *h, double freq); - void (*srslte_rf_get_time)(void *h, time_t *secs, double *frac_secs); + double (*srslte_rf_set_tx_freq)(void* h, uint32_t ch, double freq); + void (*srslte_rf_get_time)(void* h, time_t* secs, double* frac_secs); + void (*srslte_rf_sync_pps)(void* h); int (*srslte_rf_recv_with_time)(void *h, void *data, uint32_t nsamples, bool blocking, time_t *secs,double *frac_secs); int (*srslte_rf_recv_with_time_multi)(void *h, void **data, uint32_t nsamples, @@ -69,37 +70,36 @@ typedef struct { #include "rf_uhd_imp.h" -static rf_dev_t dev_uhd = { - "UHD", - rf_uhd_devname, - rf_uhd_rx_wait_lo_locked, - rf_uhd_start_rx_stream, - rf_uhd_stop_rx_stream, - rf_uhd_flush_buffer, - rf_uhd_has_rssi, - rf_uhd_get_rssi, - rf_uhd_suppress_stdout, - rf_uhd_register_error_handler, - rf_uhd_open, - .srslte_rf_open_multi = rf_uhd_open_multi, - rf_uhd_close, - rf_uhd_set_master_clock_rate, - rf_uhd_is_master_clock_dynamic, - rf_uhd_set_rx_srate, - rf_uhd_set_rx_gain, - rf_uhd_set_tx_gain, - rf_uhd_get_rx_gain, - rf_uhd_get_tx_gain, - rf_uhd_get_info, - rf_uhd_set_rx_freq, - rf_uhd_set_tx_srate, - rf_uhd_set_tx_freq, - rf_uhd_get_time, - rf_uhd_recv_with_time, - rf_uhd_recv_with_time_multi, - rf_uhd_send_timed, - .srslte_rf_send_timed_multi = rf_uhd_send_timed_multi -}; +static rf_dev_t dev_uhd = {"UHD", + rf_uhd_devname, + rf_uhd_rx_wait_lo_locked, + rf_uhd_start_rx_stream, + rf_uhd_stop_rx_stream, + rf_uhd_flush_buffer, + rf_uhd_has_rssi, + rf_uhd_get_rssi, + rf_uhd_suppress_stdout, + rf_uhd_register_error_handler, + rf_uhd_open, + .srslte_rf_open_multi = rf_uhd_open_multi, + rf_uhd_close, + rf_uhd_set_master_clock_rate, + rf_uhd_is_master_clock_dynamic, + rf_uhd_set_rx_srate, + rf_uhd_set_rx_gain, + rf_uhd_set_tx_gain, + rf_uhd_get_rx_gain, + rf_uhd_get_tx_gain, + rf_uhd_get_info, + rf_uhd_set_rx_freq, + rf_uhd_set_tx_srate, + rf_uhd_set_tx_freq, + rf_uhd_get_time, + rf_uhd_sync_pps, + rf_uhd_recv_with_time, + rf_uhd_recv_with_time_multi, + rf_uhd_send_timed, + .srslte_rf_send_timed_multi = rf_uhd_send_timed_multi}; #endif /* Define implementation for bladeRF */ @@ -107,74 +107,72 @@ static rf_dev_t dev_uhd = { #include "rf_blade_imp.h" -static rf_dev_t dev_blade = { - "bladeRF", - rf_blade_devname, - rf_blade_rx_wait_lo_locked, - rf_blade_start_rx_stream, - rf_blade_stop_rx_stream, - rf_blade_flush_buffer, - rf_blade_has_rssi, - rf_blade_get_rssi, - rf_blade_suppress_stdout, - rf_blade_register_error_handler, - rf_blade_open, - .srslte_rf_open_multi = rf_blade_open_multi, - rf_blade_close, - rf_blade_set_master_clock_rate, - rf_blade_is_master_clock_dynamic, - rf_blade_set_rx_srate, - rf_blade_set_rx_gain, - rf_blade_set_tx_gain, - rf_blade_get_rx_gain, - rf_blade_get_tx_gain, - rf_blade_get_info, - rf_blade_set_rx_freq, - rf_blade_set_tx_srate, - rf_blade_set_tx_freq, - rf_blade_get_time, - rf_blade_recv_with_time, - rf_blade_recv_with_time_multi, - rf_blade_send_timed, - .srslte_rf_send_timed_multi = rf_blade_send_timed_multi -}; +static rf_dev_t dev_blade = {"bladeRF", + rf_blade_devname, + rf_blade_rx_wait_lo_locked, + rf_blade_start_rx_stream, + rf_blade_stop_rx_stream, + rf_blade_flush_buffer, + rf_blade_has_rssi, + rf_blade_get_rssi, + rf_blade_suppress_stdout, + rf_blade_register_error_handler, + rf_blade_open, + .srslte_rf_open_multi = rf_blade_open_multi, + rf_blade_close, + rf_blade_set_master_clock_rate, + rf_blade_is_master_clock_dynamic, + rf_blade_set_rx_srate, + rf_blade_set_rx_gain, + rf_blade_set_tx_gain, + rf_blade_get_rx_gain, + rf_blade_get_tx_gain, + rf_blade_get_info, + rf_blade_set_rx_freq, + rf_blade_set_tx_srate, + rf_blade_set_tx_freq, + rf_blade_get_time, + NULL, + rf_blade_recv_with_time, + rf_blade_recv_with_time_multi, + rf_blade_send_timed, + .srslte_rf_send_timed_multi = rf_blade_send_timed_multi}; #endif #ifdef ENABLE_SOAPYSDR #include "rf_soapy_imp.h" -static rf_dev_t dev_soapy = { - "soapy", - rf_soapy_devname, - rf_soapy_rx_wait_lo_locked, - rf_soapy_start_rx_stream, - rf_soapy_stop_rx_stream, - rf_soapy_flush_buffer, - rf_soapy_has_rssi, - rf_soapy_get_rssi, - rf_soapy_suppress_stdout, - rf_soapy_register_error_handler, - rf_soapy_open, - rf_soapy_open_multi, - rf_soapy_close, - rf_soapy_set_master_clock_rate, - rf_soapy_is_master_clock_dynamic, - rf_soapy_set_rx_srate, - rf_soapy_set_rx_gain, - rf_soapy_set_tx_gain, - rf_soapy_get_rx_gain, - rf_soapy_get_tx_gain, - rf_soapy_get_info, - rf_soapy_set_rx_freq, - rf_soapy_set_tx_srate, - rf_soapy_set_tx_freq, - rf_soapy_get_time, - rf_soapy_recv_with_time, - rf_soapy_recv_with_time_multi, - rf_soapy_send_timed, - .srslte_rf_send_timed_multi = rf_soapy_send_timed_multi -}; +static rf_dev_t dev_soapy = {"soapy", + rf_soapy_devname, + rf_soapy_rx_wait_lo_locked, + rf_soapy_start_rx_stream, + rf_soapy_stop_rx_stream, + rf_soapy_flush_buffer, + rf_soapy_has_rssi, + rf_soapy_get_rssi, + rf_soapy_suppress_stdout, + rf_soapy_register_error_handler, + rf_soapy_open, + rf_soapy_open_multi, + rf_soapy_close, + rf_soapy_set_master_clock_rate, + rf_soapy_is_master_clock_dynamic, + rf_soapy_set_rx_srate, + rf_soapy_set_rx_gain, + rf_soapy_set_tx_gain, + rf_soapy_get_rx_gain, + rf_soapy_get_tx_gain, + rf_soapy_get_info, + rf_soapy_set_rx_freq, + rf_soapy_set_tx_srate, + rf_soapy_set_tx_freq, + rf_soapy_get_time, + NULL, + rf_soapy_recv_with_time, + rf_soapy_recv_with_time_multi, + rf_soapy_send_timed, + .srslte_rf_send_timed_multi = rf_soapy_send_timed_multi}; #endif @@ -208,6 +206,7 @@ static rf_dev_t dev_zmq = {"zmq", rf_zmq_set_tx_srate, rf_zmq_set_tx_freq, rf_zmq_get_time, + NULL, rf_zmq_recv_with_time, rf_zmq_recv_with_time_multi, rf_zmq_send_timed, diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 8c6f7a7cc..55d53022a 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -128,7 +128,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args, uint32_t } i++; } - fprintf(stderr, "No compatible RF frontend found\n"); + ERROR("No compatible RF frontend found\n"); return -1; } @@ -235,10 +235,9 @@ srslte_rf_info_t *srslte_rf_get_info(srslte_rf_t *rf) { return ret; } - -double srslte_rf_set_rx_freq(srslte_rf_t *rf, double freq) +double srslte_rf_set_rx_freq(srslte_rf_t* rf, uint32_t ch, double freq) { - return ((rf_dev_t*) rf->dev)->srslte_rf_set_rx_freq(rf->handler, freq); + return ((rf_dev_t*)rf->dev)->srslte_rf_set_rx_freq(rf->handler, ch, freq); } @@ -282,9 +281,9 @@ double srslte_rf_set_tx_srate(srslte_rf_t *rf, double freq) return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_srate(rf->handler, freq); } -double srslte_rf_set_tx_freq(srslte_rf_t *rf, double freq) +double srslte_rf_set_tx_freq(srslte_rf_t* rf, uint32_t ch, double freq) { - return ((rf_dev_t*) rf->dev)->srslte_rf_set_tx_freq(rf->handler, freq); + return ((rf_dev_t*)rf->dev)->srslte_rf_set_tx_freq(rf->handler, ch, freq); } void srslte_rf_get_time(srslte_rf_t *rf, time_t *secs, double *frac_secs) @@ -292,7 +291,19 @@ void srslte_rf_get_time(srslte_rf_t *rf, time_t *secs, double *frac_secs) return ((rf_dev_t*) rf->dev)->srslte_rf_get_time(rf->handler, secs, frac_secs); } - +int srslte_rf_sync(srslte_rf_t* rf) +{ + int ret = SRSLTE_ERROR; + + if (((rf_dev_t*)rf->dev)->srslte_rf_sync_pps) { + ((rf_dev_t*)rf->dev)->srslte_rf_sync_pps(rf->handler); + + ret = SRSLTE_SUCCESS; + } + + return ret; +} + int srslte_rf_send_timed3(srslte_rf_t *rf, void *data, int nsamples, diff --git a/lib/src/phy/rf/rf_soapy_imp.c b/lib/src/phy/rf/rf_soapy_imp.c index b0c3d5e69..ebbfc9225 100644 --- a/lib/src/phy/rf/rf_soapy_imp.c +++ b/lib/src/phy/rf/rf_soapy_imp.c @@ -138,10 +138,15 @@ static void* async_thread(void *h) { // this is a timeout of the readStreamStatus call, ignoring it .. } else if (ret == SOAPY_SDR_NOT_SUPPORTED) { // stopping async thread - fprintf(stderr, "Receiving async metadata not supported by device. Exiting thread.\n"); + ERROR("Receiving async metadata not supported by device. Exiting thread.\n"); handler->async_thread_running = false; } else { - fprintf(stderr, "Error while receiving aync metadata: %s (%d), flags=%d, channel=%zu, timeNs=%lld\n", SoapySDR_errToStr(ret), ret, flags, chanMask, timeNs); + ERROR("Error while receiving aync metadata: %s (%d), flags=%d, channel=%zu, timeNs=%lld\n", + SoapySDR_errToStr(ret), + ret, + flags, + chanMask, + timeNs); handler->async_thread_running = false; } } @@ -406,12 +411,12 @@ int rf_soapy_open_multi(char* args, void** h, uint32_t num_requested_channels) // rx antenna const char rx_ant_arg[] = "rxant="; char rx_ant_str[64] = {0}; - char *rx_ant_ptr = strstr(args, rx_ant_arg); + char* rx_ant_ptr = strstr(args, rx_ant_arg); if (rx_ant_ptr) { copy_subdev_string(rx_ant_str, rx_ant_ptr + strlen(rx_ant_arg)); printf("Setting Rx antenna to %s\n", rx_ant_str); if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_RX, 0, rx_ant_str) != 0) { - fprintf(stderr, "Failed to set Rx antenna.\n"); + ERROR("Failed to set Rx antenna.\n"); } remove_substring(args, rx_ant_arg); remove_substring(args, rx_ant_str); @@ -420,12 +425,12 @@ int rf_soapy_open_multi(char* args, void** h, uint32_t num_requested_channels) // tx antenna const char tx_ant_arg[] = "txant="; char tx_ant_str[64] = {0}; - char *tx_ant_ptr = strstr(args, tx_ant_arg); + char* tx_ant_ptr = strstr(args, tx_ant_arg); if (tx_ant_ptr) { copy_subdev_string(tx_ant_str, tx_ant_ptr + strlen(tx_ant_arg)); printf("Setting Tx antenna to %s\n", tx_ant_str); if (SoapySDRDevice_setAntenna(handler->device, SOAPY_SDR_TX, 0, tx_ant_str) != 0) { - fprintf(stderr, "Failed to set Tx antenna.\n"); + ERROR("Failed to set Tx antenna.\n"); } remove_substring(args, tx_ant_arg); remove_substring(args, tx_ant_str); @@ -694,13 +699,12 @@ srslte_rf_info_t * rf_soapy_get_info(void *h) srslte_rf_info_t *info = NULL; if (h) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; - info = &handler->info; + info = &handler->info; } return info; } - -double rf_soapy_set_rx_freq(void *h, double freq) +double rf_soapy_set_rx_freq(void* h, uint32_t ch, double freq) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; @@ -718,7 +722,7 @@ double rf_soapy_set_rx_freq(void *h, double freq) return SoapySDRDevice_getFrequency(handler->device, SOAPY_SDR_RX, 0); } -double rf_soapy_set_tx_freq(void *h, double freq) +double rf_soapy_set_tx_freq(void* h, uint32_t ch, double freq) { rf_soapy_handler_t *handler = (rf_soapy_handler_t*) h; for (uint32_t i = 0; i < handler->num_tx_channels; i++) { @@ -935,7 +939,7 @@ int rf_soapy_send_timed_multi(void* h, printf("U"); break; default: - fprintf(stderr, "Error during writeStream\n"); + ERROR("Error during writeStream\n"); exit(-1); return SRSLTE_ERROR; } @@ -944,7 +948,7 @@ int rf_soapy_send_timed_multi(void* h, } while (n < nsamples && trials < 100); if (n != nsamples) { - fprintf(stderr, "Couldn't write all samples after %d trials.\n", trials); + ERROR("Couldn't write all samples after %d trials.\n", trials); } return n; diff --git a/lib/src/phy/rf/rf_soapy_imp.h b/lib/src/phy/rf/rf_soapy_imp.h index de8242501..b69e73c63 100644 --- a/lib/src/phy/rf/rf_soapy_imp.h +++ b/lib/src/phy/rf/rf_soapy_imp.h @@ -79,8 +79,7 @@ SRSLTE_API void rf_soapy_suppress_stdout(void *h); SRSLTE_API void rf_soapy_register_error_handler(void *h, srslte_rf_error_handler_t error_handler); -SRSLTE_API double rf_soapy_set_rx_freq(void *h, - double freq); +SRSLTE_API double rf_soapy_set_rx_freq(void* h, uint32_t ch, double freq); SRSLTE_API int rf_soapy_recv_with_time(void *h, void *data, @@ -99,8 +98,7 @@ SRSLTE_API int rf_soapy_recv_with_time_multi(void *h, SRSLTE_API double rf_soapy_set_tx_srate(void *h, double freq); -SRSLTE_API double rf_soapy_set_tx_freq(void *h, - double freq); +SRSLTE_API double rf_soapy_set_tx_freq(void* h, uint32_t ch, double freq); SRSLTE_API void rf_soapy_get_time(void *h, time_t *secs, diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index f3a94b682..46c52f963 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -74,7 +74,7 @@ cf_t zero_mem[64*1024]; static void log_overflow(rf_uhd_handler_t *h) { if (h->uhd_error_handler) { - srslte_rf_error_t error; + srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_OVERFLOW; h->uhd_error_handler(error); @@ -94,7 +94,7 @@ static void log_late(rf_uhd_handler_t *h, bool is_rx) { #if HAVE_ASYNC_THREAD static void log_underflow(rf_uhd_handler_t *h) { if (h->uhd_error_handler) { - srslte_rf_error_t error; + srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_UNDERFLOW; h->uhd_error_handler(error); @@ -106,7 +106,7 @@ static void log_rx_error(rf_uhd_handler_t *h) { if (h->uhd_error_handler) { char error_string[512]; uhd_usrp_last_error(h->usrp, error_string, 512); - fprintf(stderr, "USRP reported the following error: %s\n", error_string); + ERROR("USRP reported the following error: %s\n", error_string); srslte_rf_error_t error; bzero(&error, sizeof(srslte_rf_error_t)); @@ -135,7 +135,7 @@ static void* async_thread(void *h) { } } } else { - fprintf(stderr, "Error while receiving aync metadata: 0x%x\n", err); + ERROR("Error while receiving aync metadata: 0x%x\n", err); return NULL; } } @@ -380,7 +380,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) REMOVE_SUBSTRING_WITHCOMAS(args, "otw_format=sc16"); /* Do nothing */ } else if (strstr(args, "otw_format=")) { - fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); + ERROR("Wrong over the wire format. Valid formats: sc12, sc16\n"); return -1; } @@ -512,9 +512,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) // Set external clock reference if (clock_src == EXTERNAL) { - uhd_usrp_set_clock_source(handler->usrp, "external", 0); + uhd_usrp_set_clock_source(handler->usrp, "external", 0); + uhd_usrp_set_time_source(handler->usrp, "external", 0); } else if (clock_src == GPSDO) { uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); + uhd_usrp_set_time_source(handler->usrp, "gpsdo", 0); } handler->has_rssi = get_has_rssi(handler); @@ -544,13 +546,13 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) uhd_rx_streamer_make(&handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); if (error) { - fprintf(stderr, "Error opening RX stream: %d\n", error); + ERROR("Error opening RX stream: %d\n", error); return -1; } uhd_tx_streamer_make(&handler->tx_stream); error = uhd_usrp_get_tx_stream(handler->usrp, &stream_args, handler->tx_stream); if (error) { - fprintf(stderr, "Error opening TX stream: %d\n", error); + ERROR("Error opening TX stream: %d\n", error); return -1; } @@ -725,7 +727,7 @@ srslte_rf_info_t *rf_uhd_get_info(void *h) return info; } -double rf_uhd_set_rx_freq(void *h, double freq) +double rf_uhd_set_rx_freq(void* h, uint32_t ch, double freq) { uhd_tune_request_t tune_request = { .target_freq = freq, @@ -734,13 +736,17 @@ double rf_uhd_set_rx_freq(void *h, double freq) }; uhd_tune_result_t tune_result; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - for (int i=0;inof_rx_channels;i++) { - uhd_usrp_set_rx_freq(handler->usrp, &tune_request, i, &tune_result); + if (ch < handler->nof_rx_channels) { + uhd_usrp_set_rx_freq(handler->usrp, &tune_request, ch, &tune_result); + } else { + for (int i = 0; i < handler->nof_rx_channels; i++) { + uhd_usrp_set_rx_freq(handler->usrp, &tune_request, i, &tune_result); + } } return freq; } -double rf_uhd_set_tx_freq(void *h, double freq) +double rf_uhd_set_tx_freq(void* h, uint32_t ch, double freq) { uhd_tune_request_t tune_request = { .target_freq = freq, @@ -749,8 +755,12 @@ double rf_uhd_set_tx_freq(void *h, double freq) }; uhd_tune_result_t tune_result; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; - for (int i=0;inof_tx_channels;i++) { - uhd_usrp_set_tx_freq(handler->usrp, &tune_request, i, &tune_result); + if (ch < handler->nof_tx_channels) { + uhd_usrp_set_tx_freq(handler->usrp, &tune_request, ch, &tune_result); + } else { + for (int i = 0; i < handler->nof_tx_channels; i++) { + uhd_usrp_set_tx_freq(handler->usrp, &tune_request, i, &tune_result); + } } return freq; } @@ -761,6 +771,14 @@ void rf_uhd_get_time(void *h, time_t *secs, double *frac_secs) { uhd_usrp_get_time_now(handler->usrp, 0, secs, frac_secs); } +void rf_uhd_sync_pps(void* h) +{ + if (h) { + rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; + uhd_usrp_set_time_unknown_pps(handler->usrp, 0, 0); + } +} + int rf_uhd_recv_with_time(void *h, void *data, uint32_t nsamples, @@ -798,7 +816,7 @@ int rf_uhd_recv_with_time_multi(void *h, uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, buffs_ptr, num_rx_samples, md, 1.0, false, &rxd_samples); if (error) { - fprintf(stderr, "Error receiving from UHD: %d\n", error); + ERROR("Error receiving from UHD: %d\n", error); log_rx_error(handler); return -1; } @@ -815,17 +833,18 @@ int rf_uhd_recv_with_time_multi(void *h, } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { log_late(handler, true); } else if (error_code == UHD_RX_METADATA_ERROR_CODE_TIMEOUT) { - fprintf(stderr, "Error timed out while receiving samples from UHD.\n"); + ERROR("Error timed out while receiving samples from UHD.\n"); return -1; - } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE ) { - fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code); + } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE) { + ERROR("Error code 0x%x was returned during streaming. Aborting.\n", error_code); + INFO("Error code 0x%x was returned during streaming. Aborting.\n", error_code); } } } else { uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, data, nsamples, md, 0.0, false, &rxd_samples); rxd_samples_total = rxd_samples; if (error) { - fprintf(stderr, "Error receiving from UHD: %d\n", error); + ERROR("Error receiving from UHD: %d\n", error); log_rx_error(handler); return -1; } @@ -909,7 +928,7 @@ int rf_uhd_send_timed_multi(void *h, uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, tx_samples, &handler->tx_md, 1.0, &txd_samples); if (error) { - fprintf(stderr, "Error sending to UHD: %d\n", error); + ERROR("Error sending to UHD: %d\n", error); goto unlock; } // Increase time spec @@ -931,7 +950,7 @@ int rf_uhd_send_timed_multi(void *h, uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); if (error) { - fprintf(stderr, "Error sending to UHD: %d\n", error); + ERROR("Error sending to UHD: %d\n", error); goto unlock; } diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 2da9f4efb..e10960a43 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -84,8 +84,7 @@ SRSLTE_API void rf_uhd_suppress_stdout(void *h); SRSLTE_API void rf_uhd_register_error_handler(void *h, srslte_rf_error_handler_t error_handler); -SRSLTE_API double rf_uhd_set_rx_freq(void *h, - double freq); +SRSLTE_API double rf_uhd_set_rx_freq(void* h, uint32_t ch, double freq); SRSLTE_API int rf_uhd_recv_with_time(void *h, void *data, @@ -107,12 +106,11 @@ SRSLTE_API double rf_uhd_set_tx_srate(void *h, SRSLTE_API double rf_uhd_set_tx_gain(void *h, double gain); -SRSLTE_API double rf_uhd_set_tx_freq(void *h, - double freq); +SRSLTE_API double rf_uhd_set_tx_freq(void* h, uint32_t ch, double freq); + +SRSLTE_API void rf_uhd_get_time(void* h, time_t* secs, double* frac_secs); -SRSLTE_API void rf_uhd_get_time(void *h, - time_t *secs, - double *frac_secs); +SRSLTE_API void rf_uhd_sync_pps(void* h); SRSLTE_API int rf_uhd_send_timed(void *h, void *data, diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index f12054e9d..1365853d2 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -57,7 +57,7 @@ int rf_rssi_scan(srslte_rf_t *rf, float *freqs, float *rssi, int nof_bands, doub srslte_rf_stop_rx_stream(rf); f = (double) freqs[i]; - srslte_rf_set_rx_freq(rf, f); + srslte_rf_set_rx_freq(rf, 0, f); srslte_rf_rx_wait_lo_locked(rf); usleep(10000); srslte_rf_start_rx_stream(rf, false); @@ -102,14 +102,13 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * int ret = SRSLTE_ERROR; srslte_ue_mib_sync_t ue_mib; uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - if (srslte_ue_mib_sync_init_multi(&ue_mib, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); goto clean_exit; } - if (srslte_ue_mib_sync_set_cell(&ue_mib, cell->id, cell->cp)) { - fprintf(stderr, "Error initiating srslte_ue_mib_sync\n"); + if (srslte_ue_mib_sync_set_cell(&ue_mib, *cell)) { + ERROR("Error initiating srslte_ue_mib_sync\n"); goto clean_exit; } @@ -131,7 +130,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * /* Find and decode MIB */ ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL); if (ret < 0) { - fprintf(stderr, "Error decoding MIB\n"); + ERROR("Error decoding MIB\n"); goto clean_exit; } if (ret == 1) { @@ -162,8 +161,9 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, srslte_ue_cellsearch_result_t found_cells[3]; bzero(found_cells, 3*sizeof(srslte_ue_cellsearch_result_t)); - - if (srslte_ue_cellsearch_init_multi(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*) rf)) { + + if (srslte_ue_cellsearch_init_multi( + &cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, nof_rx_antennas, (void*)rf)) { fprintf(stderr, "Error initiating UE cell detect\n"); return SRSLTE_ERROR; } @@ -177,6 +177,10 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, INFO("Starting receiver...\n"); srslte_rf_start_rx_stream(rf, false); + if (config->force_tdd) { + srslte_ue_sync_set_frame_type(&cs.ue_sync, SRSLTE_TDD); + } + /* 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; if (force_N_id_2 >= 0) { @@ -187,11 +191,11 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, } if (ret < 0) { srslte_rf_stop_rx_stream(rf); - fprintf(stderr, "Error searching cell\n"); + ERROR("Error searching cell\n"); return SRSLTE_ERROR; } else if (ret == 0) { srslte_rf_stop_rx_stream(rf); - fprintf(stderr, "Could not find any cell in this frequency\n"); + ERROR("Could not find any cell in this frequency\n"); return SRSLTE_SUCCESS; } @@ -201,16 +205,20 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, } else { printf(" "); } - printf("Found Cell_id: %3d CP: %s, DetectRatio=%2.0f%% PSR=%.2f, Power=%.1f dBm\n", - found_cells[i].cell_id, srslte_cp_string(found_cells[i].cp), - found_cells[i].mode*100, - found_cells[i].psr, 20*log10(found_cells[i].peak*1000)); + printf("Found Cell_id: %3d %s, CP: %s, DetectRatio=%2.0f%% PSR=%.2f, Power=%.1f dBm\n", + found_cells[i].cell_id, + found_cells[i].frame_type == SRSLTE_FDD ? "FDD" : "TDD", + srslte_cp_string(found_cells[i].cp), + found_cells[i].mode * 100, + found_cells[i].psr, + 20 * log10(found_cells[i].peak * 1000)); } - - // Save result + + // Save result if (cell) { cell->id = found_cells[max_peak_cell].cell_id; - cell->cp = found_cells[max_peak_cell].cp; + cell->cp = found_cells[max_peak_cell].cp; + cell->frame_type = found_cells[max_peak_cell].frame_type; } // Save CFO @@ -224,23 +232,27 @@ int rf_cell_search(srslte_rf_t *rf, uint32_t nof_rx_antennas, return ret; } - -/* Finds a cell and decodes MIB from the PBCH. - * Returns 1 if the cell is found and MIB is decoded successfully. - * 0 if no cell was found or MIB could not be decoded, +/* Finds a cell and decodes MIB from the PBCH. + * Returns 1 if the cell is found and MIB is decoded successfully. + * 0 if no cell was found or MIB could not be decoded, * -1 on error */ -int rf_search_and_decode_mib(srslte_rf_t *rf, uint32_t nof_rx_antennas, cell_search_cfg_t *config, int force_N_id_2, srslte_cell_t *cell, float *cfo) +int rf_search_and_decode_mib(srslte_rf_t* rf, + uint32_t nof_rx_antennas, + cell_search_cfg_t* config, + int force_N_id_2, + srslte_cell_t* cell, + float* cfo) { - int ret = SRSLTE_ERROR; - + int ret = SRSLTE_ERROR; + printf("Searching for cell...\n"); ret = rf_cell_search(rf, nof_rx_antennas, config, force_N_id_2, cell, cfo); if (ret > 0) { printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3); ret = rf_mib_decoder(rf, nof_rx_antennas, config, cell, cfo); if (ret < 0) { - fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id); + ERROR("Could not decode PBCH from CELL ID %d\n", cell->id); return SRSLTE_ERROR; } } diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index a2b934f27..944704691 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -695,7 +695,7 @@ srslte_rf_info_t* rf_zmq_get_info(void* h) return info; } -double rf_zmq_set_rx_freq(void* h, double freq) +double rf_zmq_set_rx_freq(void* h, uint32_t ch, double freq) { double ret = NAN; if (h) { @@ -706,7 +706,7 @@ double rf_zmq_set_rx_freq(void* h, double freq) return ret; } -double rf_zmq_set_tx_freq(void* h, double freq) +double rf_zmq_set_tx_freq(void* h, uint32_t ch, double freq) { double ret = NAN; if (h) { diff --git a/lib/src/phy/rf/rf_zmq_imp.h b/lib/src/phy/rf/rf_zmq_imp.h index 979c656e5..f316bf8e2 100644 --- a/lib/src/phy/rf/rf_zmq_imp.h +++ b/lib/src/phy/rf/rf_zmq_imp.h @@ -76,7 +76,7 @@ SRSLTE_API void rf_zmq_suppress_stdout(void* h); SRSLTE_API void rf_zmq_register_error_handler(void* h, srslte_rf_error_handler_t error_handler); -SRSLTE_API double rf_zmq_set_rx_freq(void* h, double freq); +SRSLTE_API double rf_zmq_set_rx_freq(void* h, uint32_t ch, double freq); SRSLTE_API int rf_zmq_recv_with_time(void* h, void* data, @@ -96,7 +96,7 @@ SRSLTE_API double rf_zmq_set_tx_srate(void* h, double freq); SRSLTE_API double rf_zmq_set_tx_gain(void* h, double gain); -SRSLTE_API double rf_zmq_set_tx_freq(void* h, double freq); +SRSLTE_API double rf_zmq_set_tx_freq(void* h, uint32_t ch, double freq); SRSLTE_API void rf_zmq_get_time(void* h, time_t* secs, double* frac_secs); diff --git a/lib/src/phy/scrambling/test/scrambling_test.c b/lib/src/phy/scrambling/test/scrambling_test.c index 10a197cc1..c380b06c5 100644 --- a/lib/src/phy/scrambling/test/scrambling_test.c +++ b/lib/src/phy/scrambling/test/scrambling_test.c @@ -90,7 +90,7 @@ int init_sequence(srslte_sequence_t *seq, char *name) { bzero(seq, sizeof(srslte_sequence_t)); return srslte_sequence_pdsch(seq, 1234, 0, 0, cell_id, nof_bits); } else { - fprintf(stderr, "Unsupported sequence name %s\n", name); + ERROR("Unsupported sequence name %s\n", name); return -1; } } @@ -106,7 +106,7 @@ int main(int argc, char **argv) { parse_args(argc, argv); if (init_sequence(&seq, srslte_sequence_name) == -1) { - fprintf(stderr, "Error initiating sequence %s\n", srslte_sequence_name); + ERROR("Error initiating sequence %s\n", srslte_sequence_name); exit(-1); } diff --git a/lib/src/phy/sync/cfo.c b/lib/src/phy/sync/cfo.c index a1529be13..c45007cdb 100644 --- a/lib/src/phy/sync/cfo.c +++ b/lib/src/phy/sync/cfo.c @@ -24,10 +24,10 @@ * */ -#include -#include +#include "srslte/srslte.h" #include -#include +#include +#include #include "srslte/phy/utils/cexptab.h" #include "srslte/phy/sync/cfo.h" @@ -87,7 +87,7 @@ int srslte_cfo_resize(srslte_cfo_t *h, uint32_t samples) { srslte_cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, samples); h->nsamples = samples; } else { - fprintf(stderr, "Error in cfo_resize(): nof_samples must be lower than initialized\n"); + ERROR("Error in cfo_resize(): nof_samples must be lower than initialized\n"); return SRSLTE_ERROR; } #endif /* SRSLTE_CFO_USE_EXP_TABLE */ diff --git a/lib/src/phy/sync/cp.c b/lib/src/phy/sync/cp.c index 80d0a2179..bb3005804 100644 --- a/lib/src/phy/sync/cp.c +++ b/lib/src/phy/sync/cp.c @@ -24,8 +24,8 @@ * */ +#include "srslte/srslte.h" #include -#include #include "srslte/phy/sync/cp.h" #include "srslte/phy/utils/vector.h" @@ -54,7 +54,7 @@ void srslte_cp_synch_free(srslte_cp_synch_t *q) int srslte_cp_synch_resize(srslte_cp_synch_t *q, uint32_t symbol_sz) { if (symbol_sz > q->max_symbol_sz) { - fprintf(stderr, "Error in cp_synch_resize(): symbol_sz must be lower than initialized\n"); + ERROR("Error in cp_synch_resize(): symbol_sz must be lower than initialized\n"); return SRSLTE_ERROR; } q->symbol_sz = symbol_sz; diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index ac54264eb..2dce17edb 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -131,7 +131,7 @@ int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, } if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error creating DFT plan \n"); + ERROR("Error creating DFT plan \n"); goto clean_and_exit; } srslte_dft_plan_set_mirror(&q->dftp_input, true); @@ -139,7 +139,7 @@ int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, srslte_dft_plan_set_norm(&q->dftp_input, false); if (srslte_dft_plan(&q->idftp_input, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error creating DFT plan \n"); + ERROR("Error creating DFT plan \n"); goto clean_and_exit; } srslte_dft_plan_set_mirror(&q->idftp_input, true); @@ -150,7 +150,7 @@ int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); if (!q->tmp_input) { - fprintf(stderr, "Error allocating memory\n"); + ERROR("Error allocating memory\n"); goto clean_and_exit; } @@ -158,20 +158,20 @@ int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, q->conv_output = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (!q->conv_output) { - fprintf(stderr, "Error allocating memory\n"); + ERROR("Error allocating memory\n"); goto clean_and_exit; } bzero(q->conv_output, sizeof(cf_t) * buffer_size); q->conv_output_avg = srslte_vec_malloc(buffer_size * sizeof(float)); if (!q->conv_output_avg) { - fprintf(stderr, "Error allocating memory\n"); + ERROR("Error allocating memory\n"); goto clean_and_exit; } bzero(q->conv_output_avg, sizeof(float) * buffer_size); #ifdef SRSLTE_PSS_ACCUMULATE_ABS q->conv_output_abs = srslte_vec_malloc(buffer_size * sizeof(float)); if (!q->conv_output_abs) { - fprintf(stderr, "Error allocating memory\n"); + ERROR("Error allocating memory\n"); goto clean_and_exit; } bzero(q->conv_output_abs, sizeof(float) * buffer_size); @@ -180,12 +180,12 @@ int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, for (N_id_2=0;N_id_2<3;N_id_2++) { q->pss_signal_time[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (!q->pss_signal_time[N_id_2]) { - fprintf(stderr, "Error allocating memory\n"); + ERROR("Error allocating memory\n"); goto clean_and_exit; } /* The PSS is translated into the time domain for each N_id_2 */ if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { - fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); + ERROR("Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); @@ -194,7 +194,7 @@ int srslte_pss_init_fft_offset_decim(srslte_pss_t *q, if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { - fprintf(stderr, "Error initiating convolution FFT\n"); + ERROR("Error initiating convolution FFT\n"); goto clean_and_exit; } for(N_id_2=0; N_id_2<3; N_id_2++) { @@ -232,7 +232,7 @@ int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, i ret = SRSLTE_ERROR; if (fft_size > q->max_fft_size || frame_size > q->max_frame_size) { - fprintf(stderr, "Error in pss_config(): fft_size and frame_size must be lower than initialized\n"); + ERROR("Error in pss_config(): fft_size and frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } @@ -251,12 +251,12 @@ int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, i buffer_size = fft_size + frame_size + 1; if (srslte_dft_replan(&q->dftp_input, fft_size)) { - fprintf(stderr, "Error creating DFT plan \n"); + ERROR("Error creating DFT plan \n"); return SRSLTE_ERROR; } if (srslte_dft_replan(&q->idftp_input, fft_size)) { - fprintf(stderr, "Error creating DFT plan \n"); + ERROR("Error creating DFT plan \n"); return SRSLTE_ERROR; } @@ -273,7 +273,7 @@ int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, i // Generate PSS sequences for this FFT size for (N_id_2=0;N_id_2<3;N_id_2++) { if (srslte_pss_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { - fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); + ERROR("Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); return SRSLTE_ERROR; } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); @@ -281,7 +281,7 @@ int srslte_pss_resize(srslte_pss_t *q, uint32_t frame_size, uint32_t fft_size, i #ifdef CONVOLUTION_FFT if (srslte_conv_fft_cc_replan(&q->conv_fft, frame_size, fft_size)) { - fprintf(stderr, "Error initiating convolution FFT\n"); + ERROR("Error initiating convolution FFT\n"); return SRSLTE_ERROR; } for(int i =0; i< 3; i++) { @@ -360,7 +360,7 @@ int srslte_pss_generate(cf_t *signal, uint32_t N_id_2) { int sign = -1; if (N_id_2 > 2) { - fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); + ERROR("Invalid N_id_2 %d\n", N_id_2); return -1; } @@ -397,12 +397,11 @@ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_ memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); } - -/** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise +/** Sets the current N_id_2 value. Returns -1 on ERROR(0 otherwise */ int srslte_pss_set_N_id_2(srslte_pss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid((N_id_2))) { - fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); + ERROR("Invalid N_id_2 %d\n", N_id_2); return -1; } else { q->N_id_2 = N_id_2; @@ -466,7 +465,7 @@ int srslte_pss_find_pss(srslte_pss_t *q, const cf_t *input, float *corr_peak_val uint32_t conv_output_len; if (!srslte_N_id_2_isvalid(q->N_id_2)) { - fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); + ERROR("Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } @@ -552,7 +551,7 @@ int srslte_pss_chest(srslte_pss_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN] { if (!srslte_N_id_2_isvalid(q->N_id_2)) { - fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); + ERROR("Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } @@ -586,7 +585,7 @@ void srslte_pss_sic(srslte_pss_t *q, cf_t *input) { srslte_vec_sub_ccc(input, q->tmp_fft2, input, q->fft_size); } else { - fprintf(stderr, "Error calling srslte_pss_sic(): need to enable channel estimation on filtering\n"); + ERROR("Error calling srslte_pss_sic(): need to enable channel estimation on filtering\n"); } } diff --git a/lib/src/phy/sync/sss.c b/lib/src/phy/sync/sss.c index 31091bdb3..501494b86 100644 --- a/lib/src/phy/sync/sss.c +++ b/lib/src/phy/sync/sss.c @@ -31,9 +31,10 @@ #include #include -#include "srslte/phy/sync/sss.h" #include "srslte/phy/dft/dft.h" +#include "srslte/phy/sync/sss.h" #include "srslte/phy/utils/convolution.h" +#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" void generate_sss_all_tables(srslte_sss_tables_t *tables, uint32_t N_id_2); @@ -77,7 +78,7 @@ int srslte_sss_resize(srslte_sss_t *q, uint32_t fft_size) { fft_size <= 2048) { if (fft_size > q->max_fft_size) { - fprintf(stderr, "Error in sss_synch_resize(): fft_size must be lower than initialized\n"); + ERROR("Error in sss_synch_resize(): fft_size must be lower than initialized\n"); return SRSLTE_ERROR; } if (srslte_dft_replan(&q->dftp_input, fft_size)) { @@ -98,7 +99,7 @@ void srslte_sss_free(srslte_sss_t *q) { /** Sets the N_id_2 to search for */ int srslte_sss_set_N_id_2(srslte_sss_t *q, uint32_t N_id_2) { if (!srslte_N_id_2_isvalid(N_id_2)) { - fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); + ERROR("Invalid N_id_2 %d\n", N_id_2); return SRSLTE_ERROR; } else { q->N_id_2 = N_id_2; diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 39bd98141..707a57fc3 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -24,12 +24,11 @@ * */ -#include -#include +#include "srslte/srslte.h" #include #include -#include -#include +#include +#include #include "srslte/phy/utils/debug.h" #include "srslte/phy/common/phy_common.h" @@ -79,6 +78,7 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o q->cfo_cp_enable = false; q->cfo_i_initiated = false; q->pss_filtering_enabled = false; + q->detect_frame_type = true; q->cfo_cp_nsymbols = 3; q->fft_size = fft_size; @@ -89,12 +89,12 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o srslte_sync_cfo_reset(q); if (srslte_cfo_init(&q->cfo_corr_frame, q->frame_size)) { - fprintf(stderr, "Error initiating CFO\n"); + ERROR("Error initiating CFO\n"); goto clean_exit; } if (srslte_cfo_init(&q->cfo_corr_symbol, q->fft_size)) { - fprintf(stderr, "Error initiating CFO\n"); + ERROR("Error initiating CFO\n"); goto clean_exit; } @@ -121,17 +121,25 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o decimate = 1; } + if (srslte_dft_plan(&q->idftp_sss, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { + ERROR("Error creating DFT plan \n"); + goto clean_exit; + } + srslte_dft_plan_set_mirror(&q->idftp_sss, true); + srslte_dft_plan_set_dc(&q->idftp_sss, true); + srslte_dft_plan_set_norm(&q->idftp_sss, false); + if (srslte_pss_init_fft_offset_decim(&q->pss, max_offset, fft_size, 0, decimate)) { - fprintf(stderr, "Error initializing PSS object\n"); + ERROR("Error initializing PSS object\n"); goto clean_exit; } if (srslte_sss_init(&q->sss, fft_size)) { - fprintf(stderr, "Error initializing SSS object\n"); + ERROR("Error initializing SSS object\n"); goto clean_exit; } if (srslte_cp_synch_init(&q->cp_synch, fft_size)) { - fprintf(stderr, "Error initiating CFO\n"); + ERROR("Error initiating CFO\n"); goto clean_exit; } @@ -139,7 +147,7 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); + ERROR("Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); } clean_exit: @@ -158,6 +166,8 @@ void srslte_sync_free(srslte_sync_t *q) srslte_cfo_free(&q->cfo_corr_symbol); srslte_cp_synch_free(&q->cp_synch); + srslte_dft_plan_free(&q->idftp_sss); + for (int i = 0; i < 2; i++) { if (q->cfo_i_corr[i]) { free(q->cfo_i_corr[i]); @@ -179,7 +189,7 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse fft_size_isvalid(fft_size)) { if (frame_size > q->max_frame_size) { - fprintf(stderr, "Error in sync_resize(): frame_size must be lower than initialized\n"); + ERROR("Error in sync_resize(): frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } @@ -188,26 +198,31 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse q->max_offset = max_offset; if (srslte_pss_resize(&q->pss, q->max_offset, q->fft_size, 0)) { - fprintf(stderr, "Error resizing PSS object\n"); + ERROR("Error resizing PSS object\n"); return SRSLTE_ERROR; } if (srslte_sss_resize(&q->sss, q->fft_size)) { - fprintf(stderr, "Error resizing SSS object\n"); + ERROR("Error resizing SSS object\n"); + return SRSLTE_ERROR; + } + + if (srslte_dft_replan(&q->idftp_sss, fft_size)) { + ERROR("Error resizing DFT plan \n"); return SRSLTE_ERROR; } if (srslte_cp_synch_resize(&q->cp_synch, q->fft_size)) { - fprintf(stderr, "Error resizing CFO\n"); + ERROR("Error resizing CFO\n"); return SRSLTE_ERROR; } if (srslte_cfo_resize(&q->cfo_corr_frame, q->frame_size)) { - fprintf(stderr, "Error resizing CFO\n"); + ERROR("Error resizing CFO\n"); return SRSLTE_ERROR; } if (srslte_cfo_resize(&q->cfo_corr_symbol, q->fft_size)) { - fprintf(stderr, "Error resizing CFO\n"); + ERROR("Error resizing CFO\n"); return SRSLTE_ERROR; } @@ -215,7 +230,7 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse for (int i=0;i<2;i++) { int offset=(i==0)?-1:1; if (srslte_pss_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { - fprintf(stderr, "Error initializing PSS object\n"); + ERROR("Error initializing PSS object\n"); } for (int t=0;tframe_size;t++) { q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); @@ -230,12 +245,18 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); + ERROR("Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); } return ret; } +void srslte_sync_set_frame_type(srslte_sync_t* q, srslte_frame_type_t frame_type) +{ + q->frame_type = frame_type; + q->detect_frame_type = false; +} + void srslte_sync_set_cfo_tol(srslte_sync_t *q, float tol) { q->current_cfo_tol = tol; srslte_cfo_set_tol(&q->cfo_corr_frame, tol/(15000.0*q->fft_size)); @@ -250,8 +271,14 @@ void srslte_sync_sss_en(srslte_sync_t *q, bool enabled) { q->sss_en = enabled; } -bool srslte_sync_sss_detected(srslte_sync_t *q) { - return srslte_N_id_1_isvalid(q->N_id_1); +bool srslte_sync_sss_detected(srslte_sync_t* q) +{ + return q->sss_detected; +} + +bool srslte_sync_sss_available(srslte_sync_t* q) +{ + return q->sss_available; } int srslte_sync_get_cell_id(srslte_sync_t *q) { @@ -262,12 +289,48 @@ int srslte_sync_get_cell_id(srslte_sync_t *q) { } } -int srslte_sync_set_N_id_2(srslte_sync_t *q, uint32_t N_id_2) { +int srslte_sync_set_N_id_2(srslte_sync_t* q, uint32_t N_id_2) +{ if (srslte_N_id_2_isvalid(N_id_2)) { - q->N_id_2 = N_id_2; + q->N_id_2 = N_id_2; return SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid N_id_2=%d\n", N_id_2); + ERROR("Invalid N_id_2=%d\n", N_id_2); + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + +static void generate_freq_sss(srslte_sync_t* q, uint32_t N_id_1) +{ + float sf[2][SRSLTE_SSS_LEN]; + cf_t symbol[SRSLTE_SYMBOL_SZ_MAX]; + + q->N_id_1 = N_id_1; + uint32_t cell_id = q->N_id_1 * 3 + q->N_id_2; + srslte_sss_generate(sf[0], sf[1], cell_id); + + uint32_t k = q->fft_size / 2 - 31; + + for (int n = 0; n < 2; n++) { + bzero(symbol, q->fft_size * sizeof(cf_t)); + for (uint32_t i = 0; i < SRSLTE_SSS_LEN; i++) { + __real__ symbol[k + i] = sf[n][i]; + __imag__ symbol[k + i] = 0; + } + // Get freq-domain version of the SSS signal + srslte_dft_run_c(&q->idftp_sss, symbol, q->sss_signal[n]); + } + q->sss_generated = true; + INFO("Generated SSS for N_id_1=%d, cell_id=%d\n", N_id_1, cell_id); +} + +int srslte_sync_set_N_id_1(srslte_sync_t* q, uint32_t N_id_1) +{ + if (srslte_N_id_1_isvalid(N_id_1)) { + generate_freq_sss(q, N_id_1); + return SRSLTE_SUCCESS; + } else { + ERROR("Invalid N_id_2=%d\n", N_id_1); return SRSLTE_ERROR_INVALID_INPUTS; } } @@ -300,9 +363,9 @@ void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { q->cfo_i_enable = enable; if (q->cfo_i_enable && !q->cfo_i_initiated) { for (int i=0;i<2;i++) { - int offset=(i==0)?-1:1; + int offset = (i == 0) ? -1 : 1; if (srslte_pss_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { - fprintf(stderr, "Error initializing PSS object\n"); + ERROR("Error initializing PSS object\n"); } for (int t=0;tframe_size;t++) { q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); @@ -431,38 +494,72 @@ srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, const cf_t *input, uint32_t } } -/* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space +/* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space * to correlate */ -int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) +static bool sync_sss_symbol(srslte_sync_t* q, const cf_t* input, uint32_t* sf_idx, uint32_t* N_id_1, float* corr) { int ret; srslte_sss_set_N_id_2(&q->sss, q->N_id_2); - switch(q->sss_alg) { - case SSS_DIFF: - srslte_sss_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); - break; - case SSS_PARTIAL_3: - srslte_sss_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); - break; - case SSS_FULL: - srslte_sss_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); - break; - } - - q->sf_idx = srslte_sss_subframe(q->m0, q->m1); - ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1); - if (ret >= 0) { - q->N_id_1 = (uint32_t) ret; - DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", - q->N_id_1, q->sf_idx, SRSLTE_CP_ISNORM(q->cp)?"Normal":"Extended"); - return 1; + // If N_Id_1 is set and SSS generated, correlate with sf0 and sf5 signals to find sf boundaries + if (q->sss_generated) { + bool c = q->pss.chest_on_filter; + q->pss.chest_on_filter = false; + srslte_pss_filter(&q->pss, input, q->sss_recv); + q->pss.chest_on_filter = c; + float res[2]; + for (int s = 0; s < 2; s++) { + res[s] = cabsf(srslte_vec_dot_prod_conj_ccc(q->sss_signal[s], q->sss_recv, q->fft_size)); + } + float ratio; + if (res[0] > res[1]) { + *sf_idx = 0; + ratio = res[0] / res[1]; + } else { + *sf_idx = 5; + ratio = res[1] / res[0]; + } + *N_id_1 = q->N_id_1; + *corr = ratio; + INFO("SSS correlation with N_id_1=%d, sf0=%.2f, sf5=%.2f, sf_idx=%d, ratio=%.1f\n", + q->N_id_1, + res[0], + res[1], + *sf_idx, + ratio); + if (ratio > 1.2) { + return true; + } else { + return false; + } } else { - q->N_id_1 = 1000; - return SRSLTE_SUCCESS; + switch (q->sss_alg) { + case SSS_DIFF: + srslte_sss_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + break; + case SSS_PARTIAL_3: + srslte_sss_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + break; + case SSS_FULL: + srslte_sss_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + break; + } + + *corr = q->m0_value + q->m1_value; + *sf_idx = srslte_sss_subframe(q->m0, q->m1); + ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1); + if (ret >= 0) { + *N_id_1 = (uint32_t)ret; + INFO("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", + *N_id_1, + *sf_idx, + SRSLTE_CP_ISNORM(q->cp) ? "Normal" : "Extended"); + return true; + } } + return false; } srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) @@ -531,10 +628,12 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin fft_size_isvalid(q->fft_size)) { + q->sss_detected = false; + if (peak_position) { - *peak_position = 0; + *peak_position = 0; } - + const cf_t *input_ptr = input; /* First CFO estimation stage is integer. @@ -543,7 +642,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin */ if (q->cfo_i_enable) { if (cfo_i_estimate(q, input_ptr, find_offset, &peak_pos, &q->cfo_i_value) < 0) { - fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); + ERROR("Error calling finding PSS sequence at : %d \n", peak_pos); return SRSLTE_ERROR; } // Correct it using precomputed signal and store in buffer (don't modify input signal) @@ -581,7 +680,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin srslte_pss_set_N_id_2(&q->pss, q->N_id_2); peak_pos = srslte_pss_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); if (peak_pos < 0) { - fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); + ERROR("Error calling finding PSS sequence at : %d \n", peak_pos); return SRSLTE_ERROR; } } @@ -620,8 +719,9 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin } INFO("PSS-CFO: filter=%s, estimated=%f, mean=%f\n", - q->pss_filtering_enabled?"yes":"no", q->cfo_pss, q->cfo_pss_mean); - + q->pss_filtering_enabled ? "yes" : "no", + q->cfo_pss, + q->cfo_pss_mean); } // If there is enough space for CP and SSS estimation @@ -630,36 +730,80 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin // If SSS search is enabled, correlate SSS sequence if (q->sss_en) { - // Set an invalid N_id_1 indicating SSS is yet to be detected - q->N_id_1 = 1000; - - int sss_idx = find_offset + peak_pos - 2 * q->fft_size - - SRSLTE_CP_LEN(q->fft_size, (SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_NORM_LEN : SRSLTE_CP_EXT_LEN)); + int sss_idx; + uint32_t nof_frame_type_trials; + srslte_frame_type_t frame_type_trials[2]; + float sss_corr[2]; + uint32_t sf_idx[2], N_id_1[2]; + + if (q->detect_frame_type) { + nof_frame_type_trials = 2; + frame_type_trials[0] = SRSLTE_FDD; + frame_type_trials[1] = SRSLTE_TDD; + } else { + frame_type_trials[0] = q->frame_type; + nof_frame_type_trials = 1; + } - const cf_t *sss_ptr = &input_ptr[sss_idx]; + q->sss_available = true; + for (uint32_t f = 0; f < nof_frame_type_trials; f++) { + if (frame_type_trials[f] == SRSLTE_FDD) { + sss_idx = (int)find_offset + peak_pos - 2 * SRSLTE_SYMBOL_SZ(q->fft_size, q->cp) + + SRSLTE_CP_SZ(q->fft_size, q->cp); + } else { + sss_idx = (int)find_offset + peak_pos - 4 * SRSLTE_SYMBOL_SZ(q->fft_size, q->cp) + + SRSLTE_CP_SZ(q->fft_size, q->cp); + ; + } - // Correct CFO if detected in PSS - if (q->cfo_pss_enable) { - srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); - // Equalize channel if estimated in PSS - if (q->sss_channel_equalize && q->pss.chest_on_filter && q->pss_filtering_enabled) { - srslte_vec_prod_ccc(&q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss.tmp_ce, - &q->sss_filt[q->fft_size/2-SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN); + if (sss_idx >= 0) { + const cf_t* sss_ptr = &input_ptr[sss_idx]; + + // Correct CFO if detected in PSS + if (q->cfo_pss_enable) { + srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); + // Equalize channel if estimated in PSS + if (q->sss_channel_equalize && q->pss.chest_on_filter && q->pss_filtering_enabled) { + srslte_vec_prod_ccc(&q->sss_filt[q->fft_size / 2 - SRSLTE_PSS_LEN / 2], + q->pss.tmp_ce, + &q->sss_filt[q->fft_size / 2 - SRSLTE_PSS_LEN / 2], + SRSLTE_PSS_LEN); + } + sss_ptr = q->sss_filt; + } + q->sss_detected = sync_sss_symbol(q, sss_ptr, &sf_idx[f], &N_id_1[f], &sss_corr[f]); + } else { + q->sss_available = false; } - sss_ptr = q->sss_filt; } - if (sync_sss_symbol(q, sss_ptr) < 0) { - fprintf(stderr, "Error correlating SSS\n"); - return -1; + if (q->detect_frame_type) { + if (sss_corr[0] > sss_corr[1]) { + q->frame_type = SRSLTE_FDD; + q->sf_idx = sf_idx[0]; + q->N_id_1 = N_id_1[0]; + } else { + q->frame_type = SRSLTE_TDD; + q->sf_idx = sf_idx[1] + 1; + q->N_id_1 = N_id_1[1]; + } + DEBUG("SYNC: Detected SSS %s, corr=%.2f/%.2f\n", + q->frame_type == SRSLTE_FDD ? "FDD" : "TDD", + sss_corr[0], + sss_corr[1]); + } else if (q->sss_detected) { + if (q->frame_type == SRSLTE_FDD) { + q->sf_idx = sf_idx[0]; + } else { + q->sf_idx = sf_idx[0] + 1; + } + q->N_id_1 = N_id_1[0]; } } // Detect CP length if (q->detect_cp) { srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_ptr, peak_pos + find_offset)); - } else { - DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); } ret = SRSLTE_SYNC_FOUND; @@ -669,13 +813,19 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin } else { ret = SRSLTE_SYNC_NOFOUND; } - - DEBUG("SYNC ret=%d N_id_2=%d find_offset=%d frame_len=%d, pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f kHz\n", - ret, q->N_id_2, find_offset, q->frame_size, peak_pos, q->peak_value, - q->threshold, q->sf_idx, 15*(srslte_sync_get_cfo(q))); + + DEBUG("SYNC ret=%d N_id_2=%d find_offset=%d frame_len=%d, pos=%d peak=%.2f threshold=%.2f CFO=%.3f kHz\n", + ret, + q->N_id_2, + find_offset, + q->frame_size, + peak_pos, + q->peak_value, + q->threshold, + 15 * (srslte_sync_get_cfo(q))); } else if (srslte_N_id_2_isvalid(q->N_id_2)) { - fprintf(stderr, "Must call srslte_sync_set_N_id_2() first!\n"); + ERROR("Must call srslte_sync_set_N_id_2() first!\n"); } return ret; diff --git a/lib/src/phy/sync/test/CMakeLists.txt b/lib/src/phy/sync/test/CMakeLists.txt index 35407ca94..569098116 100644 --- a/lib/src/phy/sync/test/CMakeLists.txt +++ b/lib/src/phy/sync/test/CMakeLists.txt @@ -39,8 +39,7 @@ if(SRSGUI_FOUND) if(UHD_FOUND) target_link_libraries(pss_usrp ${SRSGUI_LIBRARIES}) endif(UHD_FOUND) -else(SRSGUI_FOUND) - add_definitions(-DDISABLE_GRAPHICS) + add_definitions(-DENABLE_GUI) endif(SRSGUI_FOUND) ######################################################################## diff --git a/lib/src/phy/sync/test/cfo_test.c b/lib/src/phy/sync/test/cfo_test.c index 3764d7401..bb8498873 100644 --- a/lib/src/phy/sync/test/cfo_test.c +++ b/lib/src/phy/sync/test/cfo_test.c @@ -91,7 +91,7 @@ int main(int argc, char **argv) { } if (srslte_cfo_init(&cfocorr, num_samples)) { - fprintf(stderr, "Error initiating CFO\n"); + ERROR("Error initiating CFO\n"); return -1; } diff --git a/lib/src/phy/sync/test/cp_mex.c b/lib/src/phy/sync/test/cp_mex.c deleted file mode 100644 index 01579ba24..000000000 --- a/lib/src/phy/sync/test/cp_mex.c +++ /dev/null @@ -1,93 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define INPUT prhs[1] -#define NOF_INPUTS 2 - - -void help() -{ - mexErrMsgTxt - ("[offset,corr] = srslte_cp_synch(enbConfig, inputSignal)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - srslte_cell_t cell; - srslte_cp_synch_t cp_synch; - cf_t *input_symbols; - int frame_len; - - if (nrhs != NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - /** Allocate input buffers */ - frame_len = mexutils_read_cf(INPUT, &input_symbols); - if (frame_len < 0) { - mexErrMsgTxt("Error reading input symbols\n"); - return; - } - - uint32_t symbol_sz = srslte_symbol_sz(cell.nof_prb); - if (srslte_cp_synch_init(&cp_synch, symbol_sz)) { - fprintf(stderr, "Error initiating CP\n"); - return; - } - - uint32_t cp_len = SRSLTE_CP_LEN_NORM(1, symbol_sz); - uint32_t nsymbols = frame_len/(symbol_sz+cp_len)-1; - uint32_t peak_idx = srslte_cp_synch(&cp_synch, input_symbols, symbol_sz, nsymbols, cp_len); - - if (nlhs >= 1) { - plhs[0] = mxCreateDoubleScalar(peak_idx); - } - if (nlhs >= 2) { - mexutils_write_cf(cp_synch.corr, &plhs[1], symbol_sz, 1); - } - - srslte_cp_synch_free(&cp_synch); - free(input_symbols); - - return; -} - diff --git a/lib/src/phy/sync/test/pss_file.c b/lib/src/phy/sync/test/pss_file.c index d1ec2a130..9e0425473 100644 --- a/lib/src/phy/sync/test/pss_file.c +++ b/lib/src/phy/sync/test/pss_file.c @@ -36,14 +36,12 @@ #include "srslte/srslte.h" - -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI void init_plots(); void do_plots(float *corr, float energy, uint32_t size, cf_t ce[SRSLTE_PSS_LEN]); void do_plots_sss(float *corr_m0, float *corr_m1); void destroy_plots(); -#endif - +#endif /* ENABLE_GUI */ bool disable_plots = false; char *input_file_name; @@ -63,11 +61,11 @@ void usage(char *prog) { printf("\t-s symbol_sz [Default %d]\n", fft_size); printf("\t-t threshold [Default %.2f]\n", threshold); printf("\t-o file read offset [Default %d]\n", file_offset); -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI printf("\t-d disable plots [Default enabled]\n"); -#else +#else /* ENABLE_GUI */ printf("\t plots are disabled. Graphics library not available\n"); -#endif +#endif /* ENABLE_GUI */ printf("\t-v srslte_verbose\n"); } @@ -139,13 +137,13 @@ int main(int argc, char **argv) { uint32_t N_id_2 = cell_id%3; uint32_t N_id_1 = cell_id/3; -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI if (!disable_plots) init_plots(); -#endif - - flen = fft_size*15*5; - +#endif /* ENABLE_GUI */ + + flen = fft_size * 15 * 5; + buffer = malloc(sizeof(cf_t) * flen * 2); if (!buffer) { perror("malloc"); @@ -153,20 +151,20 @@ int main(int argc, char **argv) { } if (srslte_pss_init_fft(&pss, flen, fft_size)) { - fprintf(stderr, "Error initiating PSS\n"); + ERROR("Error initiating PSS\n"); exit(-1); } if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { - fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); + ERROR("Error setting N_id_2=%d\n", N_id_2_sync); exit(-1); } - + srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); if (srslte_sss_init(&sss, fft_size)) { - fprintf(stderr, "Error initializing SSS object\n"); + ERROR("Error initializing SSS object\n"); return SRSLTE_ERROR; } @@ -174,7 +172,7 @@ int main(int argc, char **argv) { printf("Opening file...\n"); if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", input_file_name); + ERROR("Error opening file %s\n", input_file_name); exit(-1); } printf("N_id_2: %d\n", N_id_2); @@ -202,7 +200,7 @@ int main(int argc, char **argv) { while(frame_cnt < nof_frames || nof_frames == -1) { n = srslte_filesource_read(&fsrc, buffer, flen - peak_offset); if (n < 0) { - fprintf(stderr, "Error reading samples\n"); + ERROR("Error reading samples\n"); exit(-1); } if (n < flen - peak_offset) { @@ -212,10 +210,10 @@ int main(int argc, char **argv) { peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { - fprintf(stderr, "Error finding PSS peak\n"); + ERROR("Error finding PSS peak\n"); exit(-1); } - + mean_peak = SRSLTE_VEC_CMA(peak_value, mean_peak, frame_cnt); if (peak_value >= threshold) { @@ -232,10 +230,10 @@ int main(int argc, char **argv) { // Estimate channel if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { - fprintf(stderr, "Error computing channel estimation\n"); + ERROR("Error computing channel estimation\n"); exit(-1); } - + // Find SSS int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); if (sss_idx >= 0 && sss_idx < flen-fft_size) { @@ -271,12 +269,12 @@ int main(int argc, char **argv) { if(srslte_sss_subframe(m0,m1) == 0) { -#ifndef DISABLE_GRAPHICS - if (!disable_plots) - do_plots_sss(sss.corr_output_m0, sss.corr_output_m1); -#endif +#ifdef ENABLE_GUI + if (!disable_plots) + do_plots_sss(sss.corr_output_m0, sss.corr_output_m1); +#endif /* ENABLE_GUI */ } - + } else { nof_nodet++; } @@ -307,23 +305,22 @@ int main(int argc, char **argv) { } usleep(10000); - -#ifndef DISABLE_GRAPHICS + +#ifdef ENABLE_GUI if (!disable_plots) - do_plots(pss.conv_output_avg, pss.conv_output_avg[peak_idx], pss.fft_size+pss.frame_size-1, ce); -#endif + do_plots(pss.conv_output_avg, pss.conv_output_avg[peak_idx], pss.fft_size + pss.frame_size - 1, ce); +#endif /* ENABLE_GUI */ last_peak = peak_idx; - } srslte_pss_free(&pss); free(buffer); srslte_filesource_free(&fsrc); -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI if (!disable_plots) destroy_plots(); -#endif +#endif /* ENABLE_GUI */ printf("Ok\n"); exit(0); @@ -335,8 +332,7 @@ extern cf_t *tmp2; /********************************************************************** * Plotting Functions ***********************************************************************/ -#ifndef DISABLE_GRAPHICS - +#ifdef ENABLE_GUI #include "srsgui/srsgui.h" plot_real_t pssout; @@ -403,5 +399,4 @@ void destroy_plots() { sdrgui_exit(); } - -#endif +#endif /* ENABLE_GUI */ diff --git a/lib/src/phy/sync/test/pss_mex.c b/lib/src/phy/sync/test/pss_mex.c deleted file mode 100644 index 59cc0a897..000000000 --- a/lib/src/phy/sync/test/pss_mex.c +++ /dev/null @@ -1,101 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define INPUT prhs[1] -#define NOF_INPUTS 2 - - -void help() -{ - mexErrMsgTxt - ("[offset,corr] = srslte_pss(enbConfig, inputSignal)\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - srslte_cell_t cell; - srslte_pss_t pss; - cf_t *input_symbols; - int frame_len; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - srslte_use_standard_symbol_size(true); - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - /* Allocate input buffers */ - frame_len = mexutils_read_cf(INPUT, &input_symbols); - if (frame_len < 0) { - mexErrMsgTxt("Error reading input symbols\n"); - return; - } - - if (nrhs == NOF_INPUTS+1) { - frame_len = (int) mxGetScalar(prhs[NOF_INPUTS]); - } - - if (srslte_pss_init_fft(&pss, frame_len, srslte_symbol_sz(cell.nof_prb))) { - fprintf(stderr, "Error initiating PSS\n"); - exit(-1); - } - if (srslte_pss_set_N_id_2(&pss, cell.id%3)) { - fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3); - exit(-1); - } - srslte_pss_set_ema_alpha(&pss, 1.0); - - int peak_idx = srslte_pss_find_pss(&pss, input_symbols, NULL); - - if (nlhs >= 1) { - plhs[0] = mxCreateDoubleScalar(peak_idx); - } - if (nlhs >= 2) { - mexutils_write_cf(pss.conv_output, &plhs[1], frame_len, 1); - } - - srslte_pss_free(&pss); - free(input_symbols); - - return; -} - diff --git a/lib/src/phy/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c index 08afdd025..a76c3a248 100644 --- a/lib/src/phy/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -37,17 +37,16 @@ #include "srslte/srslte.h" #include "srslte/phy/rf/rf.h" - -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI void init_plots(); void do_plots_pss(float *corr, float energy, uint32_t size); void do_plots_sss(float *corr_m0, float *corr_m1); -#endif +#endif /* ENABLE_GUI */ - -bool disable_plots = false; -int cell_id = -1; -char *rf_args=""; +bool tdd_mode = false; +bool disable_plots = false; +int cell_id = -1; +char* rf_args = ""; float rf_gain=40.0, rf_freq=-1.0; int nof_frames = -1; uint32_t fft_size=64; @@ -64,7 +63,8 @@ void usage(char *prog) { printf("\t-e Extended CP [Default Normal]\n"); printf("\t-s symbol_sz [Default %d]\n", fft_size); printf("\t-t threshold [Default %.2f]\n", threshold); -#ifndef DISABLE_GRAPHICS + printf("\t-T TDD mode [Default FDD]\n"); +#ifdef ENABLE_GUI printf("\t-d disable plots [Default enabled]\n"); #else printf("\t plots are disabled. Graphics library not available\n"); @@ -74,44 +74,47 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "adgetvnsfil")) != -1) { + while ((opt = getopt(argc, argv, "adgetTvnsfil")) != -1) { switch (opt) { - case 'a': - rf_args = argv[optind]; - break; - case 'g': - rf_gain = atof(argv[optind]); - break; - case 'f': - rf_freq = atof(argv[optind]); - break; - case 't': - threshold = atof(argv[optind]); - break; - case 'e': - cp = SRSLTE_CP_EXT; - break; - case 'i': - cell_id = atoi(argv[optind]); - break; - case 'l': - N_id_2_sync = atoi(argv[optind]); - break; - case 's': - fft_size = atoi(argv[optind]); - break; - case 'n': - nof_frames = atoi(argv[optind]); - break; - case 'd': - disable_plots = true; - break; - case 'v': - srslte_verbose++; - break; - default: - usage(argv[0]); - exit(-1); + case 'a': + rf_args = argv[optind]; + break; + case 'g': + rf_gain = atof(argv[optind]); + break; + case 'f': + rf_freq = atof(argv[optind]); + break; + case 't': + threshold = atof(argv[optind]); + break; + case 'e': + cp = SRSLTE_CP_EXT; + break; + case 'i': + cell_id = atoi(argv[optind]); + break; + case 'T': + tdd_mode = true; + break; + case 'l': + N_id_2_sync = atoi(argv[optind]); + break; + case 's': + fft_size = atoi(argv[optind]); + break; + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'd': + disable_plots = true; + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); } } if (cell_id < 0 || rf_freq < 0) { @@ -144,21 +147,21 @@ int main(int argc, char **argv) { uint32_t N_id_2 = cell_id%3; uint32_t N_id_1 = cell_id/3; -#ifndef DISABLE_GRAPHICS +#ifdef ENABLE_GUI if (!disable_plots) init_plots(); -#endif +#endif /* ENABLE_GUI */ + + float srate = 15000.0 * fft_size; - float srate = 15000.0*fft_size; - flen = srate*5/1000; printf("Opening RF device...\n"); if (srslte_rf_open(&rf, rf_args)) { - fprintf(stderr, "Error opening rf\n"); + ERROR("Error opening rf\n"); exit(-1); } - + if (srate < 10e6) { srslte_rf_set_master_clock_rate(&rf, 4*srate); } else { @@ -167,9 +170,9 @@ int main(int argc, char **argv) { printf("Set RX rate: %.2f MHz\n", srslte_rf_set_rx_srate(&rf, srate) / 1000000); printf("Set RX gain: %.1f dB\n", srslte_rf_set_rx_gain(&rf, rf_gain)); - printf("Set RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, rf_freq) / 1000000); + printf("Set RX freq: %.2f MHz\n", srslte_rf_set_rx_freq(&rf, 0, rf_freq) / 1000000); srslte_rf_rx_wait_lo_locked(&rf); - + buffer = malloc(sizeof(cf_t) * flen * 2); if (!buffer) { perror("malloc"); @@ -177,23 +180,23 @@ int main(int argc, char **argv) { } if (srslte_pss_init_fft(&pss, flen, fft_size)) { - fprintf(stderr, "Error initiating PSS\n"); + ERROR("Error initiating PSS\n"); exit(-1); } if (srslte_pss_set_N_id_2(&pss, N_id_2_sync)) { - fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync); + ERROR("Error setting N_id_2=%d\n", N_id_2_sync); exit(-1); } - + srslte_cfo_init(&cfocorr, flen); srslte_cfo_init(&cfocorr64, flen); if (srslte_sss_init(&sss, fft_size)) { - fprintf(stderr, "Error initializing SSS object\n"); + ERROR("Error initializing SSS object\n"); exit(-1); } - + srslte_sss_set_N_id_2(&sss, N_id_2); printf("N_id_2: %d\n", N_id_2); @@ -228,16 +231,16 @@ int main(int argc, char **argv) { while(frame_cnt < nof_frames || nof_frames == -1) { n = srslte_rf_recv(&rf, buffer, flen - peak_offset, 1); if (n < 0) { - fprintf(stderr, "Error receiving samples\n"); + ERROR("Error receiving samples\n"); exit(-1); } - + peak_idx = srslte_pss_find_pss(&pss, buffer, &peak_value); if (peak_idx < 0) { - fprintf(stderr, "Error finding PSS peak\n"); + ERROR("Error finding PSS peak\n"); exit(-1); } - + mean_peak = SRSLTE_VEC_CMA(peak_value, mean_peak, frame_cnt); if (peak_value >= threshold) { @@ -254,12 +257,21 @@ int main(int argc, char **argv) { // Estimate channel if (srslte_pss_chest(&pss, &buffer[peak_idx-fft_size], ce)) { - fprintf(stderr, "Error computing channel estimation\n"); + ERROR("Error computing channel estimation\n"); exit(-1); } // Find SSS - int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); + int sss_idx; + if (!tdd_mode) { + sss_idx = peak_idx - 2 * fft_size - + (SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN) + : SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); + } else { + sss_idx = peak_idx - 4 * fft_size - + 3 * (SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN) + : SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN)); + } if (sss_idx >= 0 && sss_idx < flen-fft_size) { // Filter SSS @@ -293,13 +305,12 @@ int main(int argc, char **argv) { } else { INFO("No space for CFO computation. Frame starts at \n"); } - - if(srslte_sss_subframe(m0,m1) == 0) - { -#ifndef DISABLE_GRAPHICS - if (!disable_plots) - do_plots_sss(sss.corr_output_m0, sss.corr_output_m1); -#endif + + if (srslte_sss_subframe(m0, m1) == 0) { +#ifdef ENABLE_GUI + if (!disable_plots) + do_plots_sss(sss.corr_output_m0, sss.corr_output_m1); +#endif /* ENABLE_GUI */ } } else { @@ -347,12 +358,12 @@ int main(int argc, char **argv) { if (SRSLTE_VERBOSE_ISINFO()) { printf("\n"); } - -#ifndef DISABLE_GRAPHICS + +#ifdef ENABLE_GUI if (!disable_plots) { - do_plots_pss(pss.conv_output_avg, pss.conv_output_avg[peak_idx], pss.fft_size+pss.frame_size-1); + do_plots_pss(pss.conv_output_avg, pss.conv_output_avg[peak_idx], pss.fft_size + pss.frame_size - 1); } -#endif +#endif /* ENABLE_GUI */ last_peak = peak_idx; @@ -370,12 +381,10 @@ int main(int argc, char **argv) { extern cf_t *tmp2; - /********************************************************************** * Plotting Functions ***********************************************************************/ -#ifndef DISABLE_GRAPHICS - +#ifdef ENABLE_GUI #include "srsgui/srsgui.h" plot_real_t pssout; @@ -420,5 +429,4 @@ void do_plots_sss(float *corr_m0, float *corr_m1) { plot_real_setNewData(&psss1, corr_m0, SRSLTE_SSS_N); } - -#endif +#endif /* ENABLE_GUI */ diff --git a/lib/src/phy/sync/test/sss_mex.c b/lib/src/phy/sync/test/sss_mex.c deleted file mode 100644 index 56165fe3d..000000000 --- a/lib/src/phy/sync/test/sss_mex.c +++ /dev/null @@ -1,127 +0,0 @@ -/** - * - * \section COPYRIGHT - * -* Copyright 2013-2015 Software Radio Systems Limited - * - * \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 "srslte/mex/mexutils.h" - -/** MEX function to be called from MATLAB to test the channel estimator - */ - -#define ENBCFG prhs[0] -#define INPUT prhs[1] -#define ALGO prhs[2] -#define NOF_INPUTS 2 - - -void help() -{ - mexErrMsgTxt - ("[N_id_1,sf_idx,corr_output_m0,corr_output_m1] = srslte_sss(enbConfig, inputSignal, [Algorithm])\n" - "\tinputSignal must be aligned to the subframe. CP length is assumed Normal.\n" - "\tAlgorithm is an optional parameter: Can be 'partial','diff','full'\n\n"); -} - -/* the gateway function */ -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - - srslte_cell_t cell; - srslte_sss_t sss; - cf_t *input_symbols; - int frame_len; - uint32_t m0, m1; - float m0_value, m1_value; - char alg[64]; - - if (nrhs < NOF_INPUTS) { - help(); - return; - } - - if (mexutils_read_cell(ENBCFG, &cell)) { - help(); - return; - } - - if (nrhs > NOF_INPUTS) { - mxGetString(ALGO, alg, (mwSize)sizeof(alg)); - } else { - strcpy(alg, "full"); - } - - /** Allocate input buffers */ - frame_len = mexutils_read_cf(INPUT, &input_symbols); - if (frame_len < 0) { - mexErrMsgTxt("Error reading input symbols\n"); - return; - } - - if (srslte_sss_init(&sss, srslte_symbol_sz(cell.nof_prb))) { - mexErrMsgTxt("Error initializing SSS object\n"); - return; - } - - srslte_sss_set_N_id_2(&sss, cell.id%3); - - // Find SSS - uint32_t sss_idx = SRSLTE_SLOT_IDX_CPNORM(5,srslte_symbol_sz(cell.nof_prb)); - if (sss_idx > frame_len) { - mexErrMsgTxt("Error too few samples provided.\n"); - return; - } - //mexPrintf("SSS begins at %d/%d. Running algorithm %s\n", sss_idx, frame_len, alg); - if (!strcmp(alg, "partial")) { - srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value); - } else if (!strcmp(alg, "diff")) { - srslte_sss_m0m1_diff(&sss, &input_symbols[sss_idx], &m0, &m0_value, &m1, &m1_value); - } else if (!strcmp(alg, "full")) { - srslte_sss_m0m1_partial(&sss, &input_symbols[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); - } else { - mexErrMsgTxt("Unsupported algorithm type\n"); - return; - } - - //mexPrintf("m0: %d, m1: %d, N_id_1: %d\n", m0, m1, srslte_sss_N_id_1(&sss, m0, m1)); - - if (nlhs >= 1) { - plhs[0] = mxCreateDoubleScalar(srslte_sss_N_id_1(&sss, m0, m1)); - } - if (nlhs >= 2) { - plhs[1] = mxCreateDoubleScalar(srslte_sss_subframe(m0, m1)); - } - if (nlhs >= 3) { - mexutils_write_f(sss.corr_output_m0, &plhs[2], SRSLTE_SSS_N, 1); - } - if (nlhs >= 4) { - mexutils_write_f(sss.corr_output_m1, &plhs[3], SRSLTE_SSS_N, 1); - } - srslte_sss_free(&sss); - free(input_symbols); - - return; -} - diff --git a/lib/src/phy/sync/test/sync_test.c b/lib/src/phy/sync/test/sync_test.c index 7c6d02e01..f99837c7c 100644 --- a/lib/src/phy/sync/test/sync_test.c +++ b/lib/src/phy/sync/test/sync_test.c @@ -93,7 +93,7 @@ int main(int argc, char **argv) { fft_size = srslte_symbol_sz(nof_prb); if (fft_size < 0) { - fprintf(stderr, "Invalid nof_prb=%d\n", nof_prb); + ERROR("Invalid nof_prb=%d\n", nof_prb); exit(-1); } @@ -110,12 +110,12 @@ int main(int argc, char **argv) { } if (srslte_ofdm_tx_init(&ifft, cp, buffer, fft_buffer, nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); + ERROR("Error creating iFFT object\n"); exit(-1); } if (srslte_sync_init(&syncobj, FLEN, FLEN, fft_size)) { - fprintf(stderr, "Error initiating PSS/SSS\n"); + ERROR("Error initiating PSS/SSS\n"); return -1; } @@ -158,7 +158,7 @@ int main(int argc, char **argv) { bzero(fft_buffer, sizeof(cf_t) * offset); if (srslte_sync_find(&syncobj, fft_buffer, 0, &find_idx) < 0) { - fprintf(stderr, "Error running srslte_sync_find\n"); + ERROR("Error running srslte_sync_find\n"); exit(-1); } find_sf = srslte_sync_get_sf_idx(&syncobj); diff --git a/lib/src/phy/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c index 133aad144..bdc7141b3 100644 --- a/lib/src/phy/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -24,12 +24,12 @@ * */ +#include "srslte/srslte.h" +#include #include #include #include -#include #include -#include #include "srslte/phy/ue/ue_cell_search.h" @@ -53,16 +53,19 @@ int srslte_ue_cellsearch_init(srslte_ue_cellsearch_t * q, uint32_t max_frames, cell.nof_prb = SRSLTE_CS_NOF_PRB; if (srslte_ue_sync_init(&q->ue_sync, cell.nof_prb, true, recv_callback, stream_handler)) { - fprintf(stderr, "Error initiating ue_sync\n"); + ERROR("Error initiating ue_sync\n"); goto clean_exit; } if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); + ERROR("Error initiating ue_sync\n"); goto clean_exit; } - q->sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + q->sf_buffer[p] = NULL; + } + q->sf_buffer[0] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); q->nof_rx_antennas = 1; q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames); @@ -94,10 +97,11 @@ clean_exit: return ret; } -int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_frames, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), - uint32_t nof_rx_antennas, - void *stream_handler) +int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t* q, + uint32_t max_frames, + int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), + uint32_t nof_rx_antennas, + void* stream_handler) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -116,15 +120,15 @@ int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_fra goto clean_exit; } if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { - fprintf(stderr, "Error setting cell in ue_sync\n"); + ERROR("Error setting cell in ue_sync\n"); goto clean_exit; } - for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + for (int i = 0; i < nof_rx_antennas; i++) { + q->sf_buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); } - q->nof_rx_antennas = nof_rx_antennas; - + q->nof_rx_antennas = nof_rx_antennas; + q->candidates = calloc(sizeof(srslte_ue_cellsearch_result_t), max_frames); if (!q->candidates) { perror("malloc"); @@ -156,7 +160,7 @@ clean_exit: void srslte_ue_cellsearch_free(srslte_ue_cellsearch_t * q) { - for (int i=0;inof_rx_antennas;i++) { + for (int i = 0; i < q->nof_rx_antennas; i++) { if (q->sf_buffer[i]) { free(q->sf_buffer[i]); } @@ -213,14 +217,18 @@ static void get_cell(srslte_ue_cellsearch_t * q, uint32_t nof_detected_frames, s } } found_cell->cell_id = q->candidates[mode_pos].cell_id; - /* Now in all these cell IDs, find most frequent CP */ + /* Now in all these cell IDs, find most frequent CP and duplex mode */ uint32_t nof_normal = 0; + uint32_t nof_fdd = 0; found_cell->peak = 0; for (i=0;icandidates[i].cell_id == found_cell->cell_id) { if (SRSLTE_CP_ISNORM(q->candidates[i].cp)) { nof_normal++; - } + } + if (q->candidates[i].frame_type == SRSLTE_FDD) { + nof_fdd++; + } } // average absolute peak value found_cell->peak += q->candidates[i].peak; @@ -230,7 +238,12 @@ static void get_cell(srslte_ue_cellsearch_t * q, uint32_t nof_detected_frames, s if (nof_normal > q->mode_ntimes[mode_pos]/2) { found_cell->cp = SRSLTE_CP_NORM; } else { - found_cell->cp = SRSLTE_CP_EXT; + found_cell->cp = SRSLTE_CP_EXT; + } + if (nof_fdd > q->mode_ntimes[mode_pos] / 2) { + found_cell->frame_type = SRSLTE_FDD; + } else { + found_cell->frame_type = SRSLTE_TDD; } found_cell->mode = (float) q->mode_ntimes[mode_pos]/nof_detected_frames; @@ -257,7 +270,7 @@ int srslte_ue_cellsearch_scan(srslte_ue_cellsearch_t * q, for (uint32_t N_id_2=0;N_id_2<3 && ret >= 0;N_id_2++) { ret = srslte_ue_cellsearch_scan_N_id_2(q, N_id_2, &found_cells[N_id_2]); if (ret < 0) { - fprintf(stderr, "Error searching cell\n"); + ERROR("Error searching cell\n"); return ret; } nof_detected_cells += ret; @@ -293,29 +306,33 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_sync_set_N_id_2(&q->ue_sync, N_id_2); srslte_ue_sync_reset(&q->ue_sync); srslte_ue_sync_cfo_reset(&q->ue_sync); + srslte_ue_sync_set_nof_find_frames(&q->ue_sync, q->max_frames); do { - - ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); + ret = srslte_ue_sync_zerocopy(&q->ue_sync, q->sf_buffer); if (ret < 0) { - fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); + ERROR("Error calling srslte_ue_sync_work()\n"); return -1; } else if (ret == 1) { - /* This means a peak was found and ue_sync is now in tracking state */ - ret = srslte_sync_get_cell_id(&q->ue_sync.strack); - if (ret >= 0) { + /* This means a peak was found in find state */ + ret = srslte_sync_get_cell_id(&q->ue_sync.sfind); + if (ret >= 0) { /* Save cell id, cp and peak */ - q->candidates[nof_detected_frames].cell_id = (uint32_t) ret; - q->candidates[nof_detected_frames].cp = srslte_sync_get_cp(&q->ue_sync.strack); - q->candidates[nof_detected_frames].peak = q->ue_sync.strack.pss.peak_value; - q->candidates[nof_detected_frames].psr = srslte_sync_get_peak_value(&q->ue_sync.strack); - q->candidates[nof_detected_frames].cfo = srslte_ue_sync_get_cfo(&q->ue_sync); - DEBUG - ("CELL SEARCH: [%3d/%3d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s\n", - nof_detected_frames, nof_scanned_frames, q->nof_valid_frames, - q->candidates[nof_detected_frames].psr, q->candidates[nof_detected_frames].cell_id, - srslte_cp_string(q->candidates[nof_detected_frames].cp)); - + q->candidates[nof_detected_frames].cell_id = (uint32_t)ret; + q->candidates[nof_detected_frames].cp = srslte_sync_get_cp(&q->ue_sync.sfind); + q->candidates[nof_detected_frames].peak = q->ue_sync.sfind.pss.peak_value; + q->candidates[nof_detected_frames].psr = srslte_sync_get_peak_value(&q->ue_sync.sfind); + q->candidates[nof_detected_frames].cfo = 15000 * srslte_sync_get_cfo(&q->ue_sync.sfind); + q->candidates[nof_detected_frames].frame_type = srslte_ue_sync_get_frame_type(&q->ue_sync); + DEBUG("CELL SEARCH: [%d/%d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s, CFO=%.1f KHz\n", + nof_detected_frames, + nof_scanned_frames, + q->nof_valid_frames, + q->candidates[nof_detected_frames].psr, + q->candidates[nof_detected_frames].cell_id, + srslte_cp_string(q->candidates[nof_detected_frames].cp), + q->candidates[nof_detected_frames].cfo / 1000); + nof_detected_frames++; } } else if (ret == 0) { diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 8e9353236..9994f18e9 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -26,16 +26,11 @@ #include "srslte/phy/ue/ue_dl.h" +#include "srslte/srslte.h" #include -#include - - -#define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) -#define CURRENT_SFLEN SRSLTE_SF_LEN(CURRENT_FFTSIZE) - -#define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN_RE SRSLTE_NOF_RE(q->cell) #define MAX_SFLEN_RE SRSLTE_SF_LEN_RE(max_prb, q->cell.cp) const static srslte_dci_format_t ue_dci_formats[8][2] = { @@ -46,676 +41,731 @@ const static srslte_dci_format_t ue_dci_formats[8][2] = { /* Mode 5 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1D}, /* Mode 6 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1B}, /* Mode 7 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}, - /* Mode 8 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2B} -}; - -static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; -const uint32_t nof_common_formats = 2; - -int srslte_ue_dl_init(srslte_ue_dl_t *q, - cf_t *in_buffer[SRSLTE_MAX_PORTS], - uint32_t max_prb, - uint32_t nof_rx_antennas) + /* Mode 8 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2B}}; + +static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C}; +const uint32_t nof_common_formats = 2; + +// mi value as in table 6.9-1 36.213 for regs vector. For FDD, uses only 1st +const static uint32_t mi_reg_idx[3] = {1, 0, 2}; +const static uint32_t mi_reg_idx_inv[3] = {1, 0, 2}; + +// Table 6.9-1: mi value for differnt ul/dl TDD configurations +const static uint32_t mi_tdd_table[7][10] = {{2, 1, 0, 0, 0, 2, 1, 0, 0, 0}, // ul/dl 0 + {0, 1, 0, 0, 1, 0, 1, 0, 0, 1}, // ul/dl 1 + {0, 0, 0, 1, 0, 0, 0, 0, 1, 0}, // ul/dl 2 + {1, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // ul/dl 3 + {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // ul/dl 4 + {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, // ul/dl 5 + {1, 1, 0, 0, 0, 1, 1, 0, 0, 1}}; // ul/dl 6 + +#define MI_VALUE(sf_idx) ((q->cell.frame_type == SRSLTE_FDD) ? 1 : mi_tdd_table[sf->tdd_config.sf_config][sf_idx]) +#define MI_IDX(sf_idx) \ + (mi_reg_idx_inv[MI_VALUE(sf_idx)] + \ + ((q->cell.frame_type == SRSLTE_TDD && q->cell.phich_length == SRSLTE_PHICH_EXT && (sf_idx == 1 || sf_idx == 6)) \ + ? 3 \ + : 0)) + +int srslte_ue_dl_init(srslte_ue_dl_t* q, cf_t* in_buffer[SRSLTE_MAX_PORTS], uint32_t max_prb, uint32_t nof_rx_antennas) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - nof_rx_antennas <= SRSLTE_MAX_PORTS) - { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && nof_rx_antennas <= SRSLTE_MAX_PORTS) { ret = SRSLTE_ERROR; - + bzero(q, sizeof(srslte_ue_dl_t)); - - q->pdsch_pkt_errors = 0; - q->pdsch_pkts_total = 0; - q->pmch_pkt_errors = 0; - q->pmch_pkts_total = 0; - q->pending_ul_dci_rnti = 0; - q->nof_rx_antennas = nof_rx_antennas; + + q->pending_ul_dci_count = 0; + q->nof_rx_antennas = nof_rx_antennas; + q->mi_auto = true; + q->mi_manual_index = 0; + q->pregen_rnti = 0; for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { - q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); - if (!q->sf_symbols_m[j]) { + q->sf_symbols[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols[j]) { perror("malloc"); goto clean_exit; } - for (uint32_t i=0;ice_m[i][j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); - if (!q->ce_m[i][j]) { - perror("malloc"); - goto clean_exit; - } - bzero(q->ce_m[i][j], MAX_SFLEN_RE * sizeof(cf_t)); - } - } - - q->sf_symbols = q->sf_symbols_m[0]; - for (int i=0;ice[i] = q->ce_m[i][0]; } for (int i = 0; i < nof_rx_antennas; i++) { - if (srslte_ofdm_rx_init(&q->fft[i], SRSLTE_CP_NORM, in_buffer[i], q->sf_symbols_m[i], max_prb)) { - fprintf(stderr, "Error initiating FFT\n"); + if (srslte_ofdm_rx_init(&q->fft[i], SRSLTE_CP_NORM, in_buffer[i], q->sf_symbols[i], max_prb)) { + ERROR("Error initiating FFT\n"); goto clean_exit; } } - if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, in_buffer[0], q->sf_symbols_m[0], max_prb)) { - fprintf(stderr, "Error initiating FFT for MBSFN subframes \n"); + if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, in_buffer[0], q->sf_symbols[0], max_prb)) { + ERROR("Error initiating FFT for MBSFN subframes \n"); goto clean_exit; } srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, 2); // Set a default to init - - if (srslte_chest_dl_init(&q->chest, max_prb)) { - fprintf(stderr, "Error initiating channel estimator\n"); + + if (srslte_chest_dl_init(&q->chest, max_prb, nof_rx_antennas)) { + ERROR("Error initiating channel estimator\n"); + goto clean_exit; + } + if (srslte_chest_dl_res_init(&q->chest_res, max_prb)) { + ERROR("Error initiating channel estimator\n"); goto clean_exit; } if (srslte_pcfich_init(&q->pcfich, nof_rx_antennas)) { - fprintf(stderr, "Error creating PCFICH object\n"); + ERROR("Error creating PCFICH object\n"); goto clean_exit; } if (srslte_phich_init(&q->phich, nof_rx_antennas)) { - fprintf(stderr, "Error creating PHICH object\n"); + ERROR("Error creating PHICH object\n"); goto clean_exit; } if (srslte_pdcch_init_ue(&q->pdcch, max_prb, nof_rx_antennas)) { - fprintf(stderr, "Error creating PDCCH object\n"); + ERROR("Error creating PDCCH object\n"); goto clean_exit; } if (srslte_pdsch_init_ue(&q->pdsch, max_prb, nof_rx_antennas)) { - fprintf(stderr, "Error creating PDSCH object\n"); + ERROR("Error creating PDSCH object\n"); goto clean_exit; } - if (srslte_pmch_init_multi(&q->pmch, max_prb, nof_rx_antennas)) { - fprintf(stderr, "Error creating PMCH object\n"); + if (srslte_pmch_init(&q->pmch, max_prb, nof_rx_antennas)) { + ERROR("Error creating PMCH object\n"); goto clean_exit; } - for (int i = 0; i < SRSLTE_MAX_TB; i++) { - q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t)); - if (!q->softbuffers[i]) { - fprintf(stderr, "Error allocating soft buffer\n"); - goto clean_exit; - } - - if (srslte_softbuffer_rx_init(q->softbuffers[i], max_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); - goto clean_exit; - } - } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parametres\n"); + ERROR("Invalid parameters\n"); } -clean_exit: +clean_exit: if (ret == SRSLTE_ERROR) { srslte_ue_dl_free(q); } return ret; } -void srslte_ue_dl_free(srslte_ue_dl_t *q) { +void srslte_ue_dl_free(srslte_ue_dl_t* q) +{ if (q) { for (int port = 0; port < SRSLTE_MAX_PORTS; port++) { srslte_ofdm_rx_free(&q->fft[port]); } srslte_ofdm_rx_free(&q->fft_mbsfn); srslte_chest_dl_free(&q->chest); - srslte_regs_free(&q->regs); + srslte_chest_dl_res_free(&q->chest_res); + for (int i = 0; i < MI_NOF_REGS; i++) { + srslte_regs_free(&q->regs[i]); + } srslte_pcfich_free(&q->pcfich); srslte_phich_free(&q->phich); srslte_pdcch_free(&q->pdcch); srslte_pdsch_free(&q->pdsch); srslte_pmch_free(&q->pmch); - for (int i = 0; i < SRSLTE_MAX_TB; i++) { - srslte_softbuffer_rx_free(q->softbuffers[i]); - if (q->softbuffers[i]) { - free(q->softbuffers[i]); - } - } for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { - if (q->sf_symbols_m[j]) { - free(q->sf_symbols_m[j]); - } - for (uint32_t i=0;ice_m[i][j]) { - free(q->ce_m[i][j]); - } + if (q->sf_symbols[j]) { + free(q->sf_symbols[j]); } } bzero(q, sizeof(srslte_ue_dl_t)); } } -int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell) +int srslte_ue_dl_set_cell(srslte_ue_dl_t* q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_cell_isvalid(&cell)) - { - q->pdsch_pkt_errors = 0; - q->pdsch_pkts_total = 0; - q->pmch_pkt_errors = 0; - q->pmch_pkts_total = 0; - q->pending_ul_dci_rnti = 0; + if (q != NULL && srslte_cell_isvalid(&cell)) { + q->pending_ul_dci_count = 0; if (q->cell.id != cell.id || q->cell.nof_prb == 0) { if (q->cell.nof_prb != 0) { - srslte_regs_free(&q->regs); + for (int i = 0; i < MI_NOF_REGS; i++) { + srslte_regs_free(&q->regs[i]); + } } - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - if (srslte_regs_init(&q->regs, q->cell)) { - fprintf(stderr, "Error resizing REGs\n"); - return SRSLTE_ERROR; + q->cell = cell; + for (int i = 0; i < MI_NOF_REGS; i++) { + if (srslte_regs_init_opts(&q->regs[i], q->cell, mi_reg_idx[i % 3], i > 2)) { + ERROR("Error resizing REGs\n"); + return SRSLTE_ERROR; + } } for (int port = 0; port < q->nof_rx_antennas; port++) { if (srslte_ofdm_rx_set_prb(&q->fft[port], q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error resizing FFT\n"); + ERROR("Error resizing FFT\n"); return SRSLTE_ERROR; } } + // In TDD, initialize PDCCH and PHICH for the worst case: max ncces and phich groupds respectively + uint32_t pdcch_init_reg = 0; + uint32_t phich_init_reg = 0; + if (q->cell.frame_type == SRSLTE_TDD) { + pdcch_init_reg = 1; // mi=0 + phich_init_reg = 2; // mi=2 + } + if (srslte_ofdm_rx_set_prb(&q->fft_mbsfn, SRSLTE_CP_EXT, q->cell.nof_prb)) { - fprintf(stderr, "Error resizing MBSFN FFT\n"); + ERROR("Error resizing MBSFN FFT\n"); return SRSLTE_ERROR; } if (srslte_chest_dl_set_cell(&q->chest, q->cell)) { - fprintf(stderr, "Error resizing channel estimator\n"); + ERROR("Error resizing channel estimator\n"); return SRSLTE_ERROR; } - if (srslte_pcfich_set_cell(&q->pcfich, &q->regs, q->cell)) { - fprintf(stderr, "Error resizing PCFICH object\n"); + if (srslte_pcfich_set_cell(&q->pcfich, &q->regs[0], q->cell)) { + ERROR("Error resizing PCFICH object\n"); return SRSLTE_ERROR; } - if (srslte_phich_set_cell(&q->phich, &q->regs, q->cell)) { - fprintf(stderr, "Error resizing PHICH object\n"); + if (srslte_phich_set_cell(&q->phich, &q->regs[phich_init_reg], q->cell)) { + ERROR("Error resizing PHICH object\n"); return SRSLTE_ERROR; } - if (srslte_pdcch_set_cell(&q->pdcch, &q->regs, q->cell)) { - fprintf(stderr, "Error resizing PDCCH object\n"); + if (srslte_pdcch_set_cell(&q->pdcch, &q->regs[pdcch_init_reg], q->cell)) { + ERROR("Error resizing PDCCH object\n"); return SRSLTE_ERROR; } if (srslte_pdsch_set_cell(&q->pdsch, q->cell)) { - fprintf(stderr, "Error resizing PDSCH object\n"); + ERROR("Error resizing PDSCH object\n"); return SRSLTE_ERROR; } if (srslte_pmch_set_cell(&q->pmch, q->cell)) { - fprintf(stderr, "Error resizing PMCH object\n"); + ERROR("Error resizing PMCH object\n"); return SRSLTE_ERROR; } - - q->current_rnti = 0; + } + if (q->pregen_rnti) { + srslte_ue_dl_set_rnti(q, q->pregen_rnti); } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + ERROR("Invalid cell properties ue_dl: Id=%d, Ports=%d, PRBs=%d\n", q->cell.id, q->cell.nof_ports, q->cell.nof_prb); } return ret; } -/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while +void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t* q, uint8_t non_mbsfn_region_length) +{ + srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); +} + +void srslte_ue_dl_set_mi_auto(srslte_ue_dl_t* q) +{ + q->mi_auto = true; +} + +void srslte_ue_dl_set_mi_manual(srslte_ue_dl_t* q, uint32_t mi_idx) +{ + q->mi_auto = false; + q->mi_manual_index = mi_idx; +} + +/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. - * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions + * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions */ -void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { +void srslte_ue_dl_set_rnti(srslte_ue_dl_t* q, uint16_t rnti) +{ srslte_pdsch_set_rnti(&q->pdsch, rnti); - + + srslte_dl_sf_cfg_t sf_cfg; + ZERO_OBJECT(sf_cfg); + // Compute UE-specific and Common search space for this RNTI - for (int cfi=0;cfi<3;cfi++) { - for (int sf_idx=0;sf_idx<10;sf_idx++) { - q->current_ss_ue[cfi][sf_idx].nof_locations = srslte_pdcch_ue_locations(&q->pdcch, q->current_ss_ue[cfi][sf_idx].loc, MAX_CANDIDATES_UE, sf_idx, cfi+1, rnti); - } - q->current_ss_common[cfi].nof_locations = srslte_pdcch_common_locations(&q->pdcch, q->current_ss_common[cfi].loc, MAX_CANDIDATES_COM, cfi+1); - } - - q->current_rnti = rnti; + for (int i = 0; i < MI_NOF_REGS; i++) { + srslte_pdcch_set_regs(&q->pdcch, &q->regs[i]); + for (int cfi = 0; cfi < 3; cfi++) { + sf_cfg.cfi = cfi + 1; + for (int sf_idx = 0; sf_idx < 10; sf_idx++) { + sf_cfg.tti = sf_idx; + q->current_ss_ue[i][cfi][sf_idx].nof_locations = srslte_pdcch_ue_locations( + &q->pdcch, &sf_cfg, q->current_ss_ue[i][cfi][sf_idx].loc, MAX_CANDIDATES_UE, rnti); + } + q->current_ss_common[i][cfi].nof_locations = + srslte_pdcch_common_locations(&q->pdcch, q->current_ss_common[i][cfi].loc, MAX_CANDIDATES_COM, cfi + 1); + } + } + q->pregen_rnti = rnti; } + /* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference * signals. */ -int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, - uint16_t mbsfn_area_id) { +int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t* q, uint16_t mbsfn_area_id) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; - if(q != NULL) { + if (q != NULL) { ret = SRSLTE_ERROR; - if(srslte_chest_dl_set_mbsfn_area_id(&q->chest, mbsfn_area_id)) { - fprintf(stderr, "Error setting MBSFN area ID \n"); + if (srslte_chest_dl_set_mbsfn_area_id(&q->chest, mbsfn_area_id)) { + ERROR("Error setting MBSFN area ID \n"); return ret; } - if(srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id)) { - fprintf(stderr, "Error setting MBSFN area ID \n"); + if (srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id)) { + ERROR("Error setting MBSFN area ID \n"); return ret; } q->current_mbsfn_area_id = mbsfn_area_id; - ret = SRSLTE_SUCCESS; + ret = SRSLTE_SUCCESS; } return ret; } -void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, - uint8_t non_mbsfn_region_length) { - srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); +static void set_mi_value(srslte_ue_dl_t* q, srslte_dl_sf_cfg_t* sf, srslte_ue_dl_cfg_t* cfg) +{ + uint32_t sf_idx = sf->tti % 10; + // Set mi value in pdcch region + if (q->mi_auto) { + INFO("Setting PHICH mi value auto. sf_idx=%d, mi=%d, idx=%d\n", sf_idx, MI_VALUE(sf_idx), MI_IDX(sf_idx)); + srslte_phich_set_regs(&q->phich, &q->regs[MI_IDX(sf_idx)]); + srslte_pdcch_set_regs(&q->pdcch, &q->regs[MI_IDX(sf_idx)]); + } else { + // No subframe 1 or 6 so no need to consider it + INFO("Setting PHICH mi value manual. sf_idx=%d, mi=%d, idx=%d\n", + sf_idx, + q->mi_manual_index, + mi_reg_idx_inv[q->mi_manual_index]); + srslte_phich_set_regs(&q->phich, &q->regs[mi_reg_idx_inv[q->mi_manual_index]]); + srslte_pdcch_set_regs(&q->pdcch, &q->regs[mi_reg_idx_inv[q->mi_manual_index]]); + } } -void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q, float rho_a, float rho_b) { +static int estimate_pdcch_pcfich(srslte_ue_dl_t* q, srslte_dl_sf_cfg_t* sf, srslte_ue_dl_cfg_t* cfg) +{ if (q) { - srslte_pdsch_set_power_allocation(&q->pdsch, rho_a); - q->rho_b = rho_b; - - uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp); - uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb; - - /* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */ - if (rho_b != 0.0f && rho_b != 1.0f) { - float scaling = 1.0f / rho_b; - for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { - for (uint32_t j = 0; j < 2; j++) { - cf_t *ptr; - ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0); - srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); - if (q->cell.cp == SRSLTE_CP_NORM) { - ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4); - srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); - } else { - ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3); - srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); - } - if (q->cell.nof_ports == 4) { - ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1); - srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); - } - } - } + + float cfi_corr = 0; + + set_mi_value(q, sf, cfg); + + /* Get channel estimates for each port */ + srslte_chest_dl_estimate_cfg(&q->chest, sf, &cfg->chest_cfg, q->sf_symbols, &q->chest_res); + + /* First decode PCFICH and obtain CFI */ + if (srslte_pcfich_decode(&q->pcfich, sf, &q->chest_res, q->sf_symbols, &cfi_corr) < 0) { + ERROR("Error decoding PCFICH\n"); + return SRSLTE_ERROR; } - } -} -void srslte_ue_dl_reset(srslte_ue_dl_t *q) { - for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ - srslte_softbuffer_rx_reset(q->softbuffers[i]); - } - bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); -} + if (q->cell.frame_type == SRSLTE_TDD && ((sf->tti % 10) == 1 || (sf->tti % 10) == 6) && sf->cfi == 3) { + sf->cfi = 2; + INFO("Received CFI=3 in subframe 1 or 6 and TDD. Setting to 2\n"); + } -/** Applies the following operations to a subframe of synchronized samples: - * - OFDM demodulation - * - Channel estimation - * - PCFICH decoding - * - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti() - * - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti() - */ -int srslte_ue_dl_decode(srslte_ue_dl_t *q, uint8_t *data[SRSLTE_MAX_CODEWORDS], - uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti(q, data, tm, tti, q->current_rnti, acks); -} + if (srslte_pdcch_extract_llr(&q->pdcch, sf, &q->chest_res, q->sf_symbols)) { + ERROR("Extracting PDCCH LLR\n"); + return false; + } + INFO("Decoded CFI=%d with correlation %.2f, sf_idx=%d\n", sf->cfi, cfi_corr, sf->tti % 10); -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi){ - - return srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); -} + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} -int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t* q, srslte_dl_sf_cfg_t* sf, srslte_ue_dl_cfg_t* cfg) { - if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { - + if (q) { /* Run FFT for all subframe data */ - for (int j=0;jnof_rx_antennas;j++) { - if(sf_type == SRSLTE_SF_MBSFN ) { + for (int j = 0; j < q->nof_rx_antennas; j++) { + if (sf->sf_type == SRSLTE_SF_MBSFN) { srslte_ofdm_rx_sf(&q->fft_mbsfn); - }else{ + } else { srslte_ofdm_rx_sf(&q->fft[j]); } } - return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, sf_type); + return estimate_pdcch_pcfich(q, sf, cfg); } else { - return SRSLTE_ERROR_INVALID_INPUTS; + return SRSLTE_ERROR_INVALID_INPUTS; } } -int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) +int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + cf_t* input[SRSLTE_MAX_PORTS]) { - if (input && q && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { - + if (q && input) { /* Run FFT for all subframe data */ - for (int j=0;jnof_rx_antennas;j++) { - srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]); + for (int j = 0; j < q->nof_rx_antennas; j++) { + if (sf->sf_type == SRSLTE_SF_MBSFN) { + srslte_ofdm_rx_sf_ng(&q->fft_mbsfn, input[j], q->sf_symbols[j]); + } else { + srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols[j]); + } } - return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); + return estimate_pdcch_pcfich(q, sf, cfg); } else { return SRSLTE_ERROR_INVALID_INPUTS; } } -int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { - - return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); -} - +static bool find_dci(srslte_dci_msg_t* dci_msg, uint32_t nof_dci_msg, srslte_dci_msg_t* match) +{ + bool found = false; + uint32_t nof_bits = match->nof_bits; -int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { - float cfi_corr; - if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { - - /* Get channel estimates for each port */ - if(sf_type == SRSLTE_SF_MBSFN){ - srslte_chest_dl_estimate_multi_mbsfn(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas, q->current_mbsfn_area_id); - }else{ - srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); + for (int k = 0; k < nof_dci_msg && !found; k++) { + if (dci_msg[k].nof_bits == nof_bits) { + if (memcmp(dci_msg[k].payload, match->payload, nof_bits) == 0) { + found = true; + } } + } + return found; +} - /* First decode PCFICH and obtain CFI */ - if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m, - srslte_chest_dl_get_noise_estimate(&q->chest), - sf_idx, cfi, &cfi_corr)<0) { - fprintf(stderr, "Error decoding PCFICH\n"); - return SRSLTE_ERROR; - } - - INFO("Decoded CFI=%d with correlation %.2f, sf_idx=%d\n", *cfi, cfi_corr, sf_idx); +static int dci_blind_search(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + uint16_t rnti, + dci_blind_search_t* search_space, + srslte_dci_cfg_t* dci_cfg, + srslte_dci_msg_t dci_msg[SRSLTE_MAX_DCI_MSG]) +{ + uint32_t nof_dci = 0; + if (rnti) { + int i = 0; + while ((dci_cfg->cif_enabled || !nof_dci) && (i < search_space->nof_locations) && (nof_dci < SRSLTE_MAX_DCI_MSG)) { + DEBUG("Searching format %s in %d,%d (%d/%d)\n", + srslte_dci_format_string(search_space->format), + search_space->loc[i].ncce, + search_space->loc[i].L, + i, + search_space->nof_locations); + + dci_msg[nof_dci].location = search_space->loc[i]; + dci_msg[nof_dci].format = search_space->format; + dci_msg[nof_dci].rnti = 0; + if (srslte_pdcch_decode_msg(&q->pdcch, sf, dci_cfg, &dci_msg[nof_dci])) { + ERROR("Error decoding DCI msg\n"); + return SRSLTE_ERROR; + } - return SRSLTE_SUCCESS; + if ((dci_msg[nof_dci].rnti == rnti) && (dci_msg[nof_dci].nof_bits > 0)) { + + dci_msg[nof_dci].rnti = rnti; + // If searching for Format1A but found Format0 save it for later + if (dci_msg[nof_dci].format == SRSLTE_DCI_FORMAT0 && search_space->format == SRSLTE_DCI_FORMAT1A) { + /* If there is space for accumulate another UL DCI dci and it was not detected before, then store it */ + if (q->pending_ul_dci_count < SRSLTE_MAX_CARRIERS && + !find_dci(q->pending_ul_dci_msg, q->pending_ul_dci_count, &dci_msg[nof_dci])) { + srslte_dci_msg_t* pending_ul_dci_msg = &q->pending_ul_dci_msg[q->pending_ul_dci_count]; + pending_ul_dci_msg->format = dci_msg[nof_dci].format; + pending_ul_dci_msg->location = dci_msg[nof_dci].location; + pending_ul_dci_msg->nof_bits = dci_msg[nof_dci].nof_bits; + pending_ul_dci_msg->rnti = dci_msg[nof_dci].rnti; + memcpy(pending_ul_dci_msg->payload, dci_msg[nof_dci].payload, dci_msg[nof_dci].nof_bits); + q->pending_ul_dci_count++; + } + // Else if we found it, save location and keep going if required + } else if (dci_msg[nof_dci].format == search_space->format) { + /* Check if the DCI is duplicated */ + if (!find_dci(dci_msg, (uint32_t)nof_dci, &dci_msg[nof_dci])) { + nof_dci++; + } + } + } + i++; + } } else { - return SRSLTE_ERROR_INVALID_INPUTS; + ERROR("RNTI not specified\n"); } + return nof_dci; } +int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + uint16_t rnti, + srslte_dci_ul_t dci_ul[SRSLTE_MAX_DCI_MSG]) +{ + srslte_dci_msg_t dci_msg[SRSLTE_MAX_DCI_MSG]; + uint32_t nof_msg = 0; + + if (rnti) { + /* Do not search if an UL DCI is already pending */ + if (q->pending_ul_dci_count) { + nof_msg = SRSLTE_MIN(SRSLTE_MAX_DCI_MSG, q->pending_ul_dci_count); + q->pending_ul_dci_count = 0; + memcpy(dci_msg, q->pending_ul_dci_msg, sizeof(srslte_dci_msg_t) * nof_msg); + } else { + + uint32_t sf_idx = sf->tti % 10; + uint32_t cfi = sf->cfi; -int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, - int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) { - uint32_t pmi = 0; - uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); + set_mi_value(q, sf, cfg); - /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ - if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (nof_tb == 1) { - if (grant->pinfo > 0 && grant->pinfo < 5) { - pmi = grant->pinfo - 1; + // Configure and run DCI blind search + dci_blind_search_t search_space; + search_space.nof_locations = 0; + dci_blind_search_t* current_ss = &search_space; + if (q->pregen_rnti == rnti) { + current_ss = &q->current_ss_ue[MI_IDX(sf_idx)][cfi - 1][sf_idx]; } else { - ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); - pmi = grant->pinfo % 4; + // If locations are not pre-generated, generate them now + current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, sf, current_ss->loc, MAX_CANDIDATES_UE, rnti); } - } else { - if (grant->pinfo == 2) { - /* Not implemented */ - } else if (grant->pinfo > 2) { - /* Reserved */ + + current_ss->format = SRSLTE_DCI_FORMAT0; + INFO("Searching UL C-RNTI in %d ue locations\n", search_space.nof_locations); + nof_msg = dci_blind_search(q, sf, rnti, current_ss, &cfg->dci_cfg, dci_msg); + } + + // Unpack DCI messages + for (uint32_t i = 0; i < nof_msg; i++) { + if (srslte_dci_msg_unpack_pusch(&q->cell, sf, &cfg->dci_cfg, &dci_msg[i], &dci_ul[i])) { + ERROR("Unpacking UL DCI\n"); + return SRSLTE_ERROR; } - pmi = grant->pinfo % 2; } - } - if(SRSLTE_SF_MBSFN == grant->sf_type) { - return srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, cfi, sf_idx); + + return nof_msg; + } else { - return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); + return 0; } } -int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, - uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti, - bool acks[SRSLTE_MAX_CODEWORDS]) { - srslte_mimo_type_t mimo_type; - srslte_dci_msg_t dci_msg; - srslte_ra_dl_dci_t dci_unpacked; - srslte_ra_dl_grant_t grant; - int ret = SRSLTE_ERROR; - uint32_t cfi; - uint32_t sf_idx = tti%10; - - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { - return ret; - } - - float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); - // Uncoment next line to do ZF by default in pdsch_ue example - //float noise_estimate = 0; - - if (srslte_pdcch_extract_llr_multi(&q->pdcch, q->sf_symbols_m, q->ce_m, noise_estimate, sf_idx, cfi)) { - fprintf(stderr, "Error extracting LLRs\n"); - return SRSLTE_ERROR; - } - - int found_dci = srslte_ue_dl_find_dl_dci(q, tm, cfi, sf_idx, rnti, &dci_msg); - if (found_dci == 1) { - - INFO("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti=%d\n", srslte_dci_format_string(dci_msg.format), - q->current_rnti, q->last_location.ncce, (1<last_location.L), tti); - - if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) { - fprintf(stderr, "Error unpacking DCI\n"); - return SRSLTE_ERROR; - } - - /* ===== These lines of code are supposed to be MAC functionality === */ - - - int rvidx[SRSLTE_MAX_CODEWORDS] = {1}; - if (dci_unpacked.rv_idx < 0) { - uint32_t sfn = tti / 10; - uint32_t k = (sfn / 2) % 4; - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (grant.tb_en[i]) { - rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; - srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); - } - } - } else { - for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { - if (grant.tb_en[i]) { - switch (i) { - case 0: - rvidx[i] = (uint32_t) dci_unpacked.rv_idx; - break; - case 1: - rvidx[i] = (uint32_t) dci_unpacked.rv_idx_1; - break; - default: - ERROR("Wrong number of transport blocks"); - return SRSLTE_ERROR; - } - srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs); - } +// Blind search for SI/P/RA-RNTI +static int find_dl_dci_type_siprarnti(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + uint16_t rnti, + srslte_dci_msg_t dci_msg[SRSLTE_MAX_DCI_MSG]) +{ + int ret = 0; + + srslte_dci_cfg_t* dci_cfg = &cfg->dci_cfg; + + // Configure and run DCI blind search + dci_blind_search_t search_space; + search_space.nof_locations = srslte_pdcch_common_locations(&q->pdcch, search_space.loc, MAX_CANDIDATES_COM, sf->cfi); + INFO("Searching SI/P/RA-RNTI in %d common locations, %d formats, tti=%d, cfi=%d, rnti=0x%x\n", + search_space.nof_locations, + nof_common_formats, + sf->tti, + sf->cfi, + rnti); + // Search for RNTI only if there is room for the common search space + if (search_space.nof_locations > 0) { + for (uint32_t f = 0; f < nof_common_formats; f++) { + search_space.format = common_formats[f]; + if ((ret = dci_blind_search(q, sf, rnti, &search_space, dci_cfg, dci_msg))) { + return ret; } } + } + return SRSLTE_SUCCESS; +} - switch(dci_msg.format) { - case SRSLTE_DCI_FORMAT1: - case SRSLTE_DCI_FORMAT1A: - case SRSLTE_DCI_FORMAT1C: - if (q->cell.nof_ports == 1) { - mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } else { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } - break; - case SRSLTE_DCI_FORMAT2: - if (SRSLTE_RA_DL_GRANT_NOF_TB(&grant) == 1 && dci_unpacked.pinfo == 0) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else { - mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } - break; - case SRSLTE_DCI_FORMAT2A: - if (SRSLTE_RA_DL_GRANT_NOF_TB(&grant) == 1 && dci_unpacked.pinfo == 0) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else { - mimo_type = SRSLTE_MIMO_TYPE_CDD; - } - break; - - /* Not implemented formats */ - case SRSLTE_DCI_FORMAT0: - case SRSLTE_DCI_FORMAT1B: - case SRSLTE_DCI_FORMAT1D: - case SRSLTE_DCI_FORMAT2B: - default: - ERROR("Transmission mode not supported."); - return SRSLTE_ERROR; - } +// Blind search for C-RNTI +static int find_dl_dci_type_crnti(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + uint16_t rnti, + srslte_dci_msg_t dci_msg[SRSLTE_MAX_DCI_MSG]) +{ + int ret = SRSLTE_SUCCESS; + dci_blind_search_t search_space; + dci_blind_search_t* current_ss = &search_space; - if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx, mimo_type)) { - ERROR("Configuing PDSCH"); - return SRSLTE_ERROR; - } - - /* ===== End of MAC functionality ========== */ + uint32_t sf_idx = sf->tti % 10; + uint32_t cfi = sf->cfi; + srslte_dci_cfg_t* dci_cfg = &cfg->dci_cfg; - q->nof_detected++; - - - if (q->pdsch_cfg.grant.mcs[0].mod > 0 && q->pdsch_cfg.grant.mcs[0].tbs >= 0) { - ret = srslte_pdsch_decode(&q->pdsch, &q->pdsch_cfg, q->softbuffers, - q->sf_symbols_m, q->ce_m, - noise_estimate, - rnti, data, acks); + // Search UE-specific search space + if (q->pregen_rnti == rnti) { + current_ss = &q->current_ss_ue[MI_IDX(sf_idx)][cfi - 1][sf_idx]; + } else { + // If locations are not pre-generated, generate them now + current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, sf, current_ss->loc, MAX_CANDIDATES_UE, rnti); + } - - for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (grant.tb_en[tb]) { - if (!acks[tb]) { - q->pdsch_pkt_errors++; - } - q->pdsch_pkts_total++; - } - } + if (cfg->cfg.tm > SRSLTE_TM8) { + ERROR("Searching DL CRNTI: Invalid TM=%d\n", cfg->cfg.tm + 1); + } - if (ret == SRSLTE_ERROR) { - } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { - fprintf(stderr, "Error calling srslte_pdsch_decode()\n"); - } + for (int f = 0; f < 2; f++) { + srslte_dci_format_t format = ue_dci_formats[cfg->cfg.tm][f]; - /* If we are in TM4 (Closed-Loop MIMO), compute condition number */ + INFO("Searching DL C-RNTI %s in %d ue locations\n", srslte_dci_format_string(format), current_ss->nof_locations); + current_ss->format = format; + if ((ret = dci_blind_search(q, sf, rnti, current_ss, dci_cfg, dci_msg))) { + return ret; } - - /* - printf("Saving signal...\n"); - srslte_vec_save_file("input", input, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); - srslte_ue_dl_save_signal(q, &q->softbuffer, sf_idx, rvidx, rnti, cfi); - //exit(-1); - */ - } - if (found_dci == 1 && ret == SRSLTE_SUCCESS) { - return q->pdsch_cfg.grant.mcs[0].tbs; + // Search Format 1A in the Common SS also + if (q->pregen_rnti == rnti) { + current_ss = &q->current_ss_common[MI_IDX(sf_idx)][cfi - 1]; } else { - return 0; + // If locations are not pre-generated, generate them now + current_ss->nof_locations = srslte_pdcch_common_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_COM, cfi); } + + // Search for RNTI only if there is room for the common search space + if (current_ss->nof_locations > 0) { + current_ss->format = SRSLTE_DCI_FORMAT1A; + INFO("Searching DL C-RNTI in %d ue locations, format 1A\n", current_ss->nof_locations); + return dci_blind_search(q, sf, rnti, current_ss, dci_cfg, dci_msg); + } + return SRSLTE_SUCCESS; } +int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + uint16_t rnti, + srslte_dci_dl_t dci_dl[SRSLTE_MAX_DCI_MSG]) +{ + set_mi_value(q, sf, cfg); -int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, - uint8_t *data, - uint32_t tti) -{ - srslte_ra_dl_grant_t grant; - int ret = SRSLTE_ERROR; - uint32_t cfi; - uint32_t sf_idx = tti%10; - - if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { - return ret; - } - - float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); - // Uncoment next line to do ZF by default in pdsch_ue example - //float noise_estimate = 0; - - grant.sf_type = SRSLTE_SF_MBSFN; - grant.mcs[0].idx = 2; - grant.tb_en[0] = true; - grant.tb_en[1] = false; - grant.nof_prb = q->pmch.cell.nof_prb; - srslte_dl_fill_ra_mcs(&grant.mcs[0], grant.nof_prb); - srslte_softbuffer_rx_reset_tbs(q->softbuffers[0], (uint32_t) grant.mcs[0].tbs); - for(int j = 0; j < 2; j++){ - for(int f = 0; f < grant.nof_prb; f++){ - grant.prb_idx[j][f] = true; - } - } - grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); - - // redundancy version is set to 0 for the PMCH - if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) { - return SRSLTE_ERROR; - } - - if (q->pmch_cfg.grant.mcs[0].mod > 0 && q->pmch_cfg.grant.mcs[0].tbs >= 0) { - ret = srslte_pmch_decode_multi(&q->pmch, &q->pmch_cfg, q->softbuffers[0], - q->sf_symbols_m, q->ce_m, - noise_estimate, - q->current_mbsfn_area_id, data); - - - if (ret == SRSLTE_ERROR) { - q->pmch_pkt_errors++; - } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { - fprintf(stderr, "Error calling srslte_pmch_decode()\n"); - } - } - - q->pmch_pkts_total++; + srslte_dci_msg_t dci_msg[SRSLTE_MAX_DCI_MSG]; - if (ret == SRSLTE_SUCCESS) { - return q->pmch_cfg.grant.mcs[0].tbs; + int nof_msg = 0; + if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || SRSLTE_RNTI_ISRAR(rnti)) { + nof_msg = find_dl_dci_type_siprarnti(q, sf, cfg, rnti, dci_msg); } else { - return ret; + nof_msg = find_dl_dci_type_crnti(q, sf, cfg, rnti, dci_msg); } + + // Unpack DCI messages + for (uint32_t i = 0; i < nof_msg; i++) { + if (srslte_dci_msg_unpack_pdsch(&q->cell, sf, &cfg->dci_cfg, &dci_msg[i], &dci_dl[i])) { + ERROR("Unpacking DL DCI\n"); + return SRSLTE_ERROR; + } + } + return nof_msg; +} + +int srslte_ue_dl_dci_to_pdsch_grant(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + srslte_dci_dl_t* dci, + srslte_pdsch_grant_t* grant) +{ + return srslte_ra_dl_dci_to_grant(&q->cell, sf, cfg->cfg.tm, dci, grant); +} + +int srslte_ue_dl_decode_pdsch(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_cfg_t* pdsch_cfg, + srslte_pdsch_res_t data[SRSLTE_MAX_CODEWORDS]) +{ + return srslte_pdsch_decode(&q->pdsch, sf, pdsch_cfg, &q->chest_res, q->sf_symbols, data); +} + +int srslte_ue_dl_decode_pmch(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pmch_cfg_t* pmch_cfg, + srslte_pdsch_res_t data[SRSLTE_MAX_CODEWORDS]) +{ + return srslte_pmch_decode(&q->pmch, sf, pmch_cfg, &q->chest_res, q->sf_symbols, &data[0]); } +int srslte_ue_dl_decode_phich(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + srslte_phich_grant_t* grant, + srslte_phich_res_t* result) +{ + srslte_phich_resource_t n_phich; + + uint32_t sf_idx = sf->tti % 10; + + set_mi_value(q, sf, cfg); + + srslte_phich_calc(&q->phich, grant, &n_phich); + INFO("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, I_phich=%d, n_group=%d, n_seq=%d, Ngroups=%d, Nsf=%d\n", + sf_idx, + grant->n_prb_lowest, + grant->n_dmrs, + grant->I_phich, + n_phich.ngroup, + n_phich.nseq, + srslte_phich_ngroups(&q->phich), + srslte_phich_nsf(&q->phich)); + + if (!srslte_phich_decode(&q->phich, sf, &q->chest_res, n_phich, q->sf_symbols, result)) { + INFO("Decoded PHICH %d with distance %f\n", result->ack_value, result->distance); + return 0; + } else { + ERROR("Error decoding PHICH\n"); + return -1; + } +} /* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus * Noise Ratio (SINR), valid for TM4 */ -int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, float *current_sinr) { - float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); - float best_sinr = -INFINITY; - uint8_t best_pmi = 0, best_ri = 0; +static int select_pmi(srslte_ue_dl_t* q, uint32_t ri, uint32_t* pmi, float* sinr_db) +{ + uint32_t best_pmi = 0; + float sinr_list[SRSLTE_MAX_CODEBOOKS]; if (q->cell.nof_ports < 2) { /* Do nothing */ return SRSLTE_SUCCESS; } else { - if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, - SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) { + if (srslte_pdsch_select_pmi(&q->pdsch, &q->chest_res, ri + 1, &best_pmi, sinr_list)) { DEBUG("SINR calculation error"); return SRSLTE_ERROR; } + /* Set PMI */ + if (pmi != NULL) { + *pmi = best_pmi; + } + + /* Set PMI */ + if (sinr_db != NULL) { + *sinr_db = 10.0f * log10f(sinr_list[*pmi % SRSLTE_MAX_CODEBOOKS]); + } + } + + return SRSLTE_SUCCESS; +} + +static int select_ri_pmi(srslte_ue_dl_t* q, uint32_t* ri, uint32_t* pmi, float* sinr_db) +{ + float best_sinr_db = -INFINITY; + uint32_t best_pmi = 0, best_ri = 0; + uint32_t max_ri = SRSLTE_MIN(q->nof_rx_antennas, q->cell.nof_ports); + + if (q->cell.nof_ports < 2) { + /* Do nothing */ + return SRSLTE_SUCCESS; + } else { /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ - for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { - float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; + for (uint32_t this_ri = 0; this_ri < max_ri; this_ri++) { + uint32_t this_pmi = 0; + float this_sinr_db = 0.0f; + if (select_pmi(q, this_ri, &this_pmi, &this_sinr_db)) { + DEBUG("SINR calculation error"); + return SRSLTE_ERROR; + } + /* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */ - if (_sinr > best_sinr + 0.1 || _sinr > 1.0e+3) { - best_sinr = _sinr; - best_pmi = (uint8_t) q->pmi[nof_layers - 1]; - best_ri = (uint8_t) (nof_layers - 1); + if (this_sinr_db > best_sinr_db + 0.1 || this_sinr_db > 20.0) { + best_sinr_db = this_sinr_db; + best_pmi = this_pmi; + best_ri = this_ri; } } } - /* Print Trace */ - if (ri != NULL && pmi != NULL && current_sinr != NULL) { - INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, - 10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx); - } - /* Set RI */ - q->ri = best_ri; if (ri != NULL) { *ri = best_ri; } @@ -725,267 +775,570 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo *pmi = best_pmi; } - /* Set current SINR */ - if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (q->pdsch_cfg.nof_layers == 1) { - *current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx]; - } else if (q->pdsch_cfg.nof_layers == 2) { - *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; - } else { - ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers); - return SRSLTE_ERROR; - } + /* Set SINR */ + if (sinr_db != NULL) { + *sinr_db = best_sinr_db; } return SRSLTE_SUCCESS; } - /* Compute the Rank Indicator (RI) by computing the condition number, valid for TM3 */ -int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint8_t *ri, float *cn) { - float _cn; - int ret = srslte_pdsch_cn_compute(&q->pdsch, q->ce_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), &_cn); +int srslte_ue_dl_select_ri(srslte_ue_dl_t* q, uint32_t* ri, float* cn) +{ + float _cn = INFINITY; + int ret = srslte_pdsch_compute_cn(&q->pdsch, &q->chest_res, &_cn); - /* Set Condition number */ - if (cn) { - *cn = _cn; - } + if (ret == SRSLTE_SUCCESS) { + /* Set Condition number */ + if (cn) { + *cn = _cn; + } - q->ri = (uint8_t)((_cn < 17.0f)? 1:0); - /* Set rank indicator */ - if (!ret && ri) { - *ri = (uint8_t) q->ri; + /* Set rank indicator */ + if (ri) { + *ri = (uint8_t)((_cn < 17.0f) ? 1 : 0); + } } return ret; } +void srslte_ue_dl_gen_cqi_periodic( + srslte_ue_dl_t* q, srslte_ue_dl_cfg_t* cfg, uint32_t wideband_value, uint32_t tti, srslte_uci_data_t* uci_data) +{ + if (srslte_cqi_periodic_ri_send(&cfg->cfg.cqi_report, tti, q->cell.frame_type)) { + /* Compute RI, PMI and SINR */ + if (q->nof_rx_antennas > 1) { + if (cfg->cfg.tm == SRSLTE_TM3) { + srslte_ue_dl_select_ri(q, &cfg->last_ri, NULL); + } else if (cfg->cfg.tm == SRSLTE_TM4) { + select_ri_pmi(q, &cfg->last_ri, NULL, NULL); + } + } else { + cfg->last_ri = 0; + } + uci_data->cfg.cqi.ri_len = 1; + uci_data->value.ri = cfg->last_ri; + } else if (srslte_cqi_periodic_send(&cfg->cfg.cqi_report, tti, q->cell.frame_type)) { + + if (cfg->cfg.cqi_report.format_is_subband) { + // TODO: Implement subband periodic reports + uci_data->cfg.cqi.type = SRSLTE_CQI_TYPE_SUBBAND; + uci_data->value.cqi.subband.subband_cqi = wideband_value; + uci_data->value.cqi.subband.subband_label = 0; + } else { + uci_data->cfg.cqi.type = SRSLTE_CQI_TYPE_WIDEBAND; + uci_data->value.cqi.wideband.wideband_cqi = wideband_value; + if (cfg->cfg.tm == SRSLTE_TM4) { + uint32_t pmi = 0; + select_pmi(q, cfg->last_ri, &pmi, NULL); + + uci_data->cfg.cqi.pmi_present = true; + uci_data->cfg.cqi.rank_is_not_one = (cfg->last_ri != 0); + uci_data->value.cqi.wideband.pmi = (uint8_t)pmi; + } + } + uci_data->cfg.cqi.data_enable = true; + uci_data->cfg.cqi.ri_len = 0; + uci_data->value.ri = cfg->last_ri; + } +} + +void srslte_ue_dl_gen_cqi_aperiodic(srslte_ue_dl_t* q, + srslte_ue_dl_cfg_t* cfg, + uint32_t wideband_value, + srslte_uci_data_t* uci_data) +{ + uint32_t pmi = 0; + float sinr_db = 0.0f; + + switch (cfg->cfg.cqi_report.aperiodic_mode) { + case SRSLTE_CQI_MODE_30: + /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 + - A UE shall report a wideband CQI value which is calculated assuming transmission on set S subbands + - The UE shall also report one subband CQI value for each set S subband. The subband CQI + value is calculated assuming transmission only in the subband + - Both the wideband and subband CQI represent channel quality for the first codeword, + even when RI>1 + - For transmission mode 3 the reported CQI values are calculated conditioned on the + reported RI. For other transmission modes they are reported conditioned on rank 1. + */ + + uci_data->cfg.cqi.type = SRSLTE_CQI_TYPE_SUBBAND_HL; + uci_data->value.cqi.subband_hl.wideband_cqi_cw0 = wideband_value; + + // TODO: implement subband CQI properly + uci_data->value.cqi.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands + uci_data->cfg.cqi.N = (q->cell.nof_prb > 7) ? (uint32_t)srslte_cqi_hl_get_no_subbands(q->cell.nof_prb) : 0; + uci_data->cfg.cqi.data_enable = true; + + /* Set RI = 1 */ + if (cfg->cfg.tm == SRSLTE_TM3 || cfg->cfg.tm == SRSLTE_TM4) { + if (q->nof_rx_antennas > 1) { + srslte_ue_dl_select_ri(q, &cfg->last_ri, NULL); + uci_data->value.ri = (uint8_t)cfg->last_ri; + uci_data->cfg.cqi.ri_len = 1; + } else { + uci_data->value.ri = 0; + } + } else { + uci_data->cfg.cqi.ri_len = 0; + } + + break; + case SRSLTE_CQI_MODE_31: + /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 + - A single precoding matrix is selected from the codebook subset assuming transmission on set S subbands + - A UE shall report one subband CQI value per codeword for each set S subband which are calculated assuming + the use of the single precoding matrix in all subbands and assuming transmission in the corresponding + subband. + - A UE shall report a wideband CQI value per codeword which is calculated assuming the use of the single + precoding matrix in all subbands and transmission on set S subbands + - The UE shall report the single selected precoding matrix indicator. + - For transmission mode 4 the reported PMI and CQI values are calculated conditioned on the reported RI. For + other transmission modes they are reported conditioned on rank 1. + */ + /* Loads the latest SINR according to the calculated RI and PMI */ + pmi = 0; + sinr_db = 0.0f; + select_ri_pmi(q, &cfg->last_ri, &pmi, &sinr_db); + + /* Fill CQI Report */ + uci_data->cfg.cqi.type = SRSLTE_CQI_TYPE_SUBBAND_HL; + + uci_data->value.cqi.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db + cfg->snr_to_cqi_offset); + uci_data->value.cqi.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands + + if (cfg->last_ri > 0) { + uci_data->cfg.cqi.rank_is_not_one = true; + uci_data->value.cqi.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db + cfg->snr_to_cqi_offset); + uci_data->value.cqi.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands + } + + uci_data->value.cqi.subband_hl.pmi = pmi; + uci_data->cfg.cqi.pmi_present = true; + uci_data->cfg.cqi.four_antenna_ports = (q->cell.nof_ports == 4); + uci_data->cfg.cqi.N = (uint32_t)((q->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(q->cell.nof_prb) : 0); -uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) { - return q->last_location.ncce; + uci_data->cfg.cqi.data_enable = true; + uci_data->cfg.cqi.ri_len = 1; + uci_data->value.ri = cfg->last_ri; + + break; + default: + ERROR("CQI mode %d not supported\n", cfg->cfg.cqi_report.aperiodic_mode); + break; + } } -static int dci_blind_search(srslte_ue_dl_t *q, dci_blind_search_t *search_space, uint16_t rnti, uint32_t cfi, srslte_dci_msg_t *dci_msg) +// Table 7.3-1 +static const uint32_t multiple_acknack[10][2] = { + {0, 0}, {1, 1}, {1, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 1}}; + +/* UE downlink procedure for reporting ACK/NACK, Section 7.3 36.213 + */ +void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_pdsch_ack_t* ack_info, + srslte_uci_data_t* uci_data) { - int ret = SRSLTE_ERROR; - uint16_t crc_rem = 0; - if (rnti) { - ret = 0; - int i=0; - while (!ret && i < search_space->nof_locations) { - DEBUG("Searching format %s in %d,%d (%d/%d)\n", - srslte_dci_format_string(search_space->format), search_space->loc[i].ncce, search_space->loc[i].L, - i, search_space->nof_locations); - - if (srslte_pdcch_decode_msg(&q->pdcch, dci_msg, &search_space->loc[i], search_space->format, cfi, &crc_rem)) { - fprintf(stderr, "Error decoding DCI msg\n"); - return SRSLTE_ERROR; + uint32_t V_dai_dl = 0; + + bool is_tdd_mode16 = sf->tdd_config.sf_config >= 1 && sf->tdd_config.sf_config <= 6; + + uint32_t nof_tb = 1; + if (ack_info->transmission_mode > SRSLTE_TM2) { + nof_tb = SRSLTE_MAX_CODEWORDS; + } + + // Implementation 3GPP 36.213 V10.13.0. Section 7.3. 2nd Clause. + if (q->cell.frame_type == SRSLTE_FDD) { + if (ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS && + uci_data->value.scheduling_request && !ack_info->is_pusch_available) { + for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) { + uint32_t dtx_count = 0; + bool bundle_spatial = true; + + for (uint32_t tb = 0; tb < nof_tb; tb++) { + if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) { + if (ack_info->cc[cc_idx].m[0].value[tb] != 1) { + bundle_spatial = false; + } + if (cc_idx != 0) { + uci_data->cfg.ack.has_scell_ack = true; + } + } else { + dtx_count++; + } + } + uci_data->value.ack.ack_value[cc_idx] = (uint8_t)((bundle_spatial && dtx_count != nof_tb) ? 1 : 0); } - if (crc_rem == rnti) { - // If searching for Format1A but found Format0 save it for later - if (dci_msg->format == SRSLTE_DCI_FORMAT0 && search_space->format == SRSLTE_DCI_FORMAT1A) - { - if (!q->pending_ul_dci_rnti) { - q->pending_ul_dci_rnti = crc_rem; - memcpy(&q->pending_ul_dci_msg, dci_msg, sizeof(srslte_dci_msg_t)); - memcpy(&q->last_location_ul, &search_space->loc[i], sizeof(srslte_dci_location_t)); + + uci_data->cfg.ack.nof_acks = ack_info->nof_cc; + uci_data->cfg.ack.tdd_ack_M = 1; + return; + + } else if ((ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS && + ack_info->is_pusch_available) || + ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3) { + uint32_t tb_count = 0; + uint32_t n = 0; + for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) { + for (uint32_t tb = 0; tb < nof_tb; tb++, n++) { + uci_data->value.ack.ack_value[n] = ack_info->cc[cc_idx].m[0].value[tb]; + if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) { + tb_count++; } - // Else if we found it, save location and leave - } else if (dci_msg->format == search_space->format) { - ret = 1; - if (dci_msg->format == SRSLTE_DCI_FORMAT0) { - memcpy(&q->last_location_ul, &search_space->loc[i], sizeof(srslte_dci_location_t)); + } + } + uci_data->cfg.ack.nof_acks = (tb_count != 0) ? n : 0; + return; + } + } + + // Calculate U_dai and count number of ACK for this subframe by spatial bundling across codewords + uint32_t nof_pos_acks = 0; + uint32_t nof_total_acks = 0; + uint32_t U_dai = 0; + for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) { + for (uint32_t i = 0; i < ack_info->cc[cc_idx].M; i++) { + bool bundle_spatial = false; + bool first_bundle = true; + for (uint32_t j = 0; j < nof_tb; j++) { + if (ack_info->cc[cc_idx].m[i].present) { + if (first_bundle) { + bundle_spatial = ack_info->cc[cc_idx].m[i].value[j] == 1; + U_dai++; + first_bundle = false; } else { - memcpy(&q->last_location, &search_space->loc[i], sizeof(srslte_dci_location_t)); + bundle_spatial &= ack_info->cc[cc_idx].m[i].value[j] == 1; + } + if (bundle_spatial) { + nof_pos_acks++; } - } + if (ack_info->cc[cc_idx].m[i].value[j] != 2) { + nof_total_acks++; + } + } } - i++; - } - } else { - fprintf(stderr, "RNTI not specified\n"); + } } - return ret; -} -int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) -{ - if (rnti && cfi > 0 && cfi < 4) { - /* Do not search if an UL DCI is already pending */ - if (q->pending_ul_dci_rnti == rnti) { - q->pending_ul_dci_rnti = 0; - memcpy(dci_msg, &q->pending_ul_dci_msg, sizeof(srslte_dci_msg_t)); - return 1; - } - - // Configure and run DCI blind search - dci_blind_search_t search_space; - search_space.nof_locations = 0; - dci_blind_search_t *current_ss = &search_space; - if (q->current_rnti == rnti) { - current_ss = &q->current_ss_ue[cfi-1][sf_idx]; + for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) { + + // Arrange bits for FDD or TDD Bundling or Multiplexing + srslte_pdsch_ack_cc_t* ack_value = &ack_info->cc[cc_idx]; + + uint32_t min_k = 10; + + if (ack_info->cc[cc_idx].M > 0) { + + uci_data->cfg.ack.tdd_ack_M = ack_value->M; + + // ACK/NACK bundling or multiplexing and M=1 + if (ack_info->tdd_ack_bundle || ack_value->M == 1) { + for (uint32_t tb = 0; tb < nof_tb; tb++) { + bool first_in_bundle = true; + for (uint32_t k = 0; k < ack_value->M; k++) { + if (ack_value->m[k].present && ack_value->m[k].value[tb] != 2) { + uci_data->cfg.ack.has_scell_ack |= (cc_idx != 0); // If a grant is detected in an scell + + // Bundle on time domain + if (first_in_bundle) { + uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] = ack_value->m[k].value[tb]; + first_in_bundle = false; + } else { + uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] = (uint8_t)( + ((uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] == 1) & (ack_value->m[k].value[tb])) ? 1 : 0); + } + // V_dai_dl is for the one with lowest k value + if (ack_value->m[k].k < min_k || q->cell.frame_type == SRSLTE_FDD) { + min_k = ack_value->m[k].k; + V_dai_dl = ack_value->m[k].resource.v_dai_dl + 1; // Table 7.3-X + if (cc_idx == 0) { + uci_data->cfg.ack.ncce[0] = ack_info->cc[cc_idx].m[k].resource.n_cce; + uci_data->cfg.ack.tdd_ack_m = k; + } + } + } + } + } + // ACK/NACK multiplexing and M > 1 + } else { + for (uint32_t k = 0; k < ack_value->M; k++) { + // Bundle spatial domain + bool spatial_ack = true; + for (uint32_t i = 0; i < nof_tb; i++) { + if (ack_value->m[k].value[i] != 2) { + spatial_ack &= (ack_value->m[k].value[i] == 1); + } + } + // In multiplexing for pusch, sort them accordingly + if (ack_value->m[k].present) { + uint32_t p = k; + if (q->cell.frame_type == SRSLTE_TDD && ack_info->is_pusch_available && ack_info->is_grant_available) { + p = ack_value->m[k].resource.v_dai_dl; + } + uci_data->value.ack.ack_value[ack_value->M * cc_idx + p] = (uint8_t)(spatial_ack ? 1 : 0); + uci_data->cfg.ack.ncce[ack_value->M * cc_idx + p] = ack_info->cc[cc_idx].m[k].resource.n_cce; + } + } + } + } + } + + bool missing_ack = false; + + // For TDD PUSCH + if (q->cell.frame_type == SRSLTE_TDD && is_tdd_mode16) { + + ack_info->V_dai_ul++; // Table 7.3-x + + uci_data->cfg.ack.tdd_is_bundling = ack_info->tdd_ack_bundle; + + // Bundling or multiplexing and M=1 + if (ack_info->tdd_ack_bundle || ack_info->cc[0].M == 1) { + // 1 or 2 ACK/NACK bits + uci_data->cfg.ack.nof_acks = nof_tb; + + // Determine if there is any missing ACK/NACK in the set and N_bundle value + + // Case not transmitting on PUSCH + if (!ack_info->is_pusch_available) { + if ((V_dai_dl != (U_dai - 1) % 4 + 1 && U_dai > 0) || U_dai == 0) { + // In ul procedure 10.2, skip ACK/NACK in bundling PUCCH + uci_data->cfg.ack.nof_acks = 0; + if (U_dai > 0) { + missing_ack = true; + } + } + // Transmitting on PUSCH and based on detected PDCCH + } else if (ack_info->is_grant_available) { + if (ack_info->V_dai_ul != (U_dai - 1) % 4 + 1) { + bzero(uci_data->value.ack.ack_value, nof_tb); + uci_data->cfg.ack.N_bundle = ack_info->V_dai_ul + 2; + } else { + uci_data->cfg.ack.N_bundle = ack_info->V_dai_ul; + } + // do not transmit case + if (ack_info->V_dai_ul == 4 && U_dai == 0) { + uci_data->cfg.ack.nof_acks = 0; + } + // Transmitting on PUSCH not based on grant + } else { + if (V_dai_dl != (U_dai - 1) % 4 + 1 && U_dai > 0) { + bzero(uci_data->value.ack.ack_value, nof_tb); + } + uci_data->cfg.ack.N_bundle = U_dai; + // do not transmit case + if (U_dai == 0) { + uci_data->cfg.ack.nof_acks = 0; + } + } + + // In PUSCH and MIMO, nack 2nd codeword if not received, in PUCCH do not transmit + if (nof_tb == 2 && uci_data->value.ack.ack_value[1] == 2 && uci_data->cfg.ack.nof_acks == 2) { + if (!ack_info->is_pusch_available) { + uci_data->cfg.ack.nof_acks = 1; + } else { + uci_data->value.ack.ack_value[1] = 0; + } + } + + // Multiplexing and M>1 } else { - // If locations are not pre-generated, generate them now - current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_UE, sf_idx, cfi, rnti); + if (ack_info->is_pusch_available) { + if (ack_info->is_grant_available) { + // Do not transmit if... + if (!(ack_info->V_dai_ul == 4 && U_dai == 0)) { + uci_data->cfg.ack.nof_acks = ack_info->V_dai_ul; + } + } else { + uci_data->cfg.ack.nof_acks = ack_info->cc[0].M; + } + + // Set DTX bits to NACKs + uint32_t count_acks = 0; + for (uint32_t i = 0; i < uci_data->cfg.ack.nof_acks; i++) { + if (uci_data->value.ack.ack_value[i] == 2) { + uci_data->value.ack.ack_value[i] = 0; + } else { + count_acks++; + } + } + if (!count_acks) { + uci_data->cfg.ack.nof_acks = 0; + } + } else { + uci_data->cfg.ack.nof_acks = ack_info->cc[0].M; + } } - - current_ss->format = SRSLTE_DCI_FORMAT0; - INFO("Searching UL C-RNTI in %d ue locations\n", search_space.nof_locations); - return dci_blind_search(q, current_ss, rnti, cfi, dci_msg); } else { - return 0; + if (q->cell.frame_type == SRSLTE_TDD) { // And subframe config 0 + uci_data->cfg.ack.N_bundle = 1; + } + uci_data->cfg.ack.nof_acks = nof_total_acks; } -} -int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) -{ - srslte_rnti_type_t rnti_type; - if (rnti == SRSLTE_SIRNTI) { - rnti_type = SRSLTE_RNTI_SI; - } else if (rnti == SRSLTE_PRNTI) { - rnti_type = SRSLTE_RNTI_PCH; - } else if (rnti <= SRSLTE_RARNTI_END) { - rnti_type = SRSLTE_RNTI_RAR; - } else { - rnti_type = SRSLTE_RNTI_USER; + // If no pending ACK/NACK + if (uci_data->cfg.ack.nof_acks == 0) { + return; } - return srslte_ue_dl_find_dl_dci_type(q, tm, cfi, sf_idx, rnti, rnti_type, dci_msg); -} -// Blind search for SI/P/RA-RNTI -static int find_dl_dci_type_siprarnti(srslte_ue_dl_t *q, uint32_t cfi, uint16_t rnti, srslte_dci_msg_t *dci_msg) -{ - int ret = 0; - // Configure and run DCI blind search - dci_blind_search_t search_space; - search_space.nof_locations = srslte_pdcch_common_locations(&q->pdcch, search_space.loc, MAX_CANDIDATES_COM, cfi); - INFO("Searching SI/P/RA-RNTI in %d common locations, %d formats\n", search_space.nof_locations, nof_common_formats); - // Search for RNTI only if there is room for the common search space - if (search_space.nof_locations > 0) { - for (int f=0;fcell.frame_type == SRSLTE_TDD && uci_data->cfg.ack.nof_acks && !ack_info->is_pusch_available && + (uci_data->value.scheduling_request || + ((uci_data->cfg.cqi.data_enable || uci_data->cfg.cqi.ri_len) && ack_info->simul_cqi_ack))) { + if (missing_ack) { + uci_data->value.ack.ack_value[0] = 0; + uci_data->value.ack.ack_value[1] = 0; + } else { + nof_pos_acks = SRSLTE_MIN(9, nof_pos_acks); + uci_data->value.ack.ack_value[0] = multiple_acknack[nof_pos_acks][0]; + uci_data->value.ack.ack_value[1] = multiple_acknack[nof_pos_acks][1]; } + uci_data->cfg.ack.nof_acks = 2; } - return SRSLTE_SUCCESS; } -// Blind search for C-RNTI -static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, - uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) { - int ret = SRSLTE_SUCCESS; - dci_blind_search_t search_space; - dci_blind_search_t *current_ss = &search_space; +int srslte_ue_dl_find_and_decode(srslte_ue_dl_t* q, + srslte_dl_sf_cfg_t* sf, + srslte_ue_dl_cfg_t* cfg, + srslte_pdsch_cfg_t* pdsch_cfg, + uint8_t* data[SRSLTE_MAX_CODEWORDS], + bool acks[SRSLTE_MAX_CODEWORDS]) +{ + int ret = SRSLTE_ERROR; - if (cfi < 1 || cfi > 3) { - ERROR("CFI must be 1 ≤ cfi ≤ 3 (cfi=%d)", cfi); - return SRSLTE_ERROR; - } + srslte_dci_dl_t dci_dl; + srslte_pmch_cfg_t pmch_cfg; + srslte_pdsch_res_t pdsch_res[SRSLTE_MAX_CODEWORDS]; + + // Use default values for PDSCH decoder + ZERO_OBJECT(pmch_cfg); - // Search UE-specific search space - if (q->current_rnti == rnti) { - current_ss = &q->current_ss_ue[cfi-1][sf_idx]; + uint32_t mi_set_len; + if (q->cell.frame_type == SRSLTE_TDD && !sf->tdd_config.configured) { + mi_set_len = 3; } else { - // If locations are not pre-generated, generate them now - current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_UE, sf_idx, cfi, rnti); + mi_set_len = 1; } - for (int f = 0; f < 2; f++) { - srslte_dci_format_t format = ue_dci_formats[tm][f]; + // Blind search PHICH mi value + ZERO_OBJECT(dci_dl); + ret = 0; + for (uint32_t i = 0; i < mi_set_len && !ret; i++) { - INFO("Searching DL C-RNTI %s in %d ue locations\n", srslte_dci_format_string(format), - current_ss->nof_locations); + if (mi_set_len == 1) { + srslte_ue_dl_set_mi_auto(q); + } else { + srslte_ue_dl_set_mi_manual(q, i); + } - current_ss->format = format; - if ((ret = dci_blind_search(q, current_ss, rnti, cfi, dci_msg))) { + if ((ret = srslte_ue_dl_decode_fft_estimate(q, sf, cfg)) < 0) { return ret; } - } - // Search Format 1A in the Common SS also - if (q->current_rnti == rnti) { - current_ss = &q->current_ss_common[cfi-1]; - } else { - // If locations are not pre-generated, generate them now - current_ss->nof_locations = srslte_pdcch_common_locations(&q->pdcch, current_ss->loc, MAX_CANDIDATES_COM, cfi); + ret = srslte_ue_dl_find_dl_dci(q, sf, cfg, pdsch_cfg->rnti, &dci_dl); } - - // Search for RNTI only if there is room for the common search space - if (current_ss->nof_locations > 0) { - current_ss->format = SRSLTE_DCI_FORMAT1A; - INFO("Searching DL C-RNTI in %d ue locations, format 1A\n", current_ss->nof_locations); - return dci_blind_search(q, current_ss, rnti, cfi, dci_msg); - } - return SRSLTE_SUCCESS; -} -int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx, - uint16_t rnti, srslte_rnti_type_t rnti_type, srslte_dci_msg_t *dci_msg) -{ - if (rnti_type == SRSLTE_RNTI_SI || rnti_type == SRSLTE_RNTI_PCH || rnti_type == SRSLTE_RNTI_RAR) { - return find_dl_dci_type_siprarnti(q, cfi, rnti, dci_msg); - } else { - return find_dl_dci_type_crnti(q, tm, cfi, sf_idx, rnti, dci_msg); + if (ret == 1) { + // Logging + char str[512]; + srslte_dci_dl_info(&dci_dl, str, 512); + INFO("PDCCH: %s, snr=%.1f dB\n", str, q->chest_res.snr_db); + + // Force known MBSFN grant + if (sf->sf_type == SRSLTE_SF_MBSFN) { + dci_dl.rnti = SRSLTE_MRNTI; + dci_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci_dl.type0_alloc.rbg_bitmask = 0xffffffff; + dci_dl.tb[0].rv = 0; + dci_dl.tb[0].mcs_idx = 2; + dci_dl.format = SRSLTE_DCI_FORMAT1; + } + + // Convert DCI message to DL grant + if (srslte_ue_dl_dci_to_pdsch_grant(q, sf, cfg, &dci_dl, &pdsch_cfg->grant)) { + ERROR("Error unpacking DCI\n"); + return SRSLTE_ERROR; + } + + // Calculate RV if not provided in the grant and reset softbuffer + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (pdsch_cfg->grant.tb[i].enabled) { + if (pdsch_cfg->grant.tb[i].rv < 0) { + uint32_t sfn = sf->tti / 10; + uint32_t k = (sfn / 2) % 4; + pdsch_cfg->grant.tb[i].rv = ((uint32_t)ceilf((float)1.5 * k)) % 4; + } + srslte_softbuffer_rx_reset_tbs(pdsch_cfg->softbuffers.rx[i], (uint32_t)pdsch_cfg->grant.tb[i].tbs); + } + } + + bool decode_enable = false; + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (pdsch_cfg->grant.tb[tb].enabled) { + decode_enable = true; + pdsch_res[tb].payload = data[tb]; + pdsch_res[tb].crc = false; + } + } + + if (decode_enable) { + if (sf->sf_type == SRSLTE_SF_NORM) { + if (srslte_ue_dl_decode_pdsch(q, sf, pdsch_cfg, pdsch_res)) { + ERROR("ERROR: Decoding PDSCH\n"); + ret = -1; + } + } else { + pmch_cfg.pdsch_cfg = *pdsch_cfg; + if (srslte_ue_dl_decode_pmch(q, sf, &pmch_cfg, pdsch_res)) { + ERROR("Decoding PMCH\n"); + ret = -1; + } + } + } + + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (pdsch_cfg->grant.tb[tb].enabled) { + acks[tb] = pdsch_res[tb].crc; + } + } } + return ret; } -bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_prb_lowest, uint32_t n_dmrs) +void srslte_ue_dl_save_signal(srslte_ue_dl_t* q, srslte_dl_sf_cfg_t* sf, srslte_pdsch_cfg_t* pdsch_cfg) { - uint8_t ack_bit; - float distance; - uint32_t ngroup, nseq; - srslte_phich_calc(&q->phich, n_prb_lowest, n_dmrs, &ngroup, &nseq); - INFO("Decoding PHICH sf_idx=%d, n_prb_lowest=%d, n_dmrs=%d, n_group=%d, n_seq=%d, Ngroups=%d, Nsf=%d\n", - sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq, - srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); - - if (!srslte_phich_decode(&q->phich, q->sf_symbols_m, q->ce_m, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { - q->last_phich_corr = distance; - INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); - } else { - fprintf(stderr, "Error decoding PHICH\n"); - return false; - } - if (ack_bit) { - return true; - } else { - return false; - } -} + uint32_t cfi = sf->cfi; + uint32_t tti = sf->tti % 10; -void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) { - srslte_vec_save_file("sf_symbols", q->sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - printf("%d samples\n", SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - srslte_vec_save_file("ce0", q->ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + srslte_vec_save_file("sf_symbols", q->sf_symbols, SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); + printf("%d samples\n", SRSLTE_NOF_RE(q->cell)); + srslte_vec_save_file("ce0", q->chest_res.ce[0], SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); if (q->cell.nof_ports > 1) { - srslte_vec_save_file("ce1", q->ce[1], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - } - srslte_vec_save_file("pcfich_ce0", q->pcfich.ce[0], q->pcfich.nof_symbols*sizeof(cf_t)); - srslte_vec_save_file("pcfich_ce1", q->pcfich.ce[1], q->pcfich.nof_symbols*sizeof(cf_t)); - srslte_vec_save_file("pcfich_symbols", q->pcfich.symbols[0], q->pcfich.nof_symbols*sizeof(cf_t)); - srslte_vec_save_file("pcfich_eq_symbols", q->pcfich.d, q->pcfich.nof_symbols*sizeof(cf_t)); - srslte_vec_save_file("pcfich_llr", q->pcfich.data_f, PCFICH_CFI_LEN*sizeof(float)); - - srslte_vec_save_file("pdcch_ce0", q->pdcch.ce[0], q->pdcch.nof_cce[cfi-1]*36*sizeof(cf_t)); - srslte_vec_save_file("pdcch_ce1", q->pdcch.ce[1], q->pdcch.nof_cce[cfi-1]*36*sizeof(cf_t)); - srslte_vec_save_file("pdcch_symbols", q->pdcch.symbols[0], q->pdcch.nof_cce[cfi-1]*36*sizeof(cf_t)); - srslte_vec_save_file("pdcch_eq_symbols", q->pdcch.d, q->pdcch.nof_cce[cfi-1]*36*sizeof(cf_t)); - srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce[cfi-1]*72*sizeof(float)); - - - srslte_vec_save_file("pdsch_symbols", q->pdsch.d[0], q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); - srslte_vec_save_file("llr", q->pdsch.e[0], q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); - int cb_len = q->pdsch_cfg.cb_segm[0].K1; - for (int i=0;ipdsch_cfg.cb_segm[0].C;i++) { - char tmpstr[64]; - snprintf(tmpstr,64,"rmout_%d.dat",i); - srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); - } - printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, - q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti); + srslte_vec_save_file("ce1", q->chest_res.ce[1], SRSLTE_NOF_RE(q->cell) * sizeof(cf_t)); + } + srslte_vec_save_file("pcfich_ce0", q->pcfich.ce[0], q->pcfich.nof_symbols * sizeof(cf_t)); + srslte_vec_save_file("pcfich_ce1", q->pcfich.ce[1], q->pcfich.nof_symbols * sizeof(cf_t)); + srslte_vec_save_file("pcfich_symbols", q->pcfich.symbols[0], q->pcfich.nof_symbols * sizeof(cf_t)); + srslte_vec_save_file("pcfich_eq_symbols", q->pcfich.d, q->pcfich.nof_symbols * sizeof(cf_t)); + srslte_vec_save_file("pcfich_llr", q->pcfich.data_f, PCFICH_CFI_LEN * sizeof(float)); + + srslte_vec_save_file("pdcch_ce0", q->pdcch.ce[0], q->pdcch.nof_cce[cfi - 1] * 36 * sizeof(cf_t)); + srslte_vec_save_file("pdcch_ce1", q->pdcch.ce[1], q->pdcch.nof_cce[cfi - 1] * 36 * sizeof(cf_t)); + srslte_vec_save_file("pdcch_symbols", q->pdcch.symbols[0], q->pdcch.nof_cce[cfi - 1] * 36 * sizeof(cf_t)); + srslte_vec_save_file("pdcch_eq_symbols", q->pdcch.d, q->pdcch.nof_cce[cfi - 1] * 36 * sizeof(cf_t)); + srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce[cfi - 1] * 72 * sizeof(float)); + + srslte_vec_save_file("pdsch_symbols", q->pdsch.d[0], pdsch_cfg->grant.nof_re * sizeof(cf_t)); + srslte_vec_save_file("llr", q->pdsch.e[0], pdsch_cfg->grant.tb[0].nof_bits * sizeof(cf_t)); + printf("Saved files for tti=%d, sf=%d, cfi=%d, tbs=%d, rv=%d\n", + tti, + tti % 10, + cfi, + pdsch_cfg->grant.tb[0].tbs, + pdsch_cfg->grant.tb[0].rv); } - - - diff --git a/lib/src/phy/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c index c003a2ba3..743c8ea4c 100644 --- a/lib/src/phy/ue/ue_mib.c +++ b/lib/src/phy/ue/ue_mib.c @@ -24,10 +24,11 @@ * */ +#include "srslte/srslte.h" +#include #include #include #include -#include #include #include "srslte/phy/ue/ue_mib.h" @@ -48,34 +49,30 @@ int srslte_ue_mib_init(srslte_ue_mib_t * q, bzero(q, sizeof(srslte_ue_mib_t)); if (srslte_pbch_init(&q->pbch)) { - fprintf(stderr, "Error initiating PBCH\n"); + ERROR("Error initiating PBCH\n"); goto clean_exit; } - q->sf_symbols = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->sf_symbols) { + q->sf_symbols[0] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); + if (!q->sf_symbols[0]) { perror("malloc"); goto clean_exit; } - - for (int i=0;ice[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(max_prb, SRSLTE_CP_NORM) * sizeof(cf_t)); - if (!q->ce[i]) { - perror("malloc"); - goto clean_exit; - } - } - if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer[0], q->sf_symbols, max_prb)) { - fprintf(stderr, "Error initializing FFT\n"); + if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer[0], q->sf_symbols[0], max_prb)) { + ERROR("Error initializing FFT\n"); goto clean_exit; } - if (srslte_chest_dl_init(&q->chest, max_prb)) { - fprintf(stderr, "Error initializing reference signal\n"); + if (srslte_chest_dl_init(&q->chest, max_prb, 1)) { + ERROR("Error initializing reference signal\n"); + goto clean_exit; + } + if (srslte_chest_dl_res_init(&q->chest_res, max_prb)) { + ERROR("Error initializing reference signal\n"); goto clean_exit; } srslte_ue_mib_reset(q); - + ret = SRSLTE_SUCCESS; } @@ -88,15 +85,11 @@ clean_exit: void srslte_ue_mib_free(srslte_ue_mib_t * q) { - if (q->sf_symbols) { - free(q->sf_symbols); - } - for (int i=0;ice[i]) { - free(q->ce[i]); - } + if (q->sf_symbols[0]) { + free(q->sf_symbols[0]); } srslte_sync_free(&q->sfind); + srslte_chest_dl_res_free(&q->chest_res); srslte_chest_dl_free(&q->chest); srslte_pbch_free(&q->pbch); srslte_ofdm_rx_free(&q->fft); @@ -114,11 +107,11 @@ int srslte_ue_mib_set_cell(srslte_ue_mib_t * q, cell.nof_ports <= SRSLTE_MAX_PORTS) { if (srslte_pbch_set_cell(&q->pbch, cell)) { - fprintf(stderr, "Error initiating PBCH\n"); + ERROR("Error initiating PBCH\n"); return SRSLTE_ERROR; } if (srslte_ofdm_rx_set_prb(&q->fft, cell.cp, cell.nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); + ERROR("Error initializing FFT\n"); return SRSLTE_ERROR; } @@ -127,7 +120,7 @@ int srslte_ue_mib_set_cell(srslte_ue_mib_t * q, } if (srslte_chest_dl_set_cell(&q->chest, cell)) { - fprintf(stderr, "Error initializing reference signal\n"); + ERROR("Error initializing reference signal\n"); return SRSLTE_ERROR; } srslte_ue_mib_reset(q); @@ -148,13 +141,16 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, int *sfn_offset) { int ret = SRSLTE_SUCCESS; - cf_t *ce_slot1[SRSLTE_MAX_PORTS]; /* Run FFT for the slot symbols */ srslte_ofdm_rx_sf(&q->fft); - + + // sf_idx is always 0 in MIB + srslte_dl_sf_cfg_t sf_cfg; + ZERO_OBJECT(sf_cfg); + /* Get channel estimates of sf idx #0 for each port */ - ret = srslte_chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0); + ret = srslte_chest_dl_estimate(&q->chest, &sf_cfg, q->sf_symbols, &q->chest_res); if (ret < 0) { return SRSLTE_ERROR; } @@ -163,19 +159,11 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, INFO("Resetting PBCH decoder after %d frames\n", q->frame_cnt); srslte_ue_mib_reset(q); } - - for (int i=0;ice[i][SRSLTE_SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)]; - } /* Decode PBCH */ - ret = srslte_pbch_decode(&q->pbch, &q->sf_symbols[SRSLTE_SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)], - ce_slot1, 0, - bch_payload, nof_tx_ports, sfn_offset); - - + ret = srslte_pbch_decode(&q->pbch, &q->chest_res, q->sf_symbols, bch_payload, nof_tx_ports, sfn_offset); if (ret < 0) { - fprintf(stderr, "Error decoding PBCH (%d)\n", ret); + ERROR("Error decoding PBCH (%d)\n", ret); } else if (ret == 1) { INFO("MIB decoded: %u\n", q->frame_cnt); srslte_ue_mib_reset(q); @@ -189,18 +177,18 @@ int srslte_ue_mib_decode(srslte_ue_mib_t * q, return ret; } -int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), +int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t* q, + int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), uint32_t nof_rx_antennas, - void *stream_handler) + void* stream_handler) { - for (int i=0;isf_buffer[i] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(SRSLTE_UE_MIB_NOF_PRB)); + for (int i = 0; i < nof_rx_antennas; i++) { + q->sf_buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(SRSLTE_UE_MIB_NOF_PRB)); } q->nof_rx_antennas = nof_rx_antennas; - + if (srslte_ue_mib_init(&q->ue_mib, q->sf_buffer, SRSLTE_UE_MIB_NOF_PRB)) { - fprintf(stderr, "Error initiating ue_mib\n"); + ERROR("Error initiating ue_mib\n"); return SRSLTE_ERROR; } if (srslte_ue_sync_init_multi(&q->ue_sync, SRSLTE_UE_MIB_NOF_PRB, false, recv_callback, nof_rx_antennas, stream_handler)) { @@ -208,27 +196,23 @@ int srslte_ue_mib_sync_init_multi(srslte_ue_mib_sync_t *q, srslte_ue_mib_free(&q->ue_mib); return SRSLTE_ERROR; } - srslte_ue_sync_decode_sss_on_track(&q->ue_sync, true); return SRSLTE_SUCCESS; } -int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t *q, - uint32_t cell_id, - srslte_cp_t cp) +int srslte_ue_mib_sync_set_cell(srslte_ue_mib_sync_t* q, srslte_cell_t cell) { - srslte_cell_t cell; // If the ports are set to 0, ue_mib goes through 1, 2 and 4 ports to blindly detect nof_ports cell.nof_ports = 0; - cell.id = cell_id; - cell.cp = cp; + + // MIB search is done at 6 PRB cell.nof_prb = SRSLTE_UE_MIB_NOF_PRB; if (srslte_ue_mib_set_cell(&q->ue_mib, cell)) { - fprintf(stderr, "Error initiating ue_mib\n"); + ERROR("Error initiating ue_mib\n"); return SRSLTE_ERROR; } if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); + ERROR("Error initiating ue_sync\n"); srslte_ue_mib_free(&q->ue_mib); return SRSLTE_ERROR; } @@ -268,10 +252,10 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, ret = SRSLTE_SUCCESS; do { - mib_ret = SRSLTE_UE_MIB_NOTFOUND; - ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); + mib_ret = SRSLTE_UE_MIB_NOTFOUND; + ret = srslte_ue_sync_zerocopy(&q->ue_sync, q->sf_buffer); if (ret < 0) { - fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); + ERROR("Error calling srslte_ue_sync_work()\n"); return -1; } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { if (ret == 1) { diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 2b146aed9..180e170c4 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -38,19 +38,20 @@ #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" - #define MAX_TIME_OFFSET 128 -#define TRACK_MAX_LOST 10 -#define TRACK_FRAME_SIZE 32 +#define TRACK_MAX_LOST 20 +#define TRACK_FRAME_SIZE 32 #define FIND_NOF_AVG_FRAMES 4 +#define PSS_OFFSET \ + (q->sf_len / 2 + ((q->cell.frame_type == SRSLTE_FDD) \ + ? 0 \ + : ((SRSLTE_CP_NSYMB(q->cell.cp) - 3) * SRSLTE_SYMBOL_SZ(q->fft_size, q->cell.cp)))) -cf_t dummy_buffer0[15*2048/2]; -cf_t dummy_buffer1[15*2048/2]; - -// FIXME: this will break for 4 antennas!! -cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1}; +static cf_t dummy_buffer0[15 * 2048 / 2]; +static cf_t dummy_buffer1[15 * 2048 / 2]; +static cf_t* dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1, dummy_buffer1, dummy_buffer1}; int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) { return srslte_ue_sync_init_file_multi(q, nof_prb, file_name, offset_time, offset_freq, 1); @@ -80,13 +81,13 @@ int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char * q->cfo_correct_enable_find = false; q->cfo_correct_enable_track = true; - if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) { - fprintf(stderr, "Error initiating CFO\n"); + if (srslte_cfo_init(&q->file_cfo_correct, 2 * q->sf_len)) { + ERROR("Error initiating CFO\n"); goto clean_exit; } - + if (srslte_filesource_init(&q->file_source, file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - fprintf(stderr, "Error opening file %s\n", file_name); + ERROR("Error opening file %s\n", file_name); goto clean_exit; } @@ -173,16 +174,16 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, return ret; } -int srslte_ue_sync_init_multi(srslte_ue_sync_t *q, - uint32_t max_prb, - bool search_cell, - int (recv_callback)(void*, cf_t*[SRSLTE_MAX_PORTS], uint32_t,srslte_timestamp_t*), +int srslte_ue_sync_init_multi(srslte_ue_sync_t* q, + uint32_t max_prb, + bool search_cell, + int(recv_callback)(void*, cf_t * [SRSLTE_MAX_PORTS], uint32_t, srslte_timestamp_t*), uint32_t nof_rx_antennas, - void *stream_handler) + void* stream_handler) { - - return srslte_ue_sync_init_multi_decim(q, max_prb,search_cell, recv_callback ,nof_rx_antennas,stream_handler,1); + + return srslte_ue_sync_init_multi_decim(q, max_prb, search_cell, recv_callback, nof_rx_antennas, stream_handler, 1); } int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, @@ -246,18 +247,21 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->decimate = 1; } - if(srslte_sync_init_decim(&q->sfind, q->frame_len, q->frame_len, q->fft_size,q->decimate)) { - fprintf(stderr, "Error initiating sync find\n"); + if (srslte_sync_init_decim(&q->sfind, q->frame_len, q->frame_len, q->fft_size, q->decimate)) { + ERROR("Error initiating sync find\n"); goto clean_exit; } if (search_cell) { - if(srslte_sync_init(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { - fprintf(stderr, "Error initiating sync track\n"); + if (srslte_sync_init(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { + ERROR("Error initiating sync track\n"); goto clean_exit; } } else { - if(srslte_sync_init(&q->strack, q->frame_len, SRSLTE_CP_LEN_NORM(1,q->fft_size), q->fft_size)) { - fprintf(stderr, "Error initiating sync track\n"); + if (srslte_sync_init(&q->strack, + q->frame_len, + SRSLTE_MAX(TRACK_FRAME_SIZE, SRSLTE_CP_LEN_NORM(1, q->fft_size)), + q->fft_size)) { + ERROR("Error initiating sync track\n"); goto clean_exit; } } @@ -276,10 +280,11 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, // FIXME: CP detection not working very well. Not supporting Extended CP right now srslte_sync_cp_en(&q->strack, false); - srslte_sync_cp_en(&q->sfind, false); + srslte_sync_cp_en(&q->sfind, false); - srslte_sync_sss_en(&q->strack, true); - q->decode_sss_on_track = true; + // Enable SSS on find and disable in track + srslte_sync_sss_en(&q->sfind, true); + srslte_sync_sss_en(&q->strack, false); ret = SRSLTE_SUCCESS; } @@ -313,15 +318,13 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - srslte_nofprb_isvalid(cell.nof_prb)) - { + if (q != NULL && srslte_nofprb_isvalid(cell.nof_prb)) { if (cell.nof_prb > q->max_prb) { - fprintf(stderr, "Error in ue_sync_set_cell(): cell.nof_prb must be lower than initialized\n"); + ERROR("Error in ue_sync_set_cell(): cell.nof_prb must be lower than initialized\n"); return SRSLTE_ERROR; } - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; q->fft_size = srslte_symbol_sz(q->cell.nof_prb); q->sf_len = SRSLTE_SF_LEN(q->fft_size); @@ -342,21 +345,26 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) } if(srslte_sync_resize(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) { - fprintf(stderr, "Error setting cell sync find\n"); + ERROR("Error setting cell sync find\n"); return SRSLTE_ERROR; } if (cell.id == 1000) { if(srslte_sync_resize(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { - fprintf(stderr, "Error setting cell sync track\n"); + ERROR("Error setting cell sync track\n"); return SRSLTE_ERROR; } } else { - if(srslte_sync_resize(&q->strack, q->frame_len, SRSLTE_CP_LEN_NORM(1,q->fft_size), q->fft_size)) { - fprintf(stderr, "Error setting cell sync track\n"); + if (srslte_sync_resize(&q->strack, + q->frame_len, + SRSLTE_MAX(TRACK_FRAME_SIZE, SRSLTE_CP_LEN_NORM(1, q->fft_size)), + q->fft_size)) { + ERROR("Error setting cell sync track\n"); return SRSLTE_ERROR; } } + // When Cell ID is 1000, ue_sync receives nof_avg_find_frames frames in find state and does not go to tracking state + // and is used to search a cell if (cell.id == 1000) { q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; @@ -375,9 +383,15 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) q->sfind.cp = cell.cp; q->strack.cp = cell.cp; - srslte_sync_set_N_id_2(&q->sfind, cell.id%3); + srslte_sync_set_frame_type(&q->sfind, cell.frame_type); + srslte_sync_set_frame_type(&q->strack, cell.frame_type); + + srslte_sync_set_N_id_2(&q->sfind, cell.id % 3); srslte_sync_set_N_id_2(&q->strack, cell.id%3); + srslte_sync_set_N_id_1(&q->sfind, cell.id / 3); + // track does not correlate SSS so no need to generate sequences + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); srslte_sync_set_cfo_ema_alpha(&q->strack, DEFAULT_CFO_EMA_TRACK); @@ -390,7 +404,6 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) srslte_sync_set_em_alpha(&q->strack, 0.0); srslte_sync_set_threshold(&q->strack, 1.2); - } // When cell is unknown, do CP CFO correction @@ -405,9 +418,24 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) return ret; } +void srslte_ue_sync_set_nof_find_frames(srslte_ue_sync_t* q, uint32_t nof_frames) +{ + q->nof_avg_find_frames = nof_frames; +} + +void srslte_ue_sync_set_frame_type(srslte_ue_sync_t* q, srslte_frame_type_t frame_type) +{ + srslte_sync_set_frame_type(&q->strack, frame_type); + srslte_sync_set_frame_type(&q->sfind, frame_type); +} + +srslte_frame_type_t srslte_ue_sync_get_frame_type(srslte_ue_sync_t* q) +{ + return q->sfind.frame_type; +} void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t *timestamp) { - memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t)); + *timestamp = q->last_timestamp; } void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw_pss, float bw_ref, @@ -481,10 +509,6 @@ void srslte_ue_sync_set_sfo_ema(srslte_ue_sync_t *q, float ema_coefficient) { q->sfo_ema = ema_coefficient; } -void srslte_ue_sync_decode_sss_on_track(srslte_ue_sync_t *q, bool enabled) { - q->decode_sss_on_track = enabled; - srslte_sync_sss_en(&q->strack, q->decode_sss_on_track); -} void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2) { if (!q->file_mode) { @@ -495,40 +519,53 @@ void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2) { } void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period) { - q->agc_period = period; + q->agc_period = period; } -static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { +static int find_peak_ok(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]) +{ - - if (srslte_sync_sss_detected(&q->sfind)) { + if (srslte_sync_sss_detected(&q->sfind)) { /* Get the subframe index (0 or 5) */ - q->sf_idx = srslte_sync_get_sf_idx(&q->sfind) + q->nof_recv_sf; + q->sf_idx = (srslte_sync_get_sf_idx(&q->sfind) + q->nof_recv_sf) % 10; + } else if (srslte_sync_sss_available(&q->sfind)) { + INFO("Found peak at %d, SSS not detected\n", q->peak_idx); + return 0; } else { - DEBUG("Found peak at %d, SSS not detected\n", q->peak_idx); + INFO("Found peak at %d, No space for SSS. Realigning frame, reading %d samples\n", q->peak_idx, q->peak_idx); + if (q->recv_callback(q->stream, input_buffer, q->peak_idx, &q->last_timestamp) < 0) { + return SRSLTE_ERROR; + } + return 0; } - - q->frame_find_cnt++; - DEBUG("Found peak %d at %d, value %.3f, Cell_id: %d CP: %s\n", - q->frame_find_cnt, q->peak_idx, - srslte_sync_get_peak_value(&q->sfind), q->cell.id, srslte_cp_string(q->cell.cp)); + + q->frame_find_cnt++; + DEBUG("Found peak %d at %d, value %.3f, Cell_id: %d CP: %s\n", + q->frame_find_cnt, + q->peak_idx, + srslte_sync_get_peak_value(&q->sfind), + q->cell.id, + srslte_cp_string(q->cell.cp)); if (q->frame_find_cnt >= q->nof_avg_find_frames || q->peak_idx < 2*q->fft_size) { - INFO("Realigning frame, reading %d samples\n", q->peak_idx+q->sf_len/2); - /* Receive the rest of the subframe so that we are subframe aligned */ - if (q->recv_callback(q->stream, input_buffer, q->peak_idx+q->sf_len/2, &q->last_timestamp) < 0) { + // Receive read_len samples until the start of the next subframe (different for FDD and TDD) + uint32_t read_len = q->peak_idx + PSS_OFFSET; + INFO("Realigning frame, reading %d samples\n", read_len); + if (q->recv_callback(q->stream, input_buffer, read_len, &q->last_timestamp) < 0) { return SRSLTE_ERROR; } - /* Reset variables */ - q->frame_ok_cnt = 0; - q->frame_no_cnt = 0; - q->frame_total_cnt = 0; - q->frame_find_cnt = 0; - q->mean_sample_offset = 0; - - /* Goto Tracking state */ - q->state = SF_TRACK; + /* Reset variables */ + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->frame_find_cnt = 0; + q->mean_sample_offset = 0; + + /* Goto Tracking state if cell ID is known already */ + if (q->cell.id < 1000) { + q->state = SF_TRACK; + } /* Set CFO values. Since we correct before track, the initial track state is CFO=0 Hz */ if (!q->cfo_is_copied) { @@ -536,28 +573,17 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS } srslte_sync_cfo_reset(&q->strack); } - - return 0; -} -static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { - - /* Make sure subframe idx is what we expect */ - if ((q->sf_idx != srslte_sync_get_sf_idx(&q->strack)) && - q->decode_sss_on_track && - srslte_sync_sss_detected(&q->strack)) - { - INFO("Warning: Expected SF idx %d but got %d! (%d frames)\n", - q->sf_idx, srslte_sync_get_sf_idx(&q->strack), q->frame_no_cnt); - q->frame_no_cnt++; - if (q->frame_no_cnt >= TRACK_MAX_LOST) { - INFO("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); - q->state = SF_FIND; - } + if (q->cell.id < 1000) { + return 0; } else { - q->frame_no_cnt = 0; + return 1; } - +} + +static int track_peak_ok(srslte_ue_sync_t* q, uint32_t track_idx) +{ + // Get sampling time offset q->last_sample_offset = ((int) track_idx - (int) q->strack.max_offset/2 - (int) q->strack.fft_size); @@ -598,7 +624,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { srslte_ue_sync_get_sfo(q), q->sfo_ema, q->sample_offset_correct_period); } - q->mean_sample_offset = 0; + q->mean_sample_offset = 0; } /* If the PSS peak is beyond the frame (we sample too slowly), @@ -606,7 +632,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) { DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset); if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, NULL) < 0) { - fprintf(stderr, "Error receiving from USRP\n"); + ERROR("Error receiving from USRP\n"); return SRSLTE_ERROR; } q->next_rf_sample_offset = 0; @@ -635,17 +661,17 @@ static int track_peak_no(srslte_ue_sync_t *q) { } static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { - - /* A negative time offset means there are samples in our buffer for the next subframe, - because we are sampling too fast. + + /* A negative time offset means there are samples in our buffer for the next subframe, + because we are sampling too fast. */ if (q->next_rf_sample_offset < 0) { q->next_rf_sample_offset = -q->next_rf_sample_offset; } - - /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */ - cf_t *ptr[SRSLTE_MAX_PORTS]; - for (int i=0;inof_rx_antennas;i++) { + + /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */ + cf_t* ptr[SRSLTE_MAX_PORTS]; + for (int i = 0; i < q->nof_rx_antennas; i++) { ptr[i] = &input_buffer[i][q->next_rf_sample_offset]; } if (q->recv_callback(q->stream, ptr, q->frame_len - q->next_rf_sample_offset, &q->last_timestamp) < 0) { @@ -657,17 +683,12 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PO return SRSLTE_SUCCESS; } -int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { - cf_t *_input_buffer[SRSLTE_MAX_PORTS]; - _input_buffer[0] = input_buffer; - return srslte_ue_sync_zerocopy_multi(q, _input_buffer); -} - /* Returns 1 if the subframe is synchronized in time, 0 otherwise */ -int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - uint32_t track_idx; - +int srslte_ue_sync_zerocopy(srslte_ue_sync_t* q, cf_t* input_buffer[SRSLTE_MAX_PORTS]) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + uint32_t track_idx; + if (q != NULL && input_buffer != NULL) { @@ -675,7 +696,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE if (q->file_mode) { int n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas); if (n < 0) { - fprintf(stderr, "Error reading input file\n"); + ERROR("Error reading input file\n"); return SRSLTE_ERROR; } if (n == 0) { @@ -684,7 +705,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE q->sf_idx = 9; n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas); if (n < 0) { - fprintf(stderr, "Error reading input file\n"); + ERROR("Error reading input file\n"); return SRSLTE_ERROR; } } else { @@ -708,7 +729,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE } else { if (receive_samples(q, input_buffer)) { - fprintf(stderr, "Error receiving samples\n"); + ERROR("Error receiving samples\n"); return SRSLTE_ERROR; } int n; @@ -716,18 +737,18 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE case SF_FIND: // Correct CFO before PSS/SSS find using the sync object corrector (initialized for 1 ms) if (q->cfo_correct_enable_find) { - for (int i=0;inof_rx_antennas;i++) { - srslte_cfo_correct(&q->strack.cfo_corr_frame, - input_buffer[i], - input_buffer[i], - -q->cfo_current_value/q->fft_size); + for (int i = 0; i < q->nof_rx_antennas; i++) { + if (input_buffer[i]) { + srslte_cfo_correct( + &q->strack.cfo_corr_frame, input_buffer[i], input_buffer[i], -q->cfo_current_value / q->fft_size); + } } } n = srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx); switch(n) { - case SRSLTE_SYNC_ERROR: - ret = SRSLTE_ERROR; - fprintf(stderr, "Error finding correlation peak (%d)\n", ret); + case SRSLTE_SYNC_ERROR: + ret = SRSLTE_ERROR; + ERROR("Error finding correlation peak (%d)\n", ret); return SRSLTE_ERROR; case SRSLTE_SYNC_FOUND: ret = find_peak_ok(q, input_buffer); @@ -737,14 +758,14 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE INFO("No space for SSS/CP detection. Realigning frame...\n"); q->recv_callback(q->stream, dummy_offset_buffer, q->frame_len/2, NULL); srslte_sync_reset(&q->sfind); - ret = SRSLTE_SUCCESS; - break; + ret = SRSLTE_SUCCESS; + break; default: ret = SRSLTE_SUCCESS; break; } if (q->do_agc) { - srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); + srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } INFO("SYNC FIND: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state); @@ -759,34 +780,36 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE // Correct CFO before PSS/SSS tracking using the sync object corrector (initialized for 1 ms) if (q->cfo_correct_enable_track) { - for (int i=0;inof_rx_antennas;i++) { - srslte_cfo_correct(&q->strack.cfo_corr_frame, - input_buffer[i], - input_buffer[i], - -q->cfo_current_value/q->fft_size); + for (int i = 0; i < q->nof_rx_antennas; i++) { + if (input_buffer[i]) { + srslte_cfo_correct( + &q->strack.cfo_corr_frame, input_buffer[i], input_buffer[i], -q->cfo_current_value / q->fft_size); + } } } /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ - if (q->sf_idx == 0 || q->sf_idx == 5) + if ((q->sfind.frame_type == SRSLTE_FDD && (q->sf_idx == 0 || q->sf_idx == 5)) || + (q->sfind.frame_type == SRSLTE_TDD && (q->sf_idx == 1 || q->sf_idx == 6))) + { // Process AGC every period - if (q->do_agc && (q->agc_period == 0 || - (q->agc_period && (q->frame_total_cnt%q->agc_period) == 0))) - { + if (q->do_agc && (q->agc_period == 0 || (q->agc_period && (q->frame_total_cnt % q->agc_period) == 0))) { srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } - /* Track PSS/SSS around the expected PSS position + /* Track PSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ - n = srslte_sync_find(&q->strack, input_buffer[0], - q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, - &track_idx); + + // Expected PSS position is different for FDD and TDD + uint32_t pss_idx = q->frame_len - PSS_OFFSET - q->fft_size - q->strack.max_offset / 2; + + n = srslte_sync_find(&q->strack, input_buffer[0], pss_idx, &track_idx); switch(n) { case SRSLTE_SYNC_ERROR: - fprintf(stderr, "Error tracking correlation peak\n"); + ERROR("Error tracking correlation peak\n"); return SRSLTE_ERROR; case SRSLTE_SYNC_FOUND: ret = track_peak_ok(q, track_idx); @@ -797,13 +820,13 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE q->state = SF_FIND; INFO("Warning: No space for SSS/CP while in tracking phase\n"); break; - case SRSLTE_SYNC_NOFOUND: - ret = track_peak_no(q); + case SRSLTE_SYNC_NOFOUND: + ret = track_peak_no(q); break; } if (ret == SRSLTE_ERROR) { - fprintf(stderr, "Error processing tracking peak\n"); + ERROR("Error processing tracking peak\n"); q->state = SF_FIND; return SRSLTE_SUCCESS; } diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 6162bef31..45a276934 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -24,6 +24,7 @@ * */ +#include "srslte/srslte.h" #include #include #include @@ -34,12 +35,14 @@ #define CURRENT_SFLEN SRSLTE_SF_LEN(CURRENT_FFTSIZE) #define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SRSLTE_NOF_RE(q->cell) #define MAX_SFLEN SRSLTE_SF_LEN(srslte_symbol_sz(max_prb)) #define DEFAULT_CFO_TOL 1.0 // Hz +static bool srs_tx_enabled(srslte_refsignal_srs_cfg_t* srs_cfg, uint32_t tti); + int srslte_ue_ul_init(srslte_ue_ul_t *q, cf_t *out_buffer, uint32_t max_prb) @@ -59,35 +62,27 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q, } if (srslte_ofdm_tx_init(&q->fft, SRSLTE_CP_NORM, q->sf_symbols, out_buffer, max_prb)) { - fprintf(stderr, "Error initiating FFT\n"); + ERROR("Error initiating FFT\n"); goto clean_exit; } srslte_ofdm_set_freq_shift(&q->fft, 0.5); srslte_ofdm_set_normalize(&q->fft, true); - q->normalize_en = false; - if (srslte_cfo_init(&q->cfo, MAX_SFLEN)) { - fprintf(stderr, "Error creating CFO object\n"); + ERROR("Error creating CFO object\n"); goto clean_exit; } - srslte_ue_ul_set_cfo_tol(q, DEFAULT_CFO_TOL); - if (srslte_pusch_init_ue(&q->pusch, max_prb)) { - fprintf(stderr, "Error creating PUSCH object\n"); + ERROR("Error creating PUSCH object\n"); goto clean_exit; } if (srslte_pucch_init_ue(&q->pucch)) { - fprintf(stderr, "Error creating PUSCH object\n"); - goto clean_exit; - } - if (srslte_softbuffer_tx_init(&q->softbuffer, max_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); + ERROR("Error creating PUSCH object\n"); goto clean_exit; } if (srslte_refsignal_ul_init(&q->signals, max_prb)) { - fprintf(stderr, "Error initiating srslte_refsignal_ul\n"); + ERROR("Error initiating srslte_refsignal_ul\n"); goto clean_exit; } q->refsignal = srslte_vec_malloc(2 * SRSLTE_NRE * max_prb * sizeof(cf_t)); @@ -101,10 +96,11 @@ int srslte_ue_ul_init(srslte_ue_ul_t *q, perror("malloc"); goto clean_exit; } + q->out_buffer = out_buffer; q->signals_pregenerated = false; ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid parameters\n"); + ERROR("Invalid parameters\n"); } clean_exit: @@ -119,8 +115,7 @@ void srslte_ue_ul_free(srslte_ue_ul_t *q) { srslte_ofdm_tx_free(&q->fft); srslte_pusch_free(&q->pusch); srslte_pucch_free(&q->pucch); - srslte_softbuffer_tx_free(&q->softbuffer); - + srslte_cfo_free(&q->cfo); srslte_refsignal_ul_free(&q->signals); @@ -134,9 +129,11 @@ void srslte_ue_ul_free(srslte_ue_ul_t *q) { free(q->srs_signal); } if (q->signals_pregenerated) { - srslte_refsignal_dmrs_pusch_pregen_free(&q->signals, &q->pregen_drms); + srslte_refsignal_dmrs_pusch_pregen_free(&q->signals, &q->pregen_dmrs); srslte_refsignal_srs_pregen_free(&q->signals, &q->pregen_srs); } + srslte_ra_ul_pusch_hopping_free(&q->hopping); + bzero(q, sizeof(srslte_ue_ul_t)); } } @@ -149,149 +146,87 @@ int srslte_ue_ul_set_cell(srslte_ue_ul_t *q, if (q != NULL && srslte_cell_isvalid(&cell)) { if (q->cell.id != cell.id || q->cell.nof_prb == 0) { - memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); + q->cell = cell; if (srslte_ofdm_tx_set_prb(&q->fft, q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error resizing FFT\n"); + ERROR("Error resizing FFT\n"); return SRSLTE_ERROR; } if (srslte_cfo_resize(&q->cfo, SRSLTE_SF_LEN_PRB(q->cell.nof_prb))) { - fprintf(stderr, "Error resizing CFO object\n"); + ERROR("Error resizing CFO object\n"); return SRSLTE_ERROR; } - srslte_ue_ul_set_cfo_tol(q, q->current_cfo_tol); - if (srslte_pusch_set_cell(&q->pusch, q->cell)) { - fprintf(stderr, "Error resizing PUSCH object\n"); + ERROR("Error resizing PUSCH object\n"); return SRSLTE_ERROR; } if (srslte_pucch_set_cell(&q->pucch, q->cell)) { - fprintf(stderr, "Error resizing PUSCH object\n"); + ERROR("Error resizing PUSCH object\n"); return SRSLTE_ERROR; } if (srslte_refsignal_ul_set_cell(&q->signals, q->cell)) { - fprintf(stderr, "Error resizing srslte_refsignal_ul\n"); + ERROR("Error resizing srslte_refsignal_ul\n"); + return SRSLTE_ERROR; + } + + if (srslte_ra_ul_pusch_hopping_init(&q->hopping, q->cell)) { + ERROR("Error setting hopping procedure cell\n"); return SRSLTE_ERROR; } q->signals_pregenerated = false; } ret = SRSLTE_SUCCESS; } else { - fprintf(stderr, "Invalid cell properties ue_ul: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); + ERROR("Invalid cell properties ue_ul: Id=%d, Ports=%d, PRBs=%d\n", cell.id, cell.nof_ports, cell.nof_prb); } return ret; } -void srslte_ue_ul_set_cfo_tol(srslte_ue_ul_t *q, float tol) { - q->current_cfo_tol = tol; - srslte_cfo_set_tol(&q->cfo, tol/(15000.0*srslte_symbol_sz(q->cell.nof_prb))); -} - -void srslte_ue_ul_set_cfo(srslte_ue_ul_t *q, float cur_cfo) { - q->current_cfo = cur_cfo; -} - -void srslte_ue_ul_set_cfo_enable(srslte_ue_ul_t *q, bool enabled) -{ - q->cfo_en = enabled; -} - -void srslte_ue_ul_set_normalization(srslte_ue_ul_t *q, bool enabled) -{ - q->normalize_en = enabled; -} - /* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while * to execute, so shall be called once the final C-RNTI has been allocated for the session. * For the connection procedure, use srslte_pusch_encode_rnti() or srslte_pusch_decode_rnti() functions */ void srslte_ue_ul_set_rnti(srslte_ue_ul_t *q, uint16_t rnti) { srslte_pusch_set_rnti(&q->pusch, rnti); - srslte_pucch_set_crnti(&q->pucch, rnti); - q->current_rnti = rnti; -} - -void srslte_ue_ul_reset(srslte_ue_ul_t *q) { - srslte_softbuffer_tx_reset(&q->softbuffer); + srslte_pucch_set_rnti(&q->pucch, rnti); + q->current_rnti = rnti; } -int srslte_ue_ul_pregen_signals(srslte_ue_ul_t *q) { +int srslte_ue_ul_pregen_signals(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg) +{ if (q->signals_pregenerated) { - srslte_refsignal_dmrs_pusch_pregen_free(&q->signals, &q->pregen_drms); + srslte_refsignal_dmrs_pusch_pregen_free(&q->signals, &q->pregen_dmrs); srslte_refsignal_srs_pregen_free(&q->signals, &q->pregen_srs); } - if (srslte_refsignal_dmrs_pusch_pregen(&q->signals, &q->pregen_drms)) { + if (srslte_refsignal_dmrs_pusch_pregen(&q->signals, &q->pregen_dmrs, &cfg->ul_cfg.dmrs)) { return SRSLTE_ERROR; } - if (srslte_refsignal_srs_pregen(&q->signals, &q->pregen_srs)) { + if (srslte_refsignal_srs_pregen(&q->signals, &q->pregen_srs, &cfg->ul_cfg.srs, &cfg->ul_cfg.dmrs)) { return SRSLTE_ERROR; } q->signals_pregenerated = true; return SRSLTE_SUCCESS; } - -void srslte_ue_ul_set_cfg(srslte_ue_ul_t *q, - srslte_refsignal_dmrs_pusch_cfg_t *dmrs_cfg, - srslte_refsignal_srs_cfg_t *srs_cfg, - srslte_pucch_cfg_t *pucch_cfg, - srslte_pucch_sched_t *pucch_sched, - srslte_uci_cfg_t *uci_cfg, - srslte_pusch_hopping_cfg_t *hopping_cfg, - srslte_ue_ul_powerctrl_t *power_ctrl) +int srslte_ue_ul_dci_to_pusch_grant(srslte_ue_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_ue_ul_cfg_t* cfg, + srslte_dci_ul_t* dci, + srslte_pusch_grant_t* grant) { - srslte_refsignal_ul_set_cfg(&q->signals, dmrs_cfg, pucch_cfg, srs_cfg); - if (pucch_cfg && dmrs_cfg) { - srslte_pucch_set_cfg(&q->pucch, pucch_cfg, dmrs_cfg->group_hopping_en); - } - if (pucch_sched) { - memcpy(&q->pucch_sched, pucch_sched, sizeof(srslte_pucch_sched_t)); - } - if (srs_cfg) { - memcpy(&q->srs_cfg, srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - } - if (uci_cfg) { - memcpy(&q->uci_cfg, uci_cfg, sizeof(srslte_uci_cfg_t)); - } - if (hopping_cfg) { - memcpy(&q->hopping_cfg, hopping_cfg, sizeof(srslte_pusch_hopping_cfg_t)); - } - if (power_ctrl) { - memcpy(&q->power_ctrl, power_ctrl, sizeof(srslte_ue_ul_powerctrl_t)); - } -} + // Update shortened before computing grant + srslte_refsignal_srs_pusch_shortened(&q->signals, sf, &cfg->ul_cfg.srs, &cfg->ul_cfg.pusch); -int srslte_ue_ul_cfg_grant(srslte_ue_ul_t *q, srslte_ra_ul_grant_t *grant, - uint32_t tti, uint32_t rvidx, uint32_t current_tx_nb) -{ - return srslte_pusch_cfg(&q->pusch, &q->pusch_cfg, grant, &q->uci_cfg, &q->hopping_cfg, &q->srs_cfg, tti, rvidx, current_tx_nb); + return srslte_ra_ul_dci_to_grant(&q->cell, sf, &cfg->ul_cfg.hopping, dci, grant); } -// Encode bits from uci_data -void pucch_encode_bits(srslte_uci_data_t *uci_data, srslte_pucch_format_t format, - uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS], - uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS]) +void srslte_ue_ul_pusch_hopping(srslte_ue_ul_t* q, + srslte_ul_sf_cfg_t* sf, + srslte_ue_ul_cfg_t* cfg, + srslte_pusch_grant_t* grant) { - if (format == SRSLTE_PUCCH_FORMAT_1A || format == SRSLTE_PUCCH_FORMAT_1B) { - pucch_bits[0] = uci_data->uci_ack; - pucch_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 1a - } - if (format >= SRSLTE_PUCCH_FORMAT_2) { - /* Put RI (goes alone) */ - if (uci_data->ri_periodic_report) { - uint8_t temp[2] = {uci_data->uci_ri, 0}; - srslte_uci_encode_cqi_pucch(temp, uci_data->uci_ri_len, pucch_bits); - } else { - /* Put CQI Report*/ - srslte_uci_encode_cqi_pucch(uci_data->uci_cqi, uci_data->uci_cqi_len, pucch_bits); - } - if (format > SRSLTE_PUCCH_FORMAT_2) { - pucch2_bits[0] = uci_data->uci_ack; - pucch2_bits[1] = uci_data->uci_ack_2; // this will be ignored in format 2a - } - } + return srslte_ra_ul_pusch_hopping(&q->hopping, sf, &cfg->ul_cfg.hopping, grant); } static float limit_norm_factor(srslte_ue_ul_t *q, float norm_factor, cf_t *output_signal) @@ -305,285 +240,147 @@ static float limit_norm_factor(srslte_ue_ul_t *q, float norm_factor, cf_t *outpu if (amp*norm_factor < 0.1) { norm_factor = 0.1/amp; } - q->last_amplitude = norm_factor*amp; return norm_factor; } -float srslte_ue_ul_get_last_amplitude(srslte_ue_ul_t *q) { - return q->last_amplitude; -} - -/* Choose PUCCH format as in Sec 10.1 of 36.213 and generate PUCCH signal - */ -int srslte_ue_ul_pucch_encode(srslte_ue_ul_t *q, srslte_uci_data_t uci_data, - uint32_t pdcch_n_cce, - uint32_t tti, - cf_t *output_signal) -{ - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - output_signal != NULL) - { - - uint32_t sf_idx = tti%10; - ret = SRSLTE_ERROR; - - uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; - uint8_t pucch2_bits[2]; - bzero(pucch_bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); - bzero(pucch2_bits, 2*sizeof(uint8_t)); - - srslte_pucch_format_t format = srslte_pucch_get_format(&uci_data, q->cell.cp); - - // Encode UCI information - pucch_encode_bits(&uci_data, format, pucch_bits, pucch2_bits); - - // Choose n_pucch - uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data.scheduling_request, &q->pucch_sched); - - if (srslte_pucch_encode(&q->pucch, format, n_pucch, sf_idx, q->current_rnti, pucch_bits, q->sf_symbols)) { - fprintf(stderr, "Error encoding TB\n"); - return ret; - } - - if (srslte_refsignal_dmrs_pucch_gen(&q->signals, format, n_pucch, sf_idx, pucch2_bits, q->refsignal)) - { - fprintf(stderr, "Error generating PUSCH DRMS signals\n"); - return ret; - } - srslte_refsignal_dmrs_pucch_put(&q->signals, format, n_pucch, q->refsignal, q->sf_symbols); - - if (srslte_ue_ul_srs_tx_enabled(&q->signals.srs_cfg, tti) && q->pucch.shortened) { - if (q->signals_pregenerated) { - srslte_refsignal_srs_pregen_put(&q->signals, &q->pregen_srs, tti, q->sf_symbols); - } else { - srslte_refsignal_srs_gen(&q->signals, tti%10, q->srs_signal); - srslte_refsignal_srs_put(&q->signals, tti, q->srs_signal, q->sf_symbols); - } - } - - q->last_pucch_format = format; - - srslte_ofdm_tx_sf(&q->fft); - - if (q->cfo_en) { - srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); - } - - if (q->normalize_en) { - float norm_factor = (float) q->cell.nof_prb/15/40; - - norm_factor = limit_norm_factor(q, norm_factor, output_signal); - - srslte_vec_sc_prod_cfc(output_signal, norm_factor, output_signal, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); - } - ret = SRSLTE_SUCCESS; - } - - return ret; -} - -int srslte_ue_ul_pusch_encode(srslte_ue_ul_t *q, uint8_t *data, cf_t *output_signal) +static void apply_cfo(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg) { - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - return srslte_ue_ul_pusch_uci_encode_rnti(q, data, uci_data, q->current_rnti, output_signal); + if (cfg->cfo_en) { + srslte_cfo_set_tol(&q->cfo, cfg->cfo_tol / (15000.0 * srslte_symbol_sz(q->cell.nof_prb))); + srslte_cfo_correct(&q->cfo, q->out_buffer, q->out_buffer, cfg->cfo_value / srslte_symbol_sz(q->cell.nof_prb)); + } } -int srslte_ue_ul_pusch_encode_rnti(srslte_ue_ul_t *q, uint8_t *data, uint16_t rnti, cf_t *output_signal) +static void apply_norm(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, float norm_factor) { - srslte_uci_data_t uci_data; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - return srslte_ue_ul_pusch_uci_encode_rnti(q, data, uci_data, rnti, output_signal); + if (cfg->normalize_en) { + norm_factor = limit_norm_factor(q, norm_factor, q->out_buffer); + srslte_vec_sc_prod_cfc(q->out_buffer, norm_factor, q->out_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + } } -int srslte_ue_ul_pusch_uci_encode(srslte_ue_ul_t *q, uint8_t *data, srslte_uci_data_t uci_data, cf_t *output_signal) +static void add_srs(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, uint32_t tti) { - return srslte_ue_ul_pusch_uci_encode_rnti(q, data, uci_data, q->current_rnti, output_signal); + if (srs_tx_enabled(&cfg->ul_cfg.srs, tti)) { + if (q->signals_pregenerated) { + srslte_refsignal_srs_pregen_put(&q->signals, &q->pregen_srs, &cfg->ul_cfg.srs, tti, q->sf_symbols); + } else { + srslte_refsignal_srs_gen(&q->signals, &cfg->ul_cfg.srs, &cfg->ul_cfg.dmrs, tti % 10, q->srs_signal); + srslte_refsignal_srs_put(&q->signals, &cfg->ul_cfg.srs, tti, q->srs_signal, q->sf_symbols); + } + } } -int srslte_ue_ul_pusch_uci_encode_rnti(srslte_ue_ul_t *q, - uint8_t *data, srslte_uci_data_t uci_data, - uint16_t rnti, - cf_t *output_signal) +static int pusch_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, srslte_pusch_data_t* data) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - output_signal != NULL) - { - - if (q->pusch_cfg.grant.L_prb == 0) { - fprintf(stderr, "Invalid UL PRB allocation (L_prb=0)\n"); - return SRSLTE_ERROR; - } - - return srslte_ue_ul_pusch_encode_rnti_softbuffer(q, data, uci_data, &q->softbuffer, rnti, output_signal); - } - return ret; -} -int srslte_ue_ul_srs_encode(srslte_ue_ul_t *q, uint32_t tti, cf_t *output_signal) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - if (q && output_signal) { - ret = SRSLTE_ERROR; - - if (srslte_ue_ul_srs_tx_enabled(&q->signals.srs_cfg, tti)) { - if (q->signals_pregenerated) { - srslte_refsignal_srs_pregen_put(&q->signals, &q->pregen_srs, tti, q->sf_symbols); - } else { - srslte_refsignal_srs_gen(&q->signals, tti%10, q->srs_signal); - srslte_refsignal_srs_put(&q->signals, tti, q->srs_signal, q->sf_symbols); - } - } - - srslte_ofdm_tx_sf(&q->fft); - - if (q->cfo_en) { - srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); - } - - if (q->normalize_en) { - float norm_factor = (float) q->cell.nof_prb/15/sqrtf(srslte_refsignal_srs_M_sc(&q->signals)); - - norm_factor = limit_norm_factor(q, norm_factor, output_signal); - srslte_vec_sc_prod_cfc(output_signal, norm_factor, output_signal, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); - } - - ret = SRSLTE_SUCCESS; - } - return ret; -} + if (q != NULL) { -int srslte_ue_ul_pusch_encode_rnti_softbuffer(srslte_ue_ul_t *q, - uint8_t *data, srslte_uci_data_t uci_data, - srslte_softbuffer_tx_t *softbuffer, - uint16_t rnti, - cf_t *output_signal) -{ - - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - output_signal != NULL) - { + bzero(q->sf_symbols, sizeof(cf_t) * SRSLTE_NOF_RE(q->cell)); - bzero(q->sf_symbols, sizeof(cf_t)*SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)); - - if (srslte_pusch_encode(&q->pusch, &q->pusch_cfg, softbuffer, data, uci_data, rnti, q->sf_symbols)) { - fprintf(stderr, "Error encoding TB\n"); + if (srslte_pusch_encode(&q->pusch, sf, &cfg->ul_cfg.pusch, data, q->sf_symbols)) { + ERROR("Error encoding PUSCH\n"); return SRSLTE_ERROR; } if (q->signals_pregenerated) { - srslte_refsignal_dmrs_pusch_pregen_put(&q->signals, &q->pregen_drms, - q->pusch_cfg.grant.L_prb, - q->pusch_cfg.sf_idx, - q->pusch_cfg.grant.ncs_dmrs, - q->pusch_cfg.grant.n_prb_tilde, - q->sf_symbols); + srslte_refsignal_dmrs_pusch_pregen_put(&q->signals, sf, &q->pregen_dmrs, &cfg->ul_cfg.pusch, q->sf_symbols); } else { - - if (srslte_refsignal_dmrs_pusch_gen(&q->signals, q->pusch_cfg.grant.L_prb, - q->pusch_cfg.sf_idx, - q->pusch_cfg.grant.ncs_dmrs, - q->refsignal)) - { - fprintf(stderr, "Error generating PUSCH DRMS signals\n"); + if (srslte_refsignal_dmrs_pusch_gen(&q->signals, + &cfg->ul_cfg.dmrs, + cfg->ul_cfg.pusch.grant.L_prb, + sf->tti % 10, + cfg->ul_cfg.pusch.grant.n_dmrs, + q->refsignal)) { + ERROR("Error generating PUSCH DMRS signals\n"); return ret; } - srslte_refsignal_dmrs_pusch_put(&q->signals, q->refsignal, - q->pusch_cfg.grant.L_prb, - q->pusch_cfg.grant.n_prb_tilde, - q->sf_symbols); + srslte_refsignal_dmrs_pusch_put(&q->signals, &cfg->ul_cfg.pusch, q->refsignal, q->sf_symbols); } - - if (srslte_ue_ul_srs_tx_enabled(&q->signals.srs_cfg, q->pusch_cfg.tti)) { - if (q->signals_pregenerated) { - srslte_refsignal_srs_pregen_put(&q->signals, &q->pregen_srs, q->pusch_cfg.tti, q->sf_symbols); - } else { - srslte_refsignal_srs_gen(&q->signals, q->pusch_cfg.sf_idx, q->srs_signal); - srslte_refsignal_srs_put(&q->signals, q->pusch_cfg.tti, q->srs_signal, q->sf_symbols); - } - } - + + add_srs(q, cfg, sf->tti); + srslte_ofdm_tx_sf(&q->fft); - - if (q->cfo_en) { - srslte_cfo_correct(&q->cfo, output_signal, output_signal, q->current_cfo / srslte_symbol_sz(q->cell.nof_prb)); - } - - if (q->normalize_en) { - float norm_factor = (float) q->cell.nof_prb/15/sqrtf(q->pusch_cfg.grant.L_prb)/2; - norm_factor = limit_norm_factor(q, norm_factor, output_signal); + apply_cfo(q, cfg); + apply_norm(q, cfg, q->cell.nof_prb / 15 / sqrtf(cfg->ul_cfg.pusch.grant.L_prb) / 2); - srslte_vec_sc_prod_cfc(output_signal, norm_factor, output_signal, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); - } - - ret = SRSLTE_SUCCESS; - } - - return ret; + ret = SRSLTE_SUCCESS; + } + + return ret; } /* Returns the transmission power for PUSCH for this subframe as defined in Section 5.1.1 of 36.213 */ -float srslte_ue_ul_pusch_power(srslte_ue_ul_t *q, float PL, float p0_preamble) +float srslte_ue_ul_pusch_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, float PL, float p0_preamble) { float p0_pusch, alpha; if (p0_preamble) { - p0_pusch = p0_preamble + q->power_ctrl.delta_preamble_msg3; + p0_pusch = p0_preamble + cfg->ul_cfg.power_ctrl.delta_preamble_msg3; alpha = 1; } else { - alpha = q->power_ctrl.alpha; - p0_pusch = q->power_ctrl.p0_nominal_pusch + q->power_ctrl.p0_ue_pusch; + alpha = cfg->ul_cfg.power_ctrl.alpha; + p0_pusch = cfg->ul_cfg.power_ctrl.p0_nominal_pusch + cfg->ul_cfg.power_ctrl.p0_ue_pusch; } - float delta=0; - if (q->power_ctrl.delta_mcs_based) { + float delta = 0; +#ifdef kk + if (ul_cfg->ul_cfg.power_ctrl.delta_mcs_based) { float beta_offset_pusch = 1; - float MPR = q->pusch_cfg.cb_segm.K1*q->pusch_cfg.cb_segm.C1+q->pusch_cfg.cb_segm.K2*q->pusch_cfg.cb_segm.C2; - if (q->pusch_cfg.cb_segm.tbs == 0) { - beta_offset_pusch = srslte_sch_beta_cqi(q->pusch_cfg.uci_cfg.I_offset_cqi); - MPR = q->pusch_cfg.last_O_cqi; + float MPR = q->pusch.cb_segm.K1 * q->pusch_cfg.cb_segm.C1 + q->pusch_cfg.cb_segm.K2 * q->pusch_cfg.cb_segm.C2; + if (q->pusch.dci.cw.tbs == 0) { + beta_offset_pusch = srslte_sch_beta_cqi(q->pusch.uci_offset.I_offset_cqi); + MPR = q->pusch_cfg.last_O_cqi; } - MPR /= q->pusch_cfg.nbits.nof_re; - delta = 10*log10((pow(2,MPR*1.25)-1)*beta_offset_pusch); + MPR /= q->pusch.dci.nof_re; + delta = 10 * log10((pow(2, MPR * 1.25) - 1) * beta_offset_pusch); } - //TODO: This implements closed-loop power control - float f=0; - - float pusch_power = 10*log10(q->pusch_cfg.grant.L_prb)+p0_pusch+alpha*PL+delta+f; - DEBUG("PUSCH: P=%f -- 10M=%f, p0=%f,alpha=%f,PL=%f,\n", - pusch_power, 10*log10(q->pusch_cfg.grant.L_prb), p0_pusch, alpha, PL); +#else + printf("Do this in pusch??"); +#endif + // TODO: This implements closed-loop power control + float f = 0; + + float pusch_power = 10 * log10(cfg->ul_cfg.pusch.grant.L_prb) + p0_pusch + alpha * PL + delta + f; + DEBUG("PUSCH: P=%f -- 10M=%f, p0=%f,alpha=%f,PL=%f,\n", + pusch_power, + 10 * log10(cfg->ul_cfg.pusch.grant.L_prb), + p0_pusch, + alpha, + PL); return SRSLTE_MIN(SRSLTE_PC_MAX, pusch_power); } /* Returns the transmission power for PUCCH for this subframe as defined in Section 5.1.2 of 36.213 */ -float srslte_ue_ul_pucch_power(srslte_ue_ul_t *q, float PL, srslte_pucch_format_t format, uint32_t n_cqi, uint32_t n_harq) { - float p0_pucch = q->power_ctrl.p0_nominal_pucch + q->power_ctrl.p0_ue_pucch; +float srslte_ue_ul_pucch_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, float PL) +{ + srslte_pucch_format_t format = cfg->ul_cfg.pucch.format; - uint8_t format_idx = format==0?0:((uint32_t) format-1); + float p0_pucch = cfg->ul_cfg.power_ctrl.p0_nominal_pucch + cfg->ul_cfg.power_ctrl.p0_ue_pucch; + + uint8_t format_idx = (uint8_t)((format == 0) ? (0) : ((uint8_t)format - 1)); + + float delta_f = cfg->ul_cfg.power_ctrl.delta_f_pucch[format_idx]; - float delta_f = q->power_ctrl.delta_f_pucch[format_idx]; - float h; - - if(format <= SRSLTE_PUCCH_FORMAT_1B) { + int n_cqi = srslte_cqi_size(&uci_cfg->cqi); + int n_harq = uci_cfg->ack.nof_acks; + + if (format <= SRSLTE_PUCCH_FORMAT_1B) { h = 0; } else { if (SRSLTE_CP_ISNORM(q->cell.cp)) { if (n_cqi >= 4) { - h = 10*log10(n_cqi/4); + h = 10.0f * log10f(n_cqi / 4.0f); } else { h = 0; } } else { if (n_cqi + n_harq >= 4) { - h = 10*log10((n_cqi+n_harq)/4); + h = 10.0f * log10f((n_cqi + n_harq) / 4.0f); } else { - h = 0; + h = 0; } } } @@ -595,51 +392,553 @@ float srslte_ue_ul_pucch_power(srslte_ue_ul_t *q, float PL, srslte_pucch_format_ DEBUG("PUCCH: P=%f -- p0=%f, PL=%f, delta_f=%f, h=%f, g=%f\n", pucch_power, p0_pucch, PL, delta_f, h, g); - - return pucch_power; + + return 0; +} + +static int srs_encode(srslte_ue_ul_t* q, uint32_t tti, srslte_ue_ul_cfg_t* cfg) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q && cfg) { + + bzero(q->sf_symbols, sizeof(cf_t) * SRSLTE_NOF_RE(q->cell)); + + add_srs(q, cfg, tti); + + srslte_ofdm_tx_sf(&q->fft); + + apply_cfo(q, cfg); + apply_norm(q, cfg, (float)q->cell.nof_prb / 15 / sqrtf(srslte_refsignal_srs_M_sc(&q->signals, &cfg->ul_cfg.srs))); + + ret = SRSLTE_SUCCESS; + } + return ret; +} + +static bool srs_tx_enabled(srslte_refsignal_srs_cfg_t* srs_cfg, uint32_t tti) +{ + 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; } /* Returns the transmission power for SRS for this subframe as defined in Section 5.1.3 of 36.213 */ -float srslte_ue_ul_srs_power(srslte_ue_ul_t *q, float PL) { - float alpha = q->power_ctrl.alpha; - float p0_pusch = q->power_ctrl.p0_nominal_pusch + q->power_ctrl.p0_ue_pusch; +float srs_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, float PL) +{ + float alpha = cfg->ul_cfg.power_ctrl.alpha; + float p0_pusch = cfg->ul_cfg.power_ctrl.p0_nominal_pusch + cfg->ul_cfg.power_ctrl.p0_ue_pusch; - //TODO: This implements closed-loop power control - float f=0; + // TODO: This implements closed-loop power control + float f = 0; - uint32_t M_sc = srslte_refsignal_srs_M_sc(&q->signals); - - float p_srs_offset; - if (q->power_ctrl.delta_mcs_based) { - p_srs_offset = -3 + q->power_ctrl.p_srs_offset; + uint32_t M_sc = srslte_refsignal_srs_M_sc(&q->signals, &cfg->ul_cfg.srs); + + float p_srs_offset; + if (cfg->ul_cfg.power_ctrl.delta_mcs_based) { + p_srs_offset = -3 + cfg->ul_cfg.power_ctrl.p_srs_offset; } else { - p_srs_offset = -10.5 + 1.5*q->power_ctrl.p_srs_offset; + p_srs_offset = -10.5 + 1.5 * cfg->ul_cfg.power_ctrl.p_srs_offset; } - - float p_srs = p_srs_offset + 10*log10(M_sc) + p0_pusch + alpha*PL + f; - - DEBUG("SRS: P=%f -- p_offset=%f, 10M=%f, p0_pusch=%f, alpha=%f, PL=%f, f=%f\n", - p_srs, p_srs_offset, 10*log10(M_sc), p0_pusch, alpha, PL, f); - + + float p_srs = p_srs_offset + 10 * log10(M_sc) + p0_pusch + alpha * PL + f; + + DEBUG("SRS: P=%f -- p_offset=%f, 10M=%f, p0_pusch=%f, alpha=%f, PL=%f, f=%f\n", + p_srs, + p_srs_offset, + 10 * log10(M_sc), + p0_pusch, + alpha, + PL, + f); + return p_srs; } +/* Choose PUCCH format based on pending transmission as described in 10.1 of 36.213 */ +static srslte_pucch_format_t +get_format(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value, srslte_cp_t cp) +{ + srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; + // No CQI data + if (!uci_cfg->cqi.data_enable && uci_cfg->cqi.ri_len == 0) { + // PUCCH Format 3 condition specified in: + // 3GPP 36.213 10.1.2.2.2 PUCCH format 3 HARQ-ACK procedure + if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 && uci_cfg->ack.has_scell_ack) { + format = SRSLTE_PUCCH_FORMAT_3; + } + // 1-bit ACK + optional SR + else if (uci_cfg->ack.nof_acks == 1) { + format = SRSLTE_PUCCH_FORMAT_1A; + } + // 2-bit ACK + optional SR + else if (uci_cfg->ack.nof_acks >= 2) { + format = SRSLTE_PUCCH_FORMAT_1B; // with channel selection if > 2 + } + // If UCI value is provided, use SR signal only, otherwise SR request opportunity + else if (uci_value) { + if (uci_value->scheduling_request) { + format = SRSLTE_PUCCH_FORMAT_1; + } + } else { + if (uci_cfg->is_scheduling_request_tti) { + format = SRSLTE_PUCCH_FORMAT_1; + } + } + } + // CQI data + else { + // CQI and no ack + if (uci_cfg->ack.nof_acks == 0) { + format = SRSLTE_PUCCH_FORMAT_2; + } + // CQI + 1-bit ACK + else if (uci_cfg->ack.nof_acks == 1 && SRSLTE_CP_ISNORM(cp)) { + format = SRSLTE_PUCCH_FORMAT_2A; + } + // CQI + 2-bit ACK + else if (uci_cfg->ack.nof_acks == 2) { + format = SRSLTE_PUCCH_FORMAT_2B; + } + // CQI + 2-bit ACK + cyclic prefix + else if (uci_cfg->ack.nof_acks == 1 && SRSLTE_CP_ISEXT(cp)) { + format = SRSLTE_PUCCH_FORMAT_2B; + } + } + return format; +} + +// n_pucch and b0b1 selection for CA, tables 10.1.2.2.1-3 to -5 +static uint32_t +get_npucch_cs(srslte_pucch_cfg_t* cfg, uint32_t n_cce, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value) +{ + uint32_t n_pucch = 0; + uint8_t* b = uci_value->ack.ack_value; + + switch (uci_cfg->ack.nof_acks) { + case 1: + n_pucch = n_cce + cfg->N_pucch_1; + break; + case 2: + if (b[1] != 1) { + /* n_pucch1_0 */ + n_pucch = n_cce + cfg->N_pucch_1; + } else { + /* n_pucch1_1 */ + n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0]; + } + if (b[0] == 1) { + b[0] = 1; + b[1] = 1; + } else { + b[0] = 0; + b[1] = 0; + } + break; + case 3: + if (b[0] != 1 && b[1] != 1) { + /* n_pucch1_2 */ + n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0]; + } else if (b[2] == 1) { + /* n_pucch1_1 */ + n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0]; + } else { + /* n_pucch1_0 */ + n_pucch = n_cce + cfg->N_pucch_1; + } + if (b[0] != 1 && b[1] != 1 && b[2] != 1) { + b[0] = 0; + b[1] = 0; + } else if (b[0] != 1 && b[1] == 1) { + b[0] = 0; + b[1] = 1; + } else if (b[0] == 1 && b[1] != 1) { + b[0] = 1; + b[1] = 0; + } else { + b[0] = 1; + b[1] = 1; + } + break; + case 4: + if (b[2] != 1 && b[3] != 1) { + /* n_pucch1_0 */ + n_pucch = n_cce + cfg->N_pucch_1; + } else if (b[1] == 1 && b[2] == 1) { + /* n_pucch1_1 */ + n_pucch = n_cce + cfg->N_pucch_1 + 1; + } else if (b[0] == 1) { + /* n_pucch1_2 */ + n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0]; + } else { + /* n_pucch1_3 */ + n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][1]; + } + if (b[2] != 1 && b[3] != 1) { + /* n_pucch1_0 */ + b[0] = (uint8_t)(b[0] != 1 ? 0 : 1); + b[1] = (uint8_t)(b[1] != 1 ? 0 : 1); + } else if (b[1] == 1 && b[2] == 1) { + /* n_pucch1_1 */ + b[0] = (uint8_t)(b[0] != 1 ? 0 : 1); + b[1] = (uint8_t)(b[3] != 1 ? 0 : 1); + } else if (b[0] == 1) { + /* n_pucch1_2 */ + b[0] = (uint8_t)((b[3] != 1 ? 0 : 1) & (b[2] != 1 ? 1 : 0)); + b[1] = (uint8_t)((b[3] != 1 ? 0 : 1) & ((b[1] != 1 ? 0 : 1) ^ (b[2] != 1 ? 0 : 1))); + } else { + /* n_pucch1_3 */ + b[0] = (uint8_t)((b[1] != 1 ? 0 : 1) & (b[0] != 1 ? 1 : 0)); + b[1] = (uint8_t)((b[3] != 1 ? 0 : 1) & ((b[1] != 1 ? 0 : 1) ^ (b[2] != 1 ? 0 : 1))); + } + break; + } + + return n_pucch; +} + +static void set_b01(uint8_t* b, uint8_t x) +{ + switch (x) { + case 0: + b[0] = 0; + b[1] = 0; + break; + case 1: + b[0] = 0; + b[1] = 1; + break; + case 2: + b[0] = 1; + b[1] = 0; + break; + case 3: + b[0] = 1; + b[1] = 1; + break; + } +} + +#define is_ack(h) (h == 1) +#define is_nack(h) (h == 0) +#define is_nackdtx(h) ((h & 1) == 0) +#define is_dtx(h) (h == 2) + +// n_pucch and b0b1 selection for TDD, tables 10.1-2, 10.1-3 and 10.1-4 +static uint32_t get_npucch_tdd(uint32_t n_pucch[4], srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value) +{ + uint8_t* b = uci_value->ack.ack_value; + switch (uci_cfg->ack.nof_acks) { + case 1: + return n_pucch[0]; + case 2: + if (is_ack(b[0]) && is_ack(b[1])) { + set_b01(b, 3); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1])) { + set_b01(b, 1); + return n_pucch[0]; + } else if (is_nackdtx(b[0]) && is_ack(b[1])) { + set_b01(b, 0); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nack(b[1])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nack(b[0]) && is_dtx(b[1])) { + set_b01(b, 2); + return n_pucch[0]; + } + break; + case 3: + uci_cfg->ack.nof_acks = 2; + if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2])) { + set_b01(b, 3); + return n_pucch[2]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 3); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2])) { + set_b01(b, 3); + return n_pucch[0]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 1); + return n_pucch[0]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2])) { + set_b01(b, 2); + return n_pucch[2]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 0); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2])) { + set_b01(b, 0); + return n_pucch[2]; + } else if (is_dtx(b[0]) && is_dtx(b[1]) && is_nack(b[2])) { + set_b01(b, 1); + return n_pucch[2]; + } else if (is_dtx(b[0]) && is_nack(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 2); + return n_pucch[0]; + } + break; + case 4: + uci_cfg->ack.nof_acks = 2; + if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 3); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nack(b[2]) && is_dtx(b[3])) { + set_b01(b, 3); + return n_pucch[2]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nack(b[0]) && is_dtx(b[1]) && is_dtx(b[2]) && is_dtx(b[3])) { + set_b01(b, 2); + return n_pucch[0]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_nack(b[3])) { + set_b01(b, 3); + return n_pucch[3]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_nack(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[0]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 3); + return n_pucch[0]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_nack(b[1]) && is_dtx(b[2]) && is_dtx(b[3])) { + set_b01(b, 0); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 2); + return n_pucch[2]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 2); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 1); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 0); + return n_pucch[2]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 0); + return n_pucch[3]; + } + } + return 0; +} + +static uint32_t get_Np(uint32_t p, uint32_t nof_prb) +{ + if (p == 0) { + return 0; + } else { + return nof_prb * (SRSLTE_NRE * p - 4) / 36; + } +} + +static uint32_t n_pucch_i_tdd(uint32_t ncce, uint32_t N_pucch_1, uint32_t nof_prb, uint32_t M, uint32_t m) +{ + uint32_t Np = 0, Np_1 = 0; + for (uint32_t p = 0; p < 4; p++) { + Np = get_Np(p, nof_prb); + Np_1 = get_Np(p + 1, nof_prb); + if (ncce >= Np && ncce < Np_1) { + uint32_t npucch = (M - m - 1) * Np + m * Np_1 + ncce + N_pucch_1; + return npucch; + } + } + ERROR("Could not find Np value for ncce=%d\n", ncce); + return 0; +} + +/** Choose PUCCH resource as described in 3GPP 36.213 version 10.13.0 section 10.1.2.2 */ +static uint32_t +get_npucch(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value, srslte_cell_t* cell) +{ + uint32_t n_pucch_res = 0; + + if (uci_value) { + if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS && cfg->format < SRSLTE_PUCCH_FORMAT_2 && + !uci_value->scheduling_request && uci_cfg->ack.nof_acks > 0) { + n_pucch_res = get_npucch_cs(cfg, uci_cfg->ack.ncce[0], uci_cfg, uci_value); + return n_pucch_res; + } else if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 && + cfg->format == SRSLTE_PUCCH_FORMAT_3) { + n_pucch_res = cfg->n3_pucch_an_list[cfg->tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS]; + return n_pucch_res; + } else if (uci_value->scheduling_request) { + // If SR signal or SR opportunity, use n_pucch_sr for format 1, 1a, 1b + n_pucch_res = cfg->n_pucch_sr; + return n_pucch_res; + } + } else if (uci_cfg->is_scheduling_request_tti) { + n_pucch_res = cfg->n_pucch_sr; + return n_pucch_res; + } + + if (cfg->format < SRSLTE_PUCCH_FORMAT_2) { + if (cfg->sps_enabled) { + n_pucch_res = cfg->n_pucch_1[cfg->tpc_for_pucch % 4]; + } else { + if (cell->frame_type == SRSLTE_FDD) { + n_pucch_res = uci_cfg->ack.ncce[0] + cfg->N_pucch_1; + } else { + if (uci_cfg->ack.tdd_is_bundling || uci_cfg->ack.tdd_ack_M == 1) { + n_pucch_res = n_pucch_i_tdd( + uci_cfg->ack.ncce[0], cfg->N_pucch_1, cell->nof_prb, uci_cfg->ack.tdd_ack_M, uci_cfg->ack.tdd_ack_m); + } else { + if (uci_cfg->ack.tdd_ack_M <= 4) { + uint32_t n_pucch[4]; + for (uint32_t i = 0; i < uci_cfg->ack.tdd_ack_M; i++) { + n_pucch[i] = + n_pucch_i_tdd(uci_cfg->ack.ncce[i], cfg->N_pucch_1, cell->nof_prb, uci_cfg->ack.tdd_ack_M, i); + } + if (uci_value) { + n_pucch_res = get_npucch_tdd(n_pucch, uci_cfg, uci_value); + } else { + ERROR("Error Not Implemented: TDD requires uci_value\n"); + } + } else { + ERROR("Invalid M=%d in PUCCH TDD multiplexing\n", uci_cfg->ack.tdd_ack_M); + } + } + } + } + } else { + n_pucch_res = cfg->n_pucch_2; + } + + return n_pucch_res; +} + +/* Procedure for determining PUCCH assignment 10.1 36.213 */ +void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell, + srslte_pucch_cfg_t* cfg, + srslte_uci_cfg_t* uci_cfg, + srslte_uci_value_t* uci_value) +{ + // Drop CQI if there is collision with ACK + if ((!cfg->simul_cqi_ack || uci_cfg->ack.has_scell_ack) && uci_cfg->ack.nof_acks > 0 && uci_cfg->cqi.data_enable) { + uci_cfg->cqi.data_enable = false; + } + + cfg->format = get_format(cfg, uci_cfg, uci_value, cell->cp); + cfg->n_pucch = get_npucch(cfg, uci_cfg, uci_value, cell); + + if (uci_value) { + if (cfg->format == SRSLTE_PUCCH_FORMAT_3) { + uint8_t* b = uci_value->ack.ack_value; + uint8_t temp[SRSLTE_UCI_MAX_ACK_BITS + 1]; + + uint32_t k = uci_cfg->ack.nof_acks; + for (; k < uci_cfg->ack.nof_acks; k++) { + temp[k] = (uint8_t)((b[k] == 1) ? 1 : 0); + } + memcpy(temp, uci_value->ack.ack_value, uci_cfg->ack.nof_acks); + if (uci_cfg->is_scheduling_request_tti) { + temp[uci_cfg->ack.nof_acks] = (uint8_t)(uci_value->scheduling_request ? 1 : 0); + k++; + } + srslte_uci_encode_ack_sr_pucch3(temp, k, b); + for (k = 32; k < SRSLTE_PUCCH3_NOF_BITS; k++) { + b[k] = b[k % 32]; + } + } + } +} + +/* Choose PUCCH format as in Sec 10.1 of 36.213 and generate PUCCH signal + */ +static int +pucch_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, srslte_uci_value_t* uci_data) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && cfg != NULL) { + + ret = SRSLTE_ERROR; + + if (!srslte_pucch_cfg_isvalid(&cfg->ul_cfg.pucch, q->cell.nof_prb)) { + ERROR("Invalid PUCCH configuration\n"); + return ret; + } + + bzero(q->sf_symbols, sizeof(cf_t) * SRSLTE_NOF_RE(q->cell)); + + // Prepare configuration + srslte_ue_ul_pucch_resource_selection(&q->cell, &cfg->ul_cfg.pucch, &cfg->ul_cfg.pucch.uci_cfg, uci_data); + + srslte_refsignal_srs_pucch_shortened(&q->signals, sf, &cfg->ul_cfg.srs, &cfg->ul_cfg.pucch); + + if (srslte_pucch_encode(&q->pucch, sf, &cfg->ul_cfg.pucch, uci_data, q->sf_symbols)) { + ERROR("Error encoding TB\n"); + return ret; + } + + if (srslte_refsignal_dmrs_pucch_gen(&q->signals, sf, &cfg->ul_cfg.pucch, q->refsignal)) { + ERROR("Error generating PUSCH DMRS signals\n"); + return ret; + } + srslte_refsignal_dmrs_pucch_put(&q->signals, &cfg->ul_cfg.pucch, q->refsignal, q->sf_symbols); + + add_srs(q, cfg, sf->tti); + + srslte_ofdm_tx_sf(&q->fft); + + apply_cfo(q, cfg); + apply_norm(q, cfg, (float)q->cell.nof_prb / 15 / 10); + + ret = SRSLTE_SUCCESS; + } + + return ret; +} + /* Returns 1 if a SR needs to be sent at current_tti given I_sr, as defined in Section 10.1 of 36.213 */ -int srslte_ue_ul_sr_send_tti(uint32_t I_sr, uint32_t current_tti) { - uint32_t sr_periodicity; +int srslte_ue_ul_sr_send_tti(srslte_pucch_cfg_t* cfg, uint32_t current_tti) +{ + if (!cfg->sr_configured) { + return SRSLTE_SUCCESS; + } + uint32_t sr_periodicity; uint32_t sr_N_offset; + uint32_t I_sr = cfg->I_sr; + if (I_sr < 5) { sr_periodicity = 5; - sr_N_offset = I_sr; + sr_N_offset = I_sr; } else if (I_sr < 15) { sr_periodicity = 10; - sr_N_offset = I_sr-5; + sr_N_offset = I_sr - 5; } else if (I_sr < 35) { sr_periodicity = 20; - sr_N_offset = I_sr-15; + sr_N_offset = I_sr - 15; } else if (I_sr < 75) { sr_periodicity = 40; - sr_N_offset = I_sr-35; + sr_N_offset = I_sr - 35; } else if (I_sr < 155) { sr_periodicity = 80; sr_N_offset = I_sr-75; @@ -660,16 +959,78 @@ int srslte_ue_ul_sr_send_tti(uint32_t I_sr, uint32_t current_tti) { return SRSLTE_SUCCESS; } - -bool srslte_ue_ul_srs_tx_enabled(srslte_refsignal_srs_cfg_t *srs_cfg, uint32_t tti) { - 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; +bool srslte_ue_ul_gen_sr(srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, srslte_uci_data_t* uci_data, bool sr_request) +{ + uci_data->value.scheduling_request = false; + if (srslte_ue_ul_sr_send_tti(&cfg->ul_cfg.pucch, sf->tti)) { + if (sr_request) { + // Get I_sr parameter + uci_data->value.scheduling_request = true; } + uci_data->cfg.is_scheduling_request_tti = true; + return true; } - return false; + return false; } +#define uci_pending(cfg) (cfg.ack.nof_acks > 0 || cfg.cqi.data_enable || cfg.cqi.ri_len > 0) +int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, srslte_pusch_data_t* data) +{ + int ret = SRSLTE_SUCCESS; + + /* Convert DTX to NACK in channel-selection mode (Release 10 only)*/ + if (cfg->ul_cfg.pucch.ack_nack_feedback_mode != SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL) { + uint32_t dtx_count = 0; + for (uint32_t a = 0; a < cfg->ul_cfg.pusch.uci_cfg.ack.nof_acks; a++) { + if (data->uci.ack.ack_value[a] == 2) { + data->uci.ack.ack_value[a] = 0; + dtx_count++; + } + } + + /* If all bits are DTX, do not transmit HARQ */ + if (dtx_count == cfg->ul_cfg.pusch.uci_cfg.ack.nof_acks) { + cfg->ul_cfg.pusch.uci_cfg.ack.nof_acks = 0; + } + } + + if (cfg->grant_available) { + ret = pusch_encode(q, sf, cfg, data) ? -1 : 1; + } else if ((uci_pending(cfg->ul_cfg.pucch.uci_cfg) || data->uci.scheduling_request) && + cfg->cc_idx == 0) { // Send PUCCH over PCell only + if (!cfg->ul_cfg.pucch.rnti) { + cfg->ul_cfg.pucch.rnti = q->current_rnti; + if (!q->current_rnti) { + printf("PUCCH: Warning PUCCH rnti or current_rnti are not set\n"); + } + } + ret = pucch_encode(q, sf, cfg, &data->uci) ? -1 : 1; + } else if (srs_tx_enabled(&cfg->ul_cfg.srs, sf->tti)) { + ret = srs_encode(q, sf->tti, cfg) ? -1 : 1; + } + + return ret; +} + +bool srslte_ue_ul_info( + srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, srslte_uci_value_t* uci_data, char* str, uint32_t str_len) +{ + uint32_t n = 0; + bool ret = false; + + if (cfg->grant_available) { + n = snprintf(str, str_len, "PUSCH: cc=%d, tti_tx=%d, %s", cfg->cc_idx, sf->tti, sf->shortened ? "shortened, " : ""); + srslte_pusch_tx_info(&cfg->ul_cfg.pusch, uci_data, &str[n], str_len - n); + ret = true; + } else if ((uci_pending(cfg->ul_cfg.pucch.uci_cfg) || uci_data->scheduling_request) && + cfg->cc_idx == 0) { // Send PUCCH over PCell only + n = sprintf(str, "PUCCH: cc=0, tti_tx=%d, %s", sf->tti, sf->shortened ? "shortened, " : ""); + srslte_pucch_tx_info(&cfg->ul_cfg.pucch, uci_data, &str[n], str_len - n); + ret = true; + } else if (srs_tx_enabled(&cfg->ul_cfg.srs, sf->tti)) { + n = sprintf(str, "SRS: tx_tti=%d", sf->tti); + ret = true; + } + return ret; +} diff --git a/lib/src/phy/utils/convolution.c b/lib/src/phy/utils/convolution.c index 59807ad5b..3ad798a89 100644 --- a/lib/src/phy/utils/convolution.c +++ b/lib/src/phy/utils/convolution.c @@ -24,10 +24,9 @@ * */ - +#include "srslte/srslte.h" #include #include -#include #include "srslte/phy/dft/dft.h" #include "srslte/phy/utils/vector.h" @@ -50,15 +49,15 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_ return SRSLTE_ERROR; } if (srslte_dft_plan(&q->input_plan,q->output_len,SRSLTE_DFT_FORWARD,SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error initiating input plan\n"); + ERROR("Error initiating input plan\n"); return SRSLTE_ERROR; } if (srslte_dft_plan(&q->filter_plan,q->output_len,SRSLTE_DFT_FORWARD,SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error initiating filter plan\n"); + ERROR("Error initiating filter plan\n"); return SRSLTE_ERROR; } if (srslte_dft_plan(&q->output_plan,q->output_len,SRSLTE_DFT_BACKWARD,SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error initiating output plan\n"); + ERROR("Error initiating output plan\n"); return SRSLTE_ERROR; } srslte_dft_plan_set_norm(&q->input_plan, true); @@ -70,7 +69,7 @@ int srslte_conv_fft_cc_init(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_ int srslte_conv_fft_cc_replan(srslte_conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { if (input_len > q->max_input_len || filter_len > q->max_filter_len) { - fprintf(stderr, "Error in conv_fft_cc_replan(): input_len and filter_len must be lower than initialized\n"); + ERROR("Error in conv_fft_cc_replan(): input_len and filter_len must be lower than initialized\n"); return -1; } @@ -82,15 +81,15 @@ int srslte_conv_fft_cc_replan(srslte_conv_fft_cc_t *q, uint32_t input_len, uint3 return SRSLTE_ERROR; } if (srslte_dft_replan(&q->input_plan,q->output_len)) { - fprintf(stderr, "Error initiating input plan\n"); + ERROR("Error initiating input plan\n"); return SRSLTE_ERROR; } if (srslte_dft_replan(&q->filter_plan,q->output_len)) { - fprintf(stderr, "Error initiating filter plan\n"); + ERROR("Error initiating filter plan\n"); return SRSLTE_ERROR; } if (srslte_dft_replan(&q->output_plan,q->output_len)) { - fprintf(stderr, "Error initiating output plan\n"); + ERROR("Error initiating output plan\n"); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; diff --git a/lib/src/phy/utils/mat.c b/lib/src/phy/utils/mat.c index 55b1dc177..a1f303525 100644 --- a/lib/src/phy/utils/mat.c +++ b/lib/src/phy/utils/mat.c @@ -27,7 +27,6 @@ #include #include -#include #include "srslte/phy/utils/mat.h" diff --git a/lib/src/phy/common/phy_logger.c b/lib/src/phy/utils/phy_logger.c similarity index 79% rename from lib/src/phy/common/phy_logger.c rename to lib/src/phy/utils/phy_logger.c index 5a44e1a58..449030d2c 100644 --- a/lib/src/phy/common/phy_logger.c +++ b/lib/src/phy/utils/phy_logger.c @@ -1,19 +1,14 @@ -/** +/* + * Copyright 2013-2019 Software Radio Systems Limited * - * \section COPYRIGHT + * This file is part of srsLTE. * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify + * 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. * - * srsUE is distributed in the hope that it will be useful, + * 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. @@ -24,17 +19,17 @@ * */ +#include "srslte/phy/utils/phy_logger.h" +#include "srslte/srslte.h" #include #include -#include +#include #include +#include #include #include -#include -#include "srslte/srslte.h" -#include "srslte/phy/common/phy_logger.h" /********************************************************************* - Functions for external logging + Functions for external logging *********************************************************************/ static phy_log_handler_t phy_log_handler; static void *callback_ctx = NULL; diff --git a/lib/src/phy/utils/ringbuffer.c b/lib/src/phy/utils/ringbuffer.c index 346b27c36..8f8ab4563 100644 --- a/lib/src/phy/utils/ringbuffer.c +++ b/lib/src/phy/utils/ringbuffer.c @@ -2,6 +2,7 @@ #include #include +#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/ringbuffer.h" #include "srslte/phy/utils/vector.h" @@ -65,8 +66,8 @@ int srslte_ringbuffer_write(srslte_ringbuffer_t *q, void *p, int nof_bytes) return 0; } if (q->count + w_bytes > q->capacity) { - w_bytes = q->capacity - q->count; - fprintf(stderr, "Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); + w_bytes = q->capacity - q->count; + ERROR("Buffer overrun: lost %d bytes\n", nof_bytes - w_bytes); } if (w_bytes > q->capacity - q->wpm) { int x = q->capacity - q->wpm; diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c index 03e33305b..88f6ae7b9 100644 --- a/lib/src/phy/utils/test/vector_test.c +++ b/lib/src/phy/utils/test/vector_test.c @@ -24,15 +24,15 @@ * */ -#include -#include -#include +#include "srslte/srslte.h" #include +#include +#include #include +#include +#include #include -#include -#include -#include +#include #include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/simd.h" diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 367b18f32..e4328d314 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -31,11 +31,10 @@ #include #include +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector_simd.h" -#include "srslte/phy/utils/bit.h" - - void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, const uint32_t len) { srslte_vec_xor_bbb_simd(x, y, z, len); @@ -233,7 +232,7 @@ void srslte_vec_sprint_hex(char *str, const uint32_t max_str_len, uint8_t *x, co nbytes = len/8; // check that hex string fits in buffer (every byte takes 3 characters, plus brackets) if ((3*(len/8 + ((len%8)?1:0))) + 2 >= max_str_len) { - fprintf(stderr, "Buffer too small for printing hex string (max_str_len=%d, payload_len=%d).\n", max_str_len, len); + ERROR("Buffer too small for printing hex string (max_str_len=%d, payload_len=%d).\n", max_str_len, len); return; } diff --git a/lib/src/phy/utils/vector_simd.c b/lib/src/phy/utils/vector_simd.c index 1143219b6..72cc91336 100644 --- a/lib/src/phy/utils/vector_simd.c +++ b/lib/src/phy/utils/vector_simd.c @@ -32,7 +32,6 @@ #include #include -#include #include "srslte/phy/utils/vector_simd.h" #include "srslte/phy/utils/simd.h" diff --git a/lib/src/radio/CMakeLists.txt b/lib/src/radio/CMakeLists.txt index 7fa479f8c..5ef709a7b 100644 --- a/lib/src/radio/CMakeLists.txt +++ b/lib/src/radio/CMakeLists.txt @@ -19,7 +19,7 @@ # if(RF_FOUND) - add_library(srslte_radio STATIC radio.cc radio_multi.cc) + add_library(srslte_radio STATIC radio.cc radio_multi.cc radio_sync.cc) target_link_libraries(srslte_radio srslte_rf) install(TARGETS srslte_radio DESTINATION ${LIBRARY_DIR}) endif(RF_FOUND) diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 4e0a442ef..975cc9535 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -28,19 +28,23 @@ extern "C" { #include "srslte/phy/rf/rf.h" } +#include "srslte/common/log_filter.h" #include "srslte/radio/radio.h" #include #include +uint32_t zero_tti = 0; + namespace srslte { -bool radio::init(char *args, char *devname, uint32_t nof_channels) +bool radio::init(log_filter* _log_h, char* args, char* devname, uint32_t nof_channels, bool enable_synch) { if (srslte_rf_open_devname(&rf_device, devname, args, nof_channels)) { - fprintf(stderr, "Error opening RF device\n"); + ERROR("Error opening RF device\n"); return false; } - + + log_h = _log_h; tx_adv_negative = false; agc_enabled = false; burst_preamble_samples = 0; @@ -60,7 +64,8 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels) burst_preamble_sec = blade_default_burst_preamble_sec; } else { burst_preamble_sec = 0; - printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); + log_h->console("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", + srslte_rf_name(&rf_device)); } if (args) { @@ -71,6 +76,19 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels) } saved_nof_channels = nof_channels; + if (enable_synch) { + sync = new radio_sync(); + if (sync) { + if (!sync->init(&rf_device)) { + ERROR("Error: initiating radio synchronization.\n"); + return false; + } + } else { + ERROR("Error: creating radio synchronization.\n"); + return false; + } + } + is_initialized = true; return true; } @@ -81,14 +99,23 @@ bool radio::is_init() { void radio::stop() { + if (zeros) { + free(zeros); + zeros = NULL; + } if (is_initialized) { srslte_rf_close(&rf_device); } + + if (sync) { + delete sync; + sync = NULL; + } } void radio::reset() { - printf("Resetting Radio...\n"); + log_h->console("Resetting Radio...\n"); srslte_rf_stop_rx_stream(&rf_device); radio_is_streaming = false; usleep(100000); @@ -128,7 +155,7 @@ void radio::set_tx_adv_neg(bool tx_adv_is_neg) { bool radio::start_agc(bool tx_gain_same_rx) { if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) { - fprintf(stderr, "Error opening RF device\n"); + ERROR("Error starting AGC Thread RF device\n"); return false; } @@ -136,30 +163,67 @@ bool radio::start_agc(bool tx_gain_same_rx) return true; } -bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) +bool radio::rx_at(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time) { - fprintf(stderr, "Not implemented\n"); + ERROR("Not implemented\n"); return false; } -bool radio::rx_now(void* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) +bool radio::rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) { - if (!radio_is_streaming) { - srslte_rf_start_rx_stream(&rf_device, false); + bool ret = true; + if (sync) { + sync->issue_rx(buffer, nof_samples, rxd_time, !radio_is_streaming); radio_is_streaming = true; - } - if (srslte_rf_recv_with_time_multi(&rf_device, buffer, nof_samples, true, - rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { - return true; } else { - return false; + if (!radio_is_streaming) { + srslte_rf_start_rx_stream(&rf_device, false); + radio_is_streaming = true; + } + + time_t* full_secs = rxd_time ? &rxd_time->full_secs : NULL; + double* frac_secs = rxd_time ? &rxd_time->frac_secs : NULL; + + if (srslte_rf_recv_with_time_multi(&rf_device, (void**)buffer, nof_samples, true, full_secs, frac_secs) > 0) { + ret = true; + } else { + ret = false; + } } + + if (zero_tti) { + bzero(buffer[0], sizeof(cf_t) * nof_samples); + zero_tti--; + if (!zero_tti) { + printf("-- end of zeros\n"); + } + } + + return ret; } void radio::get_time(srslte_timestamp_t *now) { srslte_rf_get_time(&rf_device, &now->full_secs, &now->frac_secs); } +int radio::synch_wait() +{ + int ret = SRSLTE_ERROR; + + if (sync) { + ret = sync->wait(); + } + + return ret; +} + +void radio::synch_issue() +{ + if (sync) { + sync->issue_sync(); + } +} + // TODO: Use Calibrated values for this float radio::set_tx_power(float power) { @@ -195,10 +259,11 @@ bool radio::is_first_of_burst() { #define BLOCKING_TX true -bool radio::tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) { - void *_buffer[SRSLTE_MAX_PORTS]; +bool radio::tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) +{ + cf_t* _buffer[SRSLTE_MAX_PORTS]; - _buffer[0] = buffer; + _buffer[0] = (buffer) ? buffer : zeros; for (int p = 1; p < SRSLTE_MAX_PORTS; p++) { _buffer[p] = zeros; } @@ -206,7 +271,8 @@ bool radio::tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_ return this->tx(_buffer, nof_samples, tx_time); } -bool radio::tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) { +bool radio::tx(cf_t* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) +{ if (!tx_adv_negative) { srslte_timestamp_sub(&tx_time, 0, tx_adv_sec); } else { @@ -217,21 +283,31 @@ bool radio::tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_time if (burst_preamble_samples != 0) { srslte_timestamp_t tx_time_pad; srslte_timestamp_copy(&tx_time_pad, &tx_time); - srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); - save_trace(1, &tx_time_pad); - srslte_rf_send_timed_multi(&rf_device, buffer, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); - is_start_of_burst = false; + srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded); + srslte_rf_send_timed_multi(&rf_device, + (void**)buffer, + burst_preamble_samples, + tx_time_pad.full_secs, + tx_time_pad.frac_secs, + true, + true, + false); + is_start_of_burst = false; } } // Save possible end of burst time srslte_timestamp_copy(&end_of_burst_time, &tx_time); - srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate); - - save_trace(0, &tx_time); - int ret = srslte_rf_send_timed_multi(&rf_device, buffer, nof_samples, - tx_time.full_secs, tx_time.frac_secs, - BLOCKING_TX, is_start_of_burst, false); + srslte_timestamp_add(&end_of_burst_time, 0, (double)nof_samples / cur_tx_srate); + + int ret = srslte_rf_send_timed_multi(&rf_device, + (void**)buffer, + nof_samples, + tx_time.full_secs, + tx_time.frac_secs, + BLOCKING_TX, + is_start_of_burst, + false); is_start_of_burst = false; if (ret > 0) { return true; @@ -243,46 +319,22 @@ bool radio::tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_time void radio::tx_end() { if (!is_start_of_burst) { - save_trace(2, &end_of_burst_time); srslte_rf_send_timed2(&rf_device, zeros, 0, end_of_burst_time.full_secs, end_of_burst_time.frac_secs, false, true); - is_start_of_burst = true; + is_start_of_burst = true; } } -void radio::start_trace() { - trace_enabled = true; -} - void radio::set_tti(uint32_t tti_) { tti = tti_; } -void radio::write_trace(std::string filename) -{ - tr_local_time.writeToBinary(filename + ".local"); - tr_is_eob.writeToBinary(filename + ".eob"); - tr_usrp_time.writeToBinary(filename + ".usrp"); - tr_tx_time.writeToBinary(filename + ".tx"); -} - -void radio::save_trace(uint32_t is_eob, srslte_timestamp_t *tx_time) { - if (trace_enabled) { - tr_local_time.push_cur_time_us(tti); - srslte_timestamp_t usrp_time; - srslte_rf_get_time(&rf_device, &usrp_time.full_secs, &usrp_time.frac_secs); - tr_usrp_time.push(tti, srslte_timestamp_uint32(&usrp_time)); - tr_tx_time.push(tti, srslte_timestamp_uint32(tx_time)); - tr_is_eob.push(tti, is_eob); - } -} - void radio::set_freq_offset(double freq) { freq_offset = freq; } -void radio::set_rx_freq(double freq) +void radio::set_rx_freq(uint32_t ch, double freq) { - rx_freq = srslte_rf_set_rx_freq(&rf_device, freq+freq_offset); + rx_freq = srslte_rf_set_rx_freq(&rf_device, ch, freq + freq_offset); } void radio::set_rx_gain(float gain) @@ -297,7 +349,9 @@ double radio::set_rx_gain_th(float gain) void radio::set_master_clock_rate(double rate) { + srslte_rf_stop_rx_stream(&rf_device); srslte_rf_set_master_clock_rate(&rf_device, rate); + srslte_rf_start_rx_stream(&rf_device, false); } void radio::set_rx_srate(double srate) @@ -305,9 +359,9 @@ void radio::set_rx_srate(double srate) srslte_rf_set_rx_srate(&rf_device, srate); } -void radio::set_tx_freq(double freq) +void radio::set_tx_freq(uint32_t ch, double freq) { - tx_freq = srslte_rf_set_tx_freq(&rf_device, freq+freq_offset); + tx_freq = srslte_rf_set_tx_freq(&rf_device, ch, freq + freq_offset); } void radio::set_tx_gain(float gain) @@ -346,7 +400,6 @@ void radio::set_tx_srate(double srate) burst_preamble_samples = (uint32_t) (cur_tx_srate * burst_preamble_sec); if (burst_preamble_samples > burst_preamble_max_samples) { fprintf(stderr, "Error setting TX srate %.1f MHz. Maximum burst preamble samples: %d, requested: %d\n", srate*1e-6, burst_preamble_max_samples, burst_preamble_samples ); - burst_preamble_samples = burst_preamble_max_samples; } burst_preamble_time_rounded = (double) burst_preamble_samples/cur_tx_srate; @@ -355,9 +408,9 @@ void radio::set_tx_srate(double srate) if (tx_adv_auto) { /* This values have been calibrated using the prach_test_usrp tool in srsLTE */ - + if (!strcmp(srslte_rf_name(&rf_device), "uhd_b200")) { - + double srate_khz = round(cur_tx_srate/1e3); if (srate_khz == 1.92e3) { // 6 PRB @@ -370,25 +423,27 @@ void radio::set_tx_srate(double srate) nsamples = 92; } else if (srate_khz == 11.52e3) { // 50 PRB - nsamples = 171; + nsamples = 167; } else if (srate_khz == 15.36e3) { // 75 PRB - nsamples = 171; + nsamples = 165; } else if (srate_khz == 23.04e3) { // 100 PRB - nsamples = 171; + nsamples = 160; } else { /* Interpolate from known values */ - printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + log_h->console( + "\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", + cur_tx_srate); nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); } }else if(!strcmp(srslte_rf_name(&rf_device), "uhd_usrp2")) { double srate_khz = round(cur_tx_srate/1e3); - if (srate_khz == 1.92e3) { - nsamples = 14;// estimated - } else if (srate_khz == 3.84e3) { - nsamples = 32; + if (srate_khz == 1.92e3) { + nsamples = 14; // estimated + } else if (srate_khz == 3.84e3) { + nsamples = 32; } else if (srate_khz == 5.76e3) { nsamples = 43; } else if (srate_khz == 11.52e3) { @@ -399,7 +454,9 @@ void radio::set_tx_srate(double srate) nsamples = 80; // to calc } else { /* Interpolate from known values */ - printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + log_h->console( + "\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", + cur_tx_srate); nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); } @@ -419,7 +476,9 @@ void radio::set_tx_srate(double srate) nsamples = 76; } else { /* Interpolate from known values */ - printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + log_h->console( + "\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", + cur_tx_srate); nsamples = cur_tx_srate*(uhd_default_tx_adv_samples * (1/cur_tx_srate) + uhd_default_tx_adv_offset_sec); } @@ -435,24 +494,27 @@ void radio::set_tx_srate(double srate) } else if (srate_khz == 3.84e3) { nsamples = 18; } else if (srate_khz == 5.76e3) { - nsamples = 16; + nsamples = 16; } else if (srate_khz == 11.52e3) { - nsamples = 21; + nsamples = 21; } else if (srate_khz == 15.36e3) { nsamples = 14; } else if (srate_khz == 23.04e3) { - nsamples = 21; + nsamples = 21; } else { /* Interpolate from known values */ - printf("\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", cur_tx_srate); + log_h->console( + "\nWarning TX/RX time offset for sampling rate %.0f KHz not calibrated. Using interpolated value\n\n", + cur_tx_srate); tx_adv_sec = blade_default_tx_adv_samples * (1/cur_tx_srate) + blade_default_tx_adv_offset_sec; } } else { - printf("\nWarning TX/RX time offset has not been calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); + log_h->console("\nWarning TX/RX time offset has not been calibrated for device %s. Set a value manually\n\n", + srslte_rf_name(&rf_device)); } } else { - nsamples = tx_adv_nsamples; - printf("Setting manual TX/RX offset to %d samples\n", nsamples); + nsamples = tx_adv_nsamples; + log_h->console("Setting manual TX/RX offset to %d samples\n", nsamples); } // Calculate TX advance in seconds from samples and sampling rate diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc index 43160c499..82243f531 100644 --- a/lib/src/radio/radio_multi.cc +++ b/lib/src/radio/radio_multi.cc @@ -1,64 +1,568 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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 "srslte/radio/radio_multi.h" +using namespace std; + +#define RADIO_INFO(_fmt, ...) INFO("[radio_multi] " _fmt, ##__VA_ARGS__) +#define RADIO_DEBUG(_fmt, ...) DEBUG("[radio_multi] " _fmt, ##__VA_ARGS__) + namespace srslte { - -bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname) + +radio_multi::radio_multi() { + log_h = NULL; + initiated = false; + radios.clear(); + rx_srate = 1.92e6; + bzero(ts_rx, sizeof(ts_rx)); + bzero(temp_buffers, sizeof(temp_buffers)); + bzero(&mutex, sizeof(mutex)); + locked = false; + nof_ports = 1; +} + +bool radio_multi::init( + log_filter* _log_h, char* args[SRSLTE_MAX_RADIOS], char* devname, uint32_t nof_radios, uint32_t nof_rf_ports) { - if (srslte_rf_open_devname(&rf_device, devname, args, nof_rx_antennas)) { - fprintf(stderr, "Error opening RF device\n"); - return false; - } - - tx_adv_negative = false; - agc_enabled = false; - burst_preamble_samples = 0; - burst_preamble_time_rounded = 0; - cur_tx_srate = 0; - is_start_of_burst = true; - - // Suppress radio stdout - srslte_rf_suppress_stdout(&rf_device); - - continuous_tx = true; - tx_adv_auto = true; - // Set default preamble length each known device - // We distinguish by device family, maybe we should calibrate per device - if (strstr(srslte_rf_name(&rf_device), "uhd")) { - burst_preamble_sec = uhd_default_burst_preamble_sec; - } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { - burst_preamble_sec = blade_default_burst_preamble_sec; - } else { - printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); + bool ret = true; + + log_h = _log_h; + + if (nof_radios == 0 || nof_radios > SRSLTE_MAX_RADIOS) { + ERROR("Wrong number of radios (%d)\n", nof_radios); + ret = false; } - if (args) { - strncpy(saved_args, args, 127); + /* Create and initiate radios */ + for (size_t i = 0; i < nof_radios && ret; i++) { + radio *r = new radio(); + if (!r->init(_log_h, args ? args[i] : NULL, devname, nof_rf_ports, nof_radios > 1)) { + ERROR("Error initiating radio index %ld\n", i); + ret = false; + } + radios.push_back(r); } - if (devname) { - strncpy(saved_devname, devname, 127); + + for (size_t r = 0; r < nof_radios && ret; r++) { + for (size_t i = 0; i < nof_rf_ports && ret; i++) { + temp_buffers[r][i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * TEMP_BUFFER_SIZE); + if (!temp_buffers[r][i]) { + ret = false; + } + } } - is_initialized = true; - return true; + pthread_mutex_init(&mutex, NULL); + + RADIO_INFO("Initiated\n"); + + initiated = ret; + nof_ports = nof_rf_ports; + + return ret; +} + +void radio_multi::synch_issue() { + RADIO_INFO("Issuing PPS synchronization\n"); + + /* If more than one radio, synchronize radios */ + if (radios.size() > 1) { + bool aligned; + bool ret = true; /* TODO: currently ignored */ + + do { + /* Issue PPS synchronising and wait */ + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->synch_issue(); + } + synch_wait(); + + /* Issue some Rx for checking initial alignment and wait */ + for (size_t i = 0; i < radios.size(); i++) { + /* Receive each radio */ + ret &= radios[i]->rx_now(temp_buffers[i], TEMP_BUFFER_SIZE, &ts_rx[i]); + } + synch_wait(); + + /* Align radios */ + aligned = align_radio_ts(); + + if (!aligned) { + RADIO_INFO("Issuing PPS synchronization\n"); + } + + /* If it was not possible to align, keep trying */ + } while (!aligned); + } } -bool radio_multi::rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) +bool radio_multi::synch_wait() { + + bool ret = true; + + if (radios.size() > 1) { + /* Wait for PPS synchronization */ + for (size_t i = 0; i < radios.size(); i++) { + RADIO_DEBUG("Waiting for radio %ld to finish PPS synchronization\n", i); + int err = radios[i]->synch_wait(); + if (err) { + ERROR("Error receiving from radio %ld, it does not support PPS synchronization\n", i); + ret &= false; + } + } + } + + return ret; +} + +void radio_multi::stop() { + RADIO_INFO("Stopping...\n"); + pthread_mutex_destroy(&mutex); + + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->stop(); + delete radios[i]; + } + + for (size_t r = 0; r < SRSLTE_MAX_RADIOS; r++) { + for (size_t i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (temp_buffers[r][i]) { + free(temp_buffers[r][i]); + } + } + } +} + +void radio_multi::reset() { + RADIO_INFO("Reseting...\n"); + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->reset(); + } +} + +bool radio_multi::start_agc(bool tx_gain_same_rx) { + bool ret = true; + + RADIO_INFO("Start AGC\n"); + + for (size_t i = 0; i < radios.size(); i++) { + ret &= radios[i]->start_agc(tx_gain_same_rx); + } + return ret; +} + +void radio_multi::set_burst_preamble(double preamble_us) { + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_burst_preamble(preamble_us); + } +} + +void radio_multi::set_tx_adv(int nsamples) { + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tx_adv(nsamples); + } +} + +void radio_multi::set_tx_adv_neg(bool tx_adv_is_neg) { + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tx_adv_neg(tx_adv_is_neg); + } +} + +bool radio_multi::is_continuous_tx() { + bool ret = false; + for (size_t i = 0; i < radios.size(); i++) { + ret |= radios[i]->is_continuous_tx(); + } + return ret; +} + +void radio_multi::set_continuous_tx(bool enable) { + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_continuous_tx(enable); + } +} + +bool radio_multi::tx_single(cf_t* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) { - void *ptr[SRSLTE_MAX_PORTS]; - for (int i=0;itx_single(buffer, nof_samples, tx_time); + + RADIO_DEBUG("Tx (Single) %d samples at %.9f\n", nof_samples, srslte_timestamp_real(&tx_time)); + + return ret; +} + +bool radio_multi::tx(cf_t *buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time) { + bool ret = true; + RADIO_DEBUG("Tx %d samples at %.9f\n", nof_samples, srslte_timestamp_real(&tx_time)); + for (size_t i = 0; i < radios.size(); i++) { + ret &= radios[i]->tx(buffer[i], nof_samples, tx_time); } - if (!radio_is_streaming) { - srslte_rf_start_rx_stream(&rf_device, false); - radio_is_streaming = true; + + return ret; +} + +void radio_multi::tx_end() { + RADIO_INFO("Tx end\n"); + + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->tx_end(); } - if (srslte_rf_recv_with_time_multi(&rf_device, ptr, nof_samples, true, - rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { - return true; +} + +bool radio_multi::rx_now(cf_t *buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], + uint32_t nof_samples, + srslte_timestamp_t *rxd_time) { + bool ret = true; + + if (locked) { + /* If locked dont even try to get samples, but set input buffers to zeros */ + for (size_t i = 0; i < radios.size(); i++) { + for (size_t p = 0; p < nof_ports; p++) { + if (buffer[i][p]) { + bzero(buffer[i][p], sizeof(cf_t) * nof_samples); + } + } + } + if (rxd_time) { + rxd_time->full_secs = 0; + rxd_time->frac_secs = 0; + } + } else if (initiated) { + + pthread_mutex_lock(&mutex); + + for (size_t i = 0; i < radios.size(); i++) { + /* Check buffer pointer integrity */ + for (size_t p = 0; p < SRSLTE_MAX_PORTS; p++) { + if (!buffer[i][p]) { + buffer[i][p] = temp_buffers[i][p]; + } + } + + /* Receive each radio */ + ret &= radios[i]->rx_now(buffer[i], nof_samples, &ts_rx[i]); + } + + synch_wait(); + + srslte_timestamp_copy(rxd_time, &ts_rx[0]); + + /* If more than 1 radio, align all radio timestamps. If alignment fails, issue PPS synchronization */ + if (radios.size() > 1) { + if (!align_radio_ts()) { + synch_issue(); + } + } + + pthread_mutex_unlock(&mutex); + } else { - return false; + ret = false; + } + + + return ret; +} + +void radio_multi::set_tx_gain(float gain, uint32_t radio_idx) { + if (radio_idx < radios.size()) { + RADIO_INFO("Set radio %d Tx gain to %.2f\n", radio_idx, gain); + radios[radio_idx]->set_tx_gain(gain); + } else if (radio_idx == UINT32_MAX) { + RADIO_INFO("Set radio all %d Tx gain to %.2f\n", radio_idx, gain); + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tx_gain(gain); + } } } - -} \ No newline at end of file +void radio_multi::set_rx_gain(float gain, uint32_t radio_idx) { + if (radio_idx < radios.size()) { + RADIO_INFO("Set radio %d Rx gain to %.2f\n", radio_idx, gain); + radios[radio_idx]->set_rx_gain(gain); + } else if (radio_idx == UINT32_MAX) { + RADIO_INFO("Set radio all %d Tx gain to %.2f\n", radio_idx, gain); + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_rx_gain(gain); + } + } +} + +void radio_multi::set_tx_rx_gain_offset(float offset) { + RADIO_INFO("Set Tx/Rx gain offset to %.2f\n", offset); + + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tx_rx_gain_offset(offset); + } +} + +double radio_multi::set_rx_gain_th(float gain) { + RADIO_INFO("Set Rx gain Threshold to %.2f\n", gain); + + double ret = 0.0f; + for (size_t i = 0; i < radios.size(); i++) { + ret = radios[i]->set_rx_gain_th(gain); + } + return ret; +} + +void radio_multi::set_freq_offset(double freq) { + RADIO_INFO("Set frequency offset to %.3f Hz\n", freq); + + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_freq_offset(freq); + } +} + +void radio_multi::set_tx_freq(double freq, uint32_t radio_idx) { + if (radio_idx < radios.size()) { + RADIO_INFO("Set radio %d Tx frequency to %.3f MHz\n", radio_idx, freq * 1e-6); + radios[radio_idx]->set_tx_freq(0, freq); + } else if (radio_idx == UINT32_MAX) { + RADIO_INFO("Set all radio Tx frequency to %.3f MHz\n", freq * 1e-6); + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tx_freq(0, freq); + } + } +} + +void radio_multi::set_rx_freq(double freq, uint32_t radio_idx) { + if (radio_idx < radios.size()) { + RADIO_INFO("Set radio %d Rx frequency to %.3f MHz\n", radio_idx, freq * 1e-6); + radios[radio_idx]->set_rx_freq(0, freq); + } else if (radio_idx == UINT32_MAX) { + RADIO_INFO("Set all radio Rx frequency to %.3f MHz\n", freq * 1e-6); + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_rx_freq(0, freq); + } + } +} + +double radio_multi::get_freq_offset() { + return radios[0]->get_freq_offset(); +} + +double radio_multi::get_tx_freq(uint32_t radio_idx) { + return radios[radio_idx]->get_tx_freq(); +} + +double radio_multi::get_rx_freq(uint32_t radio_idx) { + return radios[radio_idx]->get_rx_freq(); +} + +void radio_multi::set_master_clock_rate(double rate) { + locked = true; + + RADIO_INFO("Set master clock rate to %.3f MHz\n", rate * 1e-6); + + pthread_mutex_lock(&mutex); + + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_master_clock_rate(rate); + } + + /* Issue synchronization */ + synch_issue(); + + pthread_mutex_unlock(&mutex); + locked = false; +} + +void radio_multi::set_tx_srate(double srate) { + RADIO_INFO("Set Tx srate to %.3f MHz\n", srate * 1e-6); + + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tx_srate(srate); + } + +} + +void radio_multi::set_rx_srate(double srate) { + RADIO_INFO("Set Rx srate to %.3f MHz\n", srate * 1e-6); + + rx_srate = srate; + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_rx_srate(srate); + } +} + +float radio_multi::get_tx_gain(uint32_t radio_idx) { + float ret = NAN; + + if (radio_idx < radios.size()) { + ret = radios[radio_idx]->get_tx_gain(); + } + + return ret; +} + +float radio_multi::get_rx_gain(uint32_t radio_idx) { + float ret = NAN; + + if (radio_idx < radios.size()) { + ret = radios[radio_idx]->get_rx_gain(); + } + + return ret; +} + +float radio_multi::get_max_tx_power() { + return radios[0]->get_max_tx_power(); +} + +float radio_multi::set_tx_power(float power) { + float ret = 0.0f; + for (size_t i = 0; i < radios.size(); i++) { + ret += radios[i]->set_tx_power(power); + } + return ret / radios.size(); +} + +float radio_multi::get_rssi() { + return radios[0]->get_rssi(); +} + +bool radio_multi::has_rssi() { + return radios[0]->has_rssi(); +} + +void radio_multi::set_tti(uint32_t tti) { + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->set_tti(tti); + } +} + +bool radio_multi::is_init() { + bool ret = initiated; + for (size_t i = 0; i < radios.size() && ret; i++) { + ret &= radios[i]->is_init(); + } + + return ret; +} + +void radio_multi::register_error_handler(srslte_rf_error_handler_t h) { + for (size_t i = 0; i < radios.size(); i++) { + radios[i]->register_error_handler(h); + } +} + +/* + * This method aligns radios from their time stamp + * It returns true if the radios have been successfully aligned. Otherwise it returns false. + */ +bool radio_multi::align_radio_ts() { + bool aligned = true; + + /* Find newest timestamp */ + size_t newer_idx = 0; + srslte_timestamp_t ts_newer = {}, ts_diff = {}; + size_t nof_samples[SRSLTE_MAX_RADIOS] = {}; + size_t count_done = 0; + + /* Find highest timestamp */ + for (size_t i = 1; i < radios.size(); i++) { + + if (srslte_timestamp_compare(&ts_rx[i], &ts_rx[newer_idx]) == 1) { + newer_idx = i; + } + + srslte_timestamp_copy(&ts_newer, &ts_rx[newer_idx]); + } + + /* Calculate number of samples that each radio needs to advance */ + for (size_t i = 0; i < radios.size() && aligned; i++) { + + /* Calculate delayed time */ + srslte_timestamp_copy(&ts_diff, &ts_newer); + srslte_timestamp_sub(&ts_diff, ts_rx[i].full_secs, ts_rx[i].frac_secs); + + /* Compute number of samples */ + nof_samples[i] = (uint32_t) floor(srslte_timestamp_real(&ts_diff) * rx_srate); + + if (nof_samples[i] > MAX_NOF_ALIGN_SAMPLES) { + RADIO_INFO("The number of samples (%ld) to align is too large (>%ld), returning false\n", + nof_samples[i], + MAX_NOF_ALIGN_SAMPLES); + aligned = false; + + } else if (nof_samples[i]) { + RADIO_INFO("Aligning %ld samples of radio %ld (@%.2f) [%.9f-%.9f=%.9f] %ld\n", + nof_samples[i], + i, + rx_srate * 1e-6, + srslte_timestamp_real(&ts_newer), + srslte_timestamp_real(&ts_rx[i]), + srslte_timestamp_real(&ts_diff), + newer_idx); + } + + } + + /* Read samples */ + while (count_done < radios.size() && aligned) { + count_done = 0; + for (size_t i = 0; i < radios.size(); i++) { + if (nof_samples[i]) { + + size_t n = SRSLTE_MIN(TEMP_BUFFER_SIZE, nof_samples[i]); + radios[i]->rx_now(temp_buffers[i], n, NULL); + nof_samples[i] -= n; + } else { + count_done++; + } + } + + /* Synchronize radios */ + if (!synch_wait()) { + synch_issue(); + } + + } + + return aligned; +} + +radio *radio_multi::get_radio_ptr(uint32_t idx) { + radio *ret = NULL; + + if (idx < radios.size()) { + ret = radios[idx]; + } + + return ret; +} + +srslte_rf_info_t *radio_multi::get_info(uint32_t radio_idx) { + srslte_rf_info_t *ret = NULL; + + if (radio_idx < radios.size()) { + ret = radios[radio_idx]->get_info(); + } + + return ret; +} + +} diff --git a/lib/src/radio/radio_sync.cc b/lib/src/radio/radio_sync.cc new file mode 100644 index 000000000..206c4d90d --- /dev/null +++ b/lib/src/radio/radio_sync.cc @@ -0,0 +1,196 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/radio/radio_sync.h" +#include "srslte/srslte.h" + +namespace srslte { + +radio_sync::radio_sync() +{ + thread_args = NULL; +} + +typedef struct { + pthread_t pthread; + sem_t start; + sem_t finish; + int status; + srslte_rf_t* device; + uint32_t nsamples; + cf_t** data; + srslte_timestamp_t* timestamp; + bool running; + bool start_streaming; + bool receive; + bool synch; + bool exit; +} radio_synch_thread_t; + +static void* radio_synch_thread(void* ptr) +{ + radio_synch_thread_t* h = (radio_synch_thread_t*)ptr; + + do { + sem_wait(&h->start); + + if (!h->exit) { + if (h->synch) { + h->status = srslte_rf_sync(h->device); + } + + if (h->start_streaming) { + srslte_rf_start_rx_stream(h->device, false); + } + + if (h->receive) { + srslte_rf_recv_with_time_multi( + h->device, (void**)h->data, h->nsamples, true, &h->timestamp->full_secs, &h->timestamp->frac_secs); + } + } + + sem_post(&h->finish); + } while (!h->exit); + + return NULL; +} + +bool radio_sync::init(srslte_rf_t* device) +{ + bool ret = false; + radio_synch_thread_t* h = (radio_synch_thread_t*)calloc(sizeof(radio_synch_thread_t), 1); + if (!h) { + ERROR("Error: Allocating multiple radio synch thread parameters\n"); + goto clean_exit; + } + + thread_args = h; + h->device = device; + h->start_streaming = false; + h->synch = false; + h->running = false; + h->exit = false; + + /* Initialise semaphores */ + if (sem_init(&h->start, 0, 0)) { + ERROR("Error: creating start semaphore\n"); + goto clean_exit; + } + + if (sem_init(&h->finish, 0, 0)) { + ERROR("Error: creating start semaphore\n"); + goto clean_exit; + } + + /* Create thread */ + if (pthread_create(&h->pthread, NULL, &radio_synch_thread, h)) { + ERROR("Error: Allocating multiple radio synch thread parameters\n"); + goto clean_exit; + } + + ret = true; + +clean_exit: + if (!ret) { + delete this; + } + + return ret; +} + +radio_sync::~radio_sync() +{ + radio_synch_thread_t* h = (radio_synch_thread_t*)thread_args; + + if (h) { + h->exit = true; + sem_post(&h->start); + + pthread_join(h->pthread, NULL); + pthread_detach(h->pthread); + + sem_destroy(&h->start); + sem_destroy(&h->finish); + + free(h); + thread_args = NULL; + } +} + +void radio_sync::issue_sync() +{ + radio_synch_thread_t* h = (radio_synch_thread_t*)thread_args; + + if (h) { + h->running = true; + ZERO_OBJECT(h->data); + h->nsamples = 0; + h->timestamp = NULL; + h->synch = true; + h->start_streaming = false; + h->receive = false; + h->exit = false; + sem_post(&h->start); + } +} + +void radio_sync::issue_rx(cf_t* data[SRSLTE_MAX_PORTS], + uint32_t nsamples, + srslte_timestamp_t* timestamp, + bool start_streaming) +{ + radio_synch_thread_t* h = (radio_synch_thread_t*)thread_args; + + if (h) { + h->running = true; + h->data = data; + h->nsamples = nsamples; + h->timestamp = timestamp; + h->synch = start_streaming; + h->start_streaming = start_streaming; + h->receive = true; + h->exit = false; + sem_post(&h->start); + } +} + +int radio_sync::wait() +{ + int ret = SRSLTE_ERROR; + radio_synch_thread_t* h = (radio_synch_thread_t*)thread_args; + + if (h) { + if (h->running) { + sem_wait(&h->finish); + h->running = false; + ret = h->status; + } else { + ret = SRSLTE_SUCCESS; + } + } + + return ret; +} + +} diff --git a/lib/src/radio/test/CMakeLists.txt b/lib/src/radio/test/CMakeLists.txt index c44fd826e..005291bba 100644 --- a/lib/src/radio/test/CMakeLists.txt +++ b/lib/src/radio/test/CMakeLists.txt @@ -20,7 +20,8 @@ if(RF_FOUND) add_executable(benchmark_radio benchmark_radio.cc) - target_link_libraries(benchmark_radio srslte_radio) + target_link_libraries(benchmark_radio srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + endif(RF_FOUND) diff --git a/lib/src/radio/test/benchmark_radio.cc b/lib/src/radio/test/benchmark_radio.cc index 844624086..4b374ee31 100644 --- a/lib/src/radio/test/benchmark_radio.cc +++ b/lib/src/radio/test/benchmark_radio.cc @@ -25,61 +25,116 @@ */ #include -#include + #include "srslte/srslte.h" #include "srslte/radio/radio_multi.h" using namespace srslte; -std::string device_args = "auto"; +static char radios_args[SRSLTE_MAX_RADIOS][64] = {"auto", "auto", "auto"}; +log_filter log_h; +std::string file_pattern = "radio%d.dat"; double freq = 2630e6; -uint32_t nof_ports = 1; +uint32_t nof_radios = 1; +uint32_t nof_ports = 1; double srate = 1.92e6; /* Hz */ -double duration = 0.01; /* in seconds, 10 ms by default */ -cf_t *buffers[SRSLTE_MAX_PORTS]; +double duration = 0.01; /* in seconds, 10 ms by default */ +cf_t* buffers[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS]; bool tx_enable = false; - -uint32_t num_lates = 0; -uint32_t num_overflows = 0; -uint32_t num_underflows = 0; -uint32_t num_other_error = 0; - - -void usage(char *prog) { - printf("Usage: %s [rpstvh]\n", prog); +bool measure_delay = false; +bool capture = false; +bool agc_enable = true; +float rf_gain = -1.0; +static bool synchronised_radios = true; + +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +#include +static pthread_t plot_thread; +static sem_t plot_sem; +static uint32_t plot_sf_idx = 0; +static plot_real_t fft_plot[SRSLTE_MAX_RADIOS] = {}; +static cf_t* fft_plot_buffer[SRSLTE_MAX_RADIOS] = {}; +static float* fft_plot_temp = NULL; +static uint32_t fft_plot_buffer_size; +srslte_dft_plan_t dft_spectrum = {}; +#endif /* ENABLE_GUI */ + +static bool fft_plot_enable = false; + +void usage(char* prog) +{ + printf("Usage: %s [foabcderpstvhmFxw]\n", prog); printf("\t-f Carrier frequency in Hz [Default %f]\n", freq); - printf("\t-a Arguments for first radio [Default %s]\n", device_args.c_str()); + printf("\t-g RF gain [Default AGC]\n"); + printf("\t-a Arguments for first radio [Default %s]\n", radios_args[0]); + printf("\t-b Arguments for second radio [Default %s]\n", radios_args[1]); + printf("\t-c Arguments for third radio [Default %s]\n", radios_args[2]); + printf("\t-r number of radios 1-%d [Default %d]\n", SRSLTE_MAX_RADIOS, nof_radios); printf("\t-p number of ports 1-%d [Default %d]\n", SRSLTE_MAX_PORTS, nof_ports); printf("\t-s sampling rate [Default %.0f]\n", srate); + printf("\t-S synchronized radios [Default %s]\n", synchronised_radios ? "enabled" : "false"); printf("\t-t duration in seconds [Default %.3f]\n", duration); + printf("\t-m measure delay [Default %s]\n", (measure_delay) ? "enabled" : "disabled"); printf("\t-x enable transmit [Default %s]\n", (tx_enable) ? "enabled" : "disabled"); + printf("\t-w capture [Default %s]\n", (capture) ? "enabled" : "disabled"); + printf("\t-o Output file pattern [Default %s]\n", file_pattern.c_str()); + printf("\t-F Display spectrum [Default %s]\n", (fft_plot_enable) ? "enabled" : "disabled"); printf("\t-v Set srslte_verbose to info (v) or debug (vv) [Default none]\n"); printf("\t-h show this message\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "foabcderpstvhmxw")) != -1) { + while ((opt = getopt(argc, argv, "foabcderpsStvhmFxwg")) != -1) { switch (opt) { case 'f': freq = atof(argv[optind]); break; + case 'g': + rf_gain = atof(argv[optind]); + agc_enable = false; + break; + case 'o': + file_pattern = argv[optind]; + break; case 'a': - device_args = std::string(argv[optind]); + strncpy(radios_args[0], argv[optind], 64); + break; + case 'b': + strncpy(radios_args[1], argv[optind], 64); + break; + case 'c': + strncpy(radios_args[2], argv[optind], 64); + break; + case 'r': + nof_radios = (uint32_t)atoi(argv[optind]); break; case 'p': - nof_ports = (uint32_t) atoi(argv[optind]); + nof_ports = (uint32_t)atoi(argv[optind]); break; case 's': srate = atof(argv[optind]); break; + case 'S': + synchronised_radios ^= true; + break; case 't': duration = atof(argv[optind]); break; + case 'm': + measure_delay ^= true; + break; case 'x': tx_enable ^= true; break; + case 'w': + capture ^= true; + break; + case 'F': + fft_plot_enable ^= true; + break; case 'v': srslte_verbose++; break; @@ -91,134 +146,377 @@ void parse_args(int argc, char **argv) { } } -bool go_exit = false; -void sig_int_handler(int signo) +static double set_gain_callback(void* h, double gain) { - printf("SIGINT received. Exiting...\n"); - if (signo == SIGINT) { - go_exit = true; - } else if (signo == SIGSEGV) { - exit(1); - } + radio* r = (radio*)h; + return r->set_rx_gain_th(gain); } -void rf_msg(srslte_rf_error_t error) +#ifdef ENABLE_GUI + +static void* plot_thread_run(void* arg) { - if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { - num_overflows++; - } else - if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) { - num_underflows++; - } else - if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { - num_lates++; - } else { - num_other_error++; + sdrgui_init(); + + for (uint32_t i = 0; i < nof_radios; i++) { + char str_buf[32] = {}; + snprintf(str_buf, 32, "Radio %d spectrum", i); + plot_real_init(&fft_plot[i]); + plot_real_setTitle(&fft_plot[i], str_buf); + plot_real_setXAxisAutoScale(&fft_plot[i], true); + plot_real_setYAxisAutoScale(&fft_plot[i], true); + + plot_scatter_addToWindowGrid(&fft_plot[i], (char*)"pdsch_ue", 0, i); + } + + while (fft_plot_enable) { + sem_wait(&plot_sem); + + if (fft_plot_buffer_size) { + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_vec_abs_square_cf(fft_plot_buffer[r], fft_plot_temp, fft_plot_buffer_size); + + for (uint32_t j = 0; j < fft_plot_buffer_size; j++) { + fft_plot_temp[j] = 10.0f * log10f(fft_plot_temp[j]); + } + + plot_real_setNewData(&fft_plot[r], fft_plot_temp, fft_plot_buffer_size); + } + } } + + return NULL; } -void print_rf_summary(void) +static int init_plots(uint32_t frame_size) { - printf("#lates=%d\n", num_lates); - printf("#overflows=%d\n", num_overflows); - printf("#underflows=%d\n", num_underflows); - printf("#num_other_error=%d\n", num_other_error); + + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + for (uint32_t r = 0; r < nof_radios; r++) { + fft_plot_buffer[r] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * frame_size); + if (!fft_plot_buffer[r]) { + ERROR("Error: Allocating buffer\n"); + return SRSLTE_ERROR; + } + } + + fft_plot_temp = (float*)srslte_vec_malloc(sizeof(float) * frame_size); + if (!fft_plot_temp) { + ERROR("Error: Allocating buffer\n"); + return SRSLTE_ERROR; + } + + if (srslte_dft_plan_c(&dft_spectrum, frame_size, SRSLTE_DFT_FORWARD)) { + ERROR("Creating DFT spectrum plan\n"); + return SRSLTE_ERROR; + } + + srslte_dft_plan_set_mirror(&dft_spectrum, true); + fft_plot_buffer_size = frame_size; + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, NULL, plot_thread_run, NULL)) { + perror("pthread_create"); + exit(-1); + } + + return SRSLTE_SUCCESS; } -int main(int argc, char **argv) +#endif /* ENABLE_GUI */ + +int main(int argc, char** argv) { - int ret = SRSLTE_ERROR; - srslte::radio_multi *radio_h = NULL; - srslte_timestamp_t ts_rx, ts_tx; + int ret = SRSLTE_ERROR; + radio* radio_h[SRSLTE_MAX_RADIOS] = {NULL}; + srslte_timestamp_t ts_prev[SRSLTE_MAX_RADIOS], ts_rx[SRSLTE_MAX_RADIOS], ts_tx; + uint32_t nof_gaps = 0; + char filename[256] = {}; + srslte_filesink_t filesink[SRSLTE_MAX_RADIOS]; + srslte_dft_plan_t dft_plan = {}, idft_plan = {}; + srslte_agc_t agc[SRSLTE_MAX_RADIOS] = {}; + + bzero(&ts_prev, sizeof(ts_prev)); bzero(&ts_rx, sizeof(ts_rx)); bzero(&ts_tx, sizeof(ts_tx)); - signal(SIGINT, sig_int_handler); + float delay_idx[SRSLTE_MAX_RADIOS] = {0}; + uint32_t delay_count = 0; /* Parse args */ parse_args(argc, argv); uint32_t nof_samples = (uint32_t) (duration * srate); - uint32_t frame_size = (uint32_t) (srate / 1000.0); /* 1 ms at srate */ - uint32_t nof_frames = duration * 1e3; + uint32_t frame_size = (uint32_t)(srate / 1000.0); /* 1 ms at srate */ + uint32_t nof_frames = (uint32_t)ceil(nof_samples / frame_size); + + /* Instanciate and allocate memory */ + printf("Instanciating objects and allocating memory...\n"); + for (uint32_t r = 0; r < nof_radios; r++) { + radio_h[r] = new radio(); + if (!radio_h[r]) { + fprintf(stderr, "Error: Calling radio_multi constructor\n"); + goto clean_exit; + } - radio_h = new radio_multi(); - if (!radio_h) { - fprintf(stderr, "Error: Calling radio_multi constructor\n"); - goto clean_exit; + for (uint32_t p = 0; p < SRSLTE_MAX_PORTS; p++) { + buffers[r][p] = NULL; + } } - for (uint32_t p = 0; p < SRSLTE_MAX_PORTS; p++) { - buffers[p] = NULL; + for (uint32_t r = 0; r < nof_radios; r++) { + for (uint32_t p = 0; p < nof_ports; p++) { + buffers[r][p] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * frame_size); + if (!buffers[r][p]) { + ERROR("Error: Allocating buffer (%d,%d)\n", r, p); + goto clean_exit; + } + } } - for (uint32_t p = 0; p < nof_ports; p++) { - buffers[p] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * frame_size); - if (!buffers[p]) { - fprintf(stderr, "Error: Allocating buffer (%d)\n", p); - goto clean_exit; - } +#ifdef ENABLE_GUI + if (fft_plot_enable) { + init_plots(frame_size); + sleep(1); } +#endif /* ENABLE_GUI */ /* Initialise instances */ printf("Initialising instances...\n"); - if (!radio_h->init((char*)device_args.c_str(), NULL, nof_ports)) { - fprintf(stderr, "Error: Calling radio_multi constructor\n"); - goto clean_exit; - } + for (uint32_t r = 0; r < nof_radios; r++) { + if (!radio_h[r]->init(&log_h, radios_args[r], NULL, nof_ports, synchronised_radios)) { + fprintf(stderr, "Error: Calling radio_multi constructor\n"); + goto clean_exit; + } - radio_h->register_error_handler(rf_msg); + radio_h[r]->set_rx_freq(0, freq); + + // enable and init agc + if (agc_enable) { + radio_h[r]->start_agc(); + if (srslte_agc_init_uhd(&agc[r], SRSLTE_AGC_MODE_PEAK_AMPLITUDE, 0, set_gain_callback, radio_h[r])) { + fprintf(stderr, "Error: Initiating AGC %d\n", r); + goto clean_exit; + } + } else { + radio_h[r]->set_rx_gain(rf_gain); + } - radio_h->set_rx_freq(freq); + // Set radio + if (srate < 10e6) { + radio_h[r]->set_master_clock_rate(4 * srate); + } else { + radio_h[r]->set_master_clock_rate(srate); + } - /* Set radio */ - printf("Setting radio...\n"); - if (srate < 10e6) { - radio_h->set_master_clock_rate(4 * srate); - } else { - radio_h->set_master_clock_rate(srate); + // Set Rx/Tx sampling rate + radio_h[r]->set_rx_srate(srate); + if (tx_enable) { + radio_h[r]->set_tx_srate(srate); + } } - radio_h->set_rx_srate(srate); - if (tx_enable) { - radio_h->set_tx_srate(srate); + /* Setup file sink */ + if (capture) { + for (uint32_t r = 0; r < nof_radios; r++) { + snprintf(filename, 256, file_pattern.c_str(), r); + INFO("Opening filesink %s for radio %d\n", filename, r); + if (srslte_filesink_init(&filesink[r], filename, SRSLTE_COMPLEX_FLOAT_BIN)) { + ERROR("Initiating filesink for radio %d\n", r); + goto clean_exit; + } + } } - /* Receive */ - printf("Initial receive for aligning radios...\n"); - radio_h->rx_now(buffers, frame_size, &ts_rx); + /* If measure delay between radios */ + if (measure_delay) { + if (nof_radios > 1) { + if (srslte_dft_plan_c(&dft_plan, frame_size, SRSLTE_DFT_FORWARD)) { + ERROR("Creating DFT plan\n"); + goto clean_exit; + } + if (srslte_dft_plan_c(&idft_plan, frame_size, SRSLTE_DFT_BACKWARD)) { + ERROR("Creating IDFT plan\n"); + goto clean_exit; + } + } else { + printf("Warning: the delay measure cannot be performed with only one radio. Disabling delay measurement.\n"); + measure_delay = false; + } + } + /* Receive */ printf("Start capturing %d frames of %d samples...\n", nof_frames, frame_size); for (uint32_t i = 0; i < nof_frames; i++) { + int gap = 0; frame_size = SRSLTE_MIN(frame_size, nof_samples); - radio_h->rx_now(buffers, frame_size, &ts_rx); + // receive each radio + for (uint32_t r = 0; r < nof_radios; r++) { + radio_h[r]->rx_now(buffers[r], frame_size, &ts_rx[r]); + } + + for (uint32_t r = 0; r < nof_radios; r++) { + radio_h[r]->synch_wait(); + } + + // run agc + if (agc_enable) { + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_agc_process(&agc[r], buffers[r][0], frame_size); + } + } + + // Transmit if (tx_enable) { - srslte_timestamp_copy(&ts_tx, &ts_rx); - srslte_timestamp_add(&ts_tx, 0, 0.004); - radio_h->tx_single(buffers[0], frame_size, ts_tx); + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_timestamp_copy(&ts_tx, &ts_rx[r]); + srslte_timestamp_add(&ts_tx, 0, 0.004); + radio_h[r]->tx_single(buffers[r][0], frame_size, ts_tx); + } + + for (uint32_t r = 0; r < nof_radios; r++) { + radio_h[r]->synch_wait(); + } } - nof_samples -= frame_size; + /* Store baseband in file */ + if (capture) { + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_filesink_write_multi(&filesink[r], (void**)buffers[r], frame_size, nof_ports); + } + } - if (go_exit) break; +#ifdef ENABLE_GUI + /* Plot fft */ + if (fft_plot_enable) { + if (frame_size != nof_samples) { + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_dft_run(&dft_spectrum, buffers[r][0], fft_plot_buffer[r]); + } + } else { + fft_plot_enable = false; + } + sem_post(&plot_sem); + } +#endif /* ENABLE_GUI */ + + /* Compute delay between radios */ + if (measure_delay && frame_size != nof_samples) { + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_dft_run_c(&dft_plan, buffers[r][0], buffers[r][0]); + } + + for (uint32_t r = 1; r < nof_radios; r++) { + int relative_delay = 0; + + srslte_vec_prod_conj_ccc(buffers[0][0], buffers[r][0], buffers[r][0], frame_size); + srslte_dft_run_c(&idft_plan, buffers[r][0], buffers[r][0]); + relative_delay = srslte_vec_max_abs_ci(buffers[r][0], frame_size); + + if (relative_delay > (int)frame_size / 2) { + relative_delay -= frame_size; + } + + delay_idx[r] += relative_delay; + INFO("Radio %d relative delay is %d sample in frame %d/%d (average %.1f)\n", + r, + relative_delay, + i + 1, + nof_frames, + delay_idx[r] / (float)(delay_count + 1)); + } + delay_count++; + } + + /* Check sample gaps */ + if (i != 0) { + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_timestamp_t ts_diff; + bzero(&ts_diff, sizeof(ts_diff)); + + srslte_timestamp_copy(&ts_diff, &ts_rx[r]); + srslte_timestamp_sub(&ts_diff, ts_prev[r].full_secs, ts_prev[r].frac_secs); + gap = (int)round(srslte_timestamp_real(&ts_diff) * srate) - frame_size; + + if (gap) { + INFO("Timestamp gap (%d samples) detected! Frame %d/%d. ts=%.9f+%.9f=%.9f\n", + gap, + i + 1, + nof_frames, + srslte_timestamp_real(&ts_prev[r]), + srslte_timestamp_real(&ts_diff), + srslte_timestamp_real(&ts_rx[r])); + nof_gaps++; + } + } + } + + /* Save timestamp */ + for (uint32_t r = 0; r < nof_radios; r++) { + srslte_timestamp_copy(&ts_prev[r], &ts_rx[r]); + } + + nof_samples -= frame_size; } - printf("Finished streaming ...\n"); + printf("Finished streaming with %d gaps...\n", nof_gaps); ret = SRSLTE_SUCCESS; + if (measure_delay) { + for (uint32_t r = 1; r < nof_radios; r++) { + printf("Radio %d is delayed %.1f samples from radio 0;\n", r, delay_idx[r] / delay_count); + } + } + clean_exit: printf("Tearing down...\n"); - radio_h->stop(); + for (uint32_t r = 0; r < nof_radios; r++) { + if (radio_h[r]) { + radio_h[r]->stop(); + delete radio_h[r]; + } + } + + for (uint32_t r = 0; r < nof_radios; r++) { + for (uint32_t p = 0; p < nof_ports; p++) { + if (buffers[r][p]) { + free(buffers[r][p]); + } + } + + if (capture) { + srslte_filesink_free(&filesink[r]); + } + } + + srslte_dft_plan_free(&dft_plan); + srslte_dft_plan_free(&idft_plan); - for (uint32_t p = 0; p < nof_ports; p++) { - if (buffers[p]) { - free(buffers[p]); +#ifdef ENABLE_GUI + pthread_join(plot_thread, NULL); + srslte_dft_plan_free(&dft_spectrum); + for (uint32_t r = 0; r < nof_radios; r++) { + if (fft_plot_buffer[r]) { + free(fft_plot_buffer[r]); } } + if (fft_plot_temp) { + free(fft_plot_temp); + } +#endif /* ENABLE_GUI */ if (ret) { printf("Failed!\n"); @@ -226,7 +524,5 @@ clean_exit: printf("Ok!\n"); } - print_rf_summary(); - return ret; } diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index 8371c1d6e..9a9966d45 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -445,23 +445,18 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg) goto unlock_and_exit; } - if (rlc_entity) { - // configure and add to array - rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); - - if (cnfg.rlc_mode != RLC_MODE_TM) { - if (rlc_entity->configure(cnfg) == false) { - rlc_log->error("Error configuring RLC entity\n."); - goto delete_and_exit; - } - } + // configure and add to array + rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); - if (not rlc_array.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { - rlc_log->error("Error inserting RLC entity in to array\n."); + if (cnfg.rlc_mode != RLC_MODE_TM) { + if (rlc_entity->configure(cnfg) == false) { + rlc_log->error("Error configuring RLC entity\n."); goto delete_and_exit; } - } else { - rlc_log->error("Error instantiating RLC\n"); + } + + if (not rlc_array.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { + rlc_log->error("Error inserting RLC entity in to array\n."); goto delete_and_exit; } rlc_log->warning("Added radio bearer %s in %s\n", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[cnfg.rlc_mode]); @@ -487,19 +482,14 @@ void rlc::add_bearer_mrb(uint32_t lcid) if (not valid_lcid_mrb(lcid)) { rlc_entity = new rlc_um(); - if (rlc_entity != NULL) { - // configure and add to array - rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); - if (not rlc_entity->configure(srslte_rlc_config_t::mch_config())) { - rlc_log->error("Error configuring RLC entity\n."); - goto delete_and_exit; - } - if (not rlc_array_mrb.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { - rlc_log->error("Error inserting RLC entity in to array\n."); - goto delete_and_exit; - } - } else { - rlc_log->error("Error instantiating RLC\n"); + // configure and add to array + rlc_entity->init(rlc_log, lcid, pdcp, rrc, mac_timers); + if (not rlc_entity->configure(srslte_rlc_config_t::mch_config())) { + rlc_log->error("Error configuring RLC entity\n."); + goto delete_and_exit; + } + if (not rlc_array_mrb.insert(rlc_map_pair_t(lcid, rlc_entity)).second) { + rlc_log->error("Error inserting RLC entity in to array\n."); goto delete_and_exit; } rlc_log->warning("Added radio bearer %s with mode RLC_UM\n", rrc->get_rb_name(lcid).c_str()); diff --git a/lib/test/asn1/srslte_asn1_rrc_connection_reconf_test.cc b/lib/test/asn1/srslte_asn1_rrc_connection_reconf_test.cc new file mode 100644 index 000000000..93a157a29 --- /dev/null +++ b/lib/test/asn1/srslte_asn1_rrc_connection_reconf_test.cc @@ -0,0 +1,90 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/asn1/liblte_rrc.h" +#include "srslte/common/log_filter.h" +#include "srslte/srslte.h" + +#define TESTASSERT(cond) \ + { \ + if (!(cond)) { \ + std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \ + return -1; \ + } \ + } + +int rrc_connection_reconf_test() +{ + srslte::log_filter log1("RRC"); + log1.set_level(srslte::LOG_LEVEL_DEBUG); + log1.set_hex_limit(128); + + LIBLTE_BIT_MSG_STRUCT bit_buf; + LIBLTE_BIT_MSG_STRUCT bit_buf2; + LIBLTE_BYTE_MSG_STRUCT byte_buf; + LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + + uint8_t rrc_message[] = {0x20, 0x02, 0x01, 0x80, 0x01, 0x10, 0x10, 0x08, 0x21, 0x60, 0xCA, 0x32, 0x00, 0x06, 0x60}; + uint32_t rrc_message_len = sizeof(rrc_message); + // 20020180011010082160CA32000660 + + bzero(&dl_dcch_msg, sizeof(dl_dcch_msg)); + srslte_bit_unpack_vector(rrc_message, bit_buf.msg, rrc_message_len * 8); + bit_buf.N_bits = rrc_message_len * 8; + liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dl_dcch_msg); + TESTASSERT(dl_dcch_msg.msg_type == LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG); + + LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT* reconf = &dl_dcch_msg.msg.rrc_con_reconfig; + TESTASSERT(reconf->rrc_transaction_id == 0); + TESTASSERT(not reconf->meas_cnfg_present); + TESTASSERT(not reconf->mob_ctrl_info_present); + TESTASSERT(reconf->N_ded_info_nas == 0); + TESTASSERT(reconf->rr_cnfg_ded_present); + TESTASSERT(not reconf->sec_cnfg_ho_present); + + // RR Config + TESTASSERT(reconf->rr_cnfg_ded.phy_cnfg_ded_present); + TESTASSERT(reconf->rr_cnfg_ded.drb_to_add_mod_list_size == 0); + + TESTASSERT(reconf->rr_cnfg_ded.phy_cnfg_ded.ext); + TESTASSERT(reconf->rr_cnfg_ded.phy_cnfg_ded.ext_groups.N_groups == 5); + TESTASSERT(reconf->rr_cnfg_ded.phy_cnfg_ded.ext_groups.groups_present[1]); + TESTASSERT(reconf->rr_cnfg_ded.phy_cnfg_ded.ext_groups.group1.pucch_config_dedicated_v1020_present); + LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_v1020* v1020 = + &reconf->rr_cnfg_ded.phy_cnfg_ded.ext_groups.group1.pucch_config_dedicated_v1020; + + TESTASSERT(v1020->pucch_format_r10_present); + TESTASSERT(v1020->pucch_format_r10_choice == LIBLTE_RRC_PUCCH_CONFIG_DEDICATED_v1020::format3_r10); + TESTASSERT(v1020->pucch_format_r10.format3_r10.N_n3_pucch_an_list_r13 == 4); + TESTASSERT(v1020->pucch_format_r10.format3_r10.n3_pucch_an_list_r13[0] == 25); + TESTASSERT(v1020->pucch_format_r10.format3_r10.n3_pucch_an_list_r13[1] == 281); + TESTASSERT(v1020->pucch_format_r10.format3_r10.n3_pucch_an_list_r13[2] == 0); + TESTASSERT(v1020->pucch_format_r10.format3_r10.n3_pucch_an_list_r13[3] == 51); + + return 0; +} + +int main(int argc, char** argv) +{ + TESTASSERT(rrc_connection_reconf_test() == 0); +} \ No newline at end of file diff --git a/lib/test/phy/CMakeLists.txt b/lib/test/phy/CMakeLists.txt index 209ba1b0d..af98fc201 100644 --- a/lib/test/phy/CMakeLists.txt +++ b/lib/test/phy/CMakeLists.txt @@ -25,3 +25,23 @@ add_executable(phy_dl_test phy_dl_test.c) target_link_libraries(phy_dl_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) add_test(phy_dl_test phy_dl_test) +# All valid number of PRBs for PUSCH +set(ue_dl_min_mcs 0) +set(ue_dl_max_mcs 28) +set(ue_dl_step_mcs 7) + +foreach (cell_n_prb 6 15 25 50 75 100) + foreach (ue_dl_tm 1 2 3 4) + foreach (ue_dl_mcs RANGE ${ue_dl_min_mcs} ${ue_dl_max_mcs} ${ue_dl_step_mcs}) + set(phy_dl_test_args "") + + set(phy_dl_test_args ${phy_dl_test_args} -p ${cell_n_prb}) + set(phy_dl_test_args ${phy_dl_test_args} -t ${ue_dl_tm}) + set(phy_dl_test_args ${phy_dl_test_args} -m ${ue_dl_mcs}) + + string(REGEX REPLACE "\ " "" test_name_args ${phy_dl_test_args}) + + add_test(phy_dl_test${test_name_args} phy_dl_test ${phy_dl_test_args}) + endforeach (ue_dl_mcs) + endforeach(ue_dl_tm) +endforeach (cell_n_prb) diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c index b2ba9c996..8a8946046 100644 --- a/lib/test/phy/phy_dl_test.c +++ b/lib/test/phy/phy_dl_test.c @@ -42,13 +42,13 @@ srslte_cell_t cell = { }; uint32_t transmission_mode = 1; -srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; -uint32_t cfi = 1; +uint32_t cfi = 1; uint32_t nof_rx_ant = 1; -uint32_t nof_subframes = 100; +uint32_t nof_subframes = 0; uint16_t rnti = 0x1234; bool print_dci_table; -uint32_t mcs = 28; +uint32_t mcs = 20; +int cross_carrier_indicator = -1; void usage(char *prog) { printf("Usage: %s [cfpndvs]\n", prog); @@ -57,35 +57,44 @@ void usage(char *prog) { printf("\t-p cell.nof_prb [Default %d]\n", cell.nof_prb); printf("\t-s number of subframes to simulate [Default %d]\n", nof_subframes); printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no"); - printf("\t-x MIMO Type: single, diversity, cdd, multiplex [Default %s]\n", srslte_mimotype2str(mimo_type)); + printf("\t-t Transmission mode: 1,2,3,4 [Default %d]\n", transmission_mode); printf("\t-m mcs [Default %d]\n", mcs); + printf("\tAdvanced parameters:\n"); + if (cross_carrier_indicator >= 0) { + printf("\t\t-a carrier-indicator [Default %d]\n", cross_carrier_indicator); + } else { + printf("\t\t-a carrier-indicator [Default none]\n"); + } printf("\t-v [set srslte_verbose to debug, default none]\n"); } +void parse_extensive_param(char* param, char* arg) +{ + int ext_code = SRSLTE_SUCCESS; + if (!strcmp(param, "carrier-indicator")) { + cross_carrier_indicator = atoi(arg); + } else { + ext_code = SRSLTE_ERROR; + } + + if (ext_code) { + ERROR("Error parsing parameter '%s' and argument '%s'\n", param, arg); + exit(ext_code); + } +} + void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "cfpndvsxm")) != -1) { + while ((opt = getopt(argc, argv, "cfapndvstm")) != -1) { switch (opt) { - case 'x': - if (srslte_str2mimotype(argv[optind], &mimo_type)) { - fprintf(stderr, "'%s' is not a valid MIMO type\n", argv[optind]); - usage(argv[0]); - exit(SRSLTE_ERROR); - } - if (mimo_type == SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { + case 't': + transmission_mode = strtol(argv[optind], NULL, 10) - 1; + if (transmission_mode == 0) { cell.nof_ports = 1; - nof_rx_ant = 1; - transmission_mode = 1; - } else { + nof_rx_ant = 1; + } else if (transmission_mode < 4) { cell.nof_ports = 2; nof_rx_ant = 2; - if (mimo_type == SRSLTE_MIMO_TYPE_TX_DIVERSITY) { - transmission_mode = 2; - } else if (mimo_type == SRSLTE_MIMO_TYPE_CDD) { - transmission_mode = 3; - } else { - transmission_mode = 4; - } } break; case 'f': @@ -106,6 +115,10 @@ void parse_args(int argc, char **argv) { case 'd': print_dci_table = true; break; + case 'a': + parse_extensive_param(argv[optind], argv[optind + 1]); + optind++; + break; case 'v': srslte_verbose++; break; @@ -119,53 +132,112 @@ void parse_args(int argc, char **argv) { int prbset_num = 1, last_prbset_num = 1; int prbset_orig = 0; -int work_enb(srslte_enb_dl_t *enb_dl, - srslte_dci_format_t dci_format, - srslte_ra_dl_dci_t *dci, - srslte_ra_dl_grant_t *grant, - srslte_softbuffer_tx_t **softbuffer_tx, - uint32_t sf_idx, uint8_t **data_tx) { +int work_enb(srslte_enb_dl_t* enb_dl, + srslte_dl_sf_cfg_t* dl_sf, + srslte_dci_cfg_t* dci_cfg, + srslte_dci_dl_t* dci, + srslte_softbuffer_tx_t** softbuffer_tx, + uint8_t** data_tx) +{ int ret = SRSLTE_ERROR; - srslte_dci_location_t location = { - .ncce = 8, - .L = 3 - }; - - srslte_enb_dl_clear_sf(enb_dl); - - srslte_enb_dl_put_base(enb_dl, sf_idx); + srslte_enb_dl_put_base(enb_dl, dl_sf); + if (srslte_enb_dl_put_pdcch_dl(enb_dl, dci_cfg, dci)) { + ERROR("Error putting PDCCH sf_idx=%d\n", dl_sf->tti); + goto quit; + } - if (srslte_enb_dl_put_pdcch_dl(enb_dl, - dci, - dci_format, - location, - rnti, - sf_idx % 10) < 0) { - fprintf(stderr, "Error putting PDCCH\n"); + // Create pdsch config + srslte_pdsch_cfg_t pdsch_cfg; + if (srslte_ra_dl_dci_to_grant(&cell, dl_sf, transmission_mode, dci, &pdsch_cfg.grant)) { + ERROR("Computing DL grant sf_idx=%d\n", dl_sf->tti); goto quit; } + char str[512]; + srslte_dci_dl_info(dci, str, 512); + INFO("eNb PDCCH: rnti=0x%x, %s\n", rnti, str); + + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + pdsch_cfg.softbuffers.tx[i] = softbuffer_tx[i]; + } - if (srslte_enb_dl_put_pdsch(enb_dl, - grant, - softbuffer_tx, - rnti, - (int[SRSLTE_MAX_CODEWORDS]) {dci->rv_idx, dci->rv_idx_1}, - sf_idx % 10, - data_tx, - mimo_type) < 0) { - fprintf(stderr, "Error putting PDSCH\n"); + // Enable power allocation + pdsch_cfg.power_scale = true; + pdsch_cfg.p_a = 0.0f; // 0 dB + pdsch_cfg.p_b = (transmission_mode > SRSLTE_TM1) ? 1 : 0; // 0 dB + pdsch_cfg.rnti = rnti; + pdsch_cfg.meas_time_en = false; + + if (srslte_enb_dl_put_pdsch(enb_dl, &pdsch_cfg, data_tx) < 0) { + ERROR("Error putting PDSCH sf_idx=%d\n", dl_sf->tti); goto quit; } + srslte_pdsch_tx_info(&pdsch_cfg, str, 512); + INFO("eNb PDSCH: rnti=0x%x, %s\n", rnti, str); srslte_enb_dl_gen_signal(enb_dl); ret = SRSLTE_SUCCESS; - quit: +quit: return ret; } +int work_ue(srslte_ue_dl_t* ue_dl, + srslte_dl_sf_cfg_t* sf_cfg_dl, + srslte_ue_dl_cfg_t* ue_dl_cfg, + srslte_dci_dl_t* dci_dl, + uint32_t sf_idx, + srslte_pdsch_res_t pdsch_res[SRSLTE_MAX_CODEWORDS]) +{ + if (srslte_ue_dl_decode_fft_estimate(ue_dl, sf_cfg_dl, ue_dl_cfg) < 0) { + ERROR("Getting PDCCH FFT estimate sf_idx=%d\n", sf_idx); + return -1; + } + + int nof_grants = srslte_ue_dl_find_dl_dci(ue_dl, sf_cfg_dl, ue_dl_cfg, rnti, dci_dl); + if (nof_grants < 0) { + ERROR("Looking for DL grants sf_idx=%d\n", sf_idx); + return -1; + } else if (nof_grants == 0) { + ERROR("Failed to find DCI in sf_idx=%d\n", sf_idx); + return -1; + } + + // Enable power allocation + ue_dl_cfg->cfg.pdsch.power_scale = true; + ue_dl_cfg->cfg.pdsch.p_a = 0.0f; // 0 dB + ue_dl_cfg->cfg.pdsch.p_b = (transmission_mode > SRSLTE_TM1) ? 1 : 0; // 0 dB + ue_dl_cfg->cfg.pdsch.rnti = dci_dl->rnti; + ue_dl_cfg->cfg.pdsch.csi_enable = false; + + char str[512]; + srslte_dci_dl_info(&dci_dl[0], str, 512); + INFO("UE PDCCH: rnti=0x%x, %s\n", rnti, str); + + if (srslte_ra_dl_dci_to_grant(&cell, sf_cfg_dl, transmission_mode, &dci_dl[0], &ue_dl_cfg->cfg.pdsch.grant)) { + ERROR("Computing DL grant sf_idx=%d\n", sf_idx); + return -1; + } + + // Reset softbuffer + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (ue_dl_cfg->cfg.pdsch.grant.tb[i].enabled) { + srslte_softbuffer_rx_reset(ue_dl_cfg->cfg.pdsch.softbuffers.rx[i]); + } + } + + if (srslte_ue_dl_decode_pdsch(ue_dl, sf_cfg_dl, &ue_dl_cfg->cfg.pdsch, pdsch_res)) { + ERROR("ERROR: Decoding PDSCH sf_idx=%d\n", sf_idx); + return -1; + } + + srslte_pdsch_tx_info(&ue_dl_cfg->cfg.pdsch, str, 512); + INFO("UE PDSCH: rnti=0x%x, %s\n", rnti, str); + + return 0; +} + unsigned int reverse(register unsigned int x) { x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); @@ -178,7 +250,7 @@ reverse(register unsigned int x) { uint32_t prbset_to_bitmask() { uint32_t mask = 0; - int nb = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); + int nb = (int)ceilf((float)cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); for (int i = 0; i < nb; i++) { if (i >= prbset_orig && i < prbset_orig + prbset_num) { mask = mask | (0x1 << i); @@ -187,18 +259,67 @@ uint32_t prbset_to_bitmask() { return reverse(mask) >> (32 - nb); } +static srslte_enb_dl_t enb_dl; +static srslte_ue_dl_t ue_dl; + +static int check_softbits(srslte_ue_dl_cfg_t* ue_dl_cfg, uint32_t sf_idx, int tb) +{ + int ret = SRSLTE_SUCCESS; + + // Generate sequence + srslte_sequence_pdsch(&ue_dl.pdsch.tmp_seq, + rnti, + ue_dl_cfg->cfg.pdsch.grant.tb[tb].cw_idx, + 2 * (sf_idx % 10), + cell.id, + ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); + + // Scramble + if (ue_dl.pdsch.llr_is_8bit) { + srslte_scrambling_sb_offset(&ue_dl.pdsch.tmp_seq, ue_dl.pdsch.e[tb], 0, ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); + } else { + srslte_scrambling_s_offset(&ue_dl.pdsch.tmp_seq, ue_dl.pdsch.e[tb], 0, ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits); + } + int16_t* rx = ue_dl.pdsch.e[tb]; + uint8_t* rx_bytes = ue_dl.pdsch.e[tb]; + for (int i = 0, k = 0; i < ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits / 8; i++) { + uint8_t w = 0; + for (int j = 0; j < 8; j++, k++) { + w |= (rx[k] > 0) ? (1 << (7 - j)) : 0; + } + rx_bytes[i] = w; + } + if (memcmp(ue_dl.pdsch.e[tb], enb_dl.pdsch.e[tb], ue_dl_cfg->cfg.pdsch.grant.tb[tb].nof_bits / 8) != 0) { + ret = SRSLTE_ERROR; + } + + return ret; +} + +static int check_evm(srslte_ue_dl_cfg_t* ue_dl_cfg, int tb) +{ + int ret = SRSLTE_SUCCESS; + srslte_vec_sub_ccc(enb_dl.pdsch.d[tb], ue_dl.pdsch.d[tb], enb_dl.pdsch.d[tb], ue_dl_cfg->cfg.pdsch.grant.nof_re); + float evm = srslte_vec_avg_power_cf(enb_dl.pdsch.d[tb], ue_dl_cfg->cfg.pdsch.grant.nof_re); + + if (evm > 0.1f) { + printf("TB%d Constellation EVM (%.3f) is too high\n", tb, evm); + ret = SRSLTE_ERROR; + } + + return ret; +} + int main(int argc, char **argv) { struct timeval t[3] = {}; size_t tx_nof_bits = 0, rx_nof_bits = 0; - srslte_enb_dl_t enb_dl; - srslte_ue_dl_t ue_dl; srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {}; srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {}; uint8_t *data_tx[SRSLTE_MAX_TB] = {}; uint8_t *data_rx[SRSLTE_MAX_TB] = {}; uint32_t count_failures = 0, count_tbs = 0; size_t pdsch_decode_us = 0; - size_t pdsch_encode_us = 0; + size_t pdsch_encode_us = 0; int ret = -1; @@ -206,16 +327,13 @@ int main(int argc, char **argv) { cf_t *signal_buffer[SRSLTE_MAX_PORTS] = {NULL}; - bzero(&enb_dl, sizeof(enb_dl)); - bzero(&ue_dl, sizeof(ue_dl)); - /* * Allocate Memory */ for (int i = 0; i < cell.nof_ports; i++) { signal_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); if (!signal_buffer[i]) { - fprintf(stderr, "Error allocating buffer\n"); + ERROR("Error allocating buffer\n"); goto quit; } } @@ -223,35 +341,35 @@ int main(int argc, char **argv) { for (int i = 0; i < SRSLTE_MAX_TB; i++) { softbuffer_tx[i] = (srslte_softbuffer_tx_t *) calloc(sizeof(srslte_softbuffer_tx_t), 1); if (!softbuffer_tx[i]) { - fprintf(stderr, "Error allocating softbuffer_tx\n"); + ERROR("Error allocating softbuffer_tx\n"); goto quit; } if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell.nof_prb)) { - fprintf(stderr, "Error initiating softbuffer_tx\n"); + ERROR("Error initiating softbuffer_tx\n"); goto quit; } softbuffer_rx[i] = (srslte_softbuffer_rx_t *) calloc(sizeof(srslte_softbuffer_rx_t), 1); if (!softbuffer_rx[i]) { - fprintf(stderr, "Error allocating softbuffer_rx\n"); + ERROR("Error allocating softbuffer_rx\n"); goto quit; } if (srslte_softbuffer_rx_init(softbuffer_rx[i], cell.nof_prb)) { - fprintf(stderr, "Error initiating softbuffer_rx\n"); + ERROR("Error initiating softbuffer_rx\n"); goto quit; } data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * MAX_DATABUFFER_SIZE); if (!data_tx[i]) { - fprintf(stderr, "Error allocating data tx\n"); + ERROR("Error allocating data tx\n"); goto quit; } data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * MAX_DATABUFFER_SIZE); if (!data_rx[i]) { - fprintf(stderr, "Error allocating data tx\n"); + ERROR("Error allocating data tx\n"); goto quit; } } @@ -260,137 +378,247 @@ int main(int argc, char **argv) { * Initialise eNb */ if (srslte_enb_dl_init(&enb_dl, signal_buffer, cell.nof_prb)) { - fprintf(stderr, "Error initiating eNb downlink\n"); + ERROR("Error initiating eNb downlink\n"); goto quit; } if (srslte_enb_dl_set_cell(&enb_dl, cell)) { - fprintf(stderr, "Error setting eNb DL cell\n"); + ERROR("Error setting eNb DL cell\n"); goto quit; } - srslte_enb_dl_set_cfi(&enb_dl, cfi); - srslte_enb_dl_set_power_allocation(&enb_dl, 0.0f, 0.0f); /* Default: none */ + if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { + ERROR("Error adding RNTI\n"); + goto quit; + } /* * Initialise UE */ if (srslte_ue_dl_init(&ue_dl, signal_buffer, cell.nof_prb, nof_rx_ant)) { - fprintf(stderr, "Error initiating UE downlink\n"); + ERROR("Error initiating UE downlink\n"); goto quit; } if (srslte_ue_dl_set_cell(&ue_dl, cell)) { - fprintf(stderr, "Error setting UE downlink cell\n"); + ERROR("Error setting UE downlink cell\n"); goto quit; } srslte_ue_dl_set_rnti(&ue_dl, rnti); - srslte_chest_dl_average_subframe(&ue_dl.chest, true); - //srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest, 4, 1.0f); + /* + * Create PDCCH Allocations + */ + uint32_t nof_locations[SRSLTE_NOF_SF_X_FRAME]; + srslte_dci_location_t dci_locations[SRSLTE_NOF_SF_X_FRAME][MAX_CANDIDATES_UE]; + uint32_t location_counter = 0; + for (uint32_t i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { + srslte_dl_sf_cfg_t sf_cfg_dl; + ZERO_OBJECT(sf_cfg_dl); + sf_cfg_dl.tti = i; + sf_cfg_dl.cfi = cfi; + sf_cfg_dl.sf_type = SRSLTE_SF_NORM; + + nof_locations[i] = srslte_pdcch_ue_locations(&enb_dl.pdcch, &sf_cfg_dl, dci_locations[i], MAX_CANDIDATES_UE, rnti); + location_counter += nof_locations[i]; + } + + if (nof_subframes == 0) { + nof_subframes = location_counter; + } + + /* + * DCI Configuration + */ + srslte_dci_dl_t dci; + srslte_dci_cfg_t dci_cfg; + dci_cfg.srs_request_enabled = false; + dci_cfg.ra_format_enabled = false; + dci_cfg.multiple_csi_request_enabled = false; + + // DCI Fixed values + dci.pid = 0; + dci.pinfo = 0; + dci.rnti = rnti; + dci.is_tdd = false; + dci.is_dwpts = false; + dci.is_ra_order = false; + dci.tb_cw_swap = false; + dci.pconf = false; + dci.power_offset = false; + dci.tpc_pucch = false; + dci.ra_preamble = false; + dci.ra_mask_idx = false; + dci.srs_request = false; + dci.srs_request_present = false; + + if (cross_carrier_indicator >= 0) { + dci.cif_present = true; + dci_cfg.cif_enabled = true; + dci.cif = (uint32_t)cross_carrier_indicator; + } else { + dci.cif_present = false; + dci_cfg.cif_enabled = false; + } + + // Set PRB Allocation type + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + prbset_num = (int)ceilf((float)cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); + last_prbset_num = prbset_num; + dci.type0_alloc.rbg_bitmask = prbset_to_bitmask(); + + // Set TB + if (transmission_mode < SRSLTE_TM3) { + dci.format = SRSLTE_DCI_FORMAT1; + dci.tb[0].mcs_idx = mcs; + dci.tb[0].rv = 0; + dci.tb[0].ndi = 0; + dci.tb[0].cw_idx = 0; + dci.tb[1].mcs_idx = 0; + dci.tb[1].rv = 1; + } else if (transmission_mode == SRSLTE_TM3) { + dci.format = SRSLTE_DCI_FORMAT2A; + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + dci.tb[i].mcs_idx = mcs; + dci.tb[i].rv = 0; + dci.tb[i].ndi = 0; + dci.tb[i].cw_idx = i; + } + } else if (transmission_mode == SRSLTE_TM4) { + dci.format = SRSLTE_DCI_FORMAT2; + dci.pinfo = 0; + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + dci.tb[i].mcs_idx = mcs; + dci.tb[i].rv = 0; + dci.tb[i].ndi = 0; + dci.tb[i].cw_idx = i; + } + } else { + ERROR("Wrong transmission mode (%d)\n", transmission_mode); + } /* * Loop */ INFO("--- Starting test ---\n"); for (uint32_t sf_idx = 0; sf_idx < nof_subframes; sf_idx++) { - bool acks[SRSLTE_MAX_TB] = {}; - /* Generate random data */ for (int t = 0; t < SRSLTE_MAX_TB; t++) { for (int i = 0; i < MAX_DATABUFFER_SIZE; i++) { - data_tx[t][i] = (uint8_t) (rand() & 0xff); + data_tx[t][i] = (uint8_t)(rand() & 0xff); } } /* * Run eNodeB */ - srslte_ra_dl_dci_t dci; - srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; - srslte_ra_dl_grant_t grant; - - bzero(&dci, sizeof(dci)); - bzero(&grant, sizeof(grant)); - - prbset_num = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); - last_prbset_num = prbset_num; - - /* Pupulate TB Common */ - dci.harq_process = 0; - - /* Pupulate TB0 */ - dci.mcs_idx = mcs; - dci.ndi = 0; - dci.rv_idx = 0; - dci.tb_en[0] = true; - - if (mimo_type == SRSLTE_MIMO_TYPE_CDD || mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - dci_format = (transmission_mode == 3) ? SRSLTE_DCI_FORMAT2A : SRSLTE_DCI_FORMAT2; - - /* Pupulate TB1 */ - dci.mcs_idx_1 = mcs; - dci.ndi_1 = 0; - dci.rv_idx_1 = 0; - dci.tb_en[1] = true; - - /* Pupulate Allocation */ - dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; - dci.type0_alloc.rbg_bitmask = prbset_to_bitmask(); - } else { - dci_format = SRSLTE_DCI_FORMAT1A; - dci.alloc_type = SRSLTE_RA_ALLOC_TYPE2; - dci.type2_alloc.riv = 0; - dci.type2_alloc.L_crb = 4; - dci.type2_alloc.RB_start = 0; - dci.type2_alloc.n_prb1a = 1; - dci.type2_alloc.n_gap = 0; - dci.type2_alloc.mode = 0; + srslte_dl_sf_cfg_t sf_cfg_dl; + sf_cfg_dl.tti = sf_idx % 10; + sf_cfg_dl.cfi = cfi; + sf_cfg_dl.sf_type = SRSLTE_SF_NORM; + + // Set DCI Location + dci.location = dci_locations[sf_idx % 10][(sf_idx / 10) % nof_locations[sf_idx % 10]]; + if (cell.nof_prb == 6) { + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + dci.tb[i].mcs_idx = (sf_idx % 5 == 0) ? 0 : mcs; + } + } else if (cell.nof_prb == 15) { + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + dci.tb[i].mcs_idx = (sf_idx % 5 == 0) ? SRSLTE_MIN(mcs, 27) : mcs; + } } - - dci.dci_is_1a = (dci_format == SRSLTE_DCI_FORMAT1A); - dci.dci_is_1c = (dci_format == SRSLTE_DCI_FORMAT1C); - - srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant); - INFO("--- Process Uplink ---\n"); + INFO("--- Process eNb ---\n"); gettimeofday(&t[1], NULL); - if (work_enb(&enb_dl, dci_format, &dci, &grant, softbuffer_tx, sf_idx, data_tx)) { + if (work_enb(&enb_dl, &sf_cfg_dl, &dci_cfg, &dci, softbuffer_tx, data_tx)) { goto quit; } gettimeofday(&t[2], NULL); get_time_interval(t); pdsch_encode_us += t[0].tv_sec * 1e6 + t[0].tv_usec; + // MIMO perfect crossed channel + if (transmission_mode > 1) { + for (int i = 0; i < SRSLTE_SF_LEN_PRB(cell.nof_prb); i++) { + cf_t x0 = signal_buffer[0][i]; + cf_t x1 = signal_buffer[1][i]; + + cf_t y0 = x0 + x1; + cf_t y1 = x0 - x1; + + signal_buffer[0][i] = y0; + signal_buffer[1][i] = y1; + } + } + /* * Run UE */ - INFO("--- Process Downlink ---\n"); + INFO("--- Process UE ---\n"); gettimeofday(&t[1], NULL); - int n = srslte_ue_dl_decode(&ue_dl, data_rx, transmission_mode - 1, sf_idx, acks); - if (n < 0) { - fprintf(stderr, "Error decoding PDSCH\n"); + + srslte_ue_dl_cfg_t ue_dl_cfg; + srslte_dci_dl_t dci_dl[SRSLTE_MAX_DCI_MSG]; + + ue_dl_cfg.cfg.tm = transmission_mode; + ue_dl_cfg.cfg.pdsch.p_a = 0.0; + ue_dl_cfg.cfg.pdsch.power_scale = false; + ue_dl_cfg.cfg.pdsch.decoder_type = SRSLTE_MIMO_DECODER_MMSE; + ue_dl_cfg.cfg.pdsch.max_nof_iterations = 10; + ue_dl_cfg.cfg.pdsch.meas_time_en = false; + + ue_dl_cfg.chest_cfg.filter_coef[0] = 4; + ue_dl_cfg.chest_cfg.filter_coef[1] = 1; + ue_dl_cfg.chest_cfg.filter_type = SRSLTE_CHEST_FILTER_GAUSS; + ue_dl_cfg.chest_cfg.noise_alg = SRSLTE_NOISE_ALG_REFS; + ue_dl_cfg.chest_cfg.rsrp_neighbour = false; + ue_dl_cfg.chest_cfg.interpolate_subframe = false; + ue_dl_cfg.chest_cfg.cfo_estimate_enable = false; + ue_dl_cfg.chest_cfg.cfo_estimate_sf_mask = false; + ue_dl_cfg.dci_cfg = dci_cfg; + + srslte_pdsch_res_t pdsch_res[SRSLTE_MAX_CODEWORDS]; + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + pdsch_res[i].payload = data_rx[i]; + pdsch_res[i].avg_iterations_block = 0.0f; + pdsch_res[i].crc = false; + ue_dl_cfg.cfg.pdsch.softbuffers.rx[i] = softbuffer_rx[i]; + } + if (work_ue(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, dci_dl, sf_idx, pdsch_res)) { goto quit; } + gettimeofday(&t[2], NULL); get_time_interval(t); pdsch_decode_us += t[0].tv_sec * 1e6 + t[0].tv_usec; - for (int i = 0; i < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); i++) { - if (!acks[i] || memcmp(data_tx[i], data_rx[i], grant.mcs[i].tbs / 8) != 0) { - printf("UE Failed decoding tb %d in subframe %d\n", i, sf_idx); - srslte_vec_fprint_hex(stdout, data_tx[i], grant.mcs[i].tbs / 8); - srslte_vec_fprint_hex(stdout, data_rx[i], grant.mcs[i].tbs / 8); - count_failures++; + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + if (ue_dl_cfg.cfg.pdsch.grant.tb[i].enabled) { + if (check_evm(&ue_dl_cfg, i)) { + count_failures++; + } else if (check_softbits(&ue_dl_cfg, sf_idx, i) != SRSLTE_SUCCESS) { + printf("TB%d: The received softbits in subframe %d DO NOT match the encoded bits (crc=%d)\n", + i, + sf_idx, + pdsch_res[i].crc); + srslte_vec_fprint_byte(stdout, (uint8_t*)enb_dl.pdsch.e[i], ue_dl_cfg.cfg.pdsch.grant.tb[i].nof_bits / 8); + srslte_vec_fprint_byte(stdout, (uint8_t*)ue_dl.pdsch.e[i], ue_dl_cfg.cfg.pdsch.grant.tb[i].nof_bits / 8); + count_failures++; + } else if (!pdsch_res[i].crc || memcmp(data_tx[i], data_rx[i], ue_dl_cfg.cfg.pdsch.grant.tb[i].tbs / 8) != 0) { + printf("UE Failed decoding tb %d in subframe %d. crc=%d; Bytes:\n", i, sf_idx, pdsch_res[i].crc); + srslte_vec_fprint_byte(stdout, data_tx[i], ue_dl_cfg.cfg.pdsch.grant.tb[i].tbs / 8); + srslte_vec_fprint_byte(stdout, data_rx[i], ue_dl_cfg.cfg.pdsch.grant.tb[i].tbs / 8); + count_failures++; + } else { + // Decoded Ok + rx_nof_bits += ue_dl_cfg.cfg.pdsch.grant.tb[i].tbs; + } + count_tbs++; + tx_nof_bits += ue_dl_cfg.cfg.pdsch.grant.tb[i].tbs; } - count_tbs++; } - - tx_nof_bits += (enb_dl.pdsch_cfg.grant.tb_en[0] ? enb_dl.pdsch_cfg.grant.mcs[0].tbs : 0); - tx_nof_bits += (enb_dl.pdsch_cfg.grant.tb_en[1] ? enb_dl.pdsch_cfg.grant.mcs[1].tbs : 0); - rx_nof_bits += (acks[0] ? ue_dl.pdsch_cfg.grant.mcs[0].tbs : 0); - rx_nof_bits += (acks[1] ? ue_dl.pdsch_cfg.grant.mcs[1].tbs : 0); } printf("Finished! The UE failed decoding %d of %d transport blocks.\n", count_failures, count_tbs); diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 370ac692c..5f72d9b8f 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -162,7 +162,7 @@ nof_ctrl_symbols = 3 [expert] #pusch_max_its = 8 # These are half iterations #pusch_8bit_decoder = false -#nof_phy_threads = 2 +#nof_phy_threads = 3 #metrics_period_secs = 1 #metrics_csv_enable = false #metrics_csv_filename = /tmp/enb_metrics.csv diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index edbed523a..3211928c1 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -84,7 +84,7 @@ public: int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res); int get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res); - int get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res); + int get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_t* dl_sched_res); void build_mch_sched(uint32_t tbs); void rl_failure(uint16_t rnti); void rl_ok(uint16_t rnti); diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h index 7099341c4..8a0461a46 100644 --- a/srsenb/hdr/mac/scheduler.h +++ b/srsenb/hdr/mac/scheduler.h @@ -27,12 +27,13 @@ #ifndef SRSENB_SCHEDULER_H #define SRSENB_SCHEDULER_H -#include +#include "scheduler_harq.h" +#include "scheduler_ue.h" +#include "srslte/common/bounded_bitset.h" #include "srslte/common/log.h" #include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/sched_interface.h" -#include "scheduler_ue.h" -#include "scheduler_harq.h" +#include #include namespace srsenb { @@ -63,8 +64,8 @@ public: public: /* Virtual methods for user metric calculation */ - virtual void new_tti(std::map &ue_db, uint32_t start_rb, uint32_t nof_rb, uint32_t nof_ctrl_symbols, uint32_t tti) = 0; - virtual dl_harq_proc* get_user_allocation(sched_ue *user) = 0; + virtual void + sched_users(std::map& ue_db, rbgmask_t* dl_mask, uint32_t nof_ctrl_symbols, uint32_t tti) = 0; }; @@ -73,9 +74,7 @@ public: public: /* Virtual methods for user metric calculation */ - virtual void reset_allocation(uint32_t nof_rb_) = 0; - virtual void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti) = 0; - virtual ul_harq_proc* get_user_allocation(sched_ue *user) = 0; + virtual void sched_users(std::map& ue_db, ul_mask_t* ul_mask, uint32_t tti) = 0; virtual bool update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0; }; @@ -140,13 +139,10 @@ public: return rv_idx[retx_idx%4]; } + static void generate_cce_location( + srslte_regs_t* regs, sched_ue::sched_dci_cce_t* location, uint32_t cfi, uint32_t sf_idx = 0, uint16_t rnti = 0); - - static void generate_cce_location(srslte_regs_t *regs, sched_ue::sched_dci_cce_t *location, - uint32_t cfi, uint32_t sf_idx = 0, uint16_t rnti = 0); - -private: - +protected: metric_dl *dl_metric; metric_ul *ul_metric; srslte::log *log_h; @@ -163,9 +159,26 @@ private: const static int MAX_CCE = 128; // This is for computing DCI locations - srslte_regs_t regs; - bool used_cce[MAX_CCE]; - + srslte_regs_t regs; + class sched_vars + { + public: + struct tti_vars_t { + srslte::bounded_bitset used_cce; + uint32_t tti_rx = 0; + tti_vars_t() : used_cce(MAX_CCE) {} + }; + void init(sched* parent_); + tti_vars_t& new_tti(uint32_t tti_rx); + tti_vars_t& tti_vars(uint32_t tti_rx); + + private: + static const uint32_t tti_array_size = 16; + sched* parent = NULL; + tti_vars_t tti_vars_[tti_array_size]; + }; + sched_vars sched_vars; + typedef struct { int buf_rar; uint16_t rnti; @@ -179,17 +192,26 @@ private: uint32_t n_tx; } sched_sib_t; + int dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST]); + int dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST]); + int dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]); - int dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST]); - int dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST]); - int dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]); - - - int generate_format1a(uint32_t rb_start, uint32_t l_crb, uint32_t tbs, uint32_t rv, srslte_ra_dl_dci_t *dci); - bool generate_dci(srslte_dci_location_t *sched_location, sched_ue::sched_dci_cce_t *locations, uint32_t aggr_level, sched_ue *user = NULL); - + void ul_sched_msg3(); + + int generate_format1a( + uint32_t rb_start, uint32_t l_crb, uint32_t tbs, uint32_t rv, uint16_t rnti, srslte_dci_dl_t* dci); + int find_empty_dci(sched_ue::sched_dci_cce_t* locations, + uint32_t aggr_level, + sched_vars::tti_vars_t* tti_vars, + sched_ue* user = NULL); + bool generate_dci(srslte_dci_location_t* sched_location, + sched_ue::sched_dci_cce_t* locations, + uint32_t aggr_level, + sched_vars::tti_vars_t* tti_vars, + sched_ue* user = NULL); std::map ue_db; + typedef std::map::iterator ue_db_it_t; sched_sib_t pending_sibs[MAX_SIBS]; @@ -224,7 +246,11 @@ private: uint32_t sfn; uint32_t current_tti; uint32_t current_cfi; - + + ul_mask_t ul_mask; + rbgmask_t dl_mask; + bool fail_dci_alloc = false; + bool configured; }; diff --git a/srsenb/hdr/mac/scheduler_harq.h b/srsenb/hdr/mac/scheduler_harq.h index 5ac38459d..d8ac01083 100644 --- a/srsenb/hdr/mac/scheduler_harq.h +++ b/srsenb/hdr/mac/scheduler_harq.h @@ -27,36 +27,37 @@ #ifndef SRSENB_SCHEDULER_HARQ_H #define SRSENB_SCHEDULER_HARQ_H -#include +#include "srslte/common/bounded_bitset.h" #include "srslte/common/log.h" #include "srslte/interfaces/sched_interface.h" +#include namespace srsenb { class harq_proc { public: - void config(uint32_t id, uint32_t max_retx, srslte::log* log_h); + void config(uint32_t id, uint32_t max_retx, srslte::log* log_h); void set_max_retx(uint32_t max_retx); void reset(uint32_t tb_idx); - uint32_t get_id(); - bool is_empty(uint32_t tb_idx); - - void new_retx(uint32_t tb_idx, uint32_t tti, int *mcs, int *tbs); - - bool get_ack(uint32_t tb_idx); + uint32_t get_id() const; + bool is_empty() const; + bool is_empty(uint32_t tb_idx) const; + + bool get_ack(uint32_t tb_idx) const; void set_ack(uint32_t tb_idx, bool ack); - - uint32_t nof_tx(uint32_t tb_idx); - uint32_t nof_retx(uint32_t tb_idx); - uint32_t get_tti(); - bool get_ndi(uint32_t tb_idx); - + + uint32_t nof_tx(uint32_t tb_idx) const; + uint32_t nof_retx(uint32_t tb_idx) const; + uint32_t get_tti() const; + bool get_ndi(uint32_t tb_idx) const; + protected: void new_tx_common(uint32_t tb_idx, uint32_t tti, int mcs, int tbs); - bool has_pending_retx_common(uint32_t tb_idx); - + void new_retx_common(uint32_t tb_idx, uint32_t tti, int* mcs, int* tbs); + bool has_pending_retx_common(uint32_t tb_idx) const; + bool ack[SRSLTE_MAX_TB]; bool active[SRSLTE_MAX_TB]; bool ndi[SRSLTE_MAX_TB]; @@ -72,21 +73,24 @@ protected: private: bool ack_received[SRSLTE_MAX_TB]; -}; +}; + +typedef srslte::bounded_bitset<25, true> rbgmask_t; class dl_harq_proc : public harq_proc { public: - void new_tx(uint32_t tb_idx, uint32_t tti, int mcs, int tbs, uint32_t n_cce); - uint32_t get_rbgmask(); - void set_rbgmask(uint32_t new_mask); - bool has_pending_retx(uint32_t tb_idx, uint32_t tti); - int get_tbs(uint32_t tb_idx); + dl_harq_proc(); + void new_tx(uint32_t tb_idx, uint32_t tti, int mcs, int tbs, uint32_t n_cce); + void new_retx(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs); + rbgmask_t get_rbgmask(); + void set_rbgmask(rbgmask_t new_mask); + bool has_pending_retx(uint32_t tb_idx, uint32_t tti) const; + int get_tbs(uint32_t tb_idx) const; uint32_t get_n_cce(); private: - uint32_t rbgmask; - uint32_t nof_rbg; - uint32_t n_cce; + rbgmask_t rbgmask; + uint32_t n_cce; }; class ul_harq_proc : public harq_proc @@ -96,15 +100,23 @@ public: struct ul_alloc_t { uint32_t RB_start; uint32_t L; - inline void set(uint32_t start, uint32_t len) {RB_start = start; L = len;} + void set(uint32_t start, uint32_t len) + { + RB_start = start; + L = len; + } }; - + void new_tx(uint32_t tti, int mcs, int tbs); - + void new_retx(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs); + ul_alloc_t get_alloc(); void set_alloc(ul_alloc_t alloc); - void re_alloc(ul_alloc_t alloc); + void set_realloc(ul_alloc_t alloc); + bool has_pending_retx(); bool is_adaptive_retx(); + bool is_rar_tx(); + bool is_new_tx(); void reset_pending_data(); bool has_pending_ack(); @@ -112,18 +124,27 @@ public: void set_rar_mcs(uint32_t mcs); bool get_rar_mcs(int* mcs); - + private: - ul_alloc_t allocation; + ul_alloc_t allocation; bool need_ack; int pending_data; uint32_t rar_mcs; bool has_rar_mcs; bool is_adaptive; - bool is_msg3; + bool is_rar; }; - -} +class ul_mask_t : public srslte::bounded_bitset<100> +{ + typedef srslte::bounded_bitset<100> base_type; + +public: + using srslte::bounded_bitset<100>::any; + using srslte::bounded_bitset<100>::fill; + bool any(ul_harq_proc::ul_alloc_t alloc) const noexcept; + void fill(ul_harq_proc::ul_alloc_t alloc) noexcept; +}; +} // namespace srsenb #endif // SRSENB_SCHEDULER_HARQ_H diff --git a/srsenb/hdr/mac/scheduler_metric.h b/srsenb/hdr/mac/scheduler_metric.h index 583ceac2b..38ab86db4 100644 --- a/srsenb/hdr/mac/scheduler_metric.h +++ b/srsenb/hdr/mac/scheduler_metric.h @@ -33,29 +33,20 @@ namespace srsenb { class dl_metric_rr : public sched::metric_dl { -public: - //interface - void new_tti(std::map &ue_db, uint32_t start_rbg, uint32_t nof_rbg, uint32_t nof_ctrl_symbols, uint32_t tti); - dl_harq_proc* get_user_allocation(sched_ue *user); -private: - - const static int MAX_RBG = 25; - - bool new_allocation(uint32_t nof_rbg, uint32_t* rbgmask); - void update_allocation(uint32_t new_mask); - bool allocation_is_valid(uint32_t mask); - dl_harq_proc* apply_user_allocation(sched_ue *user); + const static int MAX_RBG = 25; - uint32_t get_required_rbg(sched_ue *user, uint32_t tti); - uint32_t count_rbg(uint32_t mask); - uint32_t calc_rbg_mask(bool mask[25]); - - bool used_rbg[MAX_RBG]; +public: + void sched_users(std::map& ue_db, rbgmask_t* dl_mask, uint32_t nof_ctrl_symbols, uint32_t tti); +private: + bool find_allocation(uint32_t nof_rbg, rbgmask_t* rbgmask); + void update_allocation(rbgmask_t new_mask); + bool allocation_is_valid(rbgmask_t mask); + dl_harq_proc* allocate_user(sched_ue* user); uint32_t current_tti; - uint32_t total_rbg; - uint32_t used_rbg_mask; + // rbgmask_t used_rbg_mask; + rbgmask_t* used_rbg; uint32_t nof_ctrl_symbols; uint32_t available_rbg; }; @@ -63,25 +54,17 @@ private: class ul_metric_rr : public sched::metric_ul { public: - // interface - void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti); - ul_harq_proc* get_user_allocation(sched_ue *user); - bool update_allocation(ul_harq_proc::ul_alloc_t alloc); - void reset_allocation(uint32_t nof_rb_); + void sched_users(std::map& ue_db, ul_mask_t* start_mask, uint32_t tti); + private: - - const static int MAX_PRB = 100; - - bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc); - bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc); - ul_harq_proc* apply_user_allocation(sched_ue *user, bool retx_only); + bool find_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc); + bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc); + bool update_allocation(ul_harq_proc::ul_alloc_t alloc); ul_harq_proc* allocate_user_newtx_prbs(sched_ue* user); ul_harq_proc* allocate_user_retx_prbs(sched_ue *user); - - bool used_rb[MAX_PRB]; - uint32_t current_tti; - uint32_t nof_rb; + ul_mask_t* used_rb; + uint32_t current_tti; }; diff --git a/srsenb/hdr/mac/scheduler_ue.h b/srsenb/hdr/mac/scheduler_ue.h index 032f86acb..75cd4998e 100644 --- a/srsenb/hdr/mac/scheduler_ue.h +++ b/srsenb/hdr/mac/scheduler_ue.h @@ -43,13 +43,9 @@ namespace srsenb { * 1 mutex is created for every user and only access to same user variables are mutexed */ class sched_ue { - -public: - - // used by sched_metric - dl_harq_proc* dl_next_alloc; - ul_harq_proc* ul_next_alloc; +public: + // used by sched_metric to store the pdsch/pusch allocations bool has_pucch; typedef struct { @@ -92,14 +88,19 @@ public: void tpc_inc(); void tpc_dec(); - void set_max_mcs(int mcs_ul, int mcs_dl); - void set_fixed_mcs(int mcs_ul, int mcs_dl); - - - -/******************************************************* - * Functions used by scheduler metric objects - *******************************************************/ + void set_max_mcs(int mcs_ul, int mcs_dl); + void set_fixed_mcs(int mcs_ul, int mcs_dl); + + void set_dl_alloc(dl_harq_proc* alloc); + dl_harq_proc* get_dl_alloc(); + void set_ul_alloc(ul_harq_proc* alloc); + ul_harq_proc* get_ul_alloc(); + dl_harq_proc* find_dl_harq(uint32_t tti); + const dl_harq_proc* get_dl_harq(uint32_t idx) const; + + /******************************************************* + * Functions used by scheduler metric objects + *******************************************************/ uint32_t get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_symbols); uint32_t get_required_prb_ul(uint32_t req_bytes); @@ -114,12 +115,12 @@ public: void reset_timeout_dl_harq(uint32_t tti); dl_harq_proc *get_pending_dl_harq(uint32_t tti); - dl_harq_proc *get_empty_dl_harq(); - ul_harq_proc *get_ul_harq(uint32_t tti); + dl_harq_proc* get_empty_dl_harq(); + ul_harq_proc* get_ul_harq(uint32_t tti); -/******************************************************* - * Functions used by the scheduler object - *******************************************************/ + /******************************************************* + * Functions used by the scheduler object + *******************************************************/ void set_sr(); void unset_sr(); @@ -152,8 +153,8 @@ private: int alloc_pdu(int tbs, sched_interface::dl_sched_pdu_t* pdu); static uint32_t format1_count_prb(uint32_t bitmask, uint32_t cell_nof_prb); - static int cqi_to_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t max_Qm, bool is_ul, - uint32_t* mcs); + static int cqi_to_tbs( + uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t max_Qm, bool is_ul, uint32_t* mcs); int alloc_tbs_dl(uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, int *mcs); int alloc_tbs_ul(uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, int *mcs); int alloc_tbs(uint32_t nof_prb, uint32_t nof_re, uint32_t req_bytes, bool is_ul, int *mcs); @@ -164,6 +165,7 @@ private: uint32_t get_pending_dl_new_data_unlocked(uint32_t tti); uint32_t get_pending_ul_old_data_unlocked(); uint32_t get_pending_ul_new_data_unlocked(uint32_t tti); + uint32_t get_pending_dl_new_data_total_unlocked(uint32_t tti); bool needs_cqi_unlocked(uint32_t tti, bool will_send = false); @@ -203,17 +205,19 @@ private: int next_tpc_pusch; int next_tpc_pucch; - // Allowed DCI locations per CFI and per subframe - sched_dci_cce_t dci_locations[3][10]; + // Allowed DCI locations per CFI and per subframe + sched_dci_cce_t dci_locations[3][10]; - const static int SCHED_MAX_HARQ_PROC = 2*HARQ_DELAY_MS; + const static int SCHED_MAX_HARQ_PROC = SRSLTE_FDD_NOF_HARQ; dl_harq_proc dl_harq[SCHED_MAX_HARQ_PROC]; ul_harq_proc ul_harq[SCHED_MAX_HARQ_PROC]; bool phy_config_dedicated_enabled; asn1::rrc::phys_cfg_ded_s::ant_info_c_ dl_ant_info; -}; - + + dl_harq_proc* next_dl_harq_proc; + ul_harq_proc* next_ul_harq_proc; +}; } diff --git a/srsenb/hdr/mac/ue.h b/srsenb/hdr/mac/ue.h index e74c224b5..553b44e92 100644 --- a/srsenb/hdr/mac/ue.h +++ b/srsenb/hdr/mac/ue.h @@ -42,45 +42,9 @@ class ue : public srslte::read_pdu_interface, public srslte::pdu_queue::process_callback { public: - - ue() : mac_msg_dl(20), mch_mac_msg_dl(10), mac_msg_ul(20), conres_id_available(false), - dl_ri_counter(0), - dl_pmi_counter(0), - conres_id(0), - last_tti(0), - pdus(128) { - rrc = NULL; - sched = NULL; - rlc = NULL; - log_h = NULL; - rnti = 0; - pcap = NULL; - nof_failures = 0; - phr_counter = 0; - dl_cqi_counter = 0; - is_phy_added = false; - for (int i=0;i - -#include "srslte/srslte.h" -#include "phch_common.h" - -#define LOG_EXECTIME - -namespace srsenb { - -class phch_worker : public srslte::thread_pool::worker -{ -public: - - phch_worker(); - void init(phch_common *phy, srslte::log *log_h); - void stop(); - void reset(); - - cf_t *get_buffer_rx(uint32_t antenna_idx); - void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time); - - int add_rnti(uint16_t rnti); - void rem_rnti(uint16_t rnti); - uint32_t get_nof_rnti(); - - /* These are used by the GUI plotting tools */ - int read_ce_abs(float *ce_abs); - int read_ce_arg(float *ce_abs); - int read_pusch_d(cf_t *pusch_d); - int read_pucch_d(cf_t *pusch_d); - void start_plot(); - - void set_conf_dedicated_ack(uint16_t rnti, - bool rrc_completed); - - void set_config_dedicated(uint16_t rnti, srslte_refsignal_srs_cfg_t* srs_cfg, asn1::rrc::phys_cfg_ded_s* dedicated); - - uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); - -private: - constexpr static float PUSCH_RL_SNR_DB_TH = 1.0; - constexpr static float PUCCH_RL_CORR_TH = 0.15; - - void work_imp(); - - int encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants); - int encode_pmch(srslte_enb_dl_pdsch_t *grant, srslte_ra_dl_grant_t *phy_grant); - int decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch); - int encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks); - int encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants); - int encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_grants); - int decode_pucch(); - - - /* Common objects */ - srslte::log *log_h; - phch_common *phy; - bool initiated; - bool running; - - cf_t *signal_buffer_rx[SRSLTE_MAX_PORTS]; - cf_t *signal_buffer_tx[SRSLTE_MAX_PORTS]; - uint32_t tti_rx, tti_tx_dl, tti_tx_ul; - uint32_t sf_rx, sf_tx; - uint32_t t_rx, t_tx_dl, t_tx_ul; - uint32_t tx_worker_cnt; - srslte_enb_dl_t enb_dl; - srslte_enb_ul_t enb_ul; - srslte_softbuffer_tx_t temp_mbsfn_softbuffer; - srslte_timestamp_t tx_time; - - // Class to store user information - class ue { - public: - ue() : I_sr(0), I_sr_en(false), cqi_en(false), pucch_cqi_ack(false), pmi_idx(0), has_grant_tti(0), - dedicated_ack(false), ri_idx(0), ri_en(false), rnti(0) { - bzero(&phich_info, sizeof(srslte_enb_ul_phich_info_t)); - bzero(&metrics, sizeof(phy_metrics_t)); - dedicated.ant_info_present = true; - dedicated.ant_info.set(asn1::rrc::phys_cfg_ded_s::ant_info_c_::types::explicit_value); - dedicated.ant_info.explicit_value().tx_mode.value = asn1::rrc::ant_info_ded_s::tx_mode_e_::tm1; - dedicated.ant_info.explicit_value().ue_tx_ant_sel.set(asn1::rrc::setup_e::release); - } - uint32_t I_sr; - uint32_t pmi_idx; - uint32_t ri_idx; - bool I_sr_en; - bool cqi_en; - bool ri_en; - bool pucch_cqi_ack; - int has_grant_tti; - asn1::rrc::phys_cfg_ded_s dedicated; - bool dedicated_ack; - uint32_t rnti; - srslte_enb_ul_phich_info_t phich_info; - void metrics_read(phy_metrics_t *metrics); - void metrics_dl(uint32_t mcs); - void metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters); - - int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; - - private: - phy_metrics_t metrics; - }; - std::map ue_db; - - // mutex to protect worker_imp() from configuration interface - pthread_mutex_t mutex; - bool is_worker_running; -}; - -} // namespace srsenb - -#endif // SRSENB_PHCH_WORKER_H - diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index ea6c86afa..e1d3db3f0 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -27,8 +27,8 @@ #ifndef SRSENB_PHY_H #define SRSENB_PHY_H -#include "phch_common.h" -#include "phch_worker.h" +#include "phy_common.h" +#include "sf_worker.h" #include "srslte/common/log.h" #include "srslte/common/log_filter.h" #include "srslte/common/task_dispatcher.h" @@ -37,7 +37,6 @@ #include "srslte/interfaces/enb_metrics_interface.h" #include "srslte/radio/radio.h" #include "txrx.h" -#include namespace srsenb { @@ -61,9 +60,10 @@ public: void stop(); /* MAC->PHY interface */ - int add_rnti(uint16_t rnti); + int add_rnti(uint16_t rnti, bool is_temporal = false); void rem_rnti(uint16_t rnti); - + void set_mch_period_stop(uint32_t stop); + /*RRC-PHY interface*/ void configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch); @@ -71,7 +71,6 @@ public: static uint32_t tti_to_subf(uint32_t tti); void start_plot(); - void set_conf_dedicated_ack(uint16_t rnti, bool dedicated_ack); void set_config_dedicated(uint16_t rnti, asn1::rrc::phys_cfg_ded_s* dedicated); void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); @@ -90,8 +89,8 @@ private: srslte::radio *radio_handler; srslte::log *log_h; srslte::thread_pool workers_pool; - std::vector workers; - phch_common workers_common; + std::vector workers; + phy_common workers_common; prach_worker prach; txrx tx_rx; diff --git a/srsenb/hdr/phy/phch_common.h b/srsenb/hdr/phy/phy_common.h similarity index 61% rename from srsenb/hdr/phy/phch_common.h rename to srsenb/hdr/phy/phy_common.h index 4d3ff550b..af3c0fcec 100644 --- a/srsenb/hdr/phy/phch_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -1,19 +1,14 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2017 Software Radio Systems Limited - * - * \section LICENSE +/* + * Copyright 2013-2019 Software Radio Systems Limited * * This file is part of srsLTE. * - * srsUE is free software: you can redistribute it and/or modify + * 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. * - * srsUE is distributed in the hope that it will be useful, + * 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. @@ -49,33 +44,13 @@ typedef struct { std::string equalizer_mode; float estimator_fil_w; bool pregenerate_signals; -} phy_args_t; - -typedef enum{ - SUBFRAME_TYPE_REGULAR = 0, - SUBFRAME_TYPE_MBSFN, - SUBFRAME_TYPE_N_ITEMS, -} subframe_type_t; -static const char subframe_type_text[SUBFRAME_TYPE_N_ITEMS][20] = {"Regular", "MBSFN"}; - -/* Subframe config */ - -typedef struct { - subframe_type_t sf_type; - uint8_t mbsfn_area_id; - uint8_t non_mbsfn_region_length; - uint8_t mbsfn_mcs; - bool mbsfn_encode; - bool is_mcch; -} subframe_cfg_t; - - +} phy_args_t; -class phch_common +class phy_common { public: - phch_common(uint32_t nof_workers); - ~phch_common(); + phy_common(uint32_t nof_workers); + ~phy_common(); void set_nof_workers(uint32_t nof_workers); @@ -86,12 +61,14 @@ public: void worker_end(uint32_t tx_mutex_cnt, cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time); // Common objects - srslte_cell_t cell; - srslte_refsignal_dmrs_pusch_cfg_t pusch_cfg; - srslte_pusch_hopping_cfg_t hopping_cfg; - srslte_pucch_cfg_t pucch_cfg; - uint8_t pdsch_p_b; - phy_args_t params; + srslte_cell_t cell; + phy_args_t params; + + // Physical Uplink Config common + srslte_ul_cfg_t ul_cfg_com; + + // Physical Downlink Config common + srslte_dl_cfg_t dl_cfg_com; srslte::radio *radio; mac_interface_phy *mac; @@ -110,29 +87,27 @@ public: public: pending_ack_t pending_ack; uint8_t ri; - int last_ul_tbs[2*HARQ_DELAY_MS]; - srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; + srslte_ra_tb_t last_tb[SRSLTE_MAX_HARQ_PROC]; }; std::map common_ue_db; void ue_db_add_rnti(uint16_t rnti); void ue_db_rem_rnti(uint16_t rnti); - void ue_db_clear(uint32_t sf_idx); - void ue_db_set_ack_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t n_pdcch); - bool ue_db_is_ack_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t *last_n_pdcch = NULL); + void ue_db_clear(uint32_t tti); + void ue_db_set_ack_pending(uint32_t tti, uint16_t rnti, uint32_t tb_idx, uint32_t n_pdcch); + bool ue_db_is_ack_pending(uint32_t tti, uint16_t rnti, uint32_t tb_idx, uint32_t* last_n_pdcch = NULL); void ue_db_set_ri(uint16_t rnti, uint8_t ri); uint8_t ue_db_get_ri(uint16_t rnti); - void ue_db_set_last_ul_mod(uint16_t rnti, uint32_t tti, srslte_mod_t mcs); - srslte_mod_t ue_db_get_last_ul_mod(uint16_t rnti, uint32_t tti); - void ue_db_set_last_ul_tbs(uint16_t rnti, uint32_t tti, int tbs); - int ue_db_get_last_ul_tbs(uint16_t rnti, uint32_t tti); - + + void ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb); + srslte_ra_tb_t ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid); + void configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t *cfg); void build_mch_table(); void build_mcch_table(); - void get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti); - + bool is_mbsfn_sf(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); + void set_mch_period_stop(uint32_t stop); private: std::vector tx_sem; @@ -143,16 +118,19 @@ private: uint32_t max_workers; pthread_mutex_t user_mutex; - + + bool have_mtch_stop; + pthread_mutex_t mtch_mutex; + pthread_cond_t mtch_cvar; phy_interface_rrc::phy_cfg_mbsfn_t mbsfn; bool sib13_configured; bool mcch_configured; uint8_t mch_table[40]; uint8_t mcch_table[10]; - + uint32_t mch_period_stop; uint8_t mch_sf_idx_lut[10]; - bool is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti); - bool is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti); + bool is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); + bool is_mcch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); void add_rnti(uint16_t rnti); diff --git a/srsenb/hdr/phy/prach_worker.h b/srsenb/hdr/phy/prach_worker.h index 551096ce7..87962df18 100644 --- a/srsenb/hdr/phy/prach_worker.h +++ b/srsenb/hdr/phy/prach_worker.h @@ -68,11 +68,22 @@ private: const static int sf_buffer_sz = 128*1024; class sf_buffer { public: - sf_buffer() { nof_samples = 0; tti = 0; bzero(samples, sizeof(samples)); } - void reset() { nof_samples = 0; tti = 0; } - cf_t samples[sf_buffer_sz]; + sf_buffer() + { + nof_samples = 0; + tti = 0; + } + void reset() + { + nof_samples = 0; + tti = 0; + } + cf_t samples[sf_buffer_sz]; uint32_t nof_samples; uint32_t tti; +#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED + char debug_name[SRSLTE_BUFFER_POOL_LOG_NAME_LEN]; +#endif /* SRSLTE_BUFFER_POOL_LOG_ENABLED */ }; srslte::buffer_pool buffer_pool; srslte::block_queue pending_buffers; diff --git a/srsenb/hdr/phy/sf_worker.h b/srsenb/hdr/phy/sf_worker.h new file mode 100644 index 000000000..f1dda2720 --- /dev/null +++ b/srsenb/hdr/phy/sf_worker.h @@ -0,0 +1,144 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSENB_PHCH_WORKER_H +#define SRSENB_PHCH_WORKER_H + +#include + +#include "phy_common.h" +#include "srslte/srslte.h" + +#define LOG_EXECTIME + +namespace srsenb { + +class sf_worker : public srslte::thread_pool::worker +{ +public: + sf_worker(); + void init(phy_common* phy, srslte::log* log_h); + void stop(); + void reset(); + + cf_t* get_buffer_rx(uint32_t antenna_idx); + void set_time(uint32_t tti, uint32_t tx_worker_cnt, srslte_timestamp_t tx_time); + + int add_rnti(uint16_t rnti, bool is_temporal); + void rem_rnti(uint16_t rnti); + uint32_t get_nof_rnti(); + + /* These are used by the GUI plotting tools */ + int read_ce_abs(float* ce_abs); + int read_ce_arg(float* ce_abs); + int read_pusch_d(cf_t* pusch_d); + int read_pucch_d(cf_t* pusch_d); + void start_plot(); + + void set_config_dedicated(uint16_t rnti, asn1::rrc::phys_cfg_ded_s* dedicated); + + uint32_t get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]); + +private: + constexpr static float PUSCH_RL_SNR_DB_TH = 1.0; + constexpr static float PUCCH_RL_CORR_TH = 0.15; + + void work_imp(); + + int encode_pdsch(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants); + int encode_pmch(mac_interface_phy::dl_sched_grant_t* grant, srslte_mbsfn_cfg_t* mbsfn_cfg); + int decode_pusch(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_pusch); + int encode_phich(mac_interface_phy::ul_sched_ack_t* acks, uint32_t nof_acks); + int encode_pdcch_dl(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants); + int encode_pdcch_ul(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_grants); + int decode_pucch(); + + void send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value); + bool fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t* uci_cfg); + + /* Common objects */ + srslte::log* log_h; + phy_common* phy; + bool initiated; + bool running; + + cf_t* signal_buffer_rx[SRSLTE_MAX_PORTS]; + cf_t* signal_buffer_tx[SRSLTE_MAX_PORTS]; + uint32_t tti_rx, tti_tx_dl, tti_tx_ul; + uint32_t t_rx, t_tx_dl, t_tx_ul; + uint32_t tx_worker_cnt; + srslte_timestamp_t tx_time; + + srslte_enb_dl_t enb_dl; + srslte_enb_ul_t enb_ul; + + srslte_dl_sf_cfg_t dl_sf; + srslte_ul_sf_cfg_t ul_sf; + + srslte_softbuffer_tx_t temp_mbsfn_softbuffer; + + // Class to store user information + class ue + { + public: + ue(uint16_t rnti, phy_common* phy) : is_grant_available(false), rnti(0) + { + ZERO_OBJECT(phich_grant); + ZERO_OBJECT(metrics); + bzero(&metrics, sizeof(phy_metrics_t)); + + // Copy common configuartion + ul_cfg = phy->ul_cfg_com; + dl_cfg = phy->dl_cfg_com; + + // Fill RNTI + this->rnti = rnti; + dl_cfg.pdsch.rnti = rnti; + ul_cfg.pusch.rnti = rnti; + ul_cfg.pucch.rnti = rnti; + } + + bool is_grant_available; + srslte_phich_grant_t phich_grant; + + srslte_dl_cfg_t dl_cfg; + srslte_ul_cfg_t ul_cfg; + + void metrics_read(phy_metrics_t* metrics); + void metrics_dl(uint32_t mcs); + void metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters); + + private: + uint32_t rnti; + phy_metrics_t metrics; + }; + + // Each worker keeps a local copy of the user database. Uses more memory but more efficient to manage concurrency + std::map ue_db; + + // mutex to protect worker_imp() from configuration interface + pthread_mutex_t mutex; + bool is_worker_running; +}; + +} // namespace srsenb + +#endif // SRSENB_PHCH_WORKER_H diff --git a/srsenb/hdr/phy/txrx.h b/srsenb/hdr/phy/txrx.h index 8833f2b6a..788683e71 100644 --- a/srsenb/hdr/phy/txrx.h +++ b/srsenb/hdr/phy/txrx.h @@ -27,12 +27,12 @@ #ifndef SRSENB_TXRX_H #define SRSENB_TXRX_H +#include "phy_common.h" +#include "prach_worker.h" #include "srslte/common/log.h" -#include "srslte/common/threads.h" #include "srslte/common/thread_pool.h" +#include "srslte/common/threads.h" #include "srslte/radio/radio.h" -#include "phch_common.h" -#include "prach_worker.h" namespace srsenb { @@ -42,12 +42,12 @@ class txrx : public thread { public: txrx(); - bool init(srslte::radio *radio_handler, - srslte::thread_pool *_workers_pool, - phch_common *worker_com, - prach_worker *prach, - srslte::log *log_h, - uint32_t prio); + bool init(srslte::radio* radio_handler, + srslte::thread_pool* _workers_pool, + phy_common* worker_com, + prach_worker* prach, + srslte::log* log_h, + uint32_t prio); void stop(); private: @@ -57,8 +57,8 @@ private: srslte::radio *radio_h; srslte::log *log_h; srslte::thread_pool *workers_pool; - prach_worker *prach; - phch_common *worker_com; + prach_worker* prach; + phy_common* worker_com; // Main system TTI counter uint32_t tti; diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 5fb91e2c8..201d022c7 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -52,7 +52,9 @@ sib2 = }; pdsch_cnfg = { - p_b = 0; + /* Warning: Currently disabled and forced to p_b=1 for TM2/3/4 and p_b=0 for TM1 + */ + p_b = 1; rs_power = 0; }; pusch_cnfg = diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 6ad92d461..7ad9a60df 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -154,6 +154,12 @@ bool enb::init(all_args_t *args_) return false; } + if (args->enb.transmission_mode == 1) { + phy_cfg.pdsch_cnfg.p_b = 0.0; + } else { + phy_cfg.pdsch_cnfg.p_b = 1.0; + } + uint32_t prach_freq_offset = rrc_cfg.sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset; if (cell_cfg.nof_prb > 10) { @@ -179,6 +185,14 @@ bool enb::init(all_args_t *args_) rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer; rrc_cfg.enable_mbsfn = args->expert.enable_mbsfn; + // Check number of control symbols + if (cell_cfg.nof_prb < 50 && args->expert.mac.sched.nof_ctrl_symbols != 3) { + args->expert.mac.sched.nof_ctrl_symbols = 3; + mac_log.info("Setting number of control symbols to %d for %d PRB cell.\n", + args->expert.mac.sched.nof_ctrl_symbols, + cell_cfg.nof_prb); + } + // Parse EEA preference list std::vector eea_pref_list; boost::split(eea_pref_list, args->expert.eea_pref_list, @@ -253,10 +267,9 @@ bool enb::init(all_args_t *args_) dev_args = (char*) args->rf.device_args.c_str(); } - if(!radio.init(dev_args, dev_name, args->enb.nof_ports)) - { - printf("Failed to find device %s with args %s\n", - args->rf.device_name.c_str(), args->rf.device_args.c_str()); + if (!radio.init(phy_log[0], dev_args, dev_name, args->enb.nof_ports)) { + phy_log[0]->console( + "Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args.c_str()); return false; } @@ -272,8 +285,8 @@ bool enb::init(all_args_t *args_) radio.set_tx_gain(args->rf.tx_gain); ((srslte::log_filter*) phy_log[0])->console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6); - radio.set_tx_freq(args->rf.dl_freq); - radio.set_rx_freq(args->rf.ul_freq); + radio.set_tx_freq(args->enb.nof_ports, args->rf.dl_freq); + radio.set_rx_freq(args->enb.nof_ports, args->rf.ul_freq); radio.register_error_handler(rf_msg); diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 13d996377..c6ef881c9 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -24,10 +24,6 @@ * */ -//#include -//#include -//#include -//#include #include "srsenb/hdr/cfg_parser.h" #include "srslte/srslte.h" @@ -54,7 +50,7 @@ int enb::parse_cell_cfg(all_args_t* args, srslte_cell_t* cell) parser::parse_section(args->enb_files.rr_config, &phy_cnfg); cell->phich_length = (srslte_phich_length_t)(int)phichcfg.phich_dur; - cell->phich_resources = (srslte_phich_resources_t)(int)phichcfg.phich_res; + cell->phich_resources = (srslte_phich_r_t)(int)phichcfg.phich_res; if (!srslte_cell_isvalid(cell)) { fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args->enb.n_prb, args->enb.s1ap.cell_id); @@ -753,20 +749,31 @@ int enb::parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg) rrc_cfg->antenna_info.tx_mode = (ant_info_ded_s::tx_mode_e_::options)(args->enb.transmission_mode - 1); rrc_cfg->antenna_info.ue_tx_ant_sel.set(ant_info_ded_s::ue_tx_ant_sel_c_::types::setup); - if (rrc_cfg->antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm3) { - rrc_cfg->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::open_loop; - - rrc_cfg->antenna_info.codebook_subset_restrict_present = true; - rrc_cfg->antenna_info.codebook_subset_restrict.set( - ant_info_ded_s::codebook_subset_restrict_c_::types::n2_tx_ant_tm3); - rrc_cfg->antenna_info.codebook_subset_restrict.n2_tx_ant_tm3().from_number(0b11); - } else if (rrc_cfg->antenna_info.tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - rrc_cfg->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::closed_loop; - - rrc_cfg->antenna_info.codebook_subset_restrict_present = true; - rrc_cfg->antenna_info.codebook_subset_restrict.set( - ant_info_ded_s::codebook_subset_restrict_c_::types::n2_tx_ant_tm4); - rrc_cfg->antenna_info.codebook_subset_restrict.n2_tx_ant_tm4().from_number(0b111111); + switch (rrc_cfg->antenna_info.tx_mode) { + case ant_info_ded_s::tx_mode_e_::tm1: + case ant_info_ded_s::tx_mode_e_::tm2: + rrc_cfg->antenna_info.ue_tx_ant_sel.set(setup_e::release); + rrc_cfg->antenna_info.codebook_subset_restrict_present = false; + break; + case ant_info_ded_s::tx_mode_e_::tm3: + rrc_cfg->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::open_loop; + + rrc_cfg->antenna_info.codebook_subset_restrict_present = true; + rrc_cfg->antenna_info.codebook_subset_restrict.set( + ant_info_ded_s::codebook_subset_restrict_c_::types::n2_tx_ant_tm3); + rrc_cfg->antenna_info.codebook_subset_restrict.n2_tx_ant_tm3().from_number(0b11); + break; + case ant_info_ded_s::tx_mode_e_::tm4: + rrc_cfg->antenna_info.ue_tx_ant_sel.setup().value = ant_info_ded_s::ue_tx_ant_sel_c_::setup_e_::closed_loop; + + rrc_cfg->antenna_info.codebook_subset_restrict_present = true; + rrc_cfg->antenna_info.codebook_subset_restrict.set( + ant_info_ded_s::codebook_subset_restrict_c_::types::n2_tx_ant_tm4); + rrc_cfg->antenna_info.codebook_subset_restrict.n2_tx_ant_tm4().from_number(0b111111); + break; + default: + ERROR("Unsupported transmission mode %d\n", rrc_cfg->antenna_info.tx_mode.to_number()); + return SRSLTE_ERROR; } /* Parse power allocation */ @@ -930,7 +937,7 @@ int field_qci::parse(libconfig::Setting& root) field_asn1_enum_number sn_field_len("sn_field_length", &um_rlc->sn_field_len); if (sn_field_len.parse(q["rlc_config"]["ul_um"])) { - fprintf(stderr, "Error can't find sn_field_length in section ul_um\n"); + ERROR("Error can't find sn_field_length in section ul_um\n"); } } @@ -945,12 +952,12 @@ int field_qci::parse(libconfig::Setting& root) field_asn1_enum_number sn_field_len("sn_field_length", &um_rlc->sn_field_len); if (sn_field_len.parse(q["rlc_config"]["dl_um"])) { - fprintf(stderr, "Error can't find sn_field_length in section dl_um\n"); + ERROR("Error can't find sn_field_length in section dl_um\n"); } field_asn1_enum_number t_reordering("t_reordering", &um_rlc->t_reordering); if (t_reordering.parse(q["rlc_config"]["dl_um"])) { - fprintf(stderr, "Error can't find t_reordering in section dl_um\n"); + ERROR("Error can't find t_reordering in section dl_um\n"); } } @@ -960,23 +967,23 @@ int field_qci::parse(libconfig::Setting& root) field_asn1_enum_number t_poll_retx("t_poll_retx", &am_rlc->t_poll_retx); if (t_poll_retx.parse(q["rlc_config"]["ul_am"])) { - fprintf(stderr, "Error can't find t_poll_retx in section ul_am\n"); + ERROR("Error can't find t_poll_retx in section ul_am\n"); } field_asn1_enum_number poll_pdu("poll_pdu", &am_rlc->poll_pdu); if (poll_pdu.parse(q["rlc_config"]["ul_am"])) { - fprintf(stderr, "Error can't find poll_pdu in section ul_am\n"); + ERROR("Error can't find poll_pdu in section ul_am\n"); } field_asn1_enum_number poll_byte("poll_byte", &am_rlc->poll_byte); if (poll_byte.parse(q["rlc_config"]["ul_am"])) { - fprintf(stderr, "Error can't find poll_byte in section ul_am\n"); + ERROR("Error can't find poll_byte in section ul_am\n"); } field_asn1_enum_number max_retx_thresh("max_retx_thresh", &am_rlc->max_retx_thres); if (max_retx_thresh.parse(q["rlc_config"]["ul_am"])) { - fprintf(stderr, "Error can't find max_retx_thresh in section ul_am\n"); + ERROR("Error can't find max_retx_thresh in section ul_am\n"); } } @@ -985,12 +992,12 @@ int field_qci::parse(libconfig::Setting& root) field_asn1_enum_number t_reordering("t_reordering", &am_rlc->t_reordering); if (t_reordering.parse(q["rlc_config"]["dl_am"])) { - fprintf(stderr, "Error can't find t_reordering in section dl_am\n"); + ERROR("Error can't find t_reordering in section dl_am\n"); } field_asn1_enum_number t_status_prohibit("t_status_prohibit", &am_rlc->t_status_prohibit); if (t_status_prohibit.parse(q["rlc_config"]["dl_am"])) { - fprintf(stderr, "Error can't find t_status_prohibit in section dl_am\n"); + ERROR("Error can't find t_status_prohibit in section dl_am\n"); } } @@ -1004,7 +1011,7 @@ int field_qci::parse(libconfig::Setting& root) parser::field priority("priority", &lc_cfg->prio); if (priority.parse(q["logical_channel_config"])) { - fprintf(stderr, "Error can't find logical_channel_config in section priority\n"); + ERROR("Error can't find logical_channel_config in section priority\n"); } field_asn1_enum_number prioritised_bit_rate( @@ -1016,7 +1023,7 @@ int field_qci::parse(libconfig::Setting& root) field_asn1_enum_number bucket_size_duration( "bucket_size_duration", &lc_cfg->bucket_size_dur); if (bucket_size_duration.parse(q["logical_channel_config"])) { - fprintf(stderr, "Error can't find bucket_size_duration in section logical_channel_config\n"); + ERROR("Error can't find bucket_size_duration in section logical_channel_config\n"); } parser::field log_chan_group("log_chan_group", &lc_cfg->lc_ch_group); diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 5e3babcaa..174b4fb18 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -272,7 +272,7 @@ int mac::ue_rem(uint16_t rnti) int mac::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) { - memcpy(&this->cell_config, cell_cfg, sizeof(sched_interface::cell_cfg_t)); + this->cell_config = *cell_cfg; return scheduler.cell_cfg(cell_cfg); } @@ -353,6 +353,7 @@ int mac::crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc) // push the pdu through the queue if received correctly if (crc) { + Info("Pushing PDU rnti=%d, tti=%d, nof_bytes=%d\n", rnti, tti, nof_bytes); ue_db[rnti]->push_pdu(tti, nof_bytes); pdu_process_thread.notify(); } else { @@ -508,6 +509,12 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) // Register new user in RRC rrc_h->add_user(last_rnti); + + // Add temporal rnti to the PHY + if (phy_h->add_rnti(last_rnti, true)) { + Error("Registering temporal-rnti=0x%x to PHY\n", last_rnti); + } + // Trigger scheduler RACH scheduler.dl_rach_info(tti, ra_id, last_rnti, 7); @@ -516,7 +523,7 @@ int mac::rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) log_h->console("RACH: tti=%d, preamble=%d, offset=%d, temp_crnti=0x%x\n", tti, preamble_idx, time_adv, last_rnti); - // Increae RNTI counter + // Increase RNTI counter last_rnti++; if (last_rnti >= 60000) { last_rnti = 70; @@ -552,38 +559,31 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) for (uint32_t i=0;isched_grants[n].rnti = rnti; - dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format; - memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t)); - memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t)); + // Copy dci info + dl_sched_res->pdsch[n].dci = sched_result.data[i].dci; for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - dl_sched_res->sched_grants[n].softbuffers[tb] = - ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb); + dl_sched_res->pdsch[n].softbuffer_tx[tb] = ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.pid, tb); if (sched_result.data[i].nof_pdu_elems[tb] > 0) { /* Get PDU if it's a new transmission */ - dl_sched_res->sched_grants[n].data[tb] = ue_db[rnti]->generate_pdu(tb, - sched_result.data[i].pdu[tb], - sched_result.data[i].nof_pdu_elems[tb], - sched_result.data[i].tbs[tb]); + dl_sched_res->pdsch[n].data[tb] = ue_db[rnti]->generate_pdu( + tb, sched_result.data[i].pdu[tb], sched_result.data[i].nof_pdu_elems[tb], sched_result.data[i].tbs[tb]); - if (!dl_sched_res->sched_grants[n].data[tb]) { + if (!dl_sched_res->pdsch[n].data[tb]) { Error("Error! PDU was not generated (rnti=0x%04x, tb=%d)\n", rnti, tb); - sched_result.data[i].dci.tb_en[tb] = false; } if (pcap) { - pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti); + pcap->write_dl_crnti(dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti); } } else { /* TB not enabled OR no data to send: set pointers to NULL */ - dl_sched_res->sched_grants[n].data[tb] = NULL; + dl_sched_res->pdsch[n].data[tb] = NULL; } } n++; @@ -597,50 +597,45 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Copy RAR grants for (uint32_t i=0;isched_grants[n].rnti = sched_result.rar[i].rarnti; - dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A - memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.rar[i].dci, sizeof(srslte_ra_dl_dci_t)); - memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.rar[i].dci_location, sizeof(srslte_dci_location_t)); + // Copy dci info + dl_sched_res->pdsch[n].dci = sched_result.rar[i].dci; // Set softbuffer (there are no retx in RAR but a softbuffer is required) - dl_sched_res->sched_grants[n].softbuffers[0] = &rar_softbuffer_tx; + dl_sched_res->pdsch[n].softbuffer_tx[0] = &rar_softbuffer_tx; // Assemble PDU - dl_sched_res->sched_grants[n].data[0] = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); - + dl_sched_res->pdsch[n].data[0] = + assemble_rar(sched_result.rar[i].msg3_grant, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); if (pcap) { - pcap->write_dl_ranti(dl_sched_res->sched_grants[n].data[0], sched_result.rar[i].tbs, dl_sched_res->sched_grants[n].rnti, true, tti); + pcap->write_dl_ranti( + dl_sched_res->pdsch[n].data[0], sched_result.rar[i].tbs, dl_sched_res->pdsch[n].dci.rnti, true, tti); } n++; } // Copy SI and Paging grants - for (uint32_t i=0;isched_grants[n].rnti = (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH ) ? SRSLTE_SIRNTI : SRSLTE_PRNTI; - dl_sched_res->sched_grants[n].dci_format = SRSLTE_DCI_FORMAT1A; // Force Format 1A - memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.bc[i].dci, sizeof(srslte_ra_dl_dci_t)); - memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.bc[i].dci_location, sizeof(srslte_dci_location_t)); + for (uint32_t i = 0; i < sched_result.nof_bc_elems; i++) { + // Copy dci info + dl_sched_res->pdsch[n].dci = sched_result.bc[i].dci; // Set softbuffer if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) { - dl_sched_res->sched_grants[n].softbuffers[0] = &bcch_softbuffer_tx[sched_result.bc[i].index]; - dl_sched_res->sched_grants[n].data[0] = assemble_si(sched_result.bc[i].index); + dl_sched_res->pdsch[n].softbuffer_tx[0] = &bcch_softbuffer_tx[sched_result.bc[i].index]; + dl_sched_res->pdsch[n].data[0] = assemble_si(sched_result.bc[i].index); #ifdef WRITE_SIB_PCAP if (pcap) { pcap->write_dl_sirnti(dl_sched_res->sched_grants[n].data[0], sched_result.bc[i].tbs, true, tti); } #endif } else { - dl_sched_res->sched_grants[n].softbuffers[0] = &pcch_softbuffer_tx; - dl_sched_res->sched_grants[n].data[0] = pcch_payload_buffer; + dl_sched_res->pdsch[n].softbuffer_tx[0] = &pcch_softbuffer_tx; + dl_sched_res->pdsch[n].data[0] = pcch_payload_buffer; rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len); if (pcap) { - pcap->write_dl_pch(dl_sched_res->sched_grants[n].data[0], sched_result.bc[i].tbs, true, tti); + pcap->write_dl_pch(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti); } } @@ -689,30 +684,32 @@ void mac::build_mch_sched(uint32_t tbs) } } -int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res) +int mac::get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_t* dl_sched_res) { - srslte_ra_mcs_t mcs; - srslte_ra_mcs_t mcs_data; - mcs.idx = this->sib13.mbsfn_area_info_list_r9[0].mcch_cfg_r9.sig_mcs_r9; - mcs_data.idx = this->mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].pmch_cfg_r9.data_mcs_r9; - srslte_dl_fill_ra_mcs(&mcs, this->cell_config.cell.nof_prb); - srslte_dl_fill_ra_mcs(&mcs_data, this->cell_config.cell.nof_prb); - if(is_mcch){ + log_h->step(tti); + srslte_ra_tb_t mcs; + srslte_ra_tb_t mcs_data; + mcs.mcs_idx = this->sib13.mbsfn_area_info_list_r9[0].mcch_cfg_r9.sig_mcs_r9; + mcs_data.mcs_idx = this->mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].pmch_cfg_r9.data_mcs_r9; + srslte_dl_fill_ra_mcs(&mcs, 0, this->cell_config.cell.nof_prb); + srslte_dl_fill_ra_mcs(&mcs_data, 0, this->cell_config.cell.nof_prb); + if (is_mcch) { build_mch_sched(mcs_data.tbs); mch.mcch_payload = mcch_payload_buffer; mch.current_sf_allocation_num = 1; Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", mch.mtch_sched[0].lcid, mch.mtch_sched[0].stop, tti); + phy_h->set_mch_period_stop(mch.mtch_sched[0].stop); for(uint32_t i = 0; i < mch.num_mtch_sched; i++) { mch.pdu[i].lcid = srslte::sch_subh::MCH_SCHED_INFO; // mch.mtch_sched[i].lcid = 1+i; } mch.pdu[mch.num_mtch_sched].lcid = 0; - mch.pdu[mch.num_mtch_sched].nbytes = current_mcch_length; - dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI; - dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, mch.num_mtch_sched + 1, mcs.tbs/8); + mch.pdu[mch.num_mtch_sched].nbytes = current_mcch_length; + dl_sched_res->pdsch[0].dci.rnti = SRSLTE_MRNTI; + dl_sched_res->pdsch[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, mch.num_mtch_sched + 1, mcs.tbs / 8); } else { uint32_t current_lcid = 1; @@ -731,14 +728,14 @@ int mac::get_mch_sched(bool is_mcch, dl_sched_t *dl_sched_res) int bytes_received = ue_db[SRSLTE_MRNTI]->read_pdu(current_lcid, mtch_payload_buffer, requested_bytes); mch.pdu[0].lcid = current_lcid; mch.pdu[0].nbytes = bytes_received; - mch.mtch_sched[0].mtch_payload = mtch_payload_buffer; - dl_sched_res->sched_grants[0].rnti = SRSLTE_MRNTI; - if(bytes_received){ - dl_sched_res->sched_grants[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, 1, mcs_data.tbs/8); + mch.mtch_sched[0].mtch_payload = mtch_payload_buffer; + dl_sched_res->pdsch[0].dci.rnti = SRSLTE_MRNTI; + if (bytes_received) { + dl_sched_res->pdsch[0].data[0] = ue_db[SRSLTE_MRNTI]->generate_mch_pdu(mch, 1, mcs_data.tbs / 8); } } else { - dl_sched_res->sched_grants[0].rnti = 0; - dl_sched_res->sched_grants[0].data[0] = NULL; + dl_sched_res->pdsch[0].dci.rnti = 0; + dl_sched_res->pdsch[0].data[0] = NULL; } mch.current_sf_allocation_num++; } @@ -752,8 +749,8 @@ uint8_t* mac::assemble_rar(sched_interface::dl_sched_rar_grant_t* grants, uint32 if (pdu_len < rar_payload_len) { srslte::rar_pdu *pdu = &rar_pdu_msg[rar_idx]; pdu->init_tx(rar_payload[rar_idx], pdu_len); - for (uint32_t i=0;inew_subh()) { /* Search pending RAR */ int idx = grants[i].ra_id; @@ -808,22 +805,19 @@ int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) if (sched_result.pusch[i].tbs > 0) { // Get UE - uint16_t rnti = sched_result.pusch[i].rnti; + uint16_t rnti = sched_result.pusch[i].dci.rnti; if (ue_db.count(rnti)) { // Copy grant info - ul_sched_res->sched_grants[n].rnti = rnti; - ul_sched_res->sched_grants[n].current_tx_nb = sched_result.pusch[i].current_tx_nb; - ul_sched_res->sched_grants[n].needs_pdcch = sched_result.pusch[i].needs_pdcch; - memcpy(&ul_sched_res->sched_grants[n].grant, &sched_result.pusch[i].dci, sizeof(srslte_ra_ul_dci_t)); - memcpy(&ul_sched_res->sched_grants[n].location, &sched_result.pusch[i].dci_location, sizeof(srslte_dci_location_t)); - - ul_sched_res->sched_grants[n].softbuffer = ue_db[rnti]->get_rx_softbuffer(tti); + ul_sched_res->pusch[n].current_tx_nb = sched_result.pusch[i].current_tx_nb; + ul_sched_res->pusch[n].needs_pdcch = sched_result.pusch[i].needs_pdcch; + ul_sched_res->pusch[n].dci = sched_result.pusch[i].dci; + ul_sched_res->pusch[n].softbuffer_rx = ue_db[rnti]->get_rx_softbuffer(tti); if (sched_result.pusch[n].current_tx_nb == 0) { - srslte_softbuffer_rx_reset_tbs(ul_sched_res->sched_grants[n].softbuffer, sched_result.pusch[i].tbs*8); + srslte_softbuffer_rx_reset_tbs(ul_sched_res->pusch[n].softbuffer_rx, sched_result.pusch[i].tbs * 8); } - ul_sched_res->sched_grants[n].data = ue_db[rnti]->request_buffer(tti, sched_result.pusch[i].tbs); + ul_sched_res->pusch[n].data = ue_db[rnti]->request_buffer(tti, sched_result.pusch[i].tbs); ul_sched_res->nof_grants++; n++; } else { @@ -831,7 +825,7 @@ int mac::get_ul_sched(uint32_t tti, ul_sched_t *ul_sched_res) } } else { - Warning("Grant %d for rnti=0x%x has zero TBS\n", i, sched_result.pusch[i].rnti); + Warning("Grant %d for rnti=0x%x has zero TBS\n", i, sched_result.pusch[i].dci.rnti); } } diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 33f25d46f..373c450d2 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -53,7 +53,6 @@ sched::sched() : bc_aggr_level(0), rar_aggr_level(0), avail_rbg(0), P(0), start_ bzero(&cfg, sizeof(cfg)); bzero(®s, sizeof(regs)); - bzero(&used_cce, sizeof(used_cce)); bzero(&sched_cfg, sizeof(sched_cfg)); bzero(&common_locations, sizeof(common_locations)); bzero(&pdsch_re, sizeof(pdsch_re)); @@ -83,9 +82,9 @@ void sched::init(rrc_interface_mac *rrc_, srslte::log* log) sched_cfg.pdsch_mcs = -1; sched_cfg.pusch_max_mcs = 28; sched_cfg.pusch_mcs = -1; - sched_cfg.nof_ctrl_symbols = 3; - log_h = log; - rrc = rrc_; + sched_cfg.nof_ctrl_symbols = 3; + log_h = log; + rrc = rrc_; reset(); } @@ -93,7 +92,7 @@ int sched::reset() { bzero(pending_msg3, sizeof(pending_msg3_t)*10); bzero(pending_rar, sizeof(sched_rar_t)*SCHED_MAX_PENDING_RAR); - bzero(pending_sibs, sizeof(sched_sib_t)*MAX_SIBS); + bzero(pending_sibs, sizeof(sched_sib_t) * MAX_SIBS); configured = false; pthread_rwlock_wrlock(&rwlock); ue_db.clear(); @@ -104,7 +103,7 @@ int sched::reset() void sched::set_sched_cfg(sched_interface::sched_args_t* sched_cfg_) { if (sched_cfg_) { - memcpy(&sched_cfg, sched_cfg_, sizeof(sched_args_t)); + sched_cfg = *sched_cfg_; } } @@ -122,8 +121,8 @@ int sched::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) return -1; } - memcpy(&cfg, cell_cfg, sizeof(sched_interface::cell_cfg_t)); - + cfg = *cell_cfg; + // Get DCI locations if (srslte_regs_init(®s, cfg.cell)) { Error("Getting DCI locations\n"); @@ -134,7 +133,8 @@ int sched::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) si_n_rbg = ceilf((float) 4/P); rar_n_rbg = ceilf((float) 3/P); nof_rbg = (uint32_t) ceil((float) cfg.cell.nof_prb/P); - + sched_vars.init(this); + // Compute Common locations for DCI for each CFI for (uint32_t cfi=0;cfi<3;cfi++) { generate_cce_location(®s, &common_locations[cfi], cfi+1); @@ -148,7 +148,26 @@ int sched::cell_cfg(sched_interface::cell_cfg_t* cell_cfg) } } configured = true; - + + // PRACH has to fit within the PUSCH space + bool invalid_prach = cfg.cell.nof_prb == 6 and (cfg.prach_freq_offset + 6 > cfg.cell.nof_prb); + invalid_prach |= cfg.cell.nof_prb > 6 and ((cfg.prach_freq_offset + 6) > (cfg.cell.nof_prb - cfg.nrb_pucch) or + (int) cfg.prach_freq_offset < cfg.nrb_pucch); + if (invalid_prach) { + log_h->error("Invalid PRACH configuration: frequency offset=%d outside bandwidth limits\n", cfg.prach_freq_offset); + log_h->console("Invalid PRACH configuration: frequency offset=%d outside bandwidth limits\n", + cfg.prach_freq_offset); + return -1; + } + + if (common_locations[sched_cfg.nof_ctrl_symbols - 1].nof_loc[2] == 0) { + Error("SCHED: Current cfi=%d is not valid for broadcast (check scheduler.nof_ctrl_symbols in conf file).\n", + sched_cfg.nof_ctrl_symbols); + log_h->console( + "SCHED: Current cfi=%d is not valid for broadcast (check scheduler.nof_ctrl_symbols in conf file).\n", + sched_cfg.nof_ctrl_symbols); + } + return 0; } @@ -447,7 +466,7 @@ int sched::ul_sr_info(uint32_t tti, uint16_t rnti) int ret = 0; pthread_rwlock_rdlock(&rwlock); if (ue_db.count(rnti)) { - ue_db[rnti].set_sr();; + ue_db[rnti].set_sr(); } else { Error("User rnti=0x%x not found\n", rnti); ret = -1; @@ -516,8 +535,10 @@ int sched::dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST]) } } } - } - + } + + uint32_t tti_rx = (current_tti + 10240 - TX_DELAY) % 10240; + sched_vars::tti_vars_t* tti_vars = &sched_vars.tti_vars(tti_rx); for (int i=0;i 0 && n_sf >= (cfg.si_window_ms/nof_tx)*pending_sibs[i].n_tx && sf_idx==9)) { uint32_t rv = get_rvidx(pending_sibs[i].n_tx); - - // Try to allocate DCI first - if (generate_dci(&bc[nof_bc_elems].dci_location, &common_locations[current_cfi-1], bc_aggr_level)) { - int tbs = generate_format1a(start_rbg*P, si_n_rbg*P, cfg.sibs[i].len, rv, &bc[nof_bc_elems].dci); + + // Try to allocate DCI first + if (generate_dci(&bc[nof_bc_elems].dci.location, &common_locations[current_cfi - 1], bc_aggr_level, tti_vars)) { + int tbs = + generate_format1a(start_rbg * P, si_n_rbg * P, cfg.sibs[i].len, rv, SRSLTE_SIRNTI, &bc[nof_bc_elems].dci); if (tbs >= (int) cfg.sibs[i].len) { bc[nof_bc_elems].index = i; bc[nof_bc_elems].type = sched_interface::dl_sched_bc_t::BCCH; bc[nof_bc_elems].tbs = tbs; - + Debug("SCHED: SIB%d, start_rb=%d, n_rb=%d, rv=%d, len=%d, period=%d, mcs=%d\n", - i+1, start_rbg*P, si_n_rbg*P, rv, cfg.sibs[i].len, cfg.sibs[i].period_rf, bc[nof_bc_elems].dci.mcs_idx); - + i + 1, + start_rbg * P, + si_n_rbg * P, + rv, + cfg.sibs[i].len, + cfg.sibs[i].period_rf, + bc[nof_bc_elems].dci.tb[0].mcs_idx); + pending_sibs[i].n_tx++; nof_bc_elems++; @@ -567,147 +595,193 @@ int sched::dl_sched_bc(dl_sched_bc_t bc[MAX_BC_LIST]) } } } - - // Schedule Paging + + // Schedule Paging if (rrc) { - uint32_t paging_payload = 0; + uint32_t paging_payload = 0; if (rrc->is_paging_opportunity(current_tti, &paging_payload)) { if (avail_rbg > si_n_rbg && paging_payload) { - if (generate_dci(&bc[nof_bc_elems].dci_location, &common_locations[current_cfi-1], bc_aggr_level)) { - int tbs = generate_format1a(start_rbg*P, si_n_rbg*P, paging_payload, 0, &bc[nof_bc_elems].dci); + if (generate_dci(&bc[nof_bc_elems].dci.location, &common_locations[current_cfi - 1], bc_aggr_level, tti_vars)) { + int tbs = + generate_format1a(start_rbg * P, si_n_rbg * P, paging_payload, 0, SRSLTE_PRNTI, &bc[nof_bc_elems].dci); if (tbs > 0) { - + bc[nof_bc_elems].type = sched_interface::dl_sched_bc_t::PCCH; bc[nof_bc_elems].tbs = tbs; nof_bc_elems++; - - Info("SCHED: PCH start_rb=%d, tbs=%d, mcs=%d\n", start_rbg, tbs, bc[nof_bc_elems].dci.mcs_idx); + + Info("SCHED: PCH start_rb=%d, tbs=%d, mcs=%d\n", start_rbg, tbs, bc[nof_bc_elems].dci.tb[0].mcs_idx); avail_rbg -= si_n_rbg; start_rbg += si_n_rbg; } } - } + } } } - + return nof_bc_elems; } +bool is_in_tti_interval(uint32_t tti, uint32_t tti1, uint32_t tti2) +{ + tti %= 10240; + tti1 %= 10240; + tti2 %= 10240; + if (tti1 <= tti2) { + return tti >= tti1 and tti <= tti2; + } + return tti >= tti1 or tti <= tti2; +} -// Schedules RAR -int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST]) +// Schedules RAR +int sched::dl_sched_rar(dl_sched_rar_t rar[MAX_RAR_LIST]) { - int nof_rar_elems = 0; - for (uint32_t i=0;i 0 && avail_rbg >= rar_n_rbg) - { + int nof_rar_elems = 0; + for (uint32_t i = 0; i < SCHED_MAX_PENDING_RAR; i++) { + if (pending_rar[i].buf_rar > 0 && avail_rbg >= rar_n_rbg) { /* Check if we are still within the RAR window, otherwise discard it */ - if (current_tti <= (pending_rar[i].rar_tti + cfg.prach_rar_window + 3)%10240 && current_tti >= pending_rar[i].rar_tti + 3) - { - // Try to schedule DCI for this RAR - if (generate_dci(&rar[nof_rar_elems].dci_location, &rar_locations[current_cfi-1][sf_idx], rar_aggr_level)) { - + if (is_in_tti_interval( + current_tti, pending_rar[i].rar_tti + 3, pending_rar[i].rar_tti + 3 + cfg.prach_rar_window)) { + // Try to schedule DCI for this RAR + uint32_t tti_rx = (current_tti + 10240 - TX_DELAY) % 10240; + sched_vars::tti_vars_t* tti_vars = &sched_vars.tti_vars(tti_rx); + if (generate_dci( + &rar[nof_rar_elems].dci.location, &rar_locations[current_cfi - 1][sf_idx], rar_aggr_level, tti_vars)) { + /* Find all pending RARs with same transmission TTI */ uint32_t tti = pending_rar[i].rar_tti; uint32_t rar_sfidx = (tti+1)%10; uint32_t buf_rar = 0; - uint32_t nof_grants = 0; - for (int j=0;jinfo("SCHED: RAR, ra_id=%d, rnti=0x%x, rarnti_idx=%d, start_rb=%d, n_rb=%d, rar_grant_rba=%d, rar_grant_mcs=%d\n", - pending_rar[j].ra_id, pending_rar[j].rnti, rar_sfidx, start_rbg*P, rar_n_rbg*P, - rar[nof_rar_elems].grants[nof_grants].grant.rba, - rar[nof_rar_elems].grants[nof_grants].grant.trunc_mcs); + pending_msg3[pending_tti].L = L_prb; + pending_msg3[pending_tti].n_prb = n_prb; + pending_msg3[pending_tti].mcs = rar[nof_rar_elems].msg3_grant[nof_grants].grant.trunc_mcs; + + log_h->info("SCHED: RAR, ra_id=%d, rnti=0x%x, rarnti_idx=%d, start_rb=%d, n_rb=%d, rar_grant_rba=%d, " + "rar_grant_mcs=%d\n", + pending_rar[j].ra_id, + pending_rar[j].rnti, + rar_sfidx, + start_rbg * P, + rar_n_rbg * P, + rar[nof_rar_elems].msg3_grant[nof_grants].grant.rba, + rar[nof_rar_elems].msg3_grant[nof_grants].grant.trunc_mcs); } else { - log_h->warning("Only 1 RA is responded at a time. Found %d for TTI=%d\n", nof_grants+1, tti); + log_h->warning("Only 1 RA is responded at a time. Found %d for TTI=%d\n", nof_grants + 1, tti); } nof_grants++; } - } - - rar[nof_rar_elems].nof_grants = nof_grants; - rar[nof_rar_elems].rarnti = rar_sfidx; - - if (generate_format1a(start_rbg*P, rar_n_rbg*P, buf_rar, 0, &rar[nof_rar_elems].dci) >= 0) { - rar[nof_rar_elems].tbs = buf_rar; + } + + rar[nof_rar_elems].nof_grants = nof_grants; + + if (generate_format1a(start_rbg * P, rar_n_rbg * P, buf_rar, 0, rar_sfidx, &rar[nof_rar_elems].dci) >= 0) { + rar[nof_rar_elems].tbs = buf_rar; nof_rar_elems++; avail_rbg -= rar_n_rbg; start_rbg += rar_n_rbg; } else { - Error("SCHED: Allocating Format1A grant\n"); + Error("SCHED: Allocating Format1A dci\n"); } } else { log_h->warning("SCHED: Could not schedule DCI for RAR tti=%d, L=%d\n", pending_rar[i].rar_tti, rar_aggr_level); } } else { - log_h->console("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n", - pending_rar[i].rar_tti, cfg.prach_rar_window, current_tti); - pending_rar[i].buf_rar = 0; - pending_rar[i].rar_tti = 0; + log_h->console("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n", + pending_rar[i].rar_tti, + cfg.prach_rar_window, + current_tti); + log_h->error("SCHED: Could not transmit RAR within the window (RA TTI=%d, Window=%d, Now=%d)\n", + pending_rar[i].rar_tti, + cfg.prach_rar_window, + current_tti); + pending_rar[i].buf_rar = 0; + pending_rar[i].rar_tti = 0; } } - } - return nof_rar_elems; + } + return nof_rar_elems; } // Schedules data to users -int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) +int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) { + // reset global RBG mask + dl_mask.resize(nof_rbg); + dl_mask.reset(); + dl_mask.fill(0, start_rbg); + fail_dci_alloc = false; + // dl_mask.fill(dl_mask.size()-start_rbg, dl_mask.size()); + // NOTE: In case of 6 PRBs, do not transmit if there is going to be a PRACH in the UL to avoid collisions - if (cfg.cell.nof_prb<10 and srslte_prach_tti_opportunity_config(cfg.prach_config, current_tti+4, -1)) { - start_rbg = avail_rbg; + uint32_t tti_rx_ack = TTI_RX_ACK(TTI_SUB(current_tti, TX_DELAY)); + uint32_t pending_tti = tti_rx_ack % 10; + if (cfg.cell.nof_prb == 6 and (srslte_prach_tti_opportunity_config_fdd(cfg.prach_config, tti_rx_ack, -1) or + pending_msg3[pending_tti].enabled)) { + start_rbg = avail_rbg; } - uint32_t nof_ctrl_symbols = (cfg.cell.nof_prb<10)?(current_cfi+1):current_cfi; - dl_metric->new_tti(ue_db, start_rbg, avail_rbg, nof_ctrl_symbols, current_tti); - - int nof_data_elems = 0; - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - sched_ue *user = (sched_ue*) &iter->second; + typedef std::map::iterator it_t; + uint32_t nof_ctrl_symbols = SRSLTE_NOF_CTRL_SYMBOLS(cfg.cell, current_cfi); + + // clear previous user allocations + for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { + it->second.set_dl_alloc(NULL); + } + + // call scheduler metric to fill RB grid + dl_metric->sched_users(ue_db, &dl_mask, nof_ctrl_symbols, current_tti); + + int nof_data_elems = 0; + for (it_t iter = ue_db.begin(); iter != ue_db.end(); ++iter) { + sched_ue* user = (sched_ue*)&iter->second; + /** + * Tests whether the RAR and Msg3 were scheduled within the expected windows + */ uint16_t rnti = (uint16_t) iter->first; - uint32_t data_before = user->get_pending_dl_new_data(current_tti); - dl_harq_proc *h = dl_metric->get_user_allocation(user); + dl_harq_proc* h = user->get_dl_alloc(); srslte_dci_format_t dci_format = user->get_dci_format(); - data[nof_data_elems].dci_format = dci_format; - uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT1, cfg.cell.nof_prb, cfg.cell.nof_ports)); if (h) { - // Try to schedule DCI first - if (generate_dci(&data[nof_data_elems].dci_location, + uint32_t data_before = user->get_pending_dl_new_data(current_tti); + uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(&cfg.cell, NULL, NULL, dci_format)); + // Try to schedule DCI first + uint32_t tti_rx = (current_tti + 10240 - TX_DELAY) % 10240; + sched_vars::tti_vars_t* tti_vars = &sched_vars.tti_vars(tti_rx); + if (generate_dci(&data[nof_data_elems].dci.location, user->get_locations(current_cfi, sf_idx), - aggr_level, user)) - { - bool is_newtx = h->is_empty(0) && h->is_empty(1) ; - int tbs = 0; + aggr_level, + tti_vars, + user)) { + bool is_newtx = h->is_empty(0) && h->is_empty(1); + int tbs = 0; switch(dci_format) { case SRSLTE_DCI_FORMAT1: tbs = user->generate_format1(h, &data[nof_data_elems], current_tti, current_cfi); @@ -722,26 +796,42 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) Error("DCI format (%d) not implemented\n", dci_format); } if (tbs > 0) { - log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d/%d, tb_en={%s,%s}\n", - !is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(), - data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0) + h->nof_retx(1), + + log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=%s, dci=(%d,%d), n_rtx=%d, tbs=%d, buffer=%d/%d\n", + !is_newtx ? "retx" : "tx", + rnti, + h->get_id(), + h->get_rbgmask().to_hex().c_str(), + data[nof_data_elems].dci.location.L, + data[nof_data_elems].dci.location.ncce, + h->nof_retx(0) + h->nof_retx(1), tbs, - data_before, user->get_pending_dl_new_data(current_tti), - data[nof_data_elems].dci.tb_en[0]?"y":"n", - data[nof_data_elems].dci.tb_en[1]?"y":"n"); + data_before, + user->get_pending_dl_new_data(current_tti)); nof_data_elems++; } else { - log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, tbs=%d, buffer=%d\n", - !is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(), - data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, - tbs, user->get_pending_dl_new_data(current_tti)); + log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=%s, dci=%d,%d, tbs=%d, buffer=%d\n", + !is_newtx ? "retx" : "tx", + rnti, + h->get_id(), + h->get_rbgmask().to_hex().c_str(), + data[nof_data_elems].dci.location.L, + data[nof_data_elems].dci.location.ncce, + tbs, + user->get_pending_dl_new_data(current_tti)); } } else { - for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { h->reset(tb); } - Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d, cfi=%d\n", rnti, h->get_id(), current_cfi); - } + uint32_t tti_rx = TTI_SUB(current_tti, TX_DELAY); + Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d, cfi=%d, used_cce=%s\n", + rnti, + h->get_id(), + current_cfi, + sched_vars.tti_vars(tti_rx).used_cce.to_string().c_str()); + fail_dci_alloc = true; + } } // Reset blocked PIDs @@ -749,8 +839,6 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST]) } - - return nof_data_elems; } @@ -762,29 +850,28 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result) } /* If ul_sched() not yet called this tti, reset CCE state */ - if (current_tti != tti) { - bzero(used_cce, MAX_CCE*sizeof(bool)); - } + uint32_t tti_rx = (tti + 10240 - TX_DELAY) % 10240; + sched_vars::tti_vars_t* tti_vars = &sched_vars.new_tti(tti_rx); /* Initialize variables */ - current_tti = tti; - sfn = tti/10; - sf_idx = tti%10; - avail_rbg = nof_rbg; - start_rbg = 0; - current_cfi = sched_cfg.nof_ctrl_symbols; - bc_aggr_level = 2; - rar_aggr_level = 2; + current_tti = tti; + sfn = tti / 10; + sf_idx = tti % 10; + avail_rbg = nof_rbg; + start_rbg = 0; + current_cfi = sched_cfg.nof_ctrl_symbols; + bc_aggr_level = 2; + rar_aggr_level = 2; bzero(sched_result, sizeof(sched_interface::dl_sched_res_t)); pthread_mutex_lock(&sched_mutex); pthread_rwlock_rdlock(&rwlock); /* Schedule Broadcast data */ - sched_result->nof_bc_elems += dl_sched_bc(sched_result->bc); - + sched_result->nof_bc_elems += dl_sched_bc(sched_result->bc); + /* Schedule RAR */ - sched_result->nof_rar_elems += dl_sched_rar(sched_result->rar); + sched_result->nof_rar_elems += dl_sched_rar(sched_result->rar); /* Schedule pending RLC data */ sched_result->nof_data_elems += dl_sched_data(sched_result->data); @@ -798,7 +885,31 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result) return 0; } -// Uplink sched +// Uplink sched + +void sched::ul_sched_msg3() +{ + uint32_t pending_tti = current_tti % 10; + if (pending_msg3[pending_tti].enabled) { + ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[pending_tti].n_prb, pending_msg3[pending_tti].L}; + if (ul_mask.any(msg3)) { + log_h->warning("SCHED: Could not allocate msg3 within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L); + } + ul_mask.fill(msg3); + uint16_t rnti = pending_msg3[pending_tti].rnti; + if (ue_db.count(rnti)) { // TODO: is this needed? + sched_ue* user = &ue_db[rnti]; + ul_harq_proc* h = user->get_ul_harq(current_tti); + h->set_alloc(msg3); + h->set_rar_mcs(pending_msg3[pending_tti].mcs); + pending_msg3[pending_tti].enabled = false; + user->set_ul_alloc(h); + } else { + log_h->warning("SCHED: Msg3 allocated for user rnti=0x%x that no longer exists\n", rnti); + } + } +} + int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched_result) { typedef std::map::iterator it_t; @@ -807,153 +918,135 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched return 0; } - if (cfg.prach_freq_offset + 6 > cfg.cell.nof_prb and cfg.cell.nof_prb>10) { - fprintf(stderr, "Invalid PRACH configuration: frequency offset=%d outside bandwidth limits\n", cfg.prach_freq_offset); - return -1; - } - /* If dl_sched() not yet called this tti (this tti is +4ms advanced), reset CCE state */ - if (TTI_TX(current_tti) != tti) { - bzero(used_cce, MAX_CCE*sizeof(bool)); - } - + uint32_t tti_rx = (tti + 10240 - 2 * FDD_HARQ_DELAY_MS) % 10240; + sched_vars::tti_vars_t* tti_vars = &sched_vars.new_tti(tti_rx); + /* Initialize variables */ current_tti = tti; sfn = tti/10; - if (tti > HARQ_DELAY_MS) { - sf_idx = (tti-HARQ_DELAY_MS)%10; + if (tti > TX_DELAY) { + sf_idx = (tti - TX_DELAY) % 10; } else { - sf_idx = (tti+10240-HARQ_DELAY_MS)%10; + sf_idx = (tti + 10240 - TX_DELAY) % 10; } - int nof_dci_elems = 0; + int nof_dci_elems = 0; int nof_phich_elems = 0; + // current_cfi is set in dl_sched() + bzero(sched_result, sizeof(sched_interface::ul_sched_res_t)); + pthread_mutex_lock(&sched_mutex); pthread_rwlock_rdlock(&rwlock); - // current_cfi is set in dl_sched() - bzero(sched_result, sizeof(sched_interface::ul_sched_res_t)); - ul_metric->reset_allocation(cfg.cell.nof_prb); + // clear previous UL allocations + for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { + it->second.set_ul_alloc(NULL); + } + ul_mask.resize(cfg.cell.nof_prb); + ul_mask.reset(); - // Get HARQ process for this TTI + // Get HARQ process for this TTI for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - sched_ue *user = (sched_ue*) &iter->second; - uint16_t rnti = (uint16_t) iter->first; + sched_ue* user = (sched_ue*)&iter->second; + uint16_t rnti = (uint16_t)iter->first; user->has_pucch = false; - ul_harq_proc *h = user->get_ul_harq(current_tti); + ul_harq_proc* h = user->get_ul_harq(current_tti); /* Indicate PHICH acknowledgment if needed */ if (h->has_pending_ack()) { sched_result->phich[nof_phich_elems].phich = h->get_ack(0)?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; sched_result->phich[nof_phich_elems].rnti = rnti; + log_h->debug( + "SCHED: Allocated PHICH for rnti=0x%x, value=%d\n", rnti, sched_result->phich[nof_phich_elems].phich); nof_phich_elems++; } } // reserve PRBs for PRACH - if(srslte_prach_tti_opportunity_config(cfg.prach_config, tti, -1)) { + if (srslte_prach_tti_opportunity_config_fdd(cfg.prach_config, tti, -1)) { ul_harq_proc::ul_alloc_t prach = {cfg.prach_freq_offset, 6}; - if(!ul_metric->update_allocation(prach)) { + if (ul_mask.any(prach)) { log_h->warning("SCHED: Failed to allocate PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L); } - else { - log_h->debug("SCHED: Allocated PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L); - } + ul_mask.fill(prach); + log_h->debug("SCHED: Allocated PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L); } // Update available allocation if there's a pending RAR - // NOTE: It has priority over PUCCH. - if (pending_msg3[tti%10].enabled) { - ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L}; - if(ul_metric->update_allocation(msg3)) { - log_h->debug("SCHED: Allocated msg3 RBs within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L); - } - else { - log_h->warning("SCHED: Could not allocate msg3 within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L); - } - } + ul_sched_msg3(); // Allocate PUCCH resources if (cfg.nrb_pucch >= 0) { - ul_harq_proc::ul_alloc_t pucch = {0, (uint32_t) cfg.nrb_pucch}; - if (!ul_metric->update_allocation(pucch) and cfg.cell.nof_prb != 6) { - log_h->warning("SCHED: There was a collision with the PUCCH (%d, %d)\n", pucch.RB_start, pucch.RB_start+pucch.L); + ul_harq_proc::ul_alloc_t pucch = {0, (uint32_t)cfg.nrb_pucch}; + if (ul_mask.any(pucch) and cfg.cell.nof_prb != 6) { + log_h->warning( + "SCHED: There was a collision with the PUCCH (%d, %d)\n", pucch.RB_start, pucch.RB_start + pucch.L); + } else { + ul_mask.fill(pucch); } - pucch.RB_start = cfg.cell.nof_prb-cfg.nrb_pucch; - pucch.L = (uint32_t) cfg.nrb_pucch; - if (!ul_metric->update_allocation(pucch) and cfg.cell.nof_prb != 6) { + pucch.RB_start = cfg.cell.nof_prb - cfg.nrb_pucch; + pucch.L = (uint32_t)cfg.nrb_pucch; + if (ul_mask.any(pucch) and cfg.cell.nof_prb != 6) { log_h->warning("SCHED: There was a collision with the PUCCH (%d, %d)\n", pucch.RB_start, pucch.RB_start+pucch.L); + } else { + ul_mask.fill(pucch); } } else { for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; - uint16_t rnti = (uint16_t) iter->first; uint32_t prb_idx[2] = {0, 0}; if (user->get_pucch_sched(current_tti, prb_idx)) { user->has_pucch = true; // allocate PUCCH - for (int i=0;i<2;i++) { + for (int i = 0; i < 2; i++) { ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1}; - ul_metric->update_allocation(pucch); + ul_mask.fill(pucch); } } } } - ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti); + // Call scheduler for normal data + ul_metric->sched_users(ue_db, &ul_mask, current_tti); // Now allocate PUSCH for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; - uint16_t rnti = (uint16_t) iter->first; - - ul_harq_proc *h = NULL; - - // Check if there are pending Msg3 transmissions - bool is_rar = false; - if (pending_msg3[tti%10].enabled && pending_msg3[tti%10].rnti == rnti) { - h = user->get_ul_harq(tti); - if (h) { - ul_harq_proc::ul_alloc_t alloc; - alloc.L = pending_msg3[tti%10].L; - alloc.RB_start = pending_msg3[tti%10].n_prb; - h->set_alloc(alloc); - h->set_rar_mcs(pending_msg3[tti%10].mcs); - is_rar = true; - pending_msg3[tti%10].enabled = false; - } else { - Warning("No HARQ pid available for transmission of Msg3\n"); - } - } else { - h = ul_metric->get_user_allocation(user); - } - if (h) - { - ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); - bool is_newtx = h->is_empty(0); - bool needs_pdcch = !h->is_adaptive_retx() && !is_rar; + uint16_t rnti = (uint16_t)iter->first; + ul_harq_proc* h = NULL; + + h = user->get_ul_alloc(); + if (h) { + ul_harq_proc::ul_alloc_t ul_alloc = h->get_alloc(); + bool is_rar = h->is_rar_tx(); + bool is_newtx = h->is_empty(0); + bool needs_pdcch = not is_rar and (is_newtx or h->is_adaptive_retx()); // Set number of retx if (is_newtx) { if (is_rar) { h->set_max_retx(cfg.maxharq_msg3tx); } else { - h->set_max_retx(user->get_max_retx()); + h->set_max_retx(user->get_max_retx()); } } // Generate PDCCH except for RAR and non-adaptive retx if (needs_pdcch) { - uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, cfg.cell.nof_prb, cfg.cell.nof_ports)); - if (!generate_dci(&sched_result->pusch[nof_dci_elems].dci_location, - user->get_locations(current_cfi, sf_idx), - aggr_level)) - { + uint32_t aggr_level = user->get_aggr_level(srslte_dci_format_sizeof(&cfg.cell, NULL, NULL, SRSLTE_DCI_FORMAT0)); + if (!generate_dci(&sched_result->pusch[nof_dci_elems].dci.location, + user->get_locations(current_cfi, sf_idx), + aggr_level, + tti_vars)) { h->reset(0); log_h->warning("SCHED: Could not schedule UL DCI rnti=0x%x, pid=%d, L=%d, sf_idx=%d\n", - rnti, h->get_id(), aggr_level, sf_idx); + rnti, + h->get_id(), + aggr_level, + sf_idx); sched_result->pusch[nof_dci_elems].needs_pdcch = false; } else { @@ -963,7 +1056,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched sched_result->pusch[nof_dci_elems].needs_pdcch = false; } - // Generate grant unless DCI could not be generated and was required + // Generate dci unless DCI could not be generated and was required if (sched_result->pusch[nof_dci_elems].needs_pdcch == needs_pdcch) { uint32_t pending_data_before = user->get_pending_ul_new_data(current_tti); if (user->generate_format0(h, &sched_result->pusch[nof_dci_elems], current_tti, user->needs_cqi(tti, true)) > 0) @@ -974,24 +1067,35 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched user->unset_sr(); } - log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=(%d,%d), n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", - is_rar?"RAR":"UL", - is_newtx?"tx":"retx", - rnti, h->get_id(), - sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, - alloc.RB_start, alloc.RB_start+alloc.L, h->nof_retx(0), sched_result->pusch[nof_dci_elems].tbs, - user->get_pending_ul_new_data(current_tti),pending_data_before, user->get_pending_ul_old_data()); - - nof_dci_elems++; + log_h->info("SCHED: %s %s rnti=0x%x, pid=%d, dci=(%d,%d), prb=(%d,%d), n_rtx=%d, tbs=%d, bsr=%d (%d-%d)\n", + is_rar ? "Msg3" : "UL", + is_newtx ? "tx" : "retx", + rnti, + h->get_id(), + sched_result->pusch[nof_dci_elems].dci.location.L, + sched_result->pusch[nof_dci_elems].dci.location.ncce, + ul_alloc.RB_start, + ul_alloc.RB_start + ul_alloc.L, + h->nof_retx(0), + sched_result->pusch[nof_dci_elems].tbs, + user->get_pending_ul_new_data(current_tti), + pending_data_before, + user->get_pending_ul_old_data()); + + nof_dci_elems++; } else { - log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=%d,%d, grant=(%d,%d), tbs=%d, bsr=%d\n", - is_rar?"RAR":"UL", - is_newtx?"tx":"retx", - rnti, h->get_id(), - sched_result->pusch[nof_dci_elems].dci_location.L, sched_result->pusch[nof_dci_elems].dci_location.ncce, - alloc.RB_start, alloc.RB_start+alloc.L, sched_result->pusch[nof_dci_elems].tbs, - user->get_pending_ul_new_data(current_tti)); - } + log_h->warning("SCHED: Error %s %s rnti=0x%x, pid=%d, dci=(%d,%d), prb=(%d,%d), tbs=%d, bsr=%d\n", + is_rar ? "Msg3" : "UL", + is_newtx ? "tx" : "retx", + rnti, + h->get_id(), + sched_result->pusch[nof_dci_elems].dci.location.L, + sched_result->pusch[nof_dci_elems].dci.location.ncce, + ul_alloc.RB_start, + ul_alloc.RB_start + ul_alloc.L, + sched_result->pusch[nof_dci_elems].tbs, + user->get_pending_ul_new_data(current_tti)); + } } } } @@ -999,8 +1103,6 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched // Update pending data counters after this TTI for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue *) &iter->second; - uint16_t rnti = (uint16_t) iter->first; - user->get_ul_harq(current_tti)->reset_pending_data(); } @@ -1013,97 +1115,99 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched return SRSLTE_SUCCESS; } - /******************************************************* - * - * Helper functions - * + * + * Helper functions + * *******************************************************/ -void sched::generate_cce_location(srslte_regs_t *regs_, sched_ue::sched_dci_cce_t* location, - uint32_t cfi, uint32_t sf_idx, uint16_t rnti) +void sched::generate_cce_location( + srslte_regs_t* regs_, sched_ue::sched_dci_cce_t* location, uint32_t cfi, uint32_t sf_idx, uint16_t rnti) { + bzero(location, sizeof(sched_ue::sched_dci_cce_t)); + srslte_dci_location_t loc[64]; - uint32_t nloc = 0; + uint32_t nloc = 0; if (rnti == 0) { - nloc = srslte_pdcch_common_locations_ncce(srslte_regs_pdcch_ncce(regs_, cfi), - loc, 64); + nloc = srslte_pdcch_common_locations_ncce(srslte_regs_pdcch_ncce(regs_, cfi), loc, 64); } else { - nloc = srslte_pdcch_ue_locations_ncce(srslte_regs_pdcch_ncce(regs_, cfi), - loc, 64, sf_idx, rnti); + nloc = srslte_pdcch_ue_locations_ncce(srslte_regs_pdcch_ncce(regs_, cfi), loc, 64, sf_idx, rnti); } - for (uint32_t l=0;l<=3;l++) { - int n=0; - for (uint32_t i=0;icce_start[l][n] = loc[i].ncce; - n++; - } - } - location->nof_loc[l] = n; + // Save to different format + for (uint32_t i = 0; i < nloc; i++) { + uint32_t l = loc[i].L; + location->cce_start[l][location->nof_loc[l]] = loc[i].ncce; + location->nof_loc[l]++; } - } +#define NCCE(L) (1 << L) -#define NCCE(L) (1<nof_loc[aggr_level]) { Error("In generate_dci(): No locations for aggr_level=%d\n", aggr_level); - return false; + return -1; } uint32_t nof_cand = 0; uint32_t test_cand = rand()%locations->nof_loc[aggr_level]; - bool allocated=false; - while(nof_candnof_loc[aggr_level] && !allocated) { + while (nof_cand < locations->nof_loc[aggr_level]) { uint32_t ncce = locations->cce_start[aggr_level][test_cand]; bool used = false; if (user) { used = user->pucch_sr_collision(current_tti, ncce); } - for (int j=0;jused_cce.any(ncce, ncce + NCCE(aggr_level)); if (used) { test_cand++; - if (test_cand==locations->nof_loc[aggr_level]) { + if (test_cand == locations->nof_loc[aggr_level]) { test_cand = 0; } nof_cand++; } else { - for (int j=0;jL = aggr_level; - sched_location->ncce = locations->cce_start[aggr_level][test_cand]; + return -1; +} + +bool sched::generate_dci(srslte_dci_location_t* sched_location, + sched_ue::sched_dci_cce_t* locations, + uint32_t aggr_level, + sched_vars::tti_vars_t* tti_vars, + sched_ue* user) +{ + int ncce = find_empty_dci(locations, aggr_level, tti_vars, user); + if (ncce < 0) { + return false; } - - return allocated; + tti_vars->used_cce.fill(ncce, ncce + NCCE(aggr_level), true); + Debug("SCHED: Allocated DCI L=%d, ncce=%d\n", aggr_level, ncce); + + if (sched_location) { + sched_location->L = aggr_level; + sched_location->ncce = (uint32_t)ncce; + } + return true; } -int sched::generate_format1a(uint32_t rb_start, uint32_t l_crb, uint32_t tbs_bytes, uint32_t rv, srslte_ra_dl_dci_t *dci) +int sched::generate_format1a( + uint32_t rb_start, uint32_t l_crb, uint32_t tbs_bytes, uint32_t rv, uint16_t rnti, srslte_dci_dl_t* dci) { /* Calculate I_tbs for this TBS */ - int tbs = tbs_bytes*8; - int i; - int mcs = -1; - for (i=0;i<27;i++) { + int tbs = tbs_bytes * 8; + int i; + int mcs = -1; + for (i = 0; i < 27; i++) { if (srslte_ra_tbs_from_idx(i, 2) >= tbs) { dci->type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_2; - mcs = i; - tbs = srslte_ra_tbs_from_idx(i, 2); + mcs = i; + tbs = srslte_ra_tbs_from_idx(i, 2); break; } else if (srslte_ra_tbs_from_idx(i, 3) >= tbs) { dci->type2_alloc.n_prb1a = srslte_ra_type2_t::SRSLTE_RA_TYPE2_NPRB1A_3; @@ -1122,21 +1226,41 @@ int sched::generate_format1a(uint32_t rb_start, uint32_t l_crb, uint32_t tbs_byt dci->alloc_type = SRSLTE_RA_ALLOC_TYPE2; dci->type2_alloc.mode = srslte_ra_type2_t::SRSLTE_RA_TYPE2_LOC; - dci->type2_alloc.L_crb = l_crb; - dci->type2_alloc.RB_start = rb_start; - dci->harq_process = 0; - dci->mcs_idx = mcs; - dci->rv_idx = rv; - dci->tb_en[0] = true; - dci->tb_en[1] = false; - + dci->type2_alloc.riv = srslte_ra_type2_to_riv(l_crb, rb_start, cfg.cell.nof_prb); + dci->pid = 0; + dci->tb[0].mcs_idx = mcs; + dci->tb[0].rv = rv; + dci->format = SRSLTE_DCI_FORMAT1A; + dci->rnti = rnti; + return tbs; } +void sched::sched_vars::init(sched* parent_) +{ + parent = parent_; + for (uint32_t i = 0; i < tti_array_size; ++i) { + tti_vars_[i].used_cce.resize(srslte_regs_pdcch_ncce(&parent->regs, parent->sched_cfg.nof_ctrl_symbols)); + tti_vars_[i].used_cce.reset(); + } +} +sched::sched_vars::tti_vars_t& sched::sched_vars::new_tti(uint32_t tti_rx) +{ + tti_vars_t& ret = tti_vars_[tti_rx % 16]; + // if it is the first time tti is run, reset vars + if (ret.tti_rx != tti_rx) { + ret.used_cce.resize(srslte_regs_pdcch_ncce(&parent->regs, parent->sched_cfg.nof_ctrl_symbols)); + ret.used_cce.reset(); + ret.tti_rx = tti_rx; + } + return ret; +} - - +sched::sched_vars::tti_vars_t& sched::sched_vars::tti_vars(uint32_t tti_rx) +{ + return tti_vars_[tti_rx % 16]; +} } diff --git a/srsenb/src/mac/scheduler_harq.cc b/srsenb/src/mac/scheduler_harq.cc index c860c7a14..5b546f505 100644 --- a/srsenb/src/mac/scheduler_harq.cc +++ b/srsenb/src/mac/scheduler_harq.cc @@ -59,11 +59,6 @@ void harq_proc::set_max_retx(uint32_t max_retx_) { max_retx = max_retx_; } -uint32_t harq_proc::get_id() -{ - return id; -} - void harq_proc::reset(uint32_t tb_idx) { active[tb_idx] = false; @@ -76,22 +71,37 @@ void harq_proc::reset(uint32_t tb_idx) tx_cnt[tb_idx] = 0; } -bool harq_proc::is_empty(uint32_t tb_idx) +uint32_t harq_proc::get_id() const +{ + return id; +} + +bool harq_proc::is_empty() const +{ + for (uint32_t i = 0; i < SRSLTE_MAX_TB; ++i) { + if (not is_empty(i)) { + return false; + } + } + return true; +} + +bool harq_proc::is_empty(uint32_t tb_idx) const { return !active[tb_idx] || (active[tb_idx] && ack[tb_idx] && ack_received[tb_idx]); } -bool harq_proc::has_pending_retx_common(uint32_t tb_idx) +bool harq_proc::has_pending_retx_common(uint32_t tb_idx) const { return !ack[tb_idx] && n_rtx[tb_idx] < max_retx; } -uint32_t harq_proc::get_tti() +uint32_t harq_proc::get_tti() const { return (uint32_t) tti; } -bool harq_proc::get_ack(uint32_t tb_idx) +bool harq_proc::get_ack(uint32_t tb_idx) const { return ack[tb_idx]; } @@ -100,8 +110,8 @@ void harq_proc::set_ack(uint32_t tb_idx, bool ack_) { ack[tb_idx] = ack_; ack_received[tb_idx] = true; - log_h->debug("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx); - if (n_rtx[tb_idx] + 1 >= max_retx) { + log_h->info("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx); + if (!ack_ && (n_rtx[tb_idx] + 1 >= max_retx)) { Warning("SCHED: discarting TB %d pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", tb_idx, id, tti, max_retx); active[tb_idx] = false; } @@ -123,7 +133,7 @@ void harq_proc::new_tx_common(uint32_t tb_idx, uint32_t tti_, int mcs, int tbs) } } -void harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int *mcs, int *tbs) +void harq_proc::new_retx_common(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs) { ack_received[tb_idx] = false; tti = tti_; @@ -136,57 +146,82 @@ void harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int *mcs, int *tbs) } } -uint32_t harq_proc::nof_tx(uint32_t tb_idx) +uint32_t harq_proc::nof_tx(uint32_t tb_idx) const { return tx_cnt[tb_idx]; } -uint32_t harq_proc::nof_retx(uint32_t tb_idx) +uint32_t harq_proc::nof_retx(uint32_t tb_idx) const { return n_rtx[tb_idx]; } -bool harq_proc::get_ndi(uint32_t tb_idx) +bool harq_proc::get_ndi(uint32_t tb_idx) const { return ndi[tb_idx]; } -/****************************************************** +/****************************************************** * UE::DL HARQ class * ******************************************************/ +dl_harq_proc::dl_harq_proc() +{ + n_cce = 0; + rbgmask = 0; +} + void dl_harq_proc::new_tx(uint32_t tb_idx, uint32_t tti, int mcs, int tbs, uint32_t n_cce_) { n_cce = n_cce_; new_tx_common(tb_idx, tti, mcs, tbs); } +void dl_harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs) +{ + new_retx_common(tb_idx, tti_, mcs, tbs); +} + uint32_t dl_harq_proc::get_n_cce() { return n_cce; } -uint32_t dl_harq_proc::get_rbgmask() +rbgmask_t dl_harq_proc::get_rbgmask() { return rbgmask; } -void dl_harq_proc::set_rbgmask(uint32_t new_mask) +void dl_harq_proc::set_rbgmask(rbgmask_t new_mask) { rbgmask = new_mask; } -bool dl_harq_proc::has_pending_retx(uint32_t tb_idx, uint32_t current_tti) +bool dl_harq_proc::has_pending_retx(uint32_t tb_idx, uint32_t current_tti) const { - return srslte_tti_interval(current_tti, tti) >= (2*HARQ_DELAY_MS) && has_pending_retx_common(tb_idx); + uint32_t tti_diff = srslte_tti_interval(current_tti, tti); + // NOTE: tti may be ahead of current_tti due to thread flip + return tti_diff < 10240 / 2 and tti_diff >= (SRSLTE_FDD_NOF_HARQ) && !is_empty(tb_idx); } -int dl_harq_proc::get_tbs(uint32_t tb_idx) +int dl_harq_proc::get_tbs(uint32_t tb_idx) const { return last_tbs[tb_idx]; } +/****************************************************** + * UE::UL RB MASK * + ******************************************************/ + +bool ul_mask_t::any(ul_harq_proc::ul_alloc_t alloc) const noexcept +{ + return base_type::any(alloc.RB_start, alloc.RB_start + alloc.L); +} +void ul_mask_t::fill(srsenb::ul_harq_proc::ul_alloc_t alloc) noexcept +{ + base_type::fill(alloc.RB_start, alloc.RB_start + alloc.L, true); +} /****************************************************** * UE::UL HARQ class * @@ -199,28 +234,58 @@ ul_harq_proc::ul_alloc_t ul_harq_proc::get_alloc() void ul_harq_proc::set_alloc(ul_harq_proc::ul_alloc_t alloc) { + if (not is_empty(0)) { + log_h->error("Trying to overwrite an on-going harq procedure\n"); + return; + } + is_rar = false; // can be set to true through set_rar_mcs() is_adaptive = false; - memcpy(&allocation, &alloc, sizeof(ul_alloc_t)); + allocation = alloc; +} + +void ul_harq_proc::set_realloc(ul_harq_proc::ul_alloc_t alloc) +{ + if (is_empty(0)) { + log_h->error("Trying to reallocate an empty harq procedure\n"); + return; + } + if (alloc.L != allocation.L or alloc.RB_start != allocation.RB_start) { + is_adaptive = true; + } + allocation = alloc; } -void ul_harq_proc::re_alloc(ul_harq_proc::ul_alloc_t alloc) +bool ul_harq_proc::has_pending_retx() { - is_adaptive = true; - memcpy(&allocation, &alloc, sizeof(ul_alloc_t)); + return active[0] and has_pending_retx_common(0) and need_ack; } bool ul_harq_proc::is_adaptive_retx() { - return is_adaptive; + return is_adaptive and has_pending_retx(); +} + +bool ul_harq_proc::is_rar_tx() +{ + return is_rar; +} + +bool ul_harq_proc::is_new_tx() +{ + return active[0] and not has_pending_retx(); } void ul_harq_proc::new_tx(uint32_t tti_, int mcs, int tbs) { need_ack = true; new_tx_common(0, tti_, mcs, tbs); - pending_data = tbs; + pending_data = tbs; } +void ul_harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs) +{ + new_retx_common(tb_idx, tti_, mcs, tbs); +} bool ul_harq_proc::has_pending_ack() { @@ -253,8 +318,9 @@ uint32_t ul_harq_proc::get_pending_data() void ul_harq_proc::set_rar_mcs(uint32_t mcs) { - rar_mcs = mcs; - has_rar_mcs = true; + rar_mcs = mcs; + has_rar_mcs = true; + is_rar = true; } bool ul_harq_proc::get_rar_mcs(int *mcs) @@ -263,12 +329,11 @@ bool ul_harq_proc::get_rar_mcs(int *mcs) if (mcs) { *mcs = (int) rar_mcs; } - has_rar_mcs = false; + has_rar_mcs = false; + is_rar = false; return true; } return false; } - - } diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc index 154cd823e..75d876332 100644 --- a/srsenb/src/mac/scheduler_metric.cc +++ b/srsenb/src/mac/scheduler_metric.cc @@ -34,114 +34,74 @@ #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) namespace srsenb { - - - + /***************************************************************** * - * Downlink Metric + * Downlink Metric * *****************************************************************/ -uint32_t dl_metric_rr::calc_rbg_mask(bool mask[MAX_RBG]) -{ - // Build RBG bitmask - uint32_t rbg_bitmask = 0; - for (uint32_t n=0;n 0) { - if ((mask & 1) == 1) { - count++; - } - mask >>= 1; - } - return count; -} - -uint32_t dl_metric_rr::get_required_rbg(sched_ue *user, uint32_t tti) +void dl_metric_rr::sched_users(std::map& ue_db, + rbgmask_t* dl_mask, + uint32_t nof_ctrl_symbols_, + uint32_t tti) { - dl_harq_proc *h = user->get_pending_dl_harq(tti); - if (h) { - return count_rbg(h->get_rbgmask()); - } - uint32_t pending_data = user->get_pending_dl_new_data(current_tti); - return user->prb_to_rbg(user->get_required_prb_dl(pending_data, nof_ctrl_symbols)); -} + typedef std::map::iterator it_t; -void dl_metric_rr::new_tti(std::map &ue_db, uint32_t start_rbg, uint32_t nof_rbg, uint32_t nof_ctrl_symbols_, uint32_t tti) -{ - total_rbg = start_rbg+nof_rbg; - for (uint32_t i=0;isize() - used_rbg->count()); // nof_rbg; - if(ue_db.size()==0) + if (ue_db.empty()) return; // give priority in a time-domain RR basis - uint32_t priority_idx = current_tti % ue_db.size(); - std::map::iterator iter = ue_db.begin(); + uint32_t priority_idx = current_tti % (uint32_t)ue_db.size(); + it_t iter = ue_db.begin(); std::advance(iter,priority_idx); for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) { if(iter==ue_db.end()) { iter = ue_db.begin(); // wrap around } sched_ue *user = (sched_ue*) &iter->second; - user->dl_next_alloc = apply_user_allocation(user); + user->set_dl_alloc(allocate_user(user)); } } -bool dl_metric_rr::new_allocation(uint32_t nof_rbg, uint32_t *rbgmask) { - bool mask_bit[MAX_RBG]; - bzero(mask_bit, sizeof(bool)*MAX_RBG); - - for (uint32_t i=0;i 0;i++) { - if (used_rbg[i]) { - mask_bit[i] = false; - } else { - mask_bit[i] = true; +bool dl_metric_rr::find_allocation(uint32_t nof_rbg, rbgmask_t* rbgmask) +{ + *rbgmask = ~(*used_rbg); + + uint32_t i = 0; + for (; i < used_rbg->size() and nof_rbg > 0; ++i) { + if (rbgmask->test(i)) { nof_rbg--; } } - if (rbgmask) { - *rbgmask = calc_rbg_mask(mask_bit); - } - return (nof_rbg == 0); + rbgmask->fill(i, rbgmask->size(), false); + + return nof_rbg == 0; } -void dl_metric_rr::update_allocation(uint32_t new_mask) { - used_rbg_mask |= new_mask; - for (uint32_t n=0;nget_pending_dl_harq(current_tti); uint32_t req_bytes = user->get_pending_dl_new_data_total(current_tti); @@ -151,17 +111,17 @@ dl_harq_proc* dl_metric_rr::apply_user_allocation(sched_ue *user) { #else if (h && !h->is_empty()) { #endif - uint32_t retx_mask = h->get_rbgmask(); - // If can schedule the same mask, do it - if (!allocation_is_valid(retx_mask)) { - update_allocation(retx_mask); - return h; - } + rbgmask_t retx_mask = h->get_rbgmask(); + uint32_t nof_rbg = retx_mask.count(); + if (nof_rbg <= available_rbg) { + // Try to reuse the same mask + if (allocation_is_valid(retx_mask)) { + update_allocation(retx_mask); + return h; + } - // If not, try to find another mask in the current tti - uint32_t nof_rbg = count_rbg(retx_mask); - if (nof_rbg < available_rbg) { - if (new_allocation(nof_rbg, &retx_mask)) { + // If previous mask does not fit, find another with exact same number of rbgs + if (find_allocation(nof_rbg, &retx_mask)) { update_allocation(retx_mask); h->set_rbgmask(retx_mask); return h; @@ -178,9 +138,9 @@ dl_harq_proc* dl_metric_rr::apply_user_allocation(sched_ue *user) { // Allocate resources based on pending data if (req_bytes) { uint32_t pending_rbg = user->prb_to_rbg(user->get_required_prb_dl(req_bytes, nof_ctrl_symbols)); - uint32_t newtx_mask = 0; - new_allocation(pending_rbg, &newtx_mask); - if (newtx_mask) { + rbgmask_t newtx_mask(used_rbg->size()); + find_allocation(pending_rbg, &newtx_mask); + if (newtx_mask.any()) { // some empty spaces were found update_allocation(newtx_mask); h->set_rbgmask(newtx_mask); return h; @@ -191,54 +151,36 @@ dl_harq_proc* dl_metric_rr::apply_user_allocation(sched_ue *user) { return NULL; } -dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user) -{ - return user->dl_next_alloc; -} - - - - - - - - - /***************************************************************** * * Uplink Metric * *****************************************************************/ -void ul_metric_rr::reset_allocation(uint32_t nof_rb_) -{ - nof_rb = nof_rb_; - bzero(used_rb, nof_rb*sizeof(bool)); -} - -void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, uint32_t tti) +void ul_metric_rr::sched_users(std::map& ue_db, ul_mask_t* start_mask, uint32_t tti) { typedef std::map::iterator it_t; - current_tti = tti; + + current_tti = tti; + used_rb = start_mask; if(ue_db.size()==0) return; - for(it_t it = ue_db.begin(); it != ue_db.end(); ++it) { - it->second.ul_next_alloc = NULL; - } - // give priority in a time-domain RR basis uint32_t priority_idx = (current_tti+(uint32_t)ue_db.size()/2) % (uint32_t)ue_db.size(); // make DL and UL interleaved // allocate reTxs first it_t iter = ue_db.begin(); + std::advance(iter, priority_idx); for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) { if(iter==ue_db.end()) { iter = ue_db.begin(); // wrap around } sched_ue *user = (sched_ue *) &iter->second; - user->ul_next_alloc = allocate_user_retx_prbs(user); + if (user->get_ul_alloc() == NULL) { // can already be allocated for msg3 + user->set_ul_alloc(allocate_user_retx_prbs(user)); + } } // give priority in a time-domain RR basis @@ -249,34 +191,34 @@ void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, iter = ue_db.begin(); // wrap around } sched_ue *user = (sched_ue*) &iter->second; - if (!user->ul_next_alloc) { - user->ul_next_alloc = allocate_user_newtx_prbs(user); + if (user->get_ul_alloc() == NULL) { + user->set_ul_alloc(allocate_user_newtx_prbs(user)); } } } bool ul_metric_rr::allocation_is_valid(ul_harq_proc::ul_alloc_t alloc) { - if (alloc.RB_start+alloc.L > nof_rb) { + if (alloc.RB_start + alloc.L > used_rb->size()) { return false; } - for (uint32_t n=alloc.RB_start;nany(alloc); } -bool ul_metric_rr::new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc) +/** + * Finds a range of L contiguous PRBs that are empty + * @param L Size of the requested UL allocation in PRBs + * @param alloc Found allocation. It is guaranteed that 0 <= alloc->L <= L + * @return true if the requested allocation of size L was strictly met + */ +bool ul_metric_rr::find_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc) { - bzero(alloc, sizeof(ul_harq_proc::ul_alloc_t)); - for (uint32_t n=0;nL < L;n++) { - if (!used_rb[n] && alloc->L == 0) { + for (uint32_t n = 0; n < used_rb->size() && alloc->L < L; n++) { + if (not used_rb->test(n) && alloc->L == 0) { alloc->RB_start = n; } - if (!used_rb[n]) { + if (not used_rb->test(n)) { alloc->L++; } else if (alloc->L > 0) { // avoid edges @@ -303,10 +245,8 @@ bool ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc) { bool ret = false; if(allocation_is_valid(alloc)) { - ret = true; - } - for (uint32_t n=alloc.RB_start;nfill(alloc); + return true; } return ret; } @@ -316,20 +256,22 @@ ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue *user) ul_harq_proc *h = user->get_ul_harq(current_tti); // if there are procedures and we have space - if(!h->is_empty(0)) { + if (h->has_pending_retx()) { ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); // If can schedule the same mask, do it if (update_allocation(alloc)) { + h->set_realloc(alloc); return h; } - // If not, try to find another mask in the current tti - if (new_allocation(alloc.L, &alloc)) { + // If not, try to find another mask in the current tti with the same number of PRBs + if (find_allocation(alloc.L, &alloc)) { if(not update_allocation(alloc)) { - printf("SCHED: Computed UL allocation is not valid!\n"); + printf("ERROR: Scheduler failed to allocate user\n"); + return NULL; } - h->set_alloc(alloc); + h->set_realloc(alloc); return h; } } @@ -345,65 +287,18 @@ ul_harq_proc* ul_metric_rr::allocate_user_newtx_prbs(sched_ue* user) if (h->is_empty(0) and pending_data) { uint32_t pending_rb = user->get_required_prb_ul(pending_data); ul_harq_proc::ul_alloc_t alloc; - new_allocation(pending_rb, &alloc); - if (alloc.L) { - if(!update_allocation(alloc)) { - printf("SCHED: Computed UL allocation is not valid!\n"); - } - h->set_alloc(alloc); - return h; - } - } - return NULL; -} -ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user, bool retx_only) { - // Time-domain RR scheduling - uint32_t pending_data = user->get_pending_ul_new_data(current_tti); - ul_harq_proc *h = user->get_ul_harq(current_tti); - - // Schedule retx if we have space - if (!h->is_empty(0)) { - ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); - - // If can schedule the same mask, do it - if (allocation_is_valid(alloc)) { - update_allocation(alloc); - return h; - } - - // If not, try to find another mask in the current tti - if (new_allocation(alloc.L, &alloc)) { - update_allocation(alloc); + find_allocation(pending_rb, &alloc); + if (alloc.L > 0) { // at least one PRB was scheduled + if (not update_allocation(alloc)) { + printf("ERROR: Scheduler failed to allocate user\n"); + return NULL; + } h->set_alloc(alloc); return h; } } - - if (retx_only) { - return NULL; - } - - // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID - if (h->is_empty(0)) { - // Allocate resources based on pending data - if (pending_data) { - uint32_t pending_rb = user->get_required_prb_ul(pending_data); - ul_harq_proc::ul_alloc_t alloc; - new_allocation(pending_rb, &alloc); - if (alloc.L) { - update_allocation(alloc); - h->set_alloc(alloc); - return h; - } - } - } return NULL; } -ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user) -{ - return user->ul_next_alloc; -} - } diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index fa4fd6adb..6d69ededf 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -37,6 +37,7 @@ #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define MCS_FIRST_DL 4 +#define MIN_DATA_TBS 4 /****************************************************** * UE class * @@ -51,8 +52,17 @@ namespace srsenb { * *******************************************************/ -sched_ue::sched_ue() : dl_next_alloc(NULL), ul_next_alloc(NULL), has_pucch(false), power_headroom(0), rnti(0), max_mcs_dl(0), max_mcs_ul(0), - fixed_mcs_ul(0), fixed_mcs_dl(0), phy_config_dedicated_enabled(false) +sched_ue::sched_ue() : + next_dl_harq_proc(NULL), + next_ul_harq_proc(NULL), + has_pucch(false), + power_headroom(0), + rnti(0), + max_mcs_dl(0), + max_mcs_ul(0), + fixed_mcs_ul(0), + fixed_mcs_dl(0), + phy_config_dedicated_enabled(false) { log_h = NULL; @@ -61,6 +71,7 @@ sched_ue::sched_ue() : dl_next_alloc(NULL), ul_next_alloc(NULL), has_pucch(false bzero(&dci_locations, sizeof(dci_locations)); bzero(&dl_harq, sizeof(dl_harq)); bzero(&ul_harq, sizeof(ul_harq)); + bzero(&dl_ant_info, sizeof(dl_ant_info)); pthread_mutex_init(&mutex, NULL); reset(); @@ -72,8 +83,11 @@ sched_ue::~sched_ue() { pthread_mutex_destroy(&mutex); } -void sched_ue::set_cfg(uint16_t rnti_, sched_interface::ue_cfg_t *cfg_, sched_interface::cell_cfg_t *cell_cfg, - srslte_regs_t *regs, srslte::log *log_h_) +void sched_ue::set_cfg(uint16_t rnti_, + sched_interface::ue_cfg_t* cfg_, + sched_interface::cell_cfg_t* cell_cfg, + srslte_regs_t* regs, + srslte::log* log_h_) { reset(); @@ -83,18 +97,20 @@ void sched_ue::set_cfg(uint16_t rnti_, sched_interface::ue_cfg_t *cfg_, sched_in memcpy(&cell, &cell_cfg->cell, sizeof(srslte_cell_t)); P = srslte_ra_type0_P(cell.nof_prb); - max_mcs_dl = 28; - max_mcs_ul = 28; + max_mcs_dl = 28; + max_mcs_ul = 28; + + cfg = *cfg_; + + // Initialize TM + cfg.dl_cfg.tm = SRSLTE_TM1; - if (cfg_) { - memcpy(&cfg, cfg_, sizeof(sched_interface::ue_cfg_t)); - } - Info("SCHED: Added user rnti=0x%x\n", rnti); // Config HARQ processes - for (int i=0;idci; - bzero(dci, sizeof(srslte_ra_dl_dci_t)); - - uint32_t sf_idx = tti%10; - - int mcs = 0; - int tbs = 0; - - dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; - dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); - - + srslte_dci_dl_t* dci = &data->dci; + + int mcs = 0; + int tbs = 0; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = (uint32_t)h->get_rbgmask().to_uint64(); + // If this is the first transmission for this UE, make room for MAC Contention Resolution ID - bool need_conres_ce = false; + bool need_conres_ce = false; if (is_first_dl_tx()) { - need_conres_ce = true; + need_conres_ce = true; } if (h->is_empty(0)) { - uint32_t req_bytes = get_pending_dl_new_data_unlocked(tti); - - uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); - srslte_ra_dl_grant_t grant; - srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); - uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); - uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); + uint32_t req_bytes = get_pending_dl_new_data_total_unlocked(tti); + + uint32_t nof_prb = format1_count_prb((uint32_t)h->get_rbgmask().to_uint64(), cell.nof_prb); + // Calculate exact number of RE for this PRB allocation + srslte_pdsch_grant_t grant = {}; + srslte_dl_sf_cfg_t dl_sf = {}; + dl_sf.cfi = cfi; + dl_sf.tti = tti; + srslte_ra_dl_grant_to_grant_prb_allocation(dci, &grant, cell.nof_prb); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&cell, &dl_sf, &grant); + if (need_conres_ce and cell.nof_prb < 10) { // SRB0 Tx. Use a higher MCS for the PRACH to fit in 6 PRBs - tbs = srslte_ra_tbs_from_idx(srslte_ra_dl_tbs_idx_from_mcs(MCS_FIRST_DL), nof_prb) / 8; + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(MCS_FIRST_DL, false), nof_prb) / 8; mcs = MCS_FIRST_DL; } else if (fixed_mcs_dl < 0) { tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_dl_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb) / 8; - mcs = fixed_mcs_dl; + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl, false), nof_prb) / 8; + mcs = fixed_mcs_dl; } - h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); + if (tbs < MIN_DATA_TBS) { + log_h->warning("SCHED: Allocation of TBS=%d that does not account header\n", tbs); + return 0; + } + + h->new_tx(0, tti, mcs, tbs, data->dci.location.ncce); // Allocate MAC ConRes CE if (need_conres_ce) { @@ -520,14 +497,14 @@ int sched_ue::generate_format1(dl_harq_proc *h, } int rem_tbs = tbs; - int x = 0; + int x = 0; do { x = alloc_pdu(rem_tbs, &data->pdu[0][data->nof_pdu_elems[0]]); - rem_tbs -= x; if (x) { + rem_tbs -= x + 2; // count 2-byte header data->nof_pdu_elems[0]++; } - } while(rem_tbs > 0 && x > 0); + } while (rem_tbs >= MIN_DATA_TBS && x > 0); Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); } else { @@ -535,25 +512,25 @@ int sched_ue::generate_format1(dl_harq_proc *h, Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs); } - data->rnti = rnti; - if (tbs > 0) { - dci->harq_process = h->get_id(); - dci->mcs_idx = (uint32_t) mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); - dci->ndi = h->get_ndi(0); - dci->tpc_pucch = (uint8_t) next_tpc_pucch; - next_tpc_pucch = 1; - data->tbs[0] = (uint32_t) tbs; - data->tbs[1] = 0; - dci->tb_en[0] = true; - dci->tb_en[1] = false; + dci->rnti = rnti; + dci->pid = h->get_id(); + dci->tb[0].mcs_idx = (uint32_t)mcs; + dci->tb[0].rv = sched::get_rvidx(h->nof_retx(0)); + dci->tb[0].ndi = h->get_ndi(0); + + dci->tpc_pucch = (uint8_t)next_tpc_pucch; + next_tpc_pucch = 1; + data->tbs[0] = (uint32_t)tbs; + data->tbs[1] = 0; + + dci->format = SRSLTE_DCI_FORMAT1; } pthread_mutex_unlock(&mutex); return tbs; } -// Generates a Format2a grant +// Generates a Format2a dci int sched_ue::generate_format2a(dl_harq_proc *h, sched_interface::dl_sched_data_t *data, uint32_t tti, @@ -565,27 +542,29 @@ int sched_ue::generate_format2a(dl_harq_proc *h, return ret; } -// Generates a Format2a grant -int sched_ue::generate_format2a_unlocked(dl_harq_proc *h, - sched_interface::dl_sched_data_t *data, - uint32_t tti, - uint32_t cfi) +// Generates a Format2a dci +int sched_ue::generate_format2a_unlocked(dl_harq_proc* h, + sched_interface::dl_sched_data_t* data, + uint32_t tti, + uint32_t cfi) { bool tb_en[SRSLTE_MAX_TB] = {false}; - srslte_ra_dl_dci_t *dci = &data->dci; - bzero(dci, sizeof(srslte_ra_dl_dci_t)); + srslte_dci_dl_t* dci = &data->dci; + + dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci->type0_alloc.rbg_bitmask = (uint32_t)h->get_rbgmask().to_uint64(); - uint32_t sf_idx = tti%10; + uint32_t nof_prb = format1_count_prb((uint32_t)h->get_rbgmask().to_uint64(), cell.nof_prb); - dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; - dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); + // Calculate exact number of RE for this PRB allocation + srslte_pdsch_grant_t grant = {}; + srslte_dl_sf_cfg_t dl_sf = {}; + dl_sf.cfi = cfi; + dl_sf.tti = tti; + srslte_ra_dl_grant_to_grant_prb_allocation(dci, &grant, cell.nof_prb); + uint32_t nof_re = srslte_ra_dl_grant_nof_re(&cell, &dl_sf, &grant); - uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); - uint32_t nof_ctrl_symbols = cfi + (cell.nof_prb < 10 ? 1 : 0); - srslte_ra_dl_grant_t grant; - srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); - uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); bool no_retx = true; if (dl_ri == 0) { @@ -612,7 +591,7 @@ int sched_ue::generate_format2a_unlocked(dl_harq_proc *h, } for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - uint32_t req_bytes = get_pending_dl_new_data_unlocked(tti); + uint32_t req_bytes = get_pending_dl_new_data_total_unlocked(tti); int mcs = 0; int tbs = 0; @@ -623,46 +602,44 @@ int sched_ue::generate_format2a_unlocked(dl_harq_proc *h, if (fixed_mcs_dl < 0) { tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs); } else { - tbs = srslte_ra_tbs_from_idx((uint32_t)srslte_ra_dl_tbs_idx_from_mcs((uint32_t)fixed_mcs_dl), nof_prb) / 8; + tbs = srslte_ra_tbs_from_idx((uint32_t)srslte_ra_tbs_idx_from_mcs((uint32_t)fixed_mcs_dl, false), nof_prb) / 8; mcs = fixed_mcs_dl; } - h->new_tx(tb, tti, mcs, tbs, data->dci_location.ncce); + h->new_tx(tb, tti, mcs, tbs, data->dci.location.ncce); int rem_tbs = tbs; - int x = 0; + int x = 0; do { x = alloc_pdu(rem_tbs, &data->pdu[tb][data->nof_pdu_elems[tb]]); rem_tbs -= x; if (x) { data->nof_pdu_elems[tb]++; } - } while (rem_tbs > 0 && x > 0); + } while (rem_tbs >= MIN_DATA_TBS && x > 0); Debug("SCHED: Alloc format2/2a new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); } /* Fill DCI TB dedicated fields */ - if (tbs > 0) { - if (tb == 0) { - dci->mcs_idx = (uint32_t) mcs; - dci->rv_idx = sched::get_rvidx(h->nof_retx(tb)); - dci->ndi = h->get_ndi(tb); - } else { - dci->mcs_idx_1 = (uint32_t) mcs; - dci->rv_idx_1 = sched::get_rvidx(h->nof_retx(tb)); - dci->ndi_1 = h->get_ndi(tb); + if (tbs > 0 && tb_en[tb]) { + dci->tb[tb].mcs_idx = (uint32_t)mcs; + dci->tb[tb].rv = sched::get_rvidx(h->nof_retx(tb)); + if (!SRSLTE_DCI_IS_TB_EN(dci->tb[tb])) { + dci->tb[tb].rv = 2; } - data->tbs[tb] = (uint32_t) tbs; - dci->tb_en[tb] = true; + dci->tb[tb].ndi = h->get_ndi(tb); + dci->tb[tb].cw_idx = tb; + data->tbs[tb] = (uint32_t)tbs; } else { + SRSLTE_DCI_TB_DISABLE(dci->tb[tb]); data->tbs[tb] = 0; - dci->tb_en[tb] = false; } } /* Fill common fields */ - data->rnti = rnti; - dci->harq_process = h->get_id(); + dci->format = SRSLTE_DCI_FORMAT2A; + dci->rnti = rnti; + dci->pid = h->get_id(); dci->tpc_pucch = (uint8_t) next_tpc_pucch; next_tpc_pucch = 1; @@ -670,8 +647,7 @@ int sched_ue::generate_format2a_unlocked(dl_harq_proc *h, return ret; } - -// Generates a Format2 grant +// Generates a Format2 dci int sched_ue::generate_format2(dl_harq_proc *h, sched_interface::dl_sched_data_t *data, uint32_t tti, @@ -684,7 +660,8 @@ int sched_ue::generate_format2(dl_harq_proc *h, int ret = generate_format2a_unlocked(h, data, tti, cfi); /* Compute precoding information */ - if (SRSLTE_RA_DL_GRANT_NOF_TB(&data->dci) == 1) { + data->dci.format = SRSLTE_DCI_FORMAT2; + if ((SRSLTE_DCI_IS_TB_EN(data->dci.tb[0]) + SRSLTE_DCI_IS_TB_EN(data->dci.tb[1])) == 1) { data->dci.pinfo = (uint8_t) (dl_pmi + 1) % (uint8_t) 5; } else { data->dci.pinfo = (uint8_t) (dl_pmi & 1); @@ -695,62 +672,57 @@ int sched_ue::generate_format2(dl_harq_proc *h, return ret; } - -int sched_ue::generate_format0(ul_harq_proc *h, - sched_interface::ul_sched_data_t *data, - uint32_t tti, - bool cqi_request) +int sched_ue::generate_format0(ul_harq_proc* h, sched_interface::ul_sched_data_t* data, uint32_t tti, bool cqi_request) { pthread_mutex_lock(&mutex); - srslte_ra_ul_dci_t *dci = &data->dci; - bzero(dci, sizeof(srslte_ra_ul_dci_t)); - - int mcs = 0; - int tbs = 0; - + srslte_dci_ul_t* dci = &data->dci; + + int mcs = 0; + int tbs = 0; + ul_harq_proc::ul_alloc_t allocation = h->get_alloc(); bool is_newtx = true; if (h->get_rar_mcs(&mcs)) { - tbs = srslte_ra_tbs_from_idx(srslte_ra_ul_tbs_idx_from_mcs(mcs), allocation.L) / 8; + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs, true), allocation.L) / 8; h->new_tx(tti, mcs, tbs); } else if (h->is_empty(0)) { uint32_t req_bytes = get_pending_ul_new_data_unlocked(tti); - + uint32_t N_srs = 0; uint32_t nof_re = (2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs)*allocation.L*SRSLTE_NRE; if (fixed_mcs_ul < 0) { tbs = alloc_tbs_ul(allocation.L, nof_re, req_bytes, &mcs); } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_ul_tbs_idx_from_mcs(fixed_mcs_ul), allocation.L) / 8; + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul, true), allocation.L) / 8; mcs = fixed_mcs_ul; } - - h->new_tx(tti, mcs, tbs); - } else { + h->new_tx(tti, mcs, tbs); + + } else { h->new_retx(0, tti, &mcs, NULL); is_newtx = false; - tbs = srslte_ra_tbs_from_idx(srslte_ra_ul_tbs_idx_from_mcs(mcs), allocation.L) / 8; + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs, true), allocation.L) / 8; } - - data->rnti = rnti; - data->tbs = tbs; - + + data->tbs = tbs; + if (tbs > 0) { - dci->type2_alloc.L_crb = allocation.L; - dci->type2_alloc.RB_start = allocation.RB_start; - dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); + dci->rnti = rnti; + dci->format = SRSLTE_DCI_FORMAT0; + dci->type2_alloc.riv = srslte_ra_type2_to_riv(allocation.L, allocation.RB_start, cell.nof_prb); + dci->tb.rv = sched::get_rvidx(h->nof_retx(0)); if (!is_newtx && h->is_adaptive_retx()) { - dci->mcs_idx = 28+dci->rv_idx; + dci->tb.mcs_idx = 28 + dci->tb.rv; } else { - dci->mcs_idx = mcs; + dci->tb.mcs_idx = mcs; } - dci->ndi = h->get_ndi(0); - dci->cqi_request = cqi_request; - dci->freq_hop_fl = srslte_ra_ul_dci_t::SRSLTE_RA_PUSCH_HOP_DISABLED; + dci->tb.ndi = h->get_ndi(0); + dci->cqi_request = cqi_request; + dci->freq_hop_fl = srslte_dci_ul_t::SRSLTE_RA_PUSCH_HOP_DISABLED; dci->tpc_pusch = next_tpc_pusch; next_tpc_pusch = 1; } @@ -835,6 +807,13 @@ uint32_t sched_ue::get_pending_dl_new_data(uint32_t tti) uint32_t sched_ue::get_pending_dl_new_data_total(uint32_t tti) { pthread_mutex_lock(&mutex); + uint32_t req_bytes = get_pending_dl_new_data_total_unlocked(tti); + pthread_mutex_unlock(&mutex); + return req_bytes; +} + +uint32_t sched_ue::get_pending_dl_new_data_total_unlocked(uint32_t tti) +{ uint32_t req_bytes = get_pending_dl_new_data_unlocked(tti); if(req_bytes>0) { req_bytes += (req_bytes < 128) ? 2 : 3; // consider the header @@ -842,7 +821,6 @@ uint32_t sched_ue::get_pending_dl_new_data_total(uint32_t tti) req_bytes += 6; // count for RAR } } - pthread_mutex_unlock(&mutex); return req_bytes; } @@ -926,21 +904,19 @@ uint32_t sched_ue::get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_sym { pthread_mutex_lock(&mutex); - int mcs = 0; + int mcs = 0; uint32_t nof_re = 0; - int tbs = 0; + int tbs = 0; uint32_t nbytes = 0; uint32_t n; + int mcs0 = (is_first_dl_tx() and cell.nof_prb == 6) ? MCS_FIRST_DL : fixed_mcs_dl; for (n=0; n < cell.nof_prb && nbytes < req_bytes; ++n) { - nof_re = srslte_ra_dl_approx_nof_re(cell, n+1, nof_ctrl_symbols); - if (is_first_dl_tx() && cell.nof_prb < 10) { - tbs = srslte_ra_tbs_from_idx(srslte_ra_dl_tbs_idx_from_mcs(MCS_FIRST_DL), n + 1) / 8; - Info("get_required_prb: req_bytes=%d, tbs=%d, nof_prb=%d\n", req_bytes, tbs, n); - } else if (fixed_mcs_dl < 0) { + nof_re = srslte_ra_dl_approx_nof_re(&cell, n + 1, nof_ctrl_symbols); + if (mcs0 < 0) { tbs = alloc_tbs_dl(n+1, nof_re, 0, &mcs); } else { - tbs = srslte_ra_tbs_from_idx(srslte_ra_dl_tbs_idx_from_mcs(fixed_mcs_dl), n + 1) / 8; + tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs0, false), n + 1) / 8; } if (tbs > 0) { nbytes = tbs; @@ -968,13 +944,13 @@ uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes) pthread_mutex_lock(&mutex); - for (n=1;n 0) { nbytes = tbs; @@ -1018,7 +994,7 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti) uint32_t oldest_tti = 0; for (int i=0;i oldest_tti) { oldest_idx = i; oldest_tti = x; @@ -1055,7 +1031,42 @@ dl_harq_proc* sched_ue::get_empty_dl_harq() ul_harq_proc* sched_ue::get_ul_harq(uint32_t tti) { - return &ul_harq[tti%SCHED_MAX_HARQ_PROC]; + return &ul_harq[tti % SCHED_MAX_HARQ_PROC]; +} + +void sched_ue::set_dl_alloc(dl_harq_proc* alloc) +{ + next_dl_harq_proc = alloc; +} + +dl_harq_proc* sched_ue::get_dl_alloc() +{ + return next_dl_harq_proc; +} + +void sched_ue::set_ul_alloc(ul_harq_proc* alloc) +{ + next_ul_harq_proc = alloc; +} + +ul_harq_proc* sched_ue::get_ul_alloc() +{ + return next_ul_harq_proc; +} + +dl_harq_proc* sched_ue::find_dl_harq(uint32_t tti) +{ + for (uint32_t i = 0; i < SCHED_MAX_HARQ_PROC; ++i) { + if (dl_harq[i].get_tti() == tti) { + return &dl_harq[i]; + } + } + return NULL; +} + +const dl_harq_proc* sched_ue::get_dl_harq(uint32_t idx) const +{ + return &dl_harq[idx]; } srslte_dci_format_t sched_ue::get_dci_format() { @@ -1079,7 +1090,9 @@ srslte_dci_format_t sched_ue::get_dci_format() { case asn1::rrc::ant_info_ded_s::tx_mode_e_::tm7: case asn1::rrc::ant_info_ded_s::tx_mode_e_::tm8_v920: default: - Warning("Incorrect transmission mode (rnti=%04x)\n", rnti); + Warning("Incorrect transmission mode (rnti=%04x; tm=%s)\n", + rnti, + dl_ant_info.explicit_value().tx_mode.to_string().c_str()); } } @@ -1156,32 +1169,32 @@ uint32_t sched_ue::format1_count_prb(uint32_t bitmask, uint32_t cell_nof_prb) { } } } - return nof_prb; + return nof_prb; } int sched_ue::cqi_to_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t max_Qm, bool is_ul, uint32_t* mcs) { float max_coderate = srslte_cqi_to_coderate(cqi); - int sel_mcs = max_mcs+1; + int sel_mcs = max_mcs + 1; float coderate = 99; - float eff_coderate = 99; - uint32_t Qm = 1; - int tbs = 0; + float eff_coderate = 99; + uint32_t Qm = 1; + int tbs = 0; do { sel_mcs--; - uint32_t tbs_idx = (is_ul) ? srslte_ra_ul_tbs_idx_from_mcs(sel_mcs) : srslte_ra_dl_tbs_idx_from_mcs(sel_mcs); - tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); - coderate = srslte_coderate(tbs, nof_re); + uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs, is_ul); + tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb); + coderate = srslte_coderate(tbs, nof_re); srslte_mod_t mod = (is_ul) ? srslte_ra_ul_mod_from_mcs(sel_mcs) : srslte_ra_dl_mod_from_mcs(sel_mcs); Qm = SRSLTE_MIN(max_Qm, srslte_mod_bits_x_symbol(mod)); eff_coderate = coderate/Qm; } while((sel_mcs > 0 && coderate > max_coderate) || eff_coderate > 0.930); if (mcs) { - *mcs = (uint32_t) sel_mcs; + *mcs = (uint32_t)sel_mcs; } - return tbs; + return tbs; } int sched_ue::alloc_tbs_dl(uint32_t nof_prb, @@ -1213,33 +1226,33 @@ int sched_ue::alloc_tbs(uint32_t nof_prb, uint32_t cqi = is_ul?ul_cqi:dl_cqi; uint32_t max_mcs = is_ul?max_mcs_ul:max_mcs_dl; - uint32_t max_Qm = is_ul?4:6; // Allow 16-QAM in PUSCH Only + uint32_t max_Qm = is_ul ? 4 : 6; // Allow 16-QAM in PUSCH Only // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration - int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, is_ul, &sel_mcs) / 8; + int tbs_bytes = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, is_ul, &sel_mcs) / 8; /* If less bytes are requested, lower the MCS */ - if (tbs > (int) req_bytes && req_bytes > 0) { + if (tbs_bytes > (int)req_bytes && req_bytes > 0) { int req_tbs_idx = srslte_ra_tbs_to_table_idx(req_bytes * 8, nof_prb); - int req_mcs = (is_ul) ? srslte_ra_ul_mcs_from_tbs_idx(req_tbs_idx) : srslte_ra_dl_mcs_from_tbs_idx(req_tbs_idx); + int req_mcs = srslte_ra_mcs_from_tbs_idx(req_tbs_idx, is_ul); - if (req_mcs < sel_mcs) { - sel_mcs = req_mcs; - tbs = srslte_ra_tbs_from_idx(req_tbs_idx, nof_prb)/8; + if (req_mcs < (int)sel_mcs) { + sel_mcs = req_mcs; + tbs_bytes = srslte_ra_tbs_from_idx(req_tbs_idx, nof_prb) / 8; } } // Avoid the unusual case n_prb=1, mcs=6 tbs=328 (used in voip) if (nof_prb == 1 && sel_mcs == 6) { sel_mcs--; - uint32_t tbs_idx = (is_ul) ? srslte_ra_ul_tbs_idx_from_mcs(sel_mcs) : srslte_ra_dl_tbs_idx_from_mcs(sel_mcs); - tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb) / 8; + uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs, is_ul); + tbs_bytes = srslte_ra_tbs_from_idx(tbs_idx, nof_prb) / 8; } - if (mcs && tbs >= 0) { + if (mcs && tbs_bytes >= 0) { *mcs = (int) sel_mcs; } - - return tbs; + + return tbs_bytes; } diff --git a/srsenb/src/mac/ue.cc b/srsenb/src/mac/ue.cc index ccd63f578..6708ef21a 100644 --- a/srsenb/src/mac/ue.cc +++ b/srsenb/src/mac/ue.cc @@ -37,42 +37,90 @@ namespace srsenb { - + +ue::ue() : + mac_msg_dl(20), + mch_mac_msg_dl(10), + mac_msg_ul(20), + conres_id_available(false), + dl_ri_counter(0), + dl_pmi_counter(0), + conres_id(0), + last_tti(0), + pdus(128) +{ + rrc = NULL; + sched = NULL; + rlc = NULL; + log_h = NULL; + rnti = 0; + pcap = NULL; + nof_failures = 0; + phr_counter = 0; + dl_cqi_counter = 0; + is_phy_added = false; + for (int i = 0; i < NOF_RX_HARQ_PROCESSES; i++) { + pending_buffers[i] = NULL; + } + + bzero(&metrics, sizeof(mac_metrics_t)); + bzero(&mutex, sizeof(pthread_mutex_t)); + bzero(softbuffer_tx, sizeof(softbuffer_tx)); + bzero(softbuffer_rx, sizeof(softbuffer_rx)); + for (int i = 0; i < SRSLTE_MAX_TB; ++i) { + bzero(tx_payload_buffer, sizeof(uint8_t) * payload_buffer_len); + } + pthread_mutex_init(&mutex, NULL); +} + +ue::~ue() +{ + for (int i = 0; i < NOF_RX_HARQ_PROCESSES; i++) { + srslte_softbuffer_rx_free(&softbuffer_rx[i]); + } + for (int i = 0; i < NOF_TX_HARQ_PROCESSES; i++) { + srslte_softbuffer_tx_free(&softbuffer_tx[i]); + } + pthread_mutex_destroy(&mutex); +} + void ue::config(uint16_t rnti_, uint32_t nof_prb, sched_interface *sched_, rrc_interface_mac *rrc_, rlc_interface_mac *rlc_, srslte::log *log_h_) { rnti = rnti_; rlc = rlc_; - rrc = rrc_; - log_h = log_h_; - sched = sched_; + rrc = rrc_; + log_h = log_h_; + sched = sched_; pdus.init(this, log_h); - - for (int i=0;i 0) { - if (!pending_buffers[tti%NOF_HARQ_PROCESSES]) { - ret = pdus.request(len); - pending_buffers[tti%NOF_HARQ_PROCESSES] = ret; + if (!pending_buffers[tti % NOF_RX_HARQ_PROCESSES]) { + ret = pdus.request(len); + pending_buffers[tti % NOF_RX_HARQ_PROCESSES] = ret; } else { - log_h->console("Error requesting buffer for pid %d, not pushed yet\n", tti%NOF_HARQ_PROCESSES); - log_h->error("Requesting buffer for pid %d, not pushed yet\n", tti%NOF_HARQ_PROCESSES); + log_h->console("Error requesting buffer for pid %d, not pushed yet\n", tti % NOF_RX_HARQ_PROCESSES); + log_h->error("Requesting buffer for pid %d, not pushed yet\n", tti % NOF_RX_HARQ_PROCESSES); } } else { log_h->warning("Requesting buffer for zero bytes\n"); @@ -140,7 +188,7 @@ void ue::set_tti(uint32_t tti) { #include -void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp) +void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel) { // Unpack ULSCH MAC PDU mac_msg_ul.init_rx(nof_bytes, true); @@ -232,7 +280,7 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe if (!bsr_received && lcid_most_data > 2) { // Add BSR to the LCID for which most data was received sched->ul_bsr(rnti, lcid_most_data, 256, false); // false adds BSR instead of setting - Debug("BSR not received. Giving extra grant\n"); + Debug("BSR not received. Giving extra dci\n"); } Debug("MAC PDU processed\n"); @@ -241,21 +289,21 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe void ue::deallocate_pdu(uint32_t tti) { - if (pending_buffers[tti%NOF_HARQ_PROCESSES]) { - pdus.deallocate(pending_buffers[tti%NOF_HARQ_PROCESSES]); - pending_buffers[tti%NOF_HARQ_PROCESSES] = NULL; + if (pending_buffers[tti % NOF_RX_HARQ_PROCESSES]) { + pdus.deallocate(pending_buffers[tti % NOF_RX_HARQ_PROCESSES]); + pending_buffers[tti % NOF_RX_HARQ_PROCESSES] = NULL; } else { - log_h->console("Error deallocating buffer for pid=%d. Not requested\n", tti%NOF_HARQ_PROCESSES); + log_h->console("Error deallocating buffer for pid=%d. Not requested\n", tti % NOF_RX_HARQ_PROCESSES); } } void ue::push_pdu(uint32_t tti, uint32_t len) { - if (pending_buffers[tti%NOF_HARQ_PROCESSES]) { - pdus.push(pending_buffers[tti%NOF_HARQ_PROCESSES], len); - pending_buffers[tti%NOF_HARQ_PROCESSES] = NULL; + if (pending_buffers[tti % NOF_RX_HARQ_PROCESSES]) { + pdus.push(pending_buffers[tti % NOF_RX_HARQ_PROCESSES], len); + pending_buffers[tti % NOF_RX_HARQ_PROCESSES] = NULL; } else { - log_h->console("Error pushing buffer for pid=%d. Not requested\n", tti%NOF_HARQ_PROCESSES); + log_h->console("Error pushing buffer for pid=%d. Not requested\n", tti % NOF_RX_HARQ_PROCESSES); } } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index ced44ba1f..7de8f83e2 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -37,7 +37,6 @@ #include #include #include -#include #include "srsenb/hdr/enb.h" #include "srsenb/hdr/metrics_stdout.h" @@ -145,7 +144,7 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { ("expert.pusch_max_its", bpo::value(&args->expert.phy.pusch_max_its)->default_value(8), "Maximum number of turbo decoder iterations") ("expert.pusch_8bit_decoder", bpo::value(&args->expert.phy.pusch_8bit_decoder)->default_value(false), "Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)") ("expert.tx_amplitude", bpo::value(&args->expert.phy.tx_amplitude)->default_value(0.6), "Transmit amplitude factor") - ("expert.nof_phy_threads", bpo::value(&args->expert.phy.nof_phy_threads)->default_value(2), "Number of PHY threads") + ("expert.nof_phy_threads", bpo::value(&args->expert.phy.nof_phy_threads)->default_value(3), "Number of PHY threads") ("expert.link_failure_nof_err", bpo::value(&args->expert.mac.link_failure_nof_err)->default_value(100), "Number of PUSCH failures after which a radio-link failure is triggered") ("expert.max_prach_offset_us", bpo::value(&args->expert.phy.max_prach_offset_us)->default_value(30), "Maximum allowed RACH offset (in us)") ("expert.equalizer_mode", bpo::value(&args->expert.phy.equalizer_mode)->default_value("mmse"), "Equalizer mode") @@ -267,6 +266,15 @@ void parse_args(all_args_t *args, int argc, char* argv[]) { exit(1); } } + if (args->expert.enable_mbsfn) { + if (args->expert.mac.sched.nof_ctrl_symbols == 3) { + fprintf(stderr, + "nof_ctrl_symbols = %d, While using MBMS, please set number of control symbols to either 1 or 2, " + "depending on the length of the non-mbsfn region\n", + args->expert.mac.sched.nof_ctrl_symbols); + exit(1); + } + } // Apply all_level to any unset layers if (vm.count("log.all_level")) { @@ -346,7 +354,7 @@ void sig_int_handler(int signo) { sigcnt++; running = false; - printf("Stopping srsENB... Press Ctrl+C %d more times to force stop\n", 10-sigcnt); + cout << "Stopping srsENB... Press Ctrl+C " << (10 - sigcnt) << " more times to force stop" << endl; if (sigcnt >= 10) { exit(-1); } diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc deleted file mode 100644 index 4bf79fdd9..000000000 --- a/srsenb/src/phy/phch_worker.cc +++ /dev/null @@ -1,1238 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2017 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of srsLTE. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include - -#include "srslte/common/threads.h" -#include "srslte/common/log.h" - -#include "srsenb/hdr/phy/phch_worker.h" - -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) - -using namespace std; -using namespace asn1::rrc; - -// Enable this to log SI -//#define LOG_THIS(a) 1 - -// Enable this one to skip SI-RNTI -#define LOG_THIS(rnti) (rnti != 0xFFFF) - - -/* Define GUI-related things */ -#ifdef ENABLE_GUI -#include "srsgui/srsgui.h" -#include -#include -#include -#include -#include - -void init_plots(srsenb::phch_worker *worker); -pthread_t plot_thread; -sem_t plot_sem; -static int plot_worker_id = -1; -#else -#warning Compiling without srsGUI support -#endif -/*********************************************/ - - - -//#define DEBUG_WRITE_FILE - -namespace srsenb { - - -phch_worker::phch_worker() -{ - phy = NULL; - - bzero(&enb_dl, sizeof(enb_dl)); - bzero(&enb_ul, sizeof(enb_ul)); - bzero(&tx_time, sizeof(tx_time)); - - reset(); -} - -#ifdef DEBUG_WRITE_FILE -FILE *f; -#endif - -void phch_worker::init(phch_common* phy_, srslte::log *log_h_) -{ - phy = phy_; - log_h = log_h_; - - pthread_mutex_init(&mutex, NULL); - - // Init cell here - for(int p = 0; p < SRSLTE_MAX_PORTS; p++) { - signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - if (!signal_buffer_rx[p]) { - fprintf(stderr, "Error allocating memory\n"); - return; - } - bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - if (!signal_buffer_tx[p]) { - fprintf(stderr, "Error allocating memory\n"); - return; - } - bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); - } - if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) { - fprintf(stderr, "Error initiating ENB DL\n"); - return; - } - if (srslte_enb_dl_set_cell(&enb_dl, phy->cell)) { - fprintf(stderr, "Error initiating ENB DL\n"); - return; - } - if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) { - fprintf(stderr, "Error initiating ENB UL\n"); - return; - } - if (srslte_enb_ul_set_cell(&enb_ul, - phy->cell, - NULL, - &phy->pusch_cfg, - &phy->hopping_cfg, - &phy->pucch_cfg)) - { - fprintf(stderr, "Error initiating ENB UL\n"); - return; - } - - /* Setup SI-RNTI in PHY */ - add_rnti(SRSLTE_SIRNTI); - - /* Setup P-RNTI in PHY */ - add_rnti(SRSLTE_PRNTI); - - /* Setup RA-RNTI in PHY */ - for (int i=0;i<10;i++) { - add_rnti(1+i); - } - - - if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, phy->cell.nof_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); - exit(-1); - } - - srslte_softbuffer_tx_reset(&temp_mbsfn_softbuffer); - srslte_pucch_set_threshold(&enb_ul.pucch, 0.5); - srslte_sch_set_max_noi(&enb_ul.pusch.ul_sch, phy->params.pusch_max_its); - srslte_enb_dl_set_amp(&enb_dl, phy->params.tx_amplitude); - - Info("Worker %d configured cell %d PRB\n", get_id(), phy->cell.nof_prb); - - if (phy->params.pusch_8bit_decoder) { - enb_ul.pusch.llr_is_8bit = true; - enb_ul.pusch.ul_sch.llr_is_8bit = true; - } - initiated = true; - running = true; - -#ifdef DEBUG_WRITE_FILE - f = fopen("test.dat", "w"); -#endif -} - -void phch_worker::stop() -{ - running = false; - pthread_mutex_lock(&mutex); - - int cnt = 0; - while(is_worker_running && cnt<100) { - usleep(1000); - cnt++; - } - - if (!is_worker_running) { - srslte_softbuffer_tx_free(&temp_mbsfn_softbuffer); - srslte_enb_dl_free(&enb_dl); - srslte_enb_ul_free(&enb_ul); - for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { - if (signal_buffer_rx[p]) { - free(signal_buffer_rx[p]); - } - if (signal_buffer_tx[p]) { - free(signal_buffer_tx[p]); - } - } - } else { - printf("Warning could not stop properly PHY\n"); - } - pthread_mutex_unlock(&mutex); - pthread_mutex_destroy(&mutex); -} -void phch_worker::reset() -{ - initiated = false; - ue_db.clear(); -} - -cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx) -{ - return signal_buffer_rx[antenna_idx]; -} - -void phch_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestamp_t tx_time_) -{ - tti_rx = tti_; - tti_tx_dl = TTI_TX(tti_rx); - tti_tx_ul = TTI_RX_ACK(tti_rx); - - sf_rx = tti_rx%10; - sf_tx = tti_tx_dl%10; - - t_tx_dl = TTIMOD(tti_tx_dl); - t_rx = TTIMOD(tti_rx); - t_tx_ul = TTIMOD(tti_tx_ul); - - tx_worker_cnt = tx_worker_cnt_; - memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); -} - -int phch_worker::add_rnti(uint16_t rnti) -{ - if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { - return -1; - } - if (srslte_enb_ul_add_rnti(&enb_ul, rnti)) { - return -1; - } - - // Create user - ue_db[rnti].rnti = rnti; - - return SRSLTE_SUCCESS; - -} - -uint32_t phch_worker::get_nof_rnti() { - return ue_db.size(); -} - -void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){ - pthread_mutex_lock(&mutex); - if (ue_db.count(rnti)) { - ue_db[rnti].dedicated_ack = ack; - } else { - Error("Setting dedicated ack: rnti=0x%x does not exist\n", rnti); - } - pthread_mutex_unlock(&mutex); -} - -void phch_worker::set_config_dedicated(uint16_t rnti, srslte_refsignal_srs_cfg_t* srs_cfg, phys_cfg_ded_s* dedicated) -{ - bool pucch_cqi_ack = dedicated->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi; - bool pucch_ri = dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present; - - pthread_mutex_lock(&mutex); - if (ue_db.count(rnti)) { - /* PUSCH UCI and scheduling configuration */ - srslte_uci_cfg_t uci_cfg; - ZERO_OBJECT(uci_cfg); - - if (dedicated->pusch_cfg_ded_present && dedicated->sched_request_cfg_present) { - uci_cfg.I_offset_ack = dedicated->pusch_cfg_ded.beta_offset_ack_idx; - uci_cfg.I_offset_cqi = dedicated->pusch_cfg_ded.beta_offset_cqi_idx; - uci_cfg.I_offset_ri = dedicated->pusch_cfg_ded.beta_offset_ri_idx; - - srslte_pucch_sched_t pucch_sched; - ZERO_OBJECT(pucch_sched); - - pucch_sched.N_pucch_1 = phy->pucch_cfg.n1_pucch_an; - pucch_sched.n_pucch_2 = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx; - pucch_sched.n_pucch_sr = dedicated->sched_request_cfg.setup().sr_pucch_res_idx; - srslte_enb_ul_cfg_ue(&enb_ul, rnti, &uci_cfg, &pucch_sched, srs_cfg); - - ue_db[rnti].I_sr = dedicated->sched_request_cfg.setup().sr_cfg_idx; - ue_db[rnti].I_sr_en = true; - } - - /* CQI Reporting */ - if (dedicated->cqi_report_cfg.cqi_report_periodic_present and - dedicated->cqi_report_cfg.cqi_report_periodic.type() == setup_e::setup) { - ue_db[rnti].pmi_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx; - ue_db[rnti].cqi_en = true; - ue_db[rnti].pucch_cqi_ack = pucch_cqi_ack; - } else { - ue_db[rnti].pmi_idx = 0; - ue_db[rnti].cqi_en = false; - } - - /* RI reporting */ - if (pucch_ri and dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) { - ue_db[rnti].ri_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx; - ue_db[rnti].ri_en = true; - } else { - ue_db[rnti].ri_idx = 0; - ue_db[rnti].ri_en = false; - } - - if (dedicated->ant_info_present) { - /* If default antenna info then follow 3GPP 36.331 clause 9.2.4 Default physical channel configuration */ - if (dedicated->ant_info.type() == phys_cfg_ded_s::ant_info_c_::types::default_value) { - ue_db[rnti].dedicated.ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); - if (enb_dl.cell.nof_ports == 1) { - ue_db[rnti].dedicated.ant_info.explicit_value().tx_mode = ant_info_ded_s::tx_mode_e_::tm1; - } else { - ue_db[rnti].dedicated.ant_info.explicit_value().tx_mode = ant_info_ded_s::tx_mode_e_::tm2; - } - ue_db[rnti].dedicated.ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); - ue_db[rnti].ri_idx = 0; - ue_db[rnti].ri_en = false; - } else { - /* Physical channel reconfiguration according to 3GPP 36.331 clause 5.3.10.6 */ - ue_db[rnti].dedicated.ant_info.explicit_value() = dedicated->ant_info.explicit_value(); - if (dedicated->ant_info.explicit_value().tx_mode != ant_info_ded_s::tx_mode_e_::tm3 && - dedicated->ant_info.explicit_value().tx_mode != ant_info_ded_s::tx_mode_e_::tm4 && ue_db[rnti].ri_en) { - ue_db[rnti].ri_idx = 0; - ue_db[rnti].ri_en = false; - } - } - } - - /* Set PDSCH power allocation */ - if (dedicated->pdsch_cfg_ded_present) { - ue_db[rnti].dedicated.pdsch_cfg_ded_present = true; - ue_db[rnti].dedicated.pdsch_cfg_ded = dedicated->pdsch_cfg_ded; - } - } else { - Error("Setting config dedicated: rnti=0x%x does not exist\n", rnti); - } - pthread_mutex_unlock(&mutex); -} - -void phch_worker::rem_rnti(uint16_t rnti) -{ - pthread_mutex_lock(&mutex); - if (ue_db.count(rnti)) { - ue_db.erase(rnti); - - srslte_enb_dl_rem_rnti(&enb_dl, rnti); - srslte_enb_ul_rem_rnti(&enb_ul, rnti); - - // remove any pending grant for each subframe - for (uint32_t i=0;iul_grants[i].nof_grants;j++) { - if (phy->ul_grants[i].sched_grants[j].rnti == rnti) { - phy->ul_grants[i].sched_grants[j].rnti = 0; - } - } - for (uint32_t j=0;jdl_grants[i].nof_grants;j++) { - if (phy->dl_grants[i].sched_grants[j].rnti == rnti) { - phy->dl_grants[i].sched_grants[j].rnti = 0; - } - } - } - } else { - Error("Removing user: rnti=0x%x does not exist\n", rnti); - } - pthread_mutex_unlock(&mutex); -} - -void phch_worker::work_imp() -{ - if (!running) { - return; - } - - subframe_cfg_t sf_cfg; - phy->get_sf_config(&sf_cfg, tti_tx_dl);// TODO difference between tti_tx_dl and t_tx_dl - - pthread_mutex_lock(&mutex); - is_worker_running = true; - - mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; - mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants; - mac_interface_phy *mac = phy->mac; - - log_h->step(tti_rx); - - Debug("Worker %d running\n", get_id()); - - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - uint16_t rnti = (uint16_t) iter->first; - ue_db[rnti].has_grant_tti = -1; - } - - // Process UL signal - srslte_enb_ul_fft(&enb_ul); - - // Decode pending UL grants for the tti they were scheduled - decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants); - - // Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals - decode_pucch(); - - // Get DL scheduling for the TX TTI from MAC - - if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { - if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) { - Error("Getting DL scheduling from MAC\n"); - goto unlock; - } - } else { - dl_grants[t_tx_dl].cfi = sf_cfg.non_mbsfn_region_length; - srslte_enb_dl_set_non_mbsfn_region(&enb_dl, sf_cfg.non_mbsfn_region_length); - if(mac->get_mch_sched(sf_cfg.is_mcch, &dl_grants[t_tx_dl])){ - Error("Getting MCH packets from MAC\n"); - goto unlock; - } - } - - if (dl_grants[t_tx_dl].cfi < 1 || dl_grants[t_tx_dl].cfi > 3) { - Error("Invalid CFI=%d\n", dl_grants[t_tx_dl].cfi); - goto unlock; - } - - // Get UL scheduling for the TX TTI from MAC - if (mac->get_ul_sched(tti_tx_ul, &ul_grants[t_tx_ul]) < 0) { - Error("Getting UL scheduling from MAC\n"); - goto unlock; - } - - // Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid - srslte_enb_dl_clear_sf(&enb_dl); - srslte_enb_dl_set_cfi(&enb_dl, dl_grants[t_tx_dl].cfi); - - if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { - srslte_enb_dl_put_base(&enb_dl, tti_tx_dl); - } else if (sf_cfg.mbsfn_encode){ - srslte_enb_dl_put_mbsfn_base(&enb_dl, tti_tx_dl); - } - - if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { - // Put UL/DL grants to resource grid. PDSCH data will be encoded as well. - encode_pdcch_dl(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); - encode_pdsch(dl_grants[t_tx_dl].sched_grants, dl_grants[t_tx_dl].nof_grants); - }else { - srslte_ra_dl_grant_t phy_grant; - phy_grant.mcs[0].idx = sf_cfg.mbsfn_mcs; - encode_pmch(&dl_grants[t_tx_dl].sched_grants[0], &phy_grant); - } - - encode_pdcch_ul(ul_grants[t_tx_ul].sched_grants, ul_grants[t_tx_ul].nof_grants); - // Put pending PHICH HARQ ACK/NACK indications into subframe - encode_phich(ul_grants[t_tx_ul].phich, ul_grants[t_tx_ul].nof_phich); - - // Prepare for receive ACK for DL grants in t_tx_dl+4 - phy->ue_db_clear(TTIMOD(TTI_TX(t_tx_dl))); - - for (uint32_t i=0;i= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { - /* For each TB */ - for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { - /* If TB enabled, set pending ACK */ - if (dl_grants[t_tx_dl].sched_grants[i].grant.tb_en[tb_idx]) { - phy->ue_db_set_ack_pending(TTIMOD(TTI_TX(t_tx_dl)), - rnti, - tb_idx, - dl_grants[t_tx_dl].sched_grants[i].location.ncce); - } - } - } - } - - // Generate signal and transmit - if(sf_cfg.sf_type == SUBFRAME_TYPE_REGULAR) { - srslte_enb_dl_gen_signal(&enb_dl); - } else { - srslte_enb_dl_gen_signal_mbsfn(&enb_dl); - } - - pthread_mutex_unlock(&mutex); - - Debug("Sending to radio\n"); - phy->worker_end(tx_worker_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); - - is_worker_running = false; - -#ifdef DEBUG_WRITE_FILE - fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f); -#endif - -#ifdef DEBUG_WRITE_FILE - if (tti_tx_dl == 10) { - fclose(f); - exit(-1); - } -#endif - - /* Tell the plotting thread to draw the plots */ -#ifdef ENABLE_GUI - if ((int) get_id() == plot_worker_id) { - sem_post(&plot_sem); - } -#endif - -unlock: - if (is_worker_running) { - is_worker_running = false; - pthread_mutex_unlock(&mutex); - } - -} - - -int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch) -{ - uint32_t wideband_cqi_value = 0, wideband_pmi = 0; - bool wideband_pmi_present = false; - - uint32_t n_rb_ho = 0; - for (uint32_t i=0;iue_db_is_ack_pending(t_rx, rnti, tb); - if (acks_pending[tb]) { - uci_data.uci_ack_len++; - } - } - - // Configure PUSCH CQI channel - srslte_cqi_value_t cqi_value; - ZERO_OBJECT(cqi_value); - - bool cqi_enabled = false; - - if (ue_db[rnti].cqi_en && ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx) ) { - uci_data.uci_ri_len = 1; /* Asumes only 1 bit for RI */ - uci_data.ri_periodic_report = true; - } else if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { - cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - cqi_enabled = true; - if (ue_db[rnti].dedicated.ant_info_present and - ue_db[rnti].dedicated.ant_info.type() == phys_cfg_ded_s::ant_info_c_::types::explicit_value and - ue_db[rnti].dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - cqi_value.wideband.pmi_present = true; - cqi_value.wideband.rank_is_not_one = phy->ue_db_get_ri(rnti) > 0; - } - } else if (grants[i].grant.cqi_request) { - cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - if (ue_db[rnti].dedicated.ant_info_present && - (ue_db[rnti].dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm3 || - ue_db[rnti].dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4)) { - cqi_value.subband_hl.ri_present = true; - } - cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0; - cqi_value.subband_hl.four_antenna_ports = (phy->cell.nof_ports == 4); - cqi_value.subband_hl.pmi_present = - (ue_db[rnti].dedicated.cqi_report_cfg.cqi_report_mode_aperiodic == cqi_report_mode_aperiodic_e::rm31); - cqi_value.subband_hl.rank_is_not_one = phy->ue_db_get_ri(rnti) > 0; - cqi_enabled = true; - } - - // mark this tti as having an ul grant to avoid pucch - ue_db[rnti].has_grant_tti = tti_rx; - - srslte_ra_ul_grant_t phy_grant; - int res = -1; - if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) { - - // Handle Format0 adaptive retx - // Use last TBS for this TB in case of mcs>28 - if (phy_grant.mcs.idx > 28) { - phy_grant.mcs.tbs = phy->ue_db_get_last_ul_tbs(rnti, tti_rx); - Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", phy_grant.mcs.idx, phy_grant.mcs.tbs, TTI_TX(tti_rx)%(2*HARQ_DELAY_MS)); - } - phy->ue_db_set_last_ul_tbs(rnti, tti_rx, phy_grant.mcs.tbs); - - if (phy_grant.mcs.mod == SRSLTE_MOD_LAST) { - phy_grant.mcs.mod = phy->ue_db_get_last_ul_mod(rnti, tti_rx); - phy_grant.Qm = srslte_mod_bits_x_symbol(phy_grant.mcs.mod); - } - phy->ue_db_set_last_ul_mod(rnti, tti_rx, phy_grant.mcs.mod); - - - if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) { - phy_grant.mcs.mod = SRSLTE_MOD_16QAM; - } - phy_grant.Qm = SRSLTE_MIN(phy_grant.Qm, 4); - res = srslte_enb_ul_get_pusch(&enb_ul, &phy_grant, grants[i].softbuffer, - rnti, grants[i].rv_idx, - grants[i].current_tx_nb, - grants[i].data, - (cqi_enabled) ? &cqi_value : NULL, - &uci_data, - sf_rx); - } else { - Error("Computing PUSCH grant\n"); - return SRSLTE_ERROR; - } - - #ifdef LOG_EXECTIME - gettimeofday(&t[2], NULL); - get_time_interval(t); - snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); - #endif - - bool crc_res = (res == 0); - - // Save PHICH scheduling for this user. Each user can have just 1 PUSCH grant per TTI - ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; - ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; - - char cqi_str[SRSLTE_CQI_STR_MAX_CHAR]; - if (cqi_enabled) { - if (ue_db[rnti].cqi_en) { - wideband_cqi_value = cqi_value.wideband.wideband_cqi; - if (cqi_value.wideband.pmi_present) { - wideband_pmi_present = true; - wideband_pmi = cqi_value.wideband.pmi; - } - } else if (grants[i].grant.cqi_request) { - wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; - if (cqi_value.subband_hl.pmi_present) { - wideband_pmi_present = true; - wideband_pmi = cqi_value.subband_hl.pmi; - if (cqi_value.subband_hl.rank_is_not_one) { - Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, pmi=%d for %d subbands\n", - cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.wideband_cqi_cw1, - cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); - } else { - Info("PUSCH: Aperiodic ri=1, CQI=%02d, pmi=%d for %d subbands\n", - cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.pmi, cqi_value.subband_hl.N); - } - } else { - Info("PUSCH: Aperiodic ri%s, CQI=%02d for %d subbands\n", - cqi_value.subband_hl.rank_is_not_one?"~1":"=1", - cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.N); - } - } - srslte_cqi_value_tostring(&cqi_value, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); - } - - float snr_db = 10*log10(srslte_chest_ul_get_snr(&enb_ul.chest)); - - /* - if (!crc_res && enb_ul.pusch_cfg.grant.L_prb == 1 && enb_ul.pusch_cfg.grant.n_prb[0] == 0 && snr_db > 5) { - srslte_vec_save_file("sf_symbols", enb_ul.sf_symbols, sizeof(cf_t)*SRSLTE_SF_LEN_RE(25, SRSLTE_CP_NORM)); - srslte_vec_save_file("ce", enb_ul.ce, sizeof(cf_t)*SRSLTE_SF_LEN_RE(25, SRSLTE_CP_NORM)); - srslte_vec_save_file("d", enb_ul.pusch.d, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); - srslte_vec_save_file("ce2", enb_ul.pusch.ce, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); - srslte_vec_save_file("z", enb_ul.pusch.z, sizeof(cf_t)*enb_ul.pusch_cfg.nbits.nof_re); - printf("saved sf_idx=%d, mcs=%d, tbs=%d, rnti=%d, rv=%d, snr=%.1f\n", tti%10, - grants[i].grant.mcs_idx, enb_ul.pusch_cfg.cb_segm.tbs, rnti, grants[i].rv_idx, snr_db); - exit(-1); - } - */ - log_h->info_hex(grants[i].data, phy_grant.mcs.tbs / 8, - "PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s%s%s%s\n", - rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb, - phy_grant.mcs.tbs / 8, phy_grant.mcs.idx, grants[i].grant.rv_idx, - snr_db, - srslte_pusch_last_noi(&enb_ul.pusch), - crc_res ? "OK" : "KO", - (acks_pending[0] || acks_pending[1]) ? ", ack=" : "", - (acks_pending[0]) ? (uci_data.uci_ack ? "1" : "0") : "", - (acks_pending[1]) ? (uci_data.uci_ack_2 ? "1" : "0") : "", - uci_data.uci_cqi_len > 0 ? cqi_str : "", - uci_data.uci_ri_len > 0 ? ((uci_data.uci_ri == 0) ? ", ri=0" : ", ri=1") : "", - timestr); - - // Notify MAC of RL status - if (grants[i].grant.rv_idx == 0) { - if (res && snr_db < PUSCH_RL_SNR_DB_TH) { - Debug("PUSCH: Radio-Link failure snr=%.1f dB\n", snr_db); - phy->mac->rl_failure(rnti); - } else { - phy->mac->rl_ok(rnti); - } - } - - // Notify MAC new received data and HARQ Indication value - phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); - uint32_t ack_idx = 0; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (acks_pending[tb]) { - bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); - bool valid = (crc_res || snr_db > PUSCH_RL_SNR_DB_TH); - phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); - } - } - - // Notify MAC of UL SNR, DL CQI and DL RI - if (snr_db >= PUSCH_RL_SNR_DB_TH) { - phy->mac->snr_info(tti_rx, rnti, snr_db); - } - if (uci_data.uci_cqi_len>0 && crc_res) { - phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value); - } - if (uci_data.uci_ri_len > 0 && crc_res) { - phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); - phy->ue_db_set_ri(rnti, uci_data.uci_ri); - } - if (wideband_pmi_present && crc_res) { - phy->mac->pmi_info(tti_rx, rnti, wideband_pmi); - } - - // Save metrics stats - ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch)); - } - } - return SRSLTE_SUCCESS; -} - - -int phch_worker::decode_pucch() -{ - srslte_uci_data_t uci_data; - - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - uint16_t rnti = (uint16_t) iter->first; - - if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) { - // Check if user needs to receive PUCCH - bool needs_pucch = false, needs_ack[SRSLTE_MAX_TB] = {false}, needs_sr = false, needs_cqi = false; - uint32_t last_n_pdcch = 0; - bzero(&uci_data, sizeof(srslte_uci_data_t)); - - if (ue_db[rnti].I_sr_en) { - if (srslte_ue_ul_sr_send_tti(ue_db[rnti].I_sr, tti_rx)) { - needs_pucch = true; - needs_sr = true; - uci_data.scheduling_request = true; - } - } - - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - needs_ack[tb] = phy->ue_db_is_ack_pending(t_rx, rnti, tb, &last_n_pdcch); - if (needs_ack[tb]) { - needs_pucch = true; - uci_data.uci_ack_len++; - } - } - srslte_cqi_value_t cqi_value; - ZERO_OBJECT(cqi_value); - - phys_cfg_ded_s* dedicated = &ue_db[rnti].dedicated; - ant_info_ded_s::tx_mode_e_ tx_mode; - if (dedicated->ant_info.type() == phys_cfg_ded_s::ant_info_c_::types::explicit_value) { - tx_mode = dedicated->ant_info.explicit_value().tx_mode; - } else { - tx_mode.value = ant_info_ded_s::tx_mode_e_::tm2; - Warning("Tx mode not yet set\n"); - } - - if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) { - if (ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx)) { - needs_pucch = true; - uci_data.uci_ri_len = 1; - uci_data.ri_periodic_report = true; - } else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { - needs_pucch = true; - needs_cqi = true; - cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - if (tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - cqi_value.wideband.pmi_present = true; - cqi_value.wideband.rank_is_not_one = phy->ue_db_get_ri(rnti) > 0; - } - uci_data.uci_cqi_len = (uint32_t) srslte_cqi_size(&cqi_value); - } - } - - if (needs_pucch) { - if (srslte_enb_ul_get_pucch(&enb_ul, rnti, last_n_pdcch, sf_rx, &uci_data)) { - fprintf(stderr, "Error getting PUCCH\n"); - return SRSLTE_ERROR; - } - /* If only one ACK is required, it can be for TB0 or TB1 */ - uint32_t ack_idx = 0; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (needs_ack[tb]) { - bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2); - bool valid = srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH; - phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); - } - } - if (uci_data.scheduling_request) { - phy->mac->sr_detected(tti_rx, rnti); - } - - char cqi_ri_str[64] = {0}; - if (srslte_pucch_get_last_corr(&enb_ul.pucch) > PUCCH_RL_CORR_TH) { - if (uci_data.ri_periodic_report) { - phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri); - phy->ue_db_set_ri(rnti, uci_data.uci_ri); - sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri); - } else if (uci_data.uci_cqi_len && needs_cqi) { - srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); - phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi); - sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi); - - if (cqi_value.type == SRSLTE_CQI_TYPE_WIDEBAND && cqi_value.wideband.pmi_present) { - phy->mac->pmi_info(tti_rx, rnti, cqi_value.wideband.pmi); - sprintf(cqi_ri_str, "%s, pmi=%d", cqi_ri_str, cqi_value.wideband.pmi); - } - } - } - log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s%s\n", - rnti, - srslte_pucch_get_last_corr(&enb_ul.pucch), - enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, - (uci_data.uci_ack_len)?(uci_data.uci_ack?", ack=1":", ack=0"):"", - (uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"", - needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", - (needs_cqi || uci_data.ri_periodic_report)?cqi_ri_str:""); - - - // Notify MAC of RL status - if (!needs_sr) { - if (srslte_pucch_get_last_corr(&enb_ul.pucch) < PUCCH_RL_CORR_TH) { - Debug("PUCCH: Radio-Link failure corr=%.1f\n", srslte_pucch_get_last_corr(&enb_ul.pucch)); - phy->mac->rl_failure(rnti); - } else { - phy->mac->rl_ok(rnti); - } - } - } - } - } - return 0; -} - - -int phch_worker::encode_phich(srslte_enb_dl_phich_t *acks, uint32_t nof_acks) -{ - for (uint32_t i=0;irnti; - if (rnti) { - if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) { - fprintf(stderr, "Error putting PDCCH %d\n",i); - return SRSLTE_ERROR; - } - - if (LOG_THIS(rnti)) { - Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(grant->dci_format), - rnti, grants[i].location.ncce, (1<tb_en[0] = true; - phy_grant->tb_en[1] = false; - phy_grant->nof_prb = enb_dl.cell.nof_prb; - phy_grant->sf_type = SRSLTE_SF_MBSFN; - srslte_dl_fill_ra_mcs(&phy_grant->mcs[0], enb_dl.cell.nof_prb); - phy_grant->Qm[0] = srslte_mod_bits_x_symbol(phy_grant->mcs[0].mod); - for(int i = 0; i < 2; i++){ - for(uint32_t j = 0; j < phy_grant->nof_prb; j++){ - phy_grant->prb_idx[i][j] = true; - } - } - srslte_enb_dl_put_pmch(&enb_dl, phy_grant, &temp_mbsfn_softbuffer, sf_tx, &grant->data[0][0]); - return SRSLTE_SUCCESS; -} - -int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) { - - /* Scales the Resources Elements affected by the power allocation (p_b) */ - srslte_enb_dl_prepare_power_allocation(&enb_dl); - - for (uint32_t i = 0; i < nof_grants; i++) { - uint16_t rnti = grants[i].rnti; - if (rnti) { - - bool rnti_is_user = true; - if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || rnti == SRSLTE_MRNTI) { - rnti_is_user = false; - } - /* Mimo type (tx scheme) shall be single or tx diversity by default */ - srslte_mimo_type_t mimo_type = (enb_dl.cell.nof_ports == 1) ? SRSLTE_MIMO_TYPE_SINGLE_ANTENNA - : SRSLTE_MIMO_TYPE_TX_DIVERSITY; - srslte_ra_dl_grant_t phy_grant; - srslte_ra_dl_dci_to_grant(&grants[i].grant, enb_dl.cell.nof_prb, rnti, &phy_grant); - - char grant_str[64]; - switch (grants[i].grant.alloc_type) { - case SRSLTE_RA_ALLOC_TYPE0: - sprintf(grant_str, "mask=0x%x", grants[i].grant.type0_alloc.rbg_bitmask); - break; - case SRSLTE_RA_ALLOC_TYPE1: - sprintf(grant_str, "mask=0x%x", grants[i].grant.type1_alloc.vrb_bitmask); - break; - default: - sprintf(grant_str, "rb_start=%d", grants[i].grant.type2_alloc.RB_start); - break; - } - - - srslte_dci_format_t dci_format = grants[i].dci_format; - switch (dci_format) { - case SRSLTE_DCI_FORMAT1: - case SRSLTE_DCI_FORMAT1A: - /* Do nothing, it keeps default */ - break; - case SRSLTE_DCI_FORMAT2A: - if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) { - mimo_type = SRSLTE_MIMO_TYPE_CDD; - } - break; - case SRSLTE_DCI_FORMAT2: - if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) { - if (phy_grant.pinfo == 0) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else { - mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } - } else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) { - mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } - break; - case SRSLTE_DCI_FORMAT0: - case SRSLTE_DCI_FORMAT1C: - case SRSLTE_DCI_FORMAT1B: - case SRSLTE_DCI_FORMAT1D: - case SRSLTE_DCI_FORMAT2B: - default: - Error("Not implemented/Undefined DCI format (%d)\n", dci_format); - } - - if (LOG_THIS(rnti)) { - uint8_t x = 0; - uint8_t *ptr = grants[i].data[0]; - uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8; - if (!ptr) { - ptr = &x; - len = 1; - } - char pinfo_str[16] = {0}; - if (dci_format == SRSLTE_DCI_FORMAT2) { - snprintf(pinfo_str, 15, ", pinfo=%x", phy_grant.pinfo); - } - char tbstr[SRSLTE_MAX_TB][128]; - for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (phy_grant.tb_en[tb]) { - snprintf(tbstr[tb], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d", - tb, - phy_grant.mcs[tb].tbs / 8, - phy_grant.mcs[tb].idx, - (tb == 0) ? grants[i].grant.rv_idx : grants[i].grant.rv_idx_1); - } else { - tbstr[tb][0] = '\0'; - } - } - log_h->info_hex(ptr, len, - "PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tti_tx_dl=%d, tx_scheme=%s%s%s%s\n", - rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl, - srslte_mimotype2str(mimo_type), pinfo_str, tbstr[0], tbstr[1]); - } - - int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1}; - - /* Set power allocation */ - float rho_a = ((enb_dl.cell.nof_ports == 1) ? 1.0f : sqrtf(2.0f)), rho_b = 1.0f; - pdsch_cfg_ded_s::p_a_e_ pdsch_cnfg_ded = ue_db[rnti].dedicated.pdsch_cfg_ded.p_a; - if (pdsch_cnfg_ded < (uint32_t)pdsch_cfg_ded_s::p_a_e_::nof_types) { - float rho_a_db = pdsch_cnfg_ded.to_number(); - rho_a *= powf(10.0f, rho_a_db / 20.0f); - } - if (phy->pdsch_p_b < 4) { - uint32_t idx0 = (phy->cell.nof_ports == 1) ? 0 : 1; - float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][phy->pdsch_p_b]; - rho_b = sqrtf(cell_specific_ratio); - } - srslte_enb_dl_set_power_allocation(&enb_dl, rho_a, rho_b); - if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) { - fprintf(stderr, "Error putting PDSCH %d\n", i); - return SRSLTE_ERROR; - } - - // Save metrics stats - ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx); - } - } - - srslte_enb_dl_apply_power_allocation(&enb_dl); - - return SRSLTE_SUCCESS; -} - - - -/************ METRICS interface ********************/ -uint32_t phch_worker::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) -{ - uint32_t cnt=0; - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - ue *u = (ue*) &iter->second; - uint16_t rnti = iter->first; - if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { - u->metrics_read(&metrics[cnt]); - cnt++; - } - } - return cnt; -} - -void phch_worker::ue::metrics_read(phy_metrics_t* metrics_) -{ - memcpy(metrics_, &metrics, sizeof(phy_metrics_t)); - bzero(&metrics, sizeof(phy_metrics_t)); -} - -void phch_worker::ue::metrics_dl(uint32_t mcs) -{ - metrics.dl.mcs = SRSLTE_VEC_CMA(mcs, metrics.dl.mcs, metrics.dl.n_samples); - metrics.dl.n_samples++; -} - -void phch_worker::ue::metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters) -{ - metrics.ul.mcs = SRSLTE_VEC_CMA((float) mcs, metrics.ul.mcs, metrics.ul.n_samples); - metrics.ul.sinr = SRSLTE_VEC_CMA((float) sinr, metrics.ul.sinr, metrics.ul.n_samples); - metrics.ul.rssi = SRSLTE_VEC_CMA((float) rssi, metrics.ul.rssi, metrics.ul.n_samples); - metrics.ul.turbo_iters = SRSLTE_VEC_CMA((float) turbo_iters, metrics.ul.turbo_iters, metrics.ul.n_samples); - metrics.ul.n_samples++; -} - - - -void phch_worker::start_plot() { -#ifdef ENABLE_GUI - if (plot_worker_id == -1) { - plot_worker_id = get_id(); - log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); - init_plots(this); - } else { - log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); - } -#else - log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); -#endif -} - - -int phch_worker::read_ce_abs(float *ce_abs) { - uint32_t i=0; - int sz = srslte_symbol_sz(phy->cell.nof_prb); - bzero(ce_abs, sizeof(float)*sz); - int g = (sz - 12*phy->cell.nof_prb)/2; - for (i = 0; i < 12*phy->cell.nof_prb; i++) { - ce_abs[g+i] = 20 * log10(std::abs(std::complex(enb_ul.ce[i]))); - if (std::isinf(ce_abs[g + i])) { - ce_abs[g+i] = -80; - } - } - return sz; -} - -int phch_worker::read_ce_arg(float *ce_arg) { - uint32_t i=0; - int sz = srslte_symbol_sz(phy->cell.nof_prb); - bzero(ce_arg, sizeof(float)*sz); - int g = (sz - 12*phy->cell.nof_prb)/2; - for (i = 0; i < 12*phy->cell.nof_prb; i++) { - ce_arg[g+i] = std::arg(std::complex(enb_ul.ce[i])) * 180.0f / (float) M_PI; - if (std::isinf(ce_arg[g + i])) { - ce_arg[g+i] = -80; - } - } - return sz; -} - -int phch_worker::read_pusch_d(cf_t* pdsch_d) -{ - int nof_re = 400;//enb_ul.pusch_cfg.nbits.nof_re - memcpy(pdsch_d, enb_ul.pusch.d, nof_re*sizeof(cf_t)); - return nof_re; -} - -int phch_worker::read_pucch_d(cf_t* pdsch_d) -{ - int nof_re = SRSLTE_PUCCH_MAX_BITS/2;//enb_ul.pusch_cfg.nbits.nof_re - memcpy(pdsch_d, enb_ul.pucch.z_tmp, nof_re*sizeof(cf_t)); - return nof_re; -} - - -} - - -/*********************************************************** - * - * PLOT TO VISUALIZE THE CHANNEL RESPONSEE - * - ***********************************************************/ - - -#ifdef ENABLE_GUI -plot_real_t pce, pce_arg; -plot_scatter_t pconst; -plot_scatter_t pconst2; -#define SCATTER_PUSCH_BUFFER_LEN (20*6*SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)) -#define SCATTER_PUSCH_PLOT_LEN 4000 -float tmp_plot[SCATTER_PUSCH_BUFFER_LEN]; -float tmp_plot_arg[SCATTER_PUSCH_BUFFER_LEN]; -cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; -cf_t tmp_pucch_plot[SRSLTE_PUCCH_MAX_BITS/2]; - -void *plot_thread_run(void *arg) { - srsenb::phch_worker *worker = (srsenb::phch_worker*) arg; - - sdrgui_init_title("srsENB"); - plot_real_init(&pce); - plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude"); - plot_real_setLabels(&pce, (char*) "Index", (char*) "dB"); - plot_real_setYAxisScale(&pce, -40, 40); - - plot_real_init(&pce_arg); - plot_real_setTitle(&pce_arg, (char*) "Channel Response - Argument"); - plot_real_setLabels(&pce_arg, (char*) "Angle", (char*) "deg"); - plot_real_setYAxisScale(&pce_arg, -180, 180); - - plot_scatter_init(&pconst); - plot_scatter_setTitle(&pconst, (char*) "PUSCH - Equalized Symbols"); - plot_scatter_setXAxisScale(&pconst, -4, 4); - plot_scatter_setYAxisScale(&pconst, -4, 4); - - plot_scatter_init(&pconst2); - plot_scatter_setTitle(&pconst2, (char*) "PUCCH - Equalized Symbols"); - plot_scatter_setXAxisScale(&pconst2, -4, 4); - plot_scatter_setYAxisScale(&pconst2, -4, 4); - - plot_real_addToWindowGrid(&pce, (char*)"srsenb", 0, 0); - plot_real_addToWindowGrid(&pce_arg, (char*)"srsenb", 1, 0); - plot_scatter_addToWindowGrid(&pconst, (char*)"srsenb", 0, 1); - plot_scatter_addToWindowGrid(&pconst2, (char*)"srsenb", 1, 1); - - int n, n_arg, n_pucch; - int readed_pusch_re=0; - while(1) { - sem_wait(&plot_sem); - - n = worker->read_pusch_d(tmp_plot2); - n_pucch = worker->read_pucch_d(tmp_pucch_plot); - plot_scatter_setNewData(&pconst, tmp_plot2, n); - plot_scatter_setNewData(&pconst2, tmp_pucch_plot, n_pucch); - - n = worker->read_ce_abs(tmp_plot); - plot_real_setNewData(&pce, tmp_plot, n); - - n_arg = worker->read_ce_arg(tmp_plot_arg); - plot_real_setNewData(&pce_arg, tmp_plot_arg, n_arg); - - } - return NULL; -} - - -void init_plots(srsenb::phch_worker *worker) { - - if (sem_init(&plot_sem, 0, 0)) { - perror("sem_init"); - exit(-1); - } - - pthread_attr_t attr; - struct sched_param param; - param.sched_priority = 0; - pthread_attr_init(&attr); - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); - pthread_attr_setschedpolicy(&attr, SCHED_OTHER); - pthread_attr_setschedparam(&attr, ¶m); - if (pthread_create(&plot_thread, &attr, plot_thread_run, worker)) { - perror("pthread_create"); - exit(-1); - } -} -#endif - - - - diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index deee93ba6..e2331d768 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -59,38 +59,48 @@ void phy::parse_config(phy_cfg_t* cfg) { // PRACH configuration + ZERO_OBJECT(prach_cfg); prach_cfg.config_idx = cfg->prach_cnfg.prach_cfg_info.prach_cfg_idx; prach_cfg.hs_flag = cfg->prach_cnfg.prach_cfg_info.high_speed_flag; prach_cfg.root_seq_idx = cfg->prach_cnfg.root_seq_idx; prach_cfg.zero_corr_zone = cfg->prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg; prach_cfg.freq_offset = cfg->prach_cnfg.prach_cfg_info.prach_freq_offset; - // PUSCH DMRS configuration - workers_common.pusch_cfg.cyclic_shift = cfg->pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift; - workers_common.pusch_cfg.delta_ss = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch; - workers_common.pusch_cfg.group_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled; - workers_common.pusch_cfg.sequence_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled; + // Uplink Physical common configuration + ZERO_OBJECT(workers_common.ul_cfg_com); - // PUSCH hopping configuration - workers_common.hopping_cfg.hop_mode = + // DMRS + workers_common.ul_cfg_com.dmrs.cyclic_shift = cfg->pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift; + workers_common.ul_cfg_com.dmrs.delta_ss = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch; + workers_common.ul_cfg_com.dmrs.group_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled; + workers_common.ul_cfg_com.dmrs.sequence_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled; + + // Hopping + workers_common.ul_cfg_com.hopping.hop_mode = cfg->pusch_cnfg.pusch_cfg_basic.hop_mode == asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame ? srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTRA_SF : srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTER_SF; ; - workers_common.hopping_cfg.n_sb = cfg->pusch_cnfg.pusch_cfg_basic.n_sb; - workers_common.hopping_cfg.hopping_offset = cfg->pusch_cnfg.pusch_cfg_basic.pusch_hop_offset; - - // PUCCH configuration - workers_common.pucch_cfg.delta_pucch_shift = - cfg->pucch_cnfg.delta_pucch_shift.to_number(); // FIXME: Why was it a % operator before? - workers_common.pucch_cfg.N_cs = cfg->pucch_cnfg.n_cs_an; - workers_common.pucch_cfg.n_rb_2 = cfg->pucch_cnfg.n_rb_cqi; - workers_common.pucch_cfg.srs_configured = false; - workers_common.pucch_cfg.n1_pucch_an = cfg->pucch_cnfg.n1_pucch_an; + workers_common.ul_cfg_com.hopping.n_sb = cfg->pusch_cnfg.pusch_cfg_basic.n_sb; + workers_common.ul_cfg_com.hopping.hopping_offset = cfg->pusch_cnfg.pusch_cfg_basic.pusch_hop_offset; + workers_common.ul_cfg_com.pusch.max_nof_iterations = workers_common.params.pusch_max_its; + workers_common.ul_cfg_com.pusch.csi_enable = false; + workers_common.ul_cfg_com.pusch.meas_time_en = true; + + // PUCCH + workers_common.ul_cfg_com.pucch.delta_pucch_shift = cfg->pucch_cnfg.delta_pucch_shift.to_number(); + workers_common.ul_cfg_com.pucch.N_cs = cfg->pucch_cnfg.n_cs_an; + workers_common.ul_cfg_com.pucch.n_rb_2 = cfg->pucch_cnfg.n_rb_cqi; + workers_common.ul_cfg_com.pucch.N_pucch_1 = cfg->pucch_cnfg.n1_pucch_an; + workers_common.ul_cfg_com.pucch.threshold_format1 = 0.8; // PDSCH configuration - workers_common.pdsch_p_b = cfg->pdsch_cnfg.p_b; + ZERO_OBJECT(workers_common.dl_cfg_com); + workers_common.dl_cfg_com.tm = SRSLTE_TM1; + workers_common.dl_cfg_com.pdsch.rs_power = cfg->pdsch_cnfg.ref_sig_pwr; + workers_common.dl_cfg_com.pdsch.p_b = cfg->pdsch_cnfg.p_b; + workers_common.dl_cfg_com.pdsch.meas_time_en = true; } bool phy::init(phy_args_t *args, @@ -162,13 +172,14 @@ uint32_t phy::tti_to_subf(uint32_t tti) { } /***** MAC->PHY interface **********/ -int phy::add_rnti(uint16_t rnti) +int phy::add_rnti(uint16_t rnti, bool is_temporal) { - if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + if (SRSLTE_RNTI_ISUSER(rnti)) { workers_common.ue_db_add_rnti(rnti); } + for (uint32_t i=0;i= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { + if (SRSLTE_RNTI_ISUSER(rnti)) { workers_common.ue_db_rem_rnti(rnti); } for (uint32_t i=0;iPHY interface **********/ -void phy::set_conf_dedicated_ack(uint16_t rnti, bool ack) -{ - for (uint32_t i = 0; i < nof_workers; i++) { - workers[i].set_conf_dedicated_ack(rnti, ack); - } -} - void phy::set_config_dedicated(uint16_t rnti, phys_cfg_ded_s* dedicated) { for (uint32_t i=0;inof_workers = nof_workers; params.max_prach_offset_us = 20; - - bzero(&pusch_cfg, sizeof(pusch_cfg)); - bzero(&hopping_cfg, sizeof(hopping_cfg)); - bzero(&pucch_cfg, sizeof(pucch_cfg)); - bzero(&ul_grants, sizeof(ul_grants)); - - for (uint32_t i=0;imax_workers = max_workers; + + ZERO_OBJECT(ul_cfg_com); + ZERO_OBJECT(dl_cfg_com); + ZERO_OBJECT(ul_grants); + + for (uint32_t i = 0; i < max_workers; i++) { sem_init(&tx_sem[i], 0, 0); // All semaphores start blocked } } -phch_common::~phch_common() { - for (uint32_t i=0;inof_workers = nof_workers; } -void phch_common::reset() { +void phy_common::reset() +{ bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*TTIMOD_SZ); bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*TTIMOD_SZ); } -bool phch_common::init(srslte_cell_t *cell_, srslte::radio* radio_h_, mac_interface_phy *mac_) +bool phy_common::init(srslte_cell_t* cell_, srslte::radio* radio_h_, mac_interface_phy* mac_) { radio = radio_h_; mac = mac_; - cell = *cell_; + memcpy(&cell, cell_, sizeof(srslte_cell_t)); pthread_mutex_init(&user_mutex, NULL); - + pthread_mutex_init(&mtch_mutex, NULL); + pthread_cond_init(&mtch_cvar, NULL); + is_first_of_burst = true; is_first_tx = true; reset(); return true; } -void phch_common::stop() { +void phy_common::stop() +{ for (uint32_t i=0;iset_tti(tti); - radio->tx((void **) buffer, nof_samples, tx_time); + radio->tx(buffer, nof_samples, tx_time); // Allow next TTI to transmit sem_post(&tx_sem[(tti+1)%nof_workers]); @@ -134,67 +132,72 @@ void phch_common::worker_end(uint32_t tti, cf_t* buffer[SRSLTE_MAX_PORTS], uint3 mac->tti_clock(); } -void phch_common::ue_db_clear(uint32_t sf_idx) +void phy_common::ue_db_clear(uint32_t tti) { for(std::map::iterator iter=common_ue_db.begin(); iter!=common_ue_db.end(); ++iter) { pending_ack_t *p = &((common_ue*)&iter->second)->pending_ack; for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { - p->is_pending[sf_idx][tb_idx] = false; + p->is_pending[TTIMOD(tti)][tb_idx] = false; } } } -void phch_common::ue_db_add_rnti(uint16_t rnti) +void phy_common::ue_db_add_rnti(uint16_t rnti) { pthread_mutex_lock(&user_mutex); - add_rnti(rnti); + if (!common_ue_db.count(rnti)) { + add_rnti(rnti); + } pthread_mutex_unlock(&user_mutex); } // Private function not mutexed -void phch_common::add_rnti(uint16_t rnti) +void phy_common::add_rnti(uint16_t rnti) { - for (int sf_idx=0;sf_idxmbsfn_area_id = area_info->mbsfn_area_id_r9; cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); cfg->mbsfn_mcs = area_info->mcch_cfg_r9.sig_mcs_r9.to_number(); - cfg->mbsfn_encode = true; - cfg->is_mcch = true; + cfg->enable = true; + cfg->is_mcch = true; + have_mtch_stop = false; return true; } } return false; } -bool phch_common::is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti) +bool phy_common::is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti) { uint32_t sfn; // System Frame Number uint8_t sf; // Subframe uint8_t offset; uint8_t period; - sfn = phy_tti/10; + sfn = phy_tti / 10; sf = phy_tti%10; // Set some defaults cfg->mbsfn_area_id = 0; cfg->non_mbsfn_region_length = 1; cfg->mbsfn_mcs = 2; - cfg->mbsfn_encode = false; + cfg->enable = false; cfg->is_mcch = false; // Check for MCCH if (is_mcch_subframe(cfg, phy_tti)) { @@ -363,12 +356,20 @@ bool phch_common::is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti) if (mcch_configured) { // Iterate through PMCH configs to see which one applies in the current frame mbsfn_area_cfg_r9_s* area_r9 = &mbsfn.mcch.msg.c1().mbsfn_area_cfg_r9(); - uint32_t sf_alloc_idx = sfn % area_r9->common_sf_alloc_period_r9.to_number(); + + uint32_t frame_alloc_idx = sfn % area_r9->common_sf_alloc_period_r9.to_number(); + uint32_t mbsfn_per_frame = area_r9->pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9 / + +area_r9->pmch_info_list_r9[0].pmch_cfg_r9.mch_sched_period_r9.to_number(); + uint32_t sf_alloc_idx = frame_alloc_idx * mbsfn_per_frame + ((sf < 4) ? sf - 1 : sf - 3); + while (!have_mtch_stop) { + pthread_cond_wait(&mtch_cvar, &mtch_mutex); + } + for (uint32_t i = 0; i < area_r9->pmch_info_list_r9.size(); i++) { - //if(sf_alloc_idx < mch_period_stop) { - cfg->mbsfn_mcs = area_r9->pmch_info_list_r9[i].pmch_cfg_r9.data_mcs_r9; - cfg->mbsfn_encode = true; - //} + if (sf_alloc_idx < mch_period_stop) { + cfg->mbsfn_mcs = mbsfn.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[i].pmch_cfg_r9.data_mcs_r9; + cfg->enable = true; + } } } @@ -393,12 +394,8 @@ bool phch_common::is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti) return false; } -void phch_common::get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti) +bool phy_common::is_mbsfn_sf(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti) { - if(is_mch_subframe(cfg, phy_tti)) { - cfg->sf_type = SUBFRAME_TYPE_MBSFN; - }else{ - cfg->sf_type = SUBFRAME_TYPE_REGULAR; - } + return is_mch_subframe(cfg, phy_tti); +} } -} \ No newline at end of file diff --git a/srsenb/src/phy/prach_worker.cc b/srsenb/src/phy/prach_worker.cc index 053711920..04c04d51b 100644 --- a/srsenb/src/phy/prach_worker.cc +++ b/srsenb/src/phy/prach_worker.cc @@ -35,11 +35,15 @@ int prach_worker::init(srslte_cell_t *cell_, srslte_prach_cfg_t *prach_cfg_, mac mac = mac_; memcpy(&prach_cfg, prach_cfg_, sizeof(srslte_prach_cfg_t)); memcpy(&cell, cell_, sizeof(srslte_cell_t)); - - max_prach_offset_us = 50; - - if (srslte_prach_init_cfg(&prach, &prach_cfg, cell.nof_prb)) { - fprintf(stderr, "Error initiating PRACH\n"); + + max_prach_offset_us = 50; + + if (srslte_prach_init(&prach, srslte_symbol_sz(cell.nof_prb))) { + return -1; + } + + if (srslte_prach_set_cfg(&prach, &prach_cfg, cell.nof_prb)) { + ERROR("Error initiating PRACH\n"); return -1; } diff --git a/srsenb/src/phy/sf_worker.cc b/srsenb/src/phy/sf_worker.cc new file mode 100644 index 000000000..a33d42251 --- /dev/null +++ b/srsenb/src/phy/sf_worker.cc @@ -0,0 +1,1014 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/common/log.h" +#include "srslte/common/threads.h" + +#include "srsenb/hdr/phy/sf_worker.h" + +#define Error(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->debug(fmt, ##__VA_ARGS__) + +using namespace std; + +// Enable this to log SI +//#define LOG_THIS(a) 1 + +// Enable this one to skip SI-RNTI +#define LOG_THIS(rnti) (rnti != 0xFFFF) + +/* Define GUI-related things */ +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +#include + +#include "srslte/srslte.h" + +void init_plots(srsenb::sf_worker* worker); +pthread_t plot_thread; +sem_t plot_sem; +static int plot_worker_id = -1; +#else +#warning Compiling without srsGUI support +#endif +/*********************************************/ + +using namespace asn1::rrc; + +//#define DEBUG_WRITE_FILE + +namespace srsenb { + +sf_worker::sf_worker() +{ + phy = NULL; + + bzero(&enb_dl, sizeof(enb_dl)); + bzero(&enb_ul, sizeof(enb_ul)); + bzero(&tx_time, sizeof(tx_time)); + + reset(); +} + +#ifdef DEBUG_WRITE_FILE +FILE* f; +#endif + +void sf_worker::init(phy_common* phy_, srslte::log* log_h_) +{ + phy = phy_; + log_h = log_h_; + + pthread_mutex_init(&mutex, NULL); + + // Init cell here + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + signal_buffer_rx[p] = (cf_t*)srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + if (!signal_buffer_rx[p]) { + ERROR("Error allocating memory\n"); + return; + } + bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + signal_buffer_tx[p] = (cf_t*)srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + if (!signal_buffer_tx[p]) { + ERROR("Error allocating memory\n"); + return; + } + bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t)); + } + if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) { + ERROR("Error initiating ENB DL\n"); + return; + } + if (srslte_enb_dl_set_cell(&enb_dl, phy->cell)) { + ERROR("Error initiating ENB DL\n"); + return; + } + if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) { + ERROR("Error initiating ENB UL\n"); + return; + } + if (srslte_enb_ul_set_cell(&enb_ul, phy->cell, &phy->ul_cfg_com.dmrs)) { + ERROR("Error initiating ENB UL\n"); + return; + } + + /* Setup SI-RNTI in PHY */ + add_rnti(SRSLTE_SIRNTI, false); + + /* Setup P-RNTI in PHY */ + add_rnti(SRSLTE_PRNTI, false); + + /* Setup RA-RNTI in PHY */ + for (int i = 0; i < 10; i++) { + add_rnti(1 + i, false); + } + + if (srslte_softbuffer_tx_init(&temp_mbsfn_softbuffer, phy->cell.nof_prb)) { + ERROR("Error initiating soft buffer\n"); + exit(-1); + } + + srslte_softbuffer_tx_reset(&temp_mbsfn_softbuffer); + + Info("Worker %d configured cell %d PRB\n", get_id(), phy->cell.nof_prb); + + if (phy->params.pusch_8bit_decoder) { + enb_ul.pusch.llr_is_8bit = true; + enb_ul.pusch.ul_sch.llr_is_8bit = true; + } + initiated = true; + running = true; + +#ifdef DEBUG_WRITE_FILE + f = fopen("test.dat", "w"); +#endif +} + +void sf_worker::stop() +{ + running = false; + pthread_mutex_lock(&mutex); + + int cnt = 0; + while (is_worker_running && cnt < 100) { + usleep(1000); + cnt++; + } + + if (!is_worker_running) { + srslte_softbuffer_tx_free(&temp_mbsfn_softbuffer); + srslte_enb_dl_free(&enb_dl); + srslte_enb_ul_free(&enb_ul); + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + if (signal_buffer_rx[p]) { + free(signal_buffer_rx[p]); + } + if (signal_buffer_tx[p]) { + free(signal_buffer_tx[p]); + } + } + // Delete all users + for (std::map::iterator it = ue_db.begin(); it != ue_db.end(); it++) { + delete it->second; + } + } else { + log_h->console("Warning could not stop properly PHY\n"); + } + pthread_mutex_unlock(&mutex); + pthread_mutex_destroy(&mutex); +} +void sf_worker::reset() +{ + initiated = false; + ue_db.clear(); +} + +cf_t* sf_worker::get_buffer_rx(uint32_t antenna_idx) +{ + return signal_buffer_rx[antenna_idx]; +} + +void sf_worker::set_time(uint32_t tti_, uint32_t tx_worker_cnt_, srslte_timestamp_t tx_time_) +{ + tti_rx = tti_; + tti_tx_dl = TTI_TX(tti_rx); + tti_tx_ul = TTI_RX_ACK(tti_rx); + + t_tx_dl = TTIMOD(tti_tx_dl); + t_rx = TTIMOD(tti_rx); + t_tx_ul = TTIMOD(tti_tx_ul); + + tx_worker_cnt = tx_worker_cnt_; + memcpy(&tx_time, &tx_time_, sizeof(srslte_timestamp_t)); +} + +int sf_worker::add_rnti(uint16_t rnti, bool is_temporal) +{ + + if (!is_temporal) { + if (srslte_enb_dl_add_rnti(&enb_dl, rnti)) { + return -1; + } + if (srslte_enb_ul_add_rnti(&enb_ul, rnti)) { + return -1; + } + } + + // Create user unless already exists + pthread_mutex_lock(&mutex); + if (!ue_db.count(rnti)) { + ue_db[rnti] = new ue(rnti, phy); + } + pthread_mutex_unlock(&mutex); + + return SRSLTE_SUCCESS; +} + +void sf_worker::rem_rnti(uint16_t rnti) +{ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + + delete ue_db[rnti]; + ue_db.erase(rnti); + + srslte_enb_dl_rem_rnti(&enb_dl, rnti); + srslte_enb_ul_rem_rnti(&enb_ul, rnti); + + // remove any pending dci for each subframe + for (uint32_t i = 0; i < TTIMOD_SZ; i++) { + for (uint32_t j = 0; j < phy->ul_grants[i].nof_grants; j++) { + if (phy->ul_grants[i].pusch[j].dci.rnti == rnti) { + phy->ul_grants[i].pusch[j].dci.rnti = 0; + } + } + for (uint32_t j = 0; j < phy->dl_grants[i].nof_grants; j++) { + if (phy->dl_grants[i].pdsch[j].dci.rnti == rnti) { + phy->dl_grants[i].pdsch[j].dci.rnti = 0; + } + } + } + } else { + Error("Removing user: rnti=0x%x does not exist\n", rnti); + } + pthread_mutex_unlock(&mutex); +} + +uint32_t sf_worker::get_nof_rnti() +{ + return ue_db.size(); +} + +void sf_worker::set_config_dedicated(uint16_t rnti, asn1::rrc::phys_cfg_ded_s* dedicated) +{ + pthread_mutex_lock(&mutex); + if (ue_db.count(rnti)) { + + if (dedicated->pusch_cfg_ded_present && dedicated->sched_request_cfg_present) { + ue_db[rnti]->ul_cfg.pusch.uci_offset.I_offset_ack = dedicated->pusch_cfg_ded.beta_offset_ack_idx; + ue_db[rnti]->ul_cfg.pusch.uci_offset.I_offset_cqi = dedicated->pusch_cfg_ded.beta_offset_cqi_idx; + ue_db[rnti]->ul_cfg.pusch.uci_offset.I_offset_ri = dedicated->pusch_cfg_ded.beta_offset_ri_idx; + + ue_db[rnti]->ul_cfg.pucch.n_pucch_2 = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx; + ue_db[rnti]->ul_cfg.pucch.n_pucch_sr = dedicated->sched_request_cfg.setup().sr_pucch_res_idx; + } + + if (dedicated->sched_request_cfg_present) { + ue_db[rnti]->ul_cfg.pucch.I_sr = dedicated->sched_request_cfg.setup().sr_cfg_idx; + ue_db[rnti]->ul_cfg.pucch.sr_configured = true; + } + + /* CQI Reporting */ + if (dedicated->cqi_report_cfg.cqi_report_periodic_present and + dedicated->cqi_report_cfg.cqi_report_periodic.type() == setup_e::setup) { + ue_db[rnti]->dl_cfg.cqi_report.periodic_configured = true; + ue_db[rnti]->dl_cfg.cqi_report.pmi_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx; + ue_db[rnti]->ul_cfg.pucch.simul_cqi_ack = + dedicated->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi; + } else { + ue_db[rnti]->dl_cfg.cqi_report.pmi_idx = 0; + } + + /* RI reporting */ + if (dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) { + ue_db[rnti]->dl_cfg.cqi_report.ri_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx; + ue_db[rnti]->dl_cfg.cqi_report.ri_idx_present = true; + } else { + ue_db[rnti]->dl_cfg.cqi_report.ri_idx_present = false; + } + + if (dedicated->ant_info_present) { + /* If default antenna info then follow 3GPP 36.331 clause 9.2.4 Default physical channel configuration */ + if (dedicated->ant_info.type() == phys_cfg_ded_s::ant_info_c_::types::default_value) { + if (enb_dl.cell.nof_ports == 1) { + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM1; + } else { + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM2; + } + ue_db[rnti]->dl_cfg.cqi_report.ri_idx = 0; + ue_db[rnti]->dl_cfg.cqi_report.ri_idx_present = false; + } else { + /* Physical channel reconfiguration according to 3GPP 36.331 clause 5.3.10.6 */ + switch (dedicated->ant_info.explicit_value().tx_mode) { + case ant_info_ded_s::tx_mode_e_::tm1: + ue_db[rnti]->dl_cfg.cqi_report.ri_idx = 0; + ue_db[rnti]->dl_cfg.cqi_report.ri_idx_present = false; + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM1; + break; + case ant_info_ded_s::tx_mode_e_::tm2: + ue_db[rnti]->dl_cfg.cqi_report.ri_idx = 0; + ue_db[rnti]->dl_cfg.cqi_report.ri_idx_present = false; + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM2; + break; + case ant_info_ded_s::tx_mode_e_::tm3: + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM3; + break; + case ant_info_ded_s::tx_mode_e_::tm4: + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM4; + break; + default: + ue_db[rnti]->dl_cfg.tm = SRSLTE_TM1; + Error("TM mode %s not supported\n", dedicated->ant_info.explicit_value().tx_mode.to_string().c_str()); + break; + } + } + } + } else { + Error("Setting config dedicated: rnti=0x%x does not exist\n", rnti); + } + pthread_mutex_unlock(&mutex); +} + +void sf_worker::work_imp() +{ + if (!running) { + return; + } + + pthread_mutex_lock(&mutex); + is_worker_running = true; + + srslte_mbsfn_cfg_t mbsfn_cfg; + srslte_sf_t sf_type = phy->is_mbsfn_sf(&mbsfn_cfg, tti_tx_dl) ? SRSLTE_SF_MBSFN : SRSLTE_SF_NORM; + + mac_interface_phy::ul_sched_t* ul_grants = phy->ul_grants; + mac_interface_phy::dl_sched_t* dl_grants = phy->dl_grants; + mac_interface_phy* mac = phy->mac; + + log_h->step(tti_rx); + + Debug("Worker %d running\n", get_id()); + + for (std::map::iterator iter = ue_db.begin(); iter != ue_db.end(); ++iter) { + uint16_t rnti = (uint16_t)iter->first; + ue_db[rnti]->is_grant_available = false; + } + + // Configure UL subframe + ZERO_OBJECT(ul_sf); + ul_sf.tti = tti_rx; + + // Process UL signal + srslte_enb_ul_fft(&enb_ul); + + // Decode pending UL grants for the tti they were scheduled + decode_pusch(ul_grants[t_rx].pusch, ul_grants[t_rx].nof_grants); + + // Decode remaining PUCCH ACKs not associated with PUSCH transmission and SR signals + decode_pucch(); + + // Get DL scheduling for the TX TTI from MAC + + if (sf_type == SRSLTE_SF_NORM) { + if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) { + Error("Getting DL scheduling from MAC\n"); + goto unlock; + } + } else { + dl_grants[t_tx_dl].cfi = mbsfn_cfg.non_mbsfn_region_length; + if (mac->get_mch_sched(tti_tx_dl, mbsfn_cfg.is_mcch, &dl_grants[t_tx_dl])) { + Error("Getting MCH packets from MAC\n"); + goto unlock; + } + } + + if (dl_grants[t_tx_dl].cfi < 1 || dl_grants[t_tx_dl].cfi > 3) { + Error("Invalid CFI=%d\n", dl_grants[t_tx_dl].cfi); + goto unlock; + } + + // Get UL scheduling for the TX TTI from MAC + if (mac->get_ul_sched(tti_tx_ul, &ul_grants[t_tx_ul]) < 0) { + Error("Getting UL scheduling from MAC\n"); + goto unlock; + } + + // Configure DL subframe + ZERO_OBJECT(dl_sf); + dl_sf.tti = tti_tx_dl; + dl_sf.cfi = dl_grants[t_tx_dl].cfi; + dl_sf.sf_type = sf_type; + dl_sf.non_mbsfn_region = mbsfn_cfg.non_mbsfn_region_length; + + // Put base signals (references, PBCH, PCFICH and PSS/SSS) into the resource grid + srslte_enb_dl_put_base(&enb_dl, &dl_sf); + + // Put DL grants to resource grid. PDSCH data will be encoded as well. + if (sf_type == SRSLTE_SF_NORM) { + encode_pdcch_dl(dl_grants[t_tx_dl].pdsch, dl_grants[t_tx_dl].nof_grants); + encode_pdsch(dl_grants[t_tx_dl].pdsch, dl_grants[t_tx_dl].nof_grants); + } else { + if (mbsfn_cfg.enable) { + encode_pmch(&dl_grants[t_tx_dl].pdsch[0], &mbsfn_cfg); + } + } + + // Put UL grants to resource grid. + encode_pdcch_ul(ul_grants[t_tx_ul].pusch, ul_grants[t_tx_ul].nof_grants); + + // Put pending PHICH HARQ ACK/NACK indications into subframe + encode_phich(ul_grants[t_tx_ul].phich, ul_grants[t_tx_ul].nof_phich); + + // Generate signal and transmit + srslte_enb_dl_gen_signal(&enb_dl); + + pthread_mutex_unlock(&mutex); + + Debug("Sending to radio\n"); + phy->worker_end(tx_worker_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time); + + is_worker_running = false; + +#ifdef DEBUG_WRITE_FILE + fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t), 1, f); +#endif + +#ifdef DEBUG_WRITE_FILE + if (tti_tx_dl == 10) { + fclose(f); + exit(-1); + } +#endif + + /* Tell the plotting thread to draw the plots */ +#ifdef ENABLE_GUI + if ((int)get_id() == plot_worker_id) { + sem_post(&plot_sem); + } +#endif + +unlock: + if (is_worker_running) { + is_worker_running = false; + pthread_mutex_unlock(&mutex); + } +} + +bool sf_worker::fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_uci_cfg_t* uci_cfg) +{ + bool uci_required = false; + + bzero(uci_cfg, sizeof(srslte_uci_cfg_t)); + + // Check if SR opportunity (will only be used in PUCCH) + uci_cfg->is_scheduling_request_tti = (srslte_ue_ul_sr_send_tti(&ue_db[rnti]->ul_cfg.pucch, tti_rx) == 1); + + uci_required |= uci_cfg->is_scheduling_request_tti; + + // Get pending ACKs with an associated PUSCH transmission + // TODO: Use ue_dl procedures to compute uci_ack_cfg for TDD and CA + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + uci_cfg->ack.pending_tb[tb] = phy->ue_db_is_ack_pending(tti_rx, rnti, tb, &uci_cfg->ack.ncce[0]); + Debug("ACK: is pending tti=%d, mod=%d, value=%d\n", tti_rx, TTIMOD(tti_rx), uci_cfg->ack.pending_tb[tb]); + if (uci_cfg->ack.pending_tb[tb]) { + uci_cfg->ack.nof_acks++; + uci_required = true; + } + } + + // Get pending CQI reports for this TTI + if (srslte_enb_dl_gen_cqi_periodic( + &enb_dl.cell, &ue_db[rnti]->dl_cfg, tti_rx, phy->ue_db_get_ri(rnti), &uci_cfg->cqi)) { + uci_required = true; + } else if (aperiodic_cqi_request) { + srslte_enb_dl_gen_cqi_aperiodic(&enb_dl.cell, &ue_db[rnti]->dl_cfg, phy->ue_db_get_ri(rnti), &uci_cfg->cqi); + uci_required = true; + } + + return uci_required; +} + +void sf_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value) +{ + // Notify SR + if (uci_cfg->is_scheduling_request_tti && uci_value->scheduling_request) { + phy->mac->sr_detected(tti_rx, rnti); + } + + /* If only one ACK is required, it can be for TB0 or TB1 */ + uint32_t ack_idx = 0; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + if (uci_cfg->ack.pending_tb[tb]) { + bool ack = uci_value->ack.ack_value[ack_idx]; + bool valid = uci_value->ack.valid; + phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); + ack_idx++; + } + } + + // Notify CQI only if CRC is valid + if (uci_value->cqi.data_crc) { + if (uci_cfg->cqi.data_enable) { + uint8_t cqi_value = 0; + switch (uci_cfg->cqi.type) { + case SRSLTE_CQI_TYPE_WIDEBAND: + cqi_value = uci_value->cqi.wideband.wideband_cqi; + break; + case SRSLTE_CQI_TYPE_SUBBAND: + cqi_value = uci_value->cqi.subband.subband_cqi; + break; + case SRSLTE_CQI_TYPE_SUBBAND_HL: + cqi_value = uci_value->cqi.subband_hl.wideband_cqi_cw0; + break; + case SRSLTE_CQI_TYPE_SUBBAND_UE: + cqi_value = uci_value->cqi.subband_ue.wideband_cqi; + break; + } + phy->mac->cqi_info(tti_rx, rnti, cqi_value); + } + if (uci_cfg->cqi.ri_len) { + phy->mac->ri_info(tti_rx, rnti, uci_value->ri); + phy->ue_db_set_ri(rnti, uci_value->ri); + } + if (uci_cfg->cqi.pmi_present) { + uint8_t pmi_value = 0; + switch (uci_cfg->cqi.type) { + case SRSLTE_CQI_TYPE_WIDEBAND: + pmi_value = uci_value->cqi.wideband.pmi; + break; + case SRSLTE_CQI_TYPE_SUBBAND_HL: + pmi_value = uci_value->cqi.subband_hl.pmi; + break; + default: + Error("CQI type=%d not implemented for PMI\n", uci_cfg->cqi.type); + break; + } + phy->mac->pmi_info(tti_rx, rnti, pmi_value); + } + } +} + +int sf_worker::decode_pusch(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_pusch) +{ + srslte_pusch_res_t pusch_res; + + for (uint32_t i = 0; i < nof_pusch; i++) { + uint16_t rnti = grants[i].dci.rnti; + if (rnti) { + // mark this tti as having an ul dci to avoid pucch + ue_db[rnti]->is_grant_available = true; + + fill_uci_cfg(rnti, grants->dci.cqi_request, &ue_db[rnti]->ul_cfg.pusch.uci_cfg); + + // Compute UL grant + srslte_pusch_grant_t* grant = &ue_db[rnti]->ul_cfg.pusch.grant; + if (srslte_ra_ul_dci_to_grant(&phy->cell, &ul_sf, &ue_db[rnti]->ul_cfg.hopping, &grants[i].dci, grant)) { + Error("Computing PUSCH dci\n"); + return SRSLTE_ERROR; + } + + uint32_t ul_pid = TTI_RX(tti_rx) % SRSLTE_FDD_NOF_HARQ; + + // Handle Format0 adaptive retx + // Use last TBS for this TB in case of mcs>28 + if (grants[i].dci.tb.mcs_idx > 28) { + grant->tb = phy->ue_db_get_last_ul_tb(rnti, ul_pid); + Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", grants[i].dci.tb.mcs_idx, grant->tb.tbs, ul_pid); + } + phy->ue_db_set_last_ul_tb(rnti, ul_pid, grant->tb); + + // Run PUSCH decoder + ue_db[rnti]->ul_cfg.pusch.softbuffers.rx = grants[i].softbuffer_rx; + pusch_res.data = grants[i].data; + if (srslte_enb_ul_get_pusch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pusch, &pusch_res)) { + Error("Decoding PUSCH\n"); + return SRSLTE_ERROR; + } + + // Save PHICH scheduling for this user. Each user can have just 1 PUSCH dci per TTI + ue_db[rnti]->phich_grant.n_prb_lowest = grant->n_prb_tilde[0]; + ue_db[rnti]->phich_grant.n_dmrs = grants[i].dci.n_dmrs; + + float snr_db = enb_ul.chest_res.snr_db; + + // Notify MAC of RL status + if (snr_db >= PUSCH_RL_SNR_DB_TH) { + phy->mac->snr_info(tti_rx, rnti, snr_db); + + if (grants[i].dci.tb.rv == 0) { + if (!pusch_res.crc) { + Debug("PUSCH: Radio-Link failure snr=%.1f dB\n", snr_db); + phy->mac->rl_failure(rnti); + } else { + phy->mac->rl_ok(rnti); + } + } + } + + // Notify MAC new received data and HARQ Indication value + phy->mac->crc_info(tti_rx, rnti, grant->tb.tbs / 8, pusch_res.crc); + + // Send UCI data to MAC + send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pusch.uci_cfg, &pusch_res.uci); + + // Save metrics stats + ue_db[rnti]->metrics_ul(grants[i].dci.tb.mcs_idx, 0, snr_db, pusch_res.avg_iterations_block); + + // Logging + char str[512]; + srslte_pusch_rx_info(&ue_db[rnti]->ul_cfg.pusch, &pusch_res, str, 512); + Info("PUSCH: %s, snr=%.1f dB\n", str, snr_db); + } + } + return SRSLTE_SUCCESS; +} + +int sf_worker::decode_pucch() +{ + srslte_pucch_res_t pucch_res; + ZERO_OBJECT(pucch_res); + + for (std::map::iterator iter = ue_db.begin(); iter != ue_db.end(); ++iter) { + uint16_t rnti = (uint16_t)iter->first; + + // If it's a User RNTI and doesn't have PUSCH grant in this TTI + if (SRSLTE_RNTI_ISUSER(rnti) && !ue_db[rnti]->is_grant_available) { + // Check if user needs to receive PUCCH + if (fill_uci_cfg(rnti, false, &ue_db[rnti]->ul_cfg.pucch.uci_cfg)) { + // Decode PUCCH + if (srslte_enb_ul_get_pucch(&enb_ul, &ul_sf, &ue_db[rnti]->ul_cfg.pucch, &pucch_res)) { + ERROR("Error getting PUCCH\n"); + return SRSLTE_ERROR; + } + + // Notify MAC of RL status (skip SR subframes) + if (!ue_db[rnti]->ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) { + if (pucch_res.correlation < PUCCH_RL_CORR_TH) { + Debug("PUCCH: Radio-Link failure corr=%.1f\n", pucch_res.correlation); + phy->mac->rl_failure(rnti); + } else { + phy->mac->rl_ok(rnti); + } + } + + // Send UCI data to MAC + send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pucch.uci_cfg, &pucch_res.uci_data); + + // Logging + char str[512]; + srslte_pucch_rx_info(&ue_db[rnti]->ul_cfg.pucch, &pucch_res.uci_data, str, 512); + Info("PUCCH: %s, corr=%.1f\n", str, pucch_res.correlation); + } + } + } + return 0; +} + +int sf_worker::encode_phich(mac_interface_phy::ul_sched_ack_t* acks, uint32_t nof_acks) +{ + for (uint32_t i = 0; i < nof_acks; i++) { + if (acks[i].rnti && ue_db.count(acks[i].rnti)) { + srslte_enb_dl_put_phich(&enb_dl, &ue_db[acks[i].rnti]->phich_grant, acks[i].ack); + + Info("PHICH: rnti=0x%x, hi=%d, I_lowest=%d, n_dmrs=%d, tti_tx_dl=%d\n", + acks[i].rnti, + acks[i].ack, + ue_db[acks[i].rnti]->phich_grant.n_prb_lowest, + ue_db[acks[i].rnti]->phich_grant.n_dmrs, + tti_tx_dl); + } + } + return SRSLTE_SUCCESS; +} + +int sf_worker::encode_pdcch_ul(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_grants) +{ + for (uint32_t i = 0; i < nof_grants; i++) { + if (grants[i].needs_pdcch) { + if (srslte_enb_dl_put_pdcch_ul(&enb_dl, &grants[i].dci_cfg, &grants[i].dci)) { + ERROR("Error putting PUSCH %d\n", i); + return SRSLTE_ERROR; + } + + // Logging + char str[512]; + srslte_dci_ul_info(&grants[i].dci, str, 512); + Info("PDCCH: %s, tti_tx_dl=%d\n", str, tti_tx_dl); + } + } + return SRSLTE_SUCCESS; +} + +int sf_worker::encode_pdcch_dl(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants) +{ + for (uint32_t i = 0; i < nof_grants; i++) { + uint16_t rnti = grants[i].dci.rnti; + if (rnti) { + if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].dci_cfg, &grants[i].dci)) { + ERROR("Error putting PDCCH %d\n", i); + return SRSLTE_ERROR; + } + + if (LOG_THIS(rnti)) { + // Logging + char str[512]; + srslte_dci_dl_info(&grants[i].dci, str, 512); + Info("PDCCH: %s, tti_tx_dl=%d\n", str, tti_tx_dl); + } + } + } + return 0; +} + +int sf_worker::encode_pmch(mac_interface_phy::dl_sched_grant_t* grant, srslte_mbsfn_cfg_t* mbsfn_cfg) +{ + srslte_pmch_cfg_t pmch_cfg; + ZERO_OBJECT(pmch_cfg); + srslte_configure_pmch(&pmch_cfg, &phy->cell, mbsfn_cfg); + srslte_ra_dl_compute_nof_re(&phy->cell, &dl_sf, &pmch_cfg.pdsch_cfg.grant); + + // Set soft buffer + pmch_cfg.pdsch_cfg.softbuffers.tx[0] = &temp_mbsfn_softbuffer; + + // Encode PMCH + if (srslte_enb_dl_put_pmch(&enb_dl, &pmch_cfg, grant->data[0])) { + Error("Error putting PMCH\n"); + return SRSLTE_ERROR; + } + + // Logging + char str[512]; + srslte_pdsch_tx_info(&pmch_cfg.pdsch_cfg, str, 512); + Info("pmch: %s\n", str); + + return SRSLTE_SUCCESS; +} + +int sf_worker::encode_pdsch(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants) +{ + + /* Scales the Resources Elements affected by the power allocation (p_b) */ + // srslte_enb_dl_prepare_power_allocation(&enb_dl); + + // Prepare for receive ACK for DL grants in t_tx_dl+4 + phy->ue_db_clear(tti_tx_ul); + + for (uint32_t i = 0; i < nof_grants; i++) { + uint16_t rnti = grants[i].dci.rnti; + if (rnti) { + + // Compute DL grant + if (srslte_ra_dl_dci_to_grant( + &phy->cell, &dl_sf, ue_db[rnti]->dl_cfg.tm, &grants[i].dci, &ue_db[rnti]->dl_cfg.pdsch.grant)) { + Error("Computing DL grant\n"); + } + + // Set soft buffer + for (uint32_t j = 0; j < SRSLTE_MAX_CODEWORDS; j++) { + ue_db[rnti]->dl_cfg.pdsch.softbuffers.tx[j] = grants[i].softbuffer_tx[j]; + } + + // Encode PDSCH + if (srslte_enb_dl_put_pdsch(&enb_dl, &ue_db[rnti]->dl_cfg.pdsch, grants[i].data)) { + Error("Error putting PDSCH %d\n", i); + return SRSLTE_ERROR; + } + + // Save pending ACK + if (SRSLTE_RNTI_ISUSER(rnti)) { + /* For each TB */ + for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) { + /* If TB enabled, set pending ACK */ + if (ue_db[rnti]->dl_cfg.pdsch.grant.tb[tb_idx].enabled) { + Debug("ACK: set pending tti=%d, mod=%d\n", tti_tx_ul, TTIMOD(tti_tx_ul)); + phy->ue_db_set_ack_pending(tti_tx_ul, rnti, tb_idx, grants[i].dci.location.ncce); + } + } + } + + if (LOG_THIS(rnti)) { + // Logging + char str[512]; + srslte_pdsch_tx_info(&ue_db[rnti]->dl_cfg.pdsch, str, 512); + Info("PDSCH: %s, tti_tx_dl=%d\n", str, tti_tx_dl); + } + + // Save metrics stats + ue_db[rnti]->metrics_dl(grants[i].dci.tb[0].mcs_idx); + } + } + + // srslte_enb_dl_apply_power_allocation(&enb_dl); + + return SRSLTE_SUCCESS; +} + +/************ METRICS interface ********************/ +uint32_t sf_worker::get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]) +{ + pthread_mutex_lock(&mutex); + uint32_t cnt = 0; + for (std::map::iterator iter = ue_db.begin(); iter != ue_db.end(); ++iter) { + ue* u = iter->second; + uint16_t rnti = iter->first; + if (SRSLTE_RNTI_ISUSER(rnti) && cnt < ENB_METRICS_MAX_USERS) { + u->metrics_read(&metrics[cnt]); + cnt++; + } + } + pthread_mutex_unlock(&mutex); + return cnt; +} + +void sf_worker::ue::metrics_read(phy_metrics_t* metrics_) +{ + if (metrics_) { + *metrics_ = metrics; + } + bzero(&metrics, sizeof(phy_metrics_t)); +} + +void sf_worker::ue::metrics_dl(uint32_t mcs) +{ + metrics.dl.mcs = SRSLTE_VEC_CMA(mcs, metrics.dl.mcs, metrics.dl.n_samples); + metrics.dl.n_samples++; +} + +void sf_worker::ue::metrics_ul(uint32_t mcs, float rssi, float sinr, uint32_t turbo_iters) +{ + metrics.ul.mcs = SRSLTE_VEC_CMA((float)mcs, metrics.ul.mcs, metrics.ul.n_samples); + metrics.ul.sinr = SRSLTE_VEC_CMA((float)sinr, metrics.ul.sinr, metrics.ul.n_samples); + metrics.ul.rssi = SRSLTE_VEC_CMA((float)sinr, metrics.ul.rssi, metrics.ul.n_samples); + metrics.ul.turbo_iters = SRSLTE_VEC_CMA((float)turbo_iters, metrics.ul.turbo_iters, metrics.ul.n_samples); + metrics.ul.n_samples++; +} + +void sf_worker::start_plot() +{ +#ifdef ENABLE_GUI + if (plot_worker_id == -1) { + plot_worker_id = get_id(); + log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); + init_plots(this); + } else { + log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); + } +#else + log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in sf_worker.cc)\n"); +#endif +} + +int sf_worker::read_ce_abs(float* ce_abs) +{ + uint32_t i = 0; + int sz = srslte_symbol_sz(phy->cell.nof_prb); + bzero(ce_abs, sizeof(float) * sz); + int g = (sz - 12 * phy->cell.nof_prb) / 2; + for (i = 0; i < 12 * phy->cell.nof_prb; i++) { + ce_abs[g + i] = 20 * log10(cabs(enb_ul.chest_res.ce[i])); + if (isinf(ce_abs[g + i])) { + ce_abs[g + i] = -80; + } + } + return sz; +} + +int sf_worker::read_ce_arg(float* ce_arg) +{ + uint32_t i = 0; + int sz = srslte_symbol_sz(phy->cell.nof_prb); + bzero(ce_arg, sizeof(float) * sz); + int g = (sz - 12 * phy->cell.nof_prb) / 2; + for (i = 0; i < 12 * phy->cell.nof_prb; i++) { + ce_arg[g + i] = cargf(enb_ul.chest_res.ce[i]) * 180.0f / (float)M_PI; + if (isinf(ce_arg[g + i])) { + ce_arg[g + i] = -80; + } + } + return sz; +} + +int sf_worker::read_pusch_d(cf_t* pdsch_d) +{ + int nof_re = 400; // enb_ul.ul_cfg.pusch.nbits.nof_re + memcpy(pdsch_d, enb_ul.pusch.d, nof_re * sizeof(cf_t)); + return nof_re; +} + +int sf_worker::read_pucch_d(cf_t* pdsch_d) +{ + int nof_re = SRSLTE_PUCCH_MAX_BITS / 2; // enb_ul.ul_cfg.pusch.nbits.nof_re + memcpy(pdsch_d, enb_ul.pucch.z_tmp, nof_re * sizeof(cf_t)); + return nof_re; +} + +} // namespace srsenb + +/*********************************************************** + * + * PLOT TO VISUALIZE THE CHANNEL RESPONSEE + * + ***********************************************************/ + +#ifdef ENABLE_GUI +plot_real_t pce, pce_arg; +plot_scatter_t pconst; +plot_scatter_t pconst2; +#define SCATTER_PUSCH_BUFFER_LEN (20 * 6 * SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)) +#define SCATTER_PUSCH_PLOT_LEN 4000 +float tmp_plot[SCATTER_PUSCH_BUFFER_LEN]; +float tmp_plot_arg[SCATTER_PUSCH_BUFFER_LEN]; +cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; +cf_t tmp_pucch_plot[SRSLTE_PUCCH_MAX_BITS / 2]; + +void* plot_thread_run(void* arg) +{ + srsenb::sf_worker* worker = (srsenb::sf_worker*)arg; + + sdrgui_init_title("srsENB"); + plot_real_init(&pce); + plot_real_setTitle(&pce, (char*)"Channel Response - Magnitude"); + plot_real_setLabels(&pce, (char*)"Index", (char*)"dB"); + plot_real_setYAxisScale(&pce, -40, 40); + + plot_real_init(&pce_arg); + plot_real_setTitle(&pce_arg, (char*)"Channel Response - Argument"); + plot_real_setLabels(&pce_arg, (char*)"Angle", (char*)"deg"); + plot_real_setYAxisScale(&pce_arg, -180, 180); + + plot_scatter_init(&pconst); + plot_scatter_setTitle(&pconst, (char*)"PUSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pconst, -4, 4); + plot_scatter_setYAxisScale(&pconst, -4, 4); + + plot_scatter_init(&pconst2); + plot_scatter_setTitle(&pconst2, (char*)"PUCCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pconst2, -4, 4); + plot_scatter_setYAxisScale(&pconst2, -4, 4); + + plot_real_addToWindowGrid(&pce, (char*)"srsenb", 0, 0); + plot_real_addToWindowGrid(&pce_arg, (char*)"srsenb", 1, 0); + plot_scatter_addToWindowGrid(&pconst, (char*)"srsenb", 0, 1); + plot_scatter_addToWindowGrid(&pconst2, (char*)"srsenb", 1, 1); + + int n, n_arg, n_pucch; + int readed_pusch_re = 0; + while (1) { + sem_wait(&plot_sem); + + n = worker->read_pusch_d(tmp_plot2); + n_pucch = worker->read_pucch_d(tmp_pucch_plot); + plot_scatter_setNewData(&pconst, tmp_plot2, n); + plot_scatter_setNewData(&pconst2, tmp_pucch_plot, n_pucch); + + n = worker->read_ce_abs(tmp_plot); + plot_real_setNewData(&pce, tmp_plot, n); + + n_arg = worker->read_ce_arg(tmp_plot_arg); + plot_real_setNewData(&pce_arg, tmp_plot_arg, n_arg); + } + return NULL; +} + +void init_plots(srsenb::sf_worker* worker) +{ + + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, &attr, plot_thread_run, worker)) { + perror("pthread_create"); + exit(-1); + } +} +#endif diff --git a/srsenb/src/phy/txrx.cc b/srsenb/src/phy/txrx.cc index d3c8a620b..835e9023f 100644 --- a/srsenb/src/phy/txrx.cc +++ b/srsenb/src/phy/txrx.cc @@ -29,8 +29,8 @@ #include "srslte/common/threads.h" #include "srslte/common/log.h" +#include "srsenb/hdr/phy/sf_worker.h" #include "srsenb/hdr/phy/txrx.h" -#include "srsenb/hdr/phy/phch_worker.h" #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) @@ -51,7 +51,12 @@ txrx::txrx() : tx_worker_cnt(0), nof_workers(0), tti(0) { prach = NULL; } -bool txrx::init(srslte::radio* radio_h_, srslte::thread_pool* workers_pool_, phch_common* worker_com_, prach_worker *prach_, srslte::log* log_h_, uint32_t prio_) +bool txrx::init(srslte::radio* radio_h_, + srslte::thread_pool* workers_pool_, + phy_common* worker_com_, + prach_worker* prach_, + srslte::log* log_h_, + uint32_t prio_) { radio_h = radio_h_; log_h = log_h_; @@ -70,13 +75,13 @@ bool txrx::init(srslte::radio* radio_h_, srslte::thread_pool* workers_pool_, phc void txrx::stop() { - running = false; + running = false; wait_thread_finish(); } void txrx::run_thread() { - phch_worker *worker = NULL; + sf_worker* worker = NULL; cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL}; srslte_timestamp_t rx_time = {}, tx_time = {}; uint32_t sf_len = SRSLTE_SF_LEN_PRB(worker_com->cell.nof_prb); @@ -100,36 +105,38 @@ void txrx::run_thread() // Configure radio radio_h->set_rx_srate(samp_rate); - radio_h->set_tx_srate(samp_rate); - - log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n",worker_com->cell.nof_prb, sf_len); + radio_h->set_tx_srate(samp_rate); + log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n", worker_com->cell.nof_prb, sf_len); // Set TTI so that first TX is at tti=0 - tti = 10235; - - printf("\n==== eNodeB started ===\n"); - printf("Type to view trace\n"); + tti = 10235; + + log_h->console("\n==== eNodeB started ===\n"); + log_h->console("Type to view trace\n"); + // Main loop while (running) { - tti = (tti+1)%10240; - worker = (phch_worker*) workers_pool->wait_worker(tti); + tti = (tti + 1) % 10240; + worker = (sf_worker*)workers_pool->wait_worker(tti); if (worker) { - for (int p = 0; p < SRSLTE_MAX_PORTS; p++){ + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { buffer[p] = worker->get_buffer_rx(p); } - - radio_h->rx_now((void **) buffer, sf_len, &rx_time); - + + radio_h->rx_now(buffer, sf_len, &rx_time); + /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ srslte_timestamp_copy(&tx_time, &rx_time); - srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3); - - Debug("Setting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n", - tti, tx_worker_cnt, - tx_time.full_secs, tx_time.frac_secs, + srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3); + + Debug("Settting TTI=%d, tx_mutex=%d, tx_time=%ld:%f to worker %d\n", + tti, + tx_worker_cnt, + tx_time.full_secs, + tx_time.frac_secs, worker->get_id()); - + worker->set_time(tti, tx_worker_cnt, tx_time); tx_worker_cnt = (tx_worker_cnt+1)%nof_workers; diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index cfe34b7e9..2aa9dc001 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -372,7 +372,7 @@ bool gtpu::mch_thread::init(std::string m1u_multiaddr_, std::string m1u_if_addr_ void gtpu::mch_thread::run_thread() { if (!initiated) { - fprintf(stderr, "Fatal error running mch_thread without initialization\n"); + ERROR("Fatal error running mch_thread without initialization\n"); return; } diff --git a/srsenb/src/upper/pdcp.cc b/srsenb/src/upper/pdcp.cc index e24195baa..d229c08a5 100644 --- a/srsenb/src/upper/pdcp.cc +++ b/srsenb/src/upper/pdcp.cc @@ -182,17 +182,17 @@ void pdcp::user_interface_rrc::write_pdu(uint32_t lcid, srslte::byte_buffer_t* p void pdcp::user_interface_rrc::write_pdu_bcch_bch(srslte::byte_buffer_t* pdu) { - fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); + ERROR("Error: Received BCCH from ue=%d\n", rnti); } void pdcp::user_interface_rrc::write_pdu_bcch_dlsch(srslte::byte_buffer_t* pdu) { - fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); + ERROR("Error: Received BCCH from ue=%d\n", rnti); } void pdcp::user_interface_rrc::write_pdu_pcch(srslte::byte_buffer_t* pdu) { - fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti); + ERROR("Error: Received PCCH from ue=%d\n", rnti); } std::string pdcp::user_interface_rrc::get_rb_name(uint32_t lcid) diff --git a/srsenb/src/upper/rlc.cc b/srsenb/src/upper/rlc.cc index d1fb7b9f3..13898cd9f 100644 --- a/srsenb/src/upper/rlc.cc +++ b/srsenb/src/upper/rlc.cc @@ -230,17 +230,17 @@ void rlc::user_interface::write_pdu(uint32_t lcid, srslte::byte_buffer_t* sdu) void rlc::user_interface::write_pdu_bcch_bch(srslte::byte_buffer_t* sdu) { - fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); + ERROR("Error: Received BCCH from ue=%d\n", rnti); } void rlc::user_interface::write_pdu_bcch_dlsch(srslte::byte_buffer_t* sdu) { - fprintf(stderr, "Error: Received BCCH from ue=%d\n", rnti); + ERROR("Error: Received BCCH from ue=%d\n", rnti); } void rlc::user_interface::write_pdu_pcch(srslte::byte_buffer_t* sdu) { - fprintf(stderr, "Error: Received PCCH from ue=%d\n", rnti); + ERROR("Error: Received PCCH from ue=%d\n", rnti); } std::string rlc::user_interface::get_rb_name(uint32_t lcid) diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index ff8740cbe..3e89c0cba 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -464,7 +464,7 @@ bool rrc::is_paging_opportunity(uint32_t tti, uint32_t *payload_len) paging_elem.ue_id.set(paging_ue_id_c::types::imsi); paging_elem.ue_id.imsi().resize(u.choice.iMSI.n_octets); memcpy(paging_elem.ue_id.imsi().data(), u.choice.iMSI.buffer, u.choice.iMSI.n_octets); - printf("Warning IMSI paging not tested\n"); + rrc_log->console("Warning IMSI paging not tested\n"); } else { paging_elem.ue_id.set(paging_ue_id_c::types::s_tmsi); paging_elem.ue_id.s_tmsi().mmec.from_number(u.choice.s_TMSI.mMEC.buffer[0]); @@ -786,7 +786,7 @@ void rrc::configure_mbsfn_sibs(sib_type2_s* sib2, sib_type13_r9_s* sib13) memcpy(&pmch_item->mbms_session_info_list_r9[1].tmgi_r9.service_id_r9[0], &byte[0], 3); // FIXME: Check if service is set to 1 } - pmch_item->pmch_cfg_r9.data_mcs_r9 = 10; + pmch_item->pmch_cfg_r9.data_mcs_r9 = 20; pmch_item->pmch_cfg_r9.mch_sched_period_r9 = pmch_cfg_r9_s::mch_sched_period_r9_e_::rf64; pmch_item->pmch_cfg_r9.sf_alloc_end_r9 = 64 * 6; @@ -1142,7 +1142,6 @@ void rrc::ue::handle_rrc_con_setup_complete(rrc_conn_setup_complete_s* msg, srsl memcpy(pdu->msg, msg_r8->ded_info_nas.data(), pdu->N_bytes); // Acknowledge Dedicated Configuration - parent->phy->set_conf_dedicated_ack(rnti, true); parent->mac->phy_config_enabled(rnti, true); if(has_tmsi) { @@ -1159,7 +1158,6 @@ void rrc::ue::handle_rrc_reconf_complete(rrc_conn_recfg_complete_s* msg, srslte: parent->rrc_log->info("RRCReconfigurationComplete transaction ID: %d\n", msg->rrc_transaction_id); // Acknowledge Dedicated Configuration - parent->phy->set_conf_dedicated_ack(rnti, true); parent->mac->phy_config_enabled(rnti, true); } @@ -1449,12 +1447,14 @@ void rrc::ue::send_connection_setup(bool is_setup) phy_cfg->sched_request_cfg.set(sched_request_cfg_c::types::setup); phy_cfg->sched_request_cfg.setup().dsr_trans_max = parent->cfg.sr_cfg.dsr_max; - // phy_cfg->ant_info_present = false; - // phy_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::default_value); // set default antenna config phy_cfg->ant_info_present = true; phy_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); - phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm1; + if (parent->cfg.cell.nof_ports == 1) { + phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm1; + } else { + phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm2; + } phy_cfg->ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); if (is_setup) { @@ -1511,18 +1511,23 @@ void rrc::ue::send_connection_setup(bool is_setup) sched_cfg.maxharq_tx = parent->cfg.mac_cnfg.ul_sch_cfg.max_harq_tx.to_number(); sched_cfg.continuous_pusch = false; sched_cfg.aperiodic_cqi_period = parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC?parent->cfg.cqi_cfg.period:0; - sched_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - sched_cfg.ue_bearers[1].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; - sched_cfg.sr_I = sr_I; - sched_cfg.sr_N_pucch = sr_N_pucch; - sched_cfg.sr_enabled = true; - sched_cfg.cqi_pucch = cqi_pucch; - sched_cfg.cqi_idx = cqi_idx; - sched_cfg.cqi_enabled = parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_PERIODIC; + sched_cfg.ue_bearers[0].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + sched_cfg.ue_bearers[1].direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + if (parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { + sched_cfg.aperiodic_cqi_period = parent->cfg.cqi_cfg.mode == parent->cfg.cqi_cfg.period; + sched_cfg.dl_cfg.cqi_report.aperiodic_configured = true; + } else { + sched_cfg.dl_cfg.cqi_report.pmi_idx = cqi_idx; + sched_cfg.dl_cfg.cqi_report.periodic_configured = true; + } + sched_cfg.pucch_cfg.I_sr = sr_I; + sched_cfg.pucch_cfg.n_pucch_sr = sr_N_pucch; + sched_cfg.pucch_cfg.sr_configured = true; + sched_cfg.pucch_cfg.n_pucch = cqi_pucch; sched_cfg.pucch_cfg.delta_pucch_shift = parent->sib2.rr_cfg_common.pucch_cfg_common.delta_pucch_shift.to_number(); sched_cfg.pucch_cfg.N_cs = parent->sib2.rr_cfg_common.pucch_cfg_common.n_cs_an; sched_cfg.pucch_cfg.n_rb_2 = parent->sib2.rr_cfg_common.pucch_cfg_common.n_rb_cqi; - sched_cfg.pucch_cfg.n1_pucch_an = parent->sib2.rr_cfg_common.pucch_cfg_common.n1_pucch_an; + sched_cfg.pucch_cfg.N_pucch_1 = parent->sib2.rr_cfg_common.pucch_cfg_common.n1_pucch_an; // Configure MAC parent->mac->ue_cfg(rnti, &sched_cfg); @@ -1539,7 +1544,6 @@ void rrc::ue::send_connection_setup(bool is_setup) // Configure PHY layer parent->phy->set_config_dedicated(rnti, phy_cfg); - parent->phy->set_conf_dedicated_ack(rnti, false); parent->mac->set_dl_ant_info(rnti, &phy_cfg->ant_info); parent->mac->phy_config_enabled(rnti, false); @@ -1679,16 +1683,9 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) conn_reconf->rr_cfg_ded.phys_cfg_ded_present = true; phys_cfg_ded_s* phy_cfg = &conn_reconf->rr_cfg_ded.phys_cfg_ded; - if (parent->cfg.antenna_info.tx_mode > ant_info_ded_s::tx_mode_e_::tm1) { - phy_cfg->ant_info_present = true; - phy_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); - phy_cfg->ant_info.explicit_value() = parent->cfg.antenna_info; - } else { - phy_cfg->ant_info_present = true; - phy_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); - phy_cfg->ant_info.explicit_value().tx_mode.value = ant_info_ded_s::tx_mode_e_::tm1; - phy_cfg->ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); - } + phy_cfg->ant_info_present = true; + phy_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); + phy_cfg->ant_info.explicit_value() = parent->cfg.antenna_info; // Configure PHY layer phy_cfg->cqi_report_cfg_present = true; @@ -1714,6 +1711,7 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) phy_cfg->cqi_report_cfg.cqi_report_periodic.set(cqi_report_periodic_c::types::setup); phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = true; phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx = 483; + parent->rrc_log->console("\nWarning: Only 1 user is supported in TM3 and TM4\n\n"); } else { phy_cfg->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present = false; } @@ -1724,7 +1722,6 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) phy_cfg->pdsch_cfg_ded.p_a = parent->cfg.pdsch_cfg; parent->phy->set_config_dedicated(rnti, phy_cfg); - parent->phy->set_conf_dedicated_ack(rnti, false); parent->mac->set_dl_ant_info(rnti, &phy_cfg->ant_info); parent->mac->phy_config_enabled(rnti, false); @@ -1742,7 +1739,7 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) conn_reconf->rr_cfg_ded.drb_to_add_mod_list.resize(1); if (get_drbid_config(&conn_reconf->rr_cfg_ded.drb_to_add_mod_list[0], 1)) { parent->rrc_log->error("Getting DRB1 configuration\n"); - printf("The QCI %d for DRB1 is invalid or not configured.\n", erabs[5].qos_params.qCI.QCI); + parent->rrc_log->console("The QCI %d for DRB1 is invalid or not configured.\n", erabs[5].qos_params.qCI.QCI); return; } @@ -1829,8 +1826,8 @@ void rrc::ue::send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBE // Get DRB configuration drb_to_add_mod_s drb_item; if (get_drbid_config(&drb_item, lcid - 2)) { - parent->rrc_log->error("Getting DRB configuration\n"); - printf("ERROR: The QCI %d is invalid or not configured.\n", erabs[lcid+4].qos_params.qCI.QCI); + parent->rrc_log->error("Getting DRB configuration\n"); + parent->rrc_log->console("ERROR: The QCI %d is invalid or not configured.\n", erabs[lcid + 4].qos_params.qCI.QCI); return; } @@ -1921,12 +1918,14 @@ bool rrc::ue::select_security_algorithms() { switch (parent->cfg.eea_preference_list[i]) { case srslte::CIPHERING_ALGORITHM_ID_EEA0: // “all bits equal to 0” – UE supports no other algorithm than EEA0, +#if 0 zero_vector = true; for (int j = 0; j < LIBLTE_S1AP_ENCRYPTIONALGORITHMS_BIT_STRING_LEN; j++) { if (security_capabilities.encryptionAlgorithms.buffer[j]) { zero_vector = false; } } +#endif if (zero_vector == true) { cipher_algo = srslte::CIPHERING_ALGORITHM_ID_EEA0; enc_algo_found = true; @@ -1965,11 +1964,13 @@ bool rrc::ue::select_security_algorithms() { case srslte::INTEGRITY_ALGORITHM_ID_EIA0: // “all bits equal to 0” – UE supports no other algorithm than EEA0, zero_vector = true; +#if 0 for (int j = 0; j < LIBLTE_S1AP_INTEGRITYPROTECTIONALGORITHMS_BIT_STRING_LEN; j++) { if (security_capabilities.integrityProtectionAlgorithms.buffer[j]) { zero_vector = false; } } +#endif if (zero_vector == true) { integ_algo = srslte::INTEGRITY_ALGORITHM_ID_EIA0; integ_algo_found = true; @@ -2038,7 +2039,7 @@ void rrc::ue::send_dl_dcch(dl_dcch_msg_s* dl_dcch_msg, byte_buffer_t* pdu) pdu->N_bytes = 1u + (uint32_t)bref.distance_bytes(pdu->msg); char buf[32]; - sprintf(buf, "SRB0 - rnti=0x%x", rnti); + sprintf(buf, "SRB1 - rnti=0x%x", rnti); parent->log_rrc_message(buf, Tx, pdu, *dl_dcch_msg); parent->pdcp->write_sdu(rnti, RB_ID_SRB1, pdu); @@ -2205,12 +2206,15 @@ int rrc::ue::cqi_allocate(uint32_t period, uint16_t* pmi_idx, uint16_t* n_pucch) parent->cqi_sched.nof_users[i_min][j_min]++; cqi_sched_prb_idx = i_min; cqi_sched_sf_idx = j_min; - cqi_allocated = true; - cqi_idx = *pmi_idx; - cqi_pucch = *n_pucch; - - parent->rrc_log->info("Allocated CQI resources for time-frequency slot (%d, %d), n_pucch_2=%d, pmi_cfg_idx=%d\n", - cqi_sched_prb_idx, cqi_sched_sf_idx, *n_pucch, *pmi_idx); + cqi_allocated = true; + cqi_idx = *pmi_idx; + cqi_pucch = *n_pucch; + + parent->rrc_log->info("Allocated CQI resources for time-frequency slot (%d, %d), n_pucch_2=%d, pmi_cfg_idx=%d\n", + cqi_sched_prb_idx, + cqi_sched_sf_idx, + *n_pucch, + *pmi_idx); return 0; } diff --git a/srsenb/test/mac/CMakeLists.txt b/srsenb/test/mac/CMakeLists.txt index fbfea5c32..8d89c277e 100644 --- a/srsenb/test/mac/CMakeLists.txt +++ b/srsenb/test/mac/CMakeLists.txt @@ -8,3 +8,13 @@ target_link_libraries(scheduler_test srsenb_mac rrc_asn1 ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + +# Scheduler test random +add_executable(scheduler_test_rand scheduler_test_rand.cc) +target_link_libraries(scheduler_test_rand srsenb_mac + srsenb_phy + srslte_common + srslte_phy + rrc_asn1 + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES}) diff --git a/srsenb/test/mac/scheduler_test_rand.cc b/srsenb/test/mac/scheduler_test_rand.cc new file mode 100644 index 000000000..dcc9d2dd8 --- /dev/null +++ b/srsenb/test/mac/scheduler_test_rand.cc @@ -0,0 +1,945 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2017 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of srsLTE. + * + * srsUE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsUE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srsenb/hdr/mac/mac.h" +#include "srsenb/hdr/phy/phy.h" + +#include "srslte/common/log_filter.h" +#include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/sched_interface.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/radio/radio.h" + +// Create classes +long int seed = time(NULL); +uint32_t err_counter = 0; +uint32_t warn_counter = 0; +struct ue_stats_t { + uint64_t nof_dl_rbs = 0; + uint64_t nof_ul_rbs = 0; +}; +std::map ue_stats; + +/******************* + * Logging * + *******************/ + +class log_tester : public srslte::log_filter +{ +public: + explicit log_tester(std::string layer) : srslte::log_filter(layer) {} + void error(const char* message, ...) __attribute__((format(printf, 2, 3))); +}; +void log_tester::error(const char* message, ...) +{ + if (level >= srslte::LOG_LEVEL_ERROR) { + char* args_msg = NULL; + va_list args; + va_start(args, message); + if (vasprintf(&args_msg, message, args) > 0) + all_log(srslte::LOG_LEVEL_ERROR, tti, args_msg); + va_end(args); + free(args_msg); + } +} +log_tester log_out("ALL"); + +void log_on_exit() +{ + log_out.info("[TESTER] UE stats:\n"); + for (auto& e : ue_stats) { + log_out.info("0x%x: {DL RBs: %lu, UL RBs: %lu}\n", e.first, e.second.nof_dl_rbs, e.second.nof_ul_rbs); + } + log_out.info("[TESTER] This was the seed: %ld\n", seed); +} + +#define Warning(fmt, ...) \ + log_out.warning(fmt, ##__VA_ARGS__); \ + warn_counter++; +#define TestError(fmt, ...) \ + log_out.error(fmt, ##__VA_ARGS__); \ + log_on_exit(); \ + exit(-1); +#define CondError(cond, fmt, ...) \ + if (cond) { \ + log_out.error(fmt, ##__VA_ARGS__); \ + log_on_exit(); \ + exit(-1); \ + } + +/******************* + * Dummies * + *******************/ +float randf() +{ + return (float)((double)rand() / (RAND_MAX)); +} + +struct sched_sim_args { + struct tti_event_t { + struct user_event_t { + uint32_t sr_data; + uint32_t dl_data; + uint32_t dl_nof_retxs; + user_event_t() : sr_data(0), dl_data(0), dl_nof_retxs(0) {} + }; + std::map users; + bool new_user; + bool rem_user; + uint32_t new_rnti; + uint32_t rem_rnti; + tti_event_t() : new_user(false), rem_user(false) {} + }; + + std::vector tti_events; + uint32_t nof_ttis; + float P_retx; + srsenb::sched_interface::ue_cfg_t ue_cfg; + srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; +}; + +// Designed for testing purposes +struct sched_tester : public srsenb::sched { + struct dl_harq_params_t { + uint32_t pid; + uint32_t nof_retxs; + uint32_t tti; + bool is_empty = true; + bool pending_retx = false; + dl_harq_params_t() = default; + dl_harq_params_t(const srsenb::dl_harq_proc& h, uint32_t tti_tx_dl) + { + pid = h.get_id(); + nof_retxs = h.nof_retx(0); + tti = h.get_tti(); + is_empty = h.is_empty(); + pending_retx = h.has_pending_retx(0, tti_tx_dl); // or h.has_pending_retx(1, h.get_tti()); + } + }; + struct tester_user_results { + uint32_t dl_pending_data = 0; + uint32_t ul_pending_data = 0; ///< data pending for UL + bool has_dl_retx = false; + bool has_dl_tx = false; + bool has_ul_tx = false; ///< has either tx or retx + bool has_ul_retx = false; + bool has_ul_newtx = false; ///< *no* retx, but has tx + bool ul_retx_got_delayed = false; + srsenb::sched_interface::ul_sched_data_t* ul_sched = NULL; // fast lookup + srsenb::sched_interface::dl_sched_data_t* dl_sched = NULL; // fast lookup + dl_harq_params_t dl_harqs[2 * FDD_HARQ_DELAY_MS]; + }; + struct sched_tti_data { + bool is_prach_tti_tx_ul = false; + uint32_t ul_sf_idx; + uint32_t tti_rx; + uint32_t tti_tx_dl; + uint32_t tti_tx_ul; + uint32_t current_cfi; + pending_msg3_t ul_pending_msg3; + srslte::bounded_bitset<128, true> used_cce; + // std::vector used_cce; + std::map ue_data; ///< stores buffer state of each user + tester_user_results total_ues; ///< stores combined UL/DL buffer state + srsenb::sched_interface::ul_sched_res_t sched_result_ul; + srsenb::sched_interface::dl_sched_res_t sched_result_dl; + typedef std::map::iterator ue_it_t; + }; + struct ue_info { + int prach_tti, rar_tti, msg3_tti; + uint32_t ra_id; + srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; + srsenb::sched_interface::ue_cfg_t user_cfg; + uint32_t dl_data; + uint32_t ul_data; + ue_info() : prach_tti(-1), rar_tti(-1), msg3_tti(-1), dl_data(0), ul_data(0) {} + }; + struct ack_info_t { + uint16_t rnti; + uint32_t tti; + bool dl_ack; + uint32_t retx_delay; + dl_harq_params_t dl_harq; + ack_info_t() : dl_ack(false), retx_delay(0) {} + }; + + sched_sim_args sim_args; + + // tester control data + typedef std::map::iterator ue_it_t; + std::map tester_ues; + std::multimap to_ack; + typedef std::multimap::iterator ack_it_t; + + // sched results + sched_tti_data tti_data; + + void add_user(uint16_t rnti, + srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg, + srsenb::sched_interface::ue_cfg_t ue_cfg_); + void rem_user(uint16_t rnti); + void test_ra(); + void test_dci_locations(); + void assert_no_empty_allocs(); + void test_collisions(); + void test_harqs(); + void run_tti(uint32_t tti_rx); + +private: + void new_tti(uint32_t tti_); + void process_tti_args(); + void before_sched(); + void process_results(); + void ack_txs(); +}; + +void sched_tester::add_user(uint16_t rnti, + srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg, + srsenb::sched_interface::ue_cfg_t ue_cfg_) +{ + uint32_t ra_id = rand() % 5; + ue_info info; + info.prach_tti = tti_data.tti_rx; + info.ra_id = ra_id; + info.bearer_cfg = bearer_cfg; + info.user_cfg = ue_cfg_; + tester_ues.insert(std::make_pair(rnti, info)); + + if (ue_cfg(rnti, &ue_cfg_)) { + TestError("[TESTER] Registering new user rnti=0x%x to SCHED\n", rnti); + } + dl_rach_info(tti_data.tti_rx, ra_id, rnti, 7); + + // setup bearers + bearer_ue_cfg(rnti, 0, &bearer_cfg); + + log_out.info("[TESTER] Adding user rnti=0x%x\n", rnti); +} + +void sched_tester::rem_user(uint16_t rnti) +{ + tester_ues.erase(rnti); + tti_data.ue_data.erase(rnti); +} + +void sched_tester::new_tti(uint32_t tti_) +{ + // NOTE: make a local copy, since some of these variables may be cleared during scheduling + tti_data.tti_rx = tti_; + tti_data.tti_tx_dl = TTI_TX(tti_); + tti_data.tti_tx_ul = TTI_RX_ACK(tti_); + tti_data.is_prach_tti_tx_ul = srslte_prach_tti_opportunity_config_fdd(cfg.prach_config, tti_data.tti_tx_ul, -1); + if (tti_data.tti_tx_ul > FDD_HARQ_DELAY_MS) { + tti_data.ul_sf_idx = (tti_data.tti_tx_ul - FDD_HARQ_DELAY_MS) % 10; + } else { + tti_data.ul_sf_idx = (tti_data.tti_tx_ul + 10240 - FDD_HARQ_DELAY_MS) % 10; + } + tti_data.ul_pending_msg3 = pending_msg3[tti_data.tti_tx_ul % 10]; + tti_data.current_cfi = sched_cfg.nof_ctrl_symbols; + tti_data.used_cce.resize(srslte_regs_pdcch_ncce(®s, tti_data.current_cfi)); + tti_data.used_cce.reset(); + tti_data.ue_data.clear(); + tti_data.total_ues = tester_user_results(); +} + +void sched_tester::process_tti_args() +{ + // may add a new user + if (sim_args.tti_events[tti_data.tti_rx].new_user) { + CondError(!srslte_prach_tti_opportunity_config_fdd(cfg.prach_config, tti_data.tti_rx, -1), + "[TESTER] New user added in a non-PRACH TTI\n"); + uint16_t rnti = sim_args.tti_events[tti_data.tti_rx].new_rnti; + add_user(rnti, sim_args.bearer_cfg, sim_args.ue_cfg); + } + + // may remove an existing user + if (sim_args.tti_events[tti_data.tti_rx].rem_user) { + uint16_t rnti = sim_args.tti_events[tti_data.tti_rx].rem_rnti; + bearer_ue_rem(rnti, 0); + ue_rem(rnti); + rem_user(rnti); + log_out.info("[TESTER] Removing user rnti=0x%x\n", rnti); + } + + // push UL SRs and DL packets + for (auto& e : sim_args.tti_events[tti_data.tti_rx].users) { + if (e.second.sr_data > 0) { + uint32_t tot_ul_data = ue_db[e.first].get_pending_ul_new_data(tti_data.tti_tx_ul) + e.second.sr_data; + uint32_t lcid = 0; + ul_bsr(e.first, lcid, tot_ul_data); + } + if (e.second.dl_data > 0) { + uint32_t lcid = 0; + // FIXME: Does it need TTI for checking pending data? + uint32_t tot_dl_data = ue_db[e.first].get_pending_dl_new_data(tti_data.tti_tx_dl) + e.second.dl_data; + dl_rlc_buffer_state(e.first, lcid, tot_dl_data, 0); + } + } +} + +void sched_tester::before_sched() +{ + typedef std::map::iterator it_t; + + // check pending data buffers + for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { + uint16_t rnti = it->first; + srsenb::sched_ue* user = &it->second; + tester_user_results d; + srsenb::ul_harq_proc* hul = user->get_ul_harq(tti_data.tti_tx_ul); + d.ul_pending_data = get_ul_buffer(rnti); + // user->get_pending_ul_new_data(tti_data.tti_tx_ul) or hul->has_pending_retx(); // get_ul_buffer(rnti); + d.dl_pending_data = get_dl_buffer(rnti); + d.has_ul_retx = hul->has_pending_retx(); + d.has_ul_tx = d.has_ul_retx or d.ul_pending_data > 0; + srsenb::dl_harq_proc* hdl = user->get_pending_dl_harq(tti_data.tti_tx_dl); + d.has_dl_retx = (hdl != NULL) and hdl->has_pending_retx(0, tti_data.tti_tx_dl); + d.has_dl_tx = (hdl != NULL) or (it->second.get_empty_dl_harq() != NULL and d.dl_pending_data > 0); + d.has_ul_newtx = not d.has_ul_retx and d.ul_pending_data > 0; + tti_data.ue_data.insert(std::make_pair(rnti, d)); + tti_data.total_ues.dl_pending_data += d.dl_pending_data; + tti_data.total_ues.ul_pending_data += d.ul_pending_data; + tti_data.total_ues.has_ul_tx |= d.has_ul_tx; + tti_data.total_ues.has_dl_tx |= d.has_dl_tx; + tti_data.total_ues.has_ul_newtx |= d.has_ul_newtx; + + for (uint32_t i = 0; i < 2 * FDD_HARQ_DELAY_MS; ++i) { + const srsenb::dl_harq_proc* h = user->get_dl_harq(i); + tti_data.ue_data[rnti].dl_harqs[i] = dl_harq_params_t(*h, tti_data.tti_tx_dl); + } + } + + // TODO: Check whether pending pending_rar.rar_tti correspond to a prach_tti +} + +void sched_tester::process_results() +{ + for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + uint16_t rnti = tti_data.sched_result_ul.pusch[i].dci.rnti; + tti_data.ue_data[rnti].ul_sched = &tti_data.sched_result_ul.pusch[i]; + CondError(tester_ues.count(rnti) == 0, + "[TESTER] [%d] The user rnti=0x%x that no longer exists got allocated.\n", + tti_data.tti_rx, + rnti); + } + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { + uint16_t rnti = tti_data.sched_result_dl.data[i].dci.rnti; + tti_data.ue_data[rnti].dl_sched = &tti_data.sched_result_dl.data[i]; + CondError(tester_ues.count(rnti) == 0, + "[TESTER] [%d] The user rnti=0x%x that no longer exists got allocated.\n", + tti_data.tti_rx, + rnti); + } + + test_dci_locations(); + test_ra(); + test_collisions(); + assert_no_empty_allocs(); + test_harqs(); +} + +void sched_tester::run_tti(uint32_t tti_rx) +{ + new_tti(tti_rx); + log_out.info("[TESTER] ---- tti=%u | nof_ues=%lu ----\n", tti_rx, ue_db.size()); + + process_tti_args(); + + ack_txs(); + before_sched(); + + dl_sched(tti_data.tti_tx_dl, &tti_data.sched_result_dl); + ul_sched(tti_data.tti_tx_ul, &tti_data.sched_result_ul); + + process_results(); +} + +/** + * Tests whether the RAR and Msg3 were scheduled within the expected windows + */ +void sched_tester::test_ra() +{ + uint32_t msg3_count = 0; + + // Test if allocations only take place for users with pending data or in RAR + for (auto& iter : tti_data.ue_data) { + uint16_t rnti = iter.first; + sched_tester::ue_info& userinfo = tester_ues[rnti]; + + // Check whether RA has completed correctly + int prach_tti = userinfo.prach_tti; + if (userinfo.msg3_tti <= prach_tti) { // Msg3 not yet sent + bool rar_not_sent = prach_tti >= userinfo.rar_tti; + uint32_t window[2] = {(uint32_t)prach_tti + 3, prach_tti + 3 + cfg.prach_rar_window}; + if (rar_not_sent) { + CondError(tti_data.tti_tx_dl > window[1], "[TESTER] There was no RAR scheduled within the RAR Window\n"); + if (tti_data.tti_tx_dl >= window[0]) { + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_rar_elems; ++i) { + for (uint32_t j = 0; j < tti_data.sched_result_dl.rar[i].nof_grants; ++j) { + if (tti_data.sched_result_dl.rar[i].msg3_grant[j].ra_id == userinfo.ra_id) { + userinfo.rar_tti = tti_data.tti_tx_dl; + } + } + } + } + } else { // RAR completed, check for Msg3 + uint32_t msg3_tti = (uint32_t)(userinfo.rar_tti + FDD_HARQ_DELAY_MS + MSG3_DELAY_MS) % 10240; + if (msg3_tti == tti_data.tti_tx_ul) { + for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + if (tti_data.sched_result_ul.pusch[i].dci.rnti == rnti) { + CondError(tti_data.sched_result_ul.pusch[i].needs_pdcch, + "[TESTER] Msg3 allocations do not require PDCCH\n"); + CondError(tti_data.ul_pending_msg3.rnti != rnti, "[TESTER] The UL pending msg3 RNTI did not match\n"); + CondError(not tti_data.ul_pending_msg3.enabled, "[TESTER] The UL pending msg3 RNTI did not match\n"); + userinfo.msg3_tti = tti_data.tti_tx_ul; + msg3_count++; + } + } + CondError(msg3_count == 0, "[TESTER] No UL msg3 allocation was made\n"); + } else if (msg3_tti < tti_data.tti_tx_ul) { + TestError("[TESTER] No UL msg3 allocation was made\n"); + } + } + } + } + for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + msg3_count -= tti_data.sched_result_ul.pusch[i].needs_pdcch ? 0 : 1; + } + CondError(msg3_count > 0, "[TESTER] There are pending msg3 that do not belong to any active UE\n"); +} + +void sched_tester::assert_no_empty_allocs() +{ + // Test if allocations only take place for users with pending data or in RAR + for (auto& iter : tti_data.ue_data) { + uint16_t rnti = iter.first; + srsenb::sched_ue* user = &ue_db[rnti]; + + if (!iter.second.has_ul_tx and tti_data.ue_data[rnti].ul_sched != NULL and + tti_data.ue_data[rnti].ul_sched->needs_pdcch) { + // FIXME: This test does not work for adaptive re-tx + TestError("[TESTER] There was a user without data that got allocated in UL\n"); + } + srsenb::ul_harq_proc* hul = user->get_ul_harq(tti_data.tti_tx_ul); + iter.second.ul_retx_got_delayed = iter.second.has_ul_retx and hul->is_new_tx(); + tti_data.total_ues.ul_retx_got_delayed |= iter.second.ul_retx_got_delayed; + // Retxs cannot give space to newtx allocations + CondError( + tti_data.total_ues.ul_retx_got_delayed, "[TESTER] There was a retx that was erased for user rnti=0x%x\n", rnti); + } + + // There must be allocations if there is pending data/retxs. + bool no_dl_allocs = true; + for (std::map::iterator it = tti_data.ue_data.begin(); it != tti_data.ue_data.end(); + ++it) { + if (it->second.dl_sched != NULL) { + no_dl_allocs = false; + } + } + // CondError(tti_data.total_ues.has_dl_tx and no_dl_allocs, "There was pending DL data but no user got allocated\n"); + // FIXME: You have to verify if there is space for the retx since it is non-adaptive +} + +/** + * Tests whether there were collisions in the DCI allocations + */ +void sched_tester::test_dci_locations() +{ + // checks if there is any collision. If not, fills the mask + auto try_fill = [&](const srslte_dci_location_t& dci_loc, const char* ch) { + uint32_t cce_start = dci_loc.ncce, cce_stop = dci_loc.ncce + (1u << dci_loc.L); + if (tti_data.used_cce.any(cce_start, cce_stop)) { + TestError("[TESTER] %s DCI collision between CCE positions (%u, %u)\n", ch, cce_start, cce_stop); + } + tti_data.used_cce.fill(cce_start, cce_stop); + }; + + // verify there are no dci collisions for UL, DL data, BC, RAR + for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + if (not tti_data.sched_result_ul.pusch[i].needs_pdcch) { + // In case of adaptive retx or Msg3 + continue; + } + srslte_dci_location_t& dci_loc = tti_data.sched_result_ul.pusch[i].dci.location; + CondError(dci_loc.L == 0, "[TESTER] Invalid aggregation level %d\n", dci_loc.L); // TODO: Extend this test + try_fill(dci_loc, "UL"); + } + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { + try_fill(tti_data.sched_result_dl.data[i].dci.location, "DL data"); + } + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_bc_elems; ++i) { + try_fill(tti_data.sched_result_dl.bc[i].dci.location, "DL BC"); + } + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_rar_elems; ++i) { + try_fill(tti_data.sched_result_dl.rar[i].dci.location, "DL RAR"); + } + + // verify if sched_result "used_cce" coincide with sched "used_cce" + if (tti_data.used_cce != sched_vars.tti_vars(tti_data.tti_rx).used_cce) { + TestError("[TESTER] The used_cce do not match: %s\n", + sched_vars.tti_vars(tti_data.tti_rx).used_cce.to_string().c_str()); + } + + // FIXME: Check postponed retxs + + // typedef std::map::iterator it_t; + // // There must be allocations if there is pending data/retxs. + // if(total_ues.has_ul_tx and ul_sched_result.empty()) { + // for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { + // uint32_t aggr_level = it->second.get_aggr_level(srslte_dci_format_sizeof(SRSLTE_DCI_FORMAT0, cfg.cell.nof_prb, + // cfg.cell.nof_ports)); if (find_empty_dci(it->second.get_locations(current_cfi, sf_idx), aggr_level) > 0) { + // TestError("[%d] There was pending UL data and free CCEs, but no user got allocated\n", tti_data.tti_rx); + // } + // } + // } +} + +void sched_tester::test_harqs() +{ + // check consistency of harq procedures and allocations + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { + uint32_t h_id = tti_data.sched_result_dl.data[i].dci.pid; + uint16_t rnti = tti_data.sched_result_dl.data[i].dci.rnti; + const srsenb::dl_harq_proc* h = ue_db[rnti].get_dl_harq(h_id); + CondError(h == NULL, "[TESTER] scheduled DL harq pid=%d does not exist\n", h_id); + CondError(h->is_empty(), "[TESTER] Cannot schedule an empty harq proc\n"); + CondError(h->get_tti() != tti_data.tti_tx_dl, + "[TESTER] The scheduled DL harq pid=%d does not a valid tti=%u", + h_id, + tti_data.tti_tx_dl); + if (tti_data.ue_data[rnti].dl_harqs[h_id].pending_retx) { // retx + CondError(tti_data.ue_data[rnti].dl_harqs[h_id].nof_retxs + 1 != h->nof_retx(0), + "[TESTER] A dl harq of user rnti=0x%x was likely overwritten.\n", + rnti); + } else { // newtx + CondError(h->nof_retx(0) != 0, "[TESTER] A new harq was scheduled but with invalid number of retxs\n"); + } + } + + // schedule future acks + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { + ack_info_t ack_data; + ack_data.rnti = tti_data.sched_result_dl.data[i].dci.rnti; + ack_data.tti = FDD_HARQ_DELAY_MS + tti_data.tti_tx_dl; + const srsenb::dl_harq_proc* dl_h = ue_db[ack_data.rnti].get_dl_harq(tti_data.sched_result_dl.data[i].dci.pid); + ack_data.dl_harq = dl_harq_params_t(*dl_h, tti_data.tti_tx_dl); + if (ack_data.dl_harq.nof_retxs == 0) { + ack_data.dl_ack = randf() > sim_args.P_retx; + } else { // always ack after three retxs + ack_data.dl_ack = ack_data.dl_harq.nof_retxs == 3; + } + + // Remove harq from the ack list if there was a harq rewrite + ack_it_t it = to_ack.begin(); + while (it != to_ack.end() and it->first < ack_data.tti) { + if (it->second.rnti == ack_data.rnti and it->second.dl_harq.pid == ack_data.dl_harq.pid) { + CondError(it->second.tti + 2 * FDD_HARQ_DELAY_MS > ack_data.tti, + "[TESTER] The retx dl harq id=%d was transmitted too soon\n", + ack_data.dl_harq.pid); + ack_it_t toerase_it = it++; + to_ack.erase(toerase_it); + continue; + } + ++it; + } + + // add new ack to the list + to_ack.insert(std::make_pair(ack_data.tti, ack_data)); + } + + // // Check whether some pids got old + // for (auto& e : ue_db) { + // for (int i = 0; i < 2 * FDD_HARQ_DELAY_MS; i++) { + // if (not(e.second.get_dl_harq(i)->is_empty(0) and e.second.get_dl_harq(1))) { + // if (srslte_tti_interval(tti_data.tti_tx_dl, e.second.get_dl_harq(i)->get_tti()) > 49) { + // TestError("[TESTER] The pid=%d for rnti=0x%x got old.\n", e.second.get_dl_harq(i)->get_id(), e.first); + // } + // } + // } + // } +} + +void sched_tester::test_collisions() +{ + srsenb::ul_mask_t ul_allocs; + ul_allocs.resize(cfg.cell.nof_prb); + + // TEST: Check if there is space for PRACH + if (tti_data.is_prach_tti_tx_ul) { + srsenb::ul_harq_proc::ul_alloc_t prach_alloc = {cfg.prach_freq_offset, 6}; + if (ul_allocs.any(prach_alloc)) { + TestError("[TESTER] There is a collision with the PRACH\n"); + } + ul_allocs.fill(prach_alloc); + } + + // TEST: check collisions in the UL PUSCH and PUCCH + for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + uint32_t L, RBstart; + srslte_ra_type2_from_riv( + tti_data.sched_result_ul.pusch[i].dci.type2_alloc.riv, &L, &RBstart, cfg.cell.nof_prb, cfg.cell.nof_prb); + CondError((RBstart + L) > cfg.cell.nof_prb, + "[TESTER] Allocated RBs (%d,%d) out of bounds (0,%d)\n", + RBstart, + RBstart + L, + cfg.cell.nof_prb); + ue_stats[tti_data.sched_result_ul.pusch[i].dci.rnti].nof_ul_rbs += L; + + if (ul_allocs.any(RBstart, RBstart + L)) { + TestError("[TESTER] There is a collision for UE UL data alloc=(%d,%d) with joint mask=%s\n", + RBstart, + RBstart + L, + ul_allocs.to_hex().c_str()); + } + ul_allocs.fill(RBstart, RBstart + L, true); + } + + // Fill PUCCH + if (cfg.cell.nof_prb != 6 or (not tti_data.is_prach_tti_tx_ul and not tti_data.ul_pending_msg3.enabled)) { + if (ul_allocs.any(0, cfg.nrb_pucch) or ul_allocs.any(cfg.cell.nof_prb - cfg.nrb_pucch, cfg.cell.nof_prb)) { + TestError("[TESTER] There is a collision with the PUCCH\n"); + } + } + ul_allocs.fill(0, cfg.nrb_pucch); + ul_allocs.fill(cfg.cell.nof_prb - cfg.nrb_pucch, cfg.cell.nof_prb); + + // TEST: Check if there is a collision with Msg3 or Msg3 alloc data is not consistent + if (tti_data.ul_pending_msg3.enabled) { + srsenb::ul_harq_proc::ul_alloc_t msg3_alloc = {tti_data.ul_pending_msg3.n_prb, tti_data.ul_pending_msg3.L}; + for (uint32_t i = msg3_alloc.RB_start; i < msg3_alloc.RB_start + msg3_alloc.L; ++i) { + if (not ul_allocs.test(i)) { + TestError( + "[TESTER] The RB %d was not allocated for the msg3 alloc=(%d,%d)\n", i, msg3_alloc.RB_start, msg3_alloc.L); + } + } + + bool passed = false; + for (uint32_t i = 0; i < tti_data.sched_result_ul.nof_dci_elems; ++i) { + if (tti_data.ul_pending_msg3.rnti == tti_data.sched_result_ul.pusch[i].dci.rnti) { + CondError(passed, "[TESTER] There can only be one msg3 allocation per UE\n"); + CondError(tti_data.sched_result_ul.pusch[i].needs_pdcch, "[TESTER] Msg3 allocations do not need PDCCH DCI\n"); + uint32_t L, RBstart; + srslte_ra_type2_from_riv( + tti_data.sched_result_ul.pusch[i].dci.type2_alloc.riv, &L, &RBstart, cfg.cell.nof_prb, cfg.cell.nof_prb); + if (RBstart != tti_data.ul_pending_msg3.n_prb or L != tti_data.ul_pending_msg3.L) { + TestError("[TESTER] The Msg3 allocation does not coincide with the expected.\n"); + } + passed = true; + } + } + CondError(not passed, "[TESTER] No Msg3 allocation was found in the sched_result\n"); + } + + // NOTE: Not possible until DCI conflict issue is resolved + // // TEST: final mask + // if(ul_allocs != ul_mask) { + // TestError("[TESTER] The UL PRB mask and the scheduler result UL mask are not consistent\n"); + // } + + srslte::bounded_bitset<100, true> dl_allocs, alloc_mask; + dl_allocs.resize(cfg.cell.nof_prb); + alloc_mask.resize(cfg.cell.nof_prb); + srslte_dl_sf_cfg_t dl_sf; + ZERO_OBJECT(dl_sf); + + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_data_elems; ++i) { + alloc_mask.reset(); + srslte_pdsch_grant_t grant; + CondError(srslte_ra_dl_dci_to_grant(&cfg.cell, &dl_sf, SRSLTE_TM1, &tti_data.sched_result_dl.data[i].dci, &grant) == + SRSLTE_ERROR, + "Failed to decode PDSCH grant\n"); + for (uint32_t i = 0; i < alloc_mask.size(); ++i) { + if (grant.prb_idx[0][i]) { + alloc_mask.set(i); + } else { + alloc_mask.reset(i); + } + } + if ((dl_allocs & alloc_mask).any()) { + TestError("[TESTER] Detected collision in the DL data allocation (%s intersects %s)\n", + dl_allocs.to_string().c_str(), + alloc_mask.to_string().c_str()); + } + dl_allocs |= alloc_mask; + ue_stats[tti_data.sched_result_dl.data[i].dci.rnti].nof_dl_rbs += alloc_mask.count(); + } + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_bc_elems; ++i) { + alloc_mask.reset(); + srslte_pdsch_grant_t grant; + CondError(srslte_ra_dl_dci_to_grant(&cfg.cell, &dl_sf, SRSLTE_TM1, &tti_data.sched_result_dl.bc[i].dci, &grant) == + SRSLTE_ERROR, + "Failed to decode PDSCH grant\n"); + for (uint32_t i = 0; i < alloc_mask.size(); ++i) { + if (grant.prb_idx[0][i]) { + alloc_mask.set(i); + } else { + alloc_mask.reset(i); + } + } + if ((dl_allocs & alloc_mask).any()) { + TestError("[TESTER] Detected collision in the DL bc allocation (%s intersects %s)\n", + dl_allocs.to_string().c_str(), + alloc_mask.to_string().c_str()); + } + dl_allocs |= alloc_mask; + } + for (uint32_t i = 0; i < tti_data.sched_result_dl.nof_rar_elems; ++i) { + alloc_mask.reset(); + srslte_pdsch_grant_t grant; + CondError(srslte_ra_dl_dci_to_grant(&cfg.cell, &dl_sf, SRSLTE_TM1, &tti_data.sched_result_dl.rar[i].dci, &grant) == + SRSLTE_ERROR, + "Failed to decode PDSCH grant\n"); + for (uint32_t i = 0; i < alloc_mask.size(); ++i) { + if (grant.prb_idx[0][i]) { + alloc_mask.set(i); + } else { + alloc_mask.reset(i); + } + } + if ((dl_allocs & alloc_mask).any()) { + TestError("[TESTER] Detected collision in the DL RAR allocation (%s intersects %s)\n", + dl_allocs.to_string().c_str(), + alloc_mask.to_string().c_str()); + } + dl_allocs |= alloc_mask; + } + + // TEST: check if resulting DL mask is equal to scheduler internal DL mask + srsenb::rbgmask_t rbgmask(nof_rbg); + srslte::bounded_bitset<100, true> rev_alloc = ~dl_allocs; + for (uint32_t i = 0; i < nof_rbg; ++i) { + uint32_t lim = SRSLTE_MIN((i + 1) * P, dl_allocs.size()); + bool val = dl_allocs.any(i * P, lim); + CondError(rev_alloc.any(i * P, lim) and val, "[TESTER] No holes can be left in an RBG\n"); + if (val) { + rbgmask.set(i); + } else { + rbgmask.reset(i); + } + } + if (rbgmask != dl_mask and not fail_dci_alloc) { + TestError("[TESTER] The UL PRB mask and the scheduler result UL mask are not consistent\n"); + } +} + +void sched_tester::ack_txs() +{ + typedef std::map::iterator it_t; + + for (ack_it_t it = to_ack.begin(); it != to_ack.end() and it->first <= tti_data.tti_rx;) { + if (ue_db.count(it->second.rnti) == 0) { + ack_it_t erase_it = it++; + to_ack.erase(erase_it); + continue; + } + if (it->second.tti == tti_data.tti_rx) { + bool ret = false; + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; ++tb) { + ret |= dl_ack_info(tti_data.tti_rx, it->second.rnti, tb, it->second.dl_ack) > 0; + } + CondError(not ret, "[TESTER] The dl harq proc that was acked does not exist\n"); + if (it->second.dl_ack) + log_out.info( + "[TESTER] DL ACK tti=%u rnti=0x%x pid=%d\n", tti_data.tti_rx, it->second.rnti, it->second.dl_harq.pid); + ack_it_t erase_it = it++; + to_ack.erase(erase_it); + continue; + } + ++it; + } + + bool ack = true; //(tti_data.tti_rx % 3) == 0; + if (tti_data.tti_rx >= FDD_HARQ_DELAY_MS) { + for (it_t it = ue_db.begin(); it != ue_db.end(); ++it) { + uint16_t rnti = it->first; + srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_data.tti_rx); + if (h != NULL and not h->is_empty()) { + ul_crc_info(tti_data.tti_rx, rnti, ack); + } + } + } +} + +srsenb::sched_interface::cell_cfg_t generate_cell_cfg() +{ + srsenb::sched_interface::cell_cfg_t cell_cfg; + srslte_cell_t& cell_cfg_phy = cell_cfg.cell; + + bzero(&cell_cfg, sizeof(srsenb::sched_interface::cell_cfg_t)); + + /* Set PHY cell configuration */ + cell_cfg_phy.id = 1; + cell_cfg_phy.cp = SRSLTE_CP_NORM; + cell_cfg_phy.nof_ports = 1; + cell_cfg_phy.nof_prb = 100; + cell_cfg_phy.phich_length = SRSLTE_PHICH_NORM; + cell_cfg_phy.phich_resources = SRSLTE_PHICH_R_1; + + cell_cfg.sibs[0].len = 18; + cell_cfg.sibs[0].period_rf = 8; + cell_cfg.sibs[1].len = 41; + cell_cfg.sibs[1].period_rf = 16; + cell_cfg.si_window_ms = 40; + cell_cfg.nrb_pucch = 2; + cell_cfg.prach_freq_offset = (cell_cfg_phy.nof_prb == 6) ? 0 : 2; + cell_cfg.prach_rar_window = 3; + cell_cfg.maxharq_msg3tx = 3; + + return cell_cfg; +} + +void test_scheduler_rand(srsenb::sched_interface::cell_cfg_t cell_cfg, const sched_sim_args& args) +{ + // Create classes + sched_tester tester; + srsenb::sched my_sched; + srsenb::dl_metric_rr dl_metric; + srsenb::ul_metric_rr ul_metric; + + log_out.set_level(srslte::LOG_LEVEL_INFO); + + tester.sim_args = args; + srslte_cell_t& cell_cfg_phy = cell_cfg.cell; + srsenb::sched_interface::dl_sched_res_t& sched_result_dl = tester.tti_data.sched_result_dl; + srsenb::sched_interface::ul_sched_res_t& sched_result_ul = tester.tti_data.sched_result_ul; + + tester.init(NULL, &log_out); + tester.set_metric(&dl_metric, &ul_metric); + tester.cell_cfg(&cell_cfg); + + bool running = true; + uint32_t tti = 0; + uint32_t nof_ttis = 0; + while (running) { + if (nof_ttis > args.nof_ttis) { + running = false; + } + log_out.step(tti); + + tester.run_tti(tti); + + nof_ttis++; + tti = (tti + 1) % 10240; + } +} + +sched_sim_args rand_sim_params(const srsenb::sched_interface::cell_cfg_t& cell_cfg, uint32_t nof_ttis) +{ + sched_sim_args sim_args; + std::vector > current_rntis; + uint16_t rnti_start = 70; + uint32_t max_conn_dur = 10000, min_conn_dur = 5000; + float P_ul_sr = randf() * 0.5, P_dl = randf() * 0.5; + float P_prach = 0.99f; // 0.1f + randf()*0.3f; + float ul_sr_exps[] = {1, 4}; // log rand + float dl_data_exps[] = {1, 4}; // log rand + uint32_t max_nof_users = 500; + + bzero(&sim_args.ue_cfg, sizeof(srsenb::sched_interface::ue_cfg_t)); + sim_args.ue_cfg.aperiodic_cqi_period = 40; + sim_args.ue_cfg.maxharq_tx = 5; + + bzero(&sim_args.bearer_cfg, sizeof(srsenb::sched_interface::ue_bearer_cfg_t)); + sim_args.bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; + + sim_args.nof_ttis = nof_ttis; + sim_args.P_retx = 0.1; + sim_args.tti_events.resize(sim_args.nof_ttis); + + for (uint32_t tti = 0; tti < sim_args.tti_events.size(); ++tti) { + if (not current_rntis.empty()) { + // may rem user + for (uint32_t i = 0; i < current_rntis.size(); ++i) { + if (current_rntis[i][2] + current_rntis[i][1] <= tti) { + std::vector >::iterator it_to_rem = current_rntis.begin() + i; + sim_args.tti_events[tti].rem_user = true; + sim_args.tti_events[tti].rem_rnti = (*it_to_rem)[0]; + current_rntis.erase(it_to_rem); + } + } + + for (uint32_t i = 0; i < current_rntis.size(); ++i) { + uint32_t rnti = current_rntis[i][0]; + if (randf() < P_ul_sr) { + float exp = ul_sr_exps[0] + randf() * (ul_sr_exps[1] - ul_sr_exps[0]); + sim_args.tti_events[tti].users[rnti].sr_data = (uint32_t)pow(10, exp); + } + if (randf() < P_dl) { + float exp = dl_data_exps[0] + randf() * (dl_data_exps[1] - dl_data_exps[0]); + sim_args.tti_events[tti].users[rnti].dl_data = (uint32_t)pow(10, exp); + } + } + } + + // may add new user (For now, we only support one UE per PRACH) + bool is_prach_tti = srslte_prach_tti_opportunity_config_fdd(cell_cfg.prach_config, tti, -1); + if (is_prach_tti and current_rntis.size() < max_nof_users and randf() < P_prach) { + std::vector elem(3); + elem[0] = rnti_start; + elem[1] = tti; + elem[2] = min_conn_dur + rand() % (max_conn_dur - min_conn_dur); + current_rntis.push_back(elem); + sim_args.tti_events[tti].new_user = true; + sim_args.tti_events[tti].new_rnti = rnti_start++; + } + } + + return sim_args; +} + +int main(int argc, char* argv[]) +{ + printf("[TESTER] This is the chosen seed: %lu\n", seed); + /* initialize random seed: */ + srand(seed); + uint32_t N_runs = 1, nof_ttis = 10240 + 10; + + for (uint32_t n = 0; n < N_runs; ++n) { + printf("Sim run number: %u\n", n + 1); + srsenb::sched_interface::cell_cfg_t cell_cfg = generate_cell_cfg(); + sched_sim_args sim_args = rand_sim_params(cell_cfg, nof_ttis); + + test_scheduler_rand(cell_cfg, sim_args); + } + + // // low UL-Txs + // printf("\n\n********* New Test ***********\n"); + // sim_args.P_sr = 0.05; + // test_scheduler_rand(sim_args); + + printf("[TESTER] Number of assertion warnings: %u\n", warn_counter); + printf("[TESTER] Number of assertion errors: %u\n", err_counter); + printf("[TESTER] This was the chosen seed: %lu\n", seed); +} diff --git a/srsepc/hdr/mbms-gw/mbms-gw.h b/srsepc/hdr/mbms-gw/mbms-gw.h index 58bfcc277..f0db07da6 100644 --- a/srsepc/hdr/mbms-gw/mbms-gw.h +++ b/srsepc/hdr/mbms-gw/mbms-gw.h @@ -33,13 +33,14 @@ #ifndef MBMS_GW_H #define MBMS_GW_H -#include +#include "srslte/asn1/gtpc.h" +#include "srslte/common/buffer_pool.h" #include "srslte/common/log.h" -#include "srslte/common/logger_file.h" #include "srslte/common/log_filter.h" -#include "srslte/common/buffer_pool.h" +#include "srslte/common/logger_file.h" #include "srslte/common/threads.h" -#include "srslte/asn1/gtpc.h" +#include "srslte/srslte.h" +#include namespace srsepc{ diff --git a/srsepc/hdr/spgw/gtpc.h b/srsepc/hdr/spgw/gtpc.h index 9adb38ac6..f7be9f873 100644 --- a/srsepc/hdr/spgw/gtpc.h +++ b/srsepc/hdr/spgw/gtpc.h @@ -47,7 +47,7 @@ public: const std::map& ip_to_imsi); void stop(); - srslte::error_t init_s11(spgw_args_t *args); + srslte::error_t init_s11(spgw_args_t* args); srslte::error_t init_ue_ip(spgw_args_t* args, const std::map& ip_to_imsi); int get_s11(); diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index 90a9ac2b9..b1b08fe42 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -21,6 +21,7 @@ * and at http://www.gnu.org/licenses/. * */ + #include "srsepc/hdr/hss/hss.h" #include "srsepc/hdr/mme/mme.h" #include "srsepc/hdr/spgw/spgw.h" @@ -153,6 +154,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("log.filename", bpo::value(&args->log_args.filename)->default_value("/tmp/epc.log"),"Log filename") ; + // clang-format on // Positional options - config file location bpo::options_description position("Positional options"); diff --git a/srsepc/src/mme/mme.cc b/srsepc/src/mme/mme.cc index 77abb0473..a635f7333 100644 --- a/srsepc/src/mme/mme.cc +++ b/srsepc/src/mme/mme.cc @@ -131,7 +131,7 @@ void mme::run_thread() while (m_running) { pdu->reset(); int max_fd = std::max(s1mme, s11); - + FD_ZERO(&m_set); FD_SET(s1mme, &m_set); FD_SET(s11, &m_set); diff --git a/srsepc/src/mme/mme_gtpc.cc b/srsepc/src/mme/mme_gtpc.cc index 5d0f4b60a..37433232b 100644 --- a/srsepc/src/mme/mme_gtpc.cc +++ b/srsepc/src/mme/mme_gtpc.cc @@ -143,14 +143,14 @@ bool mme_gtpc::send_s11_pdu(const srslte::gtpc_pdu& pdu) return true; } -void mme_gtpc::handle_s11_pdu(srslte::byte_buffer_t *msg) +void mme_gtpc::handle_s11_pdu(srslte::byte_buffer_t* msg) { m_mme_gtpc_log->debug("Received S11 message\n"); - srslte::gtpc_pdu *pdu; - pdu = (srslte::gtpc_pdu *) msg->msg; - m_mme_gtpc_log->debug("MME Received GTP-C PDU. Message type %s\n",srslte::gtpc_msg_type_to_str(pdu->header.type)); - switch(pdu->header.type){ + srslte::gtpc_pdu* pdu; + pdu = (srslte::gtpc_pdu*)msg->msg; + m_mme_gtpc_log->debug("MME Received GTP-C PDU. Message type %s\n", srslte::gtpc_msg_type_to_str(pdu->header.type)); + switch (pdu->header.type) { case srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE: handle_create_session_response(pdu); break; @@ -181,7 +181,7 @@ bool mme_gtpc::send_create_session_request(uint64_t imsi) // Setup GTP-C Header. FIXME: Length, sequence and other fields need to be added. cs_req_pdu.header.piggyback = false; cs_req_pdu.header.teid_present = true; - cs_req_pdu.header.teid = 0; // Send create session request to the butler TEID + cs_req_pdu.header.teid = 0; // Send create session request to the butler TEID cs_req_pdu.header.type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_REQUEST; // Setup GTP-C Create Session Request IEs @@ -397,7 +397,7 @@ bool mme_gtpc::send_delete_session_request(uint64_t imsi) // Send msg to SPGW send_s11_pdu(del_req_pdu); - + // Delete GTP-C context std::map::iterator it_imsi = m_mme_ctr_teid_to_imsi.find(mme_ctr_fteid.teid); if (it_imsi == m_mme_ctr_teid_to_imsi.end()) { diff --git a/srsepc/src/mme/nas.cc b/srsepc/src/mme/nas.cc index fad75279f..d5536cb41 100644 --- a/srsepc/src/mme/nas.cc +++ b/srsepc/src/mme/nas.cc @@ -301,7 +301,8 @@ bool nas::handle_imsi_attach_request_known_ue(nas* s1ap->delete_ue_ctx(nas_ctx->m_emm_ctx.imsi); // Handle new attach - err = nas::handle_imsi_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, itf, nas_log); + err = + nas::handle_imsi_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, itf, nas_log); return err; } diff --git a/srsepc/src/mme/s1ap_mngmt_proc.cc b/srsepc/src/mme/s1ap_mngmt_proc.cc index 1d67919ab..49c4f182d 100644 --- a/srsepc/src/mme/s1ap_mngmt_proc.cc +++ b/srsepc/src/mme/s1ap_mngmt_proc.cc @@ -221,7 +221,7 @@ bool s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte memcpy(s1_resp->MMEname.buffer, s1ap_args.mme_name.c_str(), s1ap_args.mme_name.length()); // Served GUMEIs - s1_resp->ServedGUMMEIs.len = 1; // TODO Only one served GUMMEI supported + s1_resp->ServedGUMMEIs.len = 1; // TODO Only one served GUMMEI supported LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT* serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0]; serv_gummei->ext = false; @@ -235,8 +235,8 @@ bool s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte serv_gummei->servedPLMNs.buffer[0].buffer[1] = ((uint8_t*)&plmn)[2]; serv_gummei->servedPLMNs.buffer[0].buffer[2] = ((uint8_t*)&plmn)[3]; - serv_gummei->servedGroupIDs.len = 1; // LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT - uint16_t tmp = htons(s1ap_args.mme_group); + serv_gummei->servedGroupIDs.len = 1; // LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT + uint16_t tmp = htons(s1ap_args.mme_group); serv_gummei->servedGroupIDs.buffer[0].buffer[0] = ((uint8_t*)&tmp)[0]; serv_gummei->servedGroupIDs.buffer[0].buffer[1] = ((uint8_t*)&tmp)[1]; @@ -244,7 +244,7 @@ bool s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte serv_gummei->servedMMECs.buffer[0].buffer[0] = s1ap_args.mme_code; s1_resp->RelativeMMECapacity.RelativeMMECapacity = 255; - s1_resp->MMERelaySupportIndicator_present = false; + s1_resp->MMERelaySupportIndicator_present = false; s1_resp->CriticalityDiagnostics_present = false; liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg); diff --git a/srsepc/src/mme/s1ap_nas_transport.cc b/srsepc/src/mme/s1ap_nas_transport.cc index 5dff3681b..b4d1d1f6a 100644 --- a/srsepc/src/mme/s1ap_nas_transport.cc +++ b/srsepc/src/mme/s1ap_nas_transport.cc @@ -87,7 +87,7 @@ void s1ap_nas_transport::init() m_nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo; m_nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_algo; - //Init NAS interface + // Init NAS interface m_nas_if.s1ap = s1ap::get_instance(); m_nas_if.gtpc = mme_gtpc::get_instance(); m_nas_if.hss = hss::get_instance(); @@ -132,7 +132,8 @@ bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUE case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST: m_s1ap_log->console("Received Initial UE message -- Detach Request\n"); m_s1ap_log->info("Received Initial UE message -- Detach Request\n"); - err = nas::handle_detach_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, m_nas_init, m_nas_if, m_s1ap->m_nas_log); + err = + nas::handle_detach_request(m_tmsi, enb_ue_s1ap_id, enb_sri, nas_msg, m_nas_init, m_nas_if, m_s1ap->m_nas_log); break; case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST: m_s1ap_log->console("Received Initial UE message -- Tracking Area Update Request\n"); diff --git a/srsepc/src/spgw/spgw.cc b/srsepc/src/spgw/spgw.cc index a683a37be..d558f1788 100644 --- a/srsepc/src/spgw/spgw.cc +++ b/srsepc/src/spgw/spgw.cc @@ -132,8 +132,8 @@ void spgw::run_thread() size_t buf_len = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET; fd_set set; - int max_fd = std::max(s1u, sgi); - max_fd = std::max(max_fd, s11); + int max_fd = std::max(s1u, sgi); + max_fd = std::max(max_fd, s11); while (m_running) { s1u_msg->reset(); diff --git a/srsue/hdr/mac/demux.h b/srsue/hdr/mac/demux.h index c20b8ebc2..d4be0ba9c 100644 --- a/srsue/hdr/mac/demux.h +++ b/srsue/hdr/mac/demux.h @@ -38,52 +38,60 @@ namespace srsue { +class mac_interface_demux +{ +public: + virtual void reset_harq(uint32_t cc_idx) = 0; + virtual bool contention_resolution_id_rcv(uint64_t id) = 0; +}; + class demux : public srslte::pdu_queue::process_callback { public: demux(); - void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer); + void init(phy_interface_mac_common* phy_h_, + rlc_interface_mac* rlc, + mac_interface_demux* mac, + srslte::log* log_h_, + srslte::timers::timer* time_alignment_timer); bool process_pdus(); uint8_t* request_buffer(uint32_t len); uint8_t* request_buffer_bcch(uint32_t len); void deallocate(uint8_t* payload_buffer_ptr); - - void push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); - void push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); - void push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp); - void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes); - void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg); + void push_pdu(uint8_t* buff, uint32_t nof_bytes); + void push_pdu_bcch(uint8_t* buff, uint32_t nof_bytes); + void push_pdu_mch(uint8_t* buff, uint32_t nof_bytes); + void push_pdu_temp_crnti(uint8_t* buff, uint32_t nof_bytes); + bool get_uecrid_successful(); - void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp); + void process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel); void mch_start_rx(uint32_t lcid); + private: - const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps - const static int NOF_BUFFER_PDUS = 64; // Number of PDU buffers per HARQ pid + const static int MAX_PDU_LEN = 150 * 1024 / 8; // ~ 150 Mbps const static int MAX_BCCH_PDU_LEN = 1024; uint8_t bcch_buffer[MAX_BCCH_PDU_LEN]; // BCCH PID has a dedicated buffer - - bool (*uecrid_callback) (void*, uint64_t); - void *uecrid_callback_arg; - + srslte::sch_pdu mac_msg; srslte::mch_pdu mch_mac_msg; srslte::sch_pdu pending_mac_msg; - uint8_t mch_lcids[SRSLTE_N_MCH_LCIDS]; - void process_sch_pdu(srslte::sch_pdu *pdu); - void process_mch_pdu(srslte::mch_pdu *pdu); - - + uint8_t mch_lcids[SRSLTE_N_MCH_LCIDS]; + void process_sch_pdu_rt(uint8_t* buff, uint32_t nof_bytes); + void process_sch_pdu(srslte::sch_pdu* pdu); + void process_mch_pdu(srslte::mch_pdu* pdu); + bool process_ce(srslte::sch_subh *subheader); - - bool is_uecrid_successful; - - phy_interface_mac_common *phy_h; + + bool is_uecrid_successful; + + phy_interface_mac_common* phy_h; srslte::log *log_h; srslte::timers::timer *time_alignment_timer; rlc_interface_mac *rlc; + mac_interface_demux* mac; // Buffer of PDUs srslte::pdu_queue pdus; diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index f9dd39461..1f1aeda85 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -27,10 +27,6 @@ #ifndef SRSUE_DL_HARQ_H #define SRSUE_DL_HARQ_H -#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) -#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #include "srslte/common/log.h" #include "srslte/common/timers.h" @@ -42,368 +38,58 @@ /* Downlink HARQ entity as defined in 5.3.2 of 36.321 */ - namespace srsue { -template class dl_harq_entity { public: + dl_harq_entity(); - const static uint32_t HARQ_BCCH_PID = N; - - dl_harq_entity() : proc(N+1) - { - pcap = NULL; - } - - bool init(srslte::log *log_h_, srslte::timers::timer *timer_aligment_timer_, demux *demux_unit_) - { - timer_aligment_timer = timer_aligment_timer_; - demux_unit = demux_unit_; - si_window_start = 0; - log_h = log_h_; - for (uint32_t i=0;iMAC interface for DL processes **************************/ - void new_grant_dl(Tgrant grant, Taction *action) - { - if (grant.rnti_type != SRSLTE_RNTI_SPS) { - uint32_t harq_pid; - // Set BCCH PID for SI RNTI - if (grant.rnti_type == SRSLTE_RNTI_SI) { - harq_pid = HARQ_BCCH_PID; - } else { - harq_pid = grant.pid%N; - } - if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) { - grant.ndi[0] = true; - Info("Set NDI=1 for Temp-RNTI DL grant\n"); - last_temporal_crnti = grant.rnti; - } - if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) { - grant.ndi[0] = true; - Info("Set NDI=1 for C-RNTI DL grant\n"); - } - proc[harq_pid].new_grant_dl(grant, action); - } else { - /* This is for SPS scheduling */ - uint32_t harq_pid = get_harq_sps_pid(grant.tti)%N; - if (grant.ndi[0]) { - grant.ndi[0] = false; - proc[harq_pid].new_grant_dl(grant, action); - } else { - if (grant.is_sps_release) { - dl_sps_assig.clear(); - if (timer_aligment_timer->is_running()) { - //phy_h->send_sps_ack(); - Warning("PHY Send SPS ACK not implemented\n"); - } - } else { - Error("SPS not implemented\n"); - //dl_sps_assig.reset(grant.tti, grant); - //grant.ndi = true; - //procs[harq_pid].save_grant(); - } - } - } - } - - - void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) - { - if (rnti_type == SRSLTE_RNTI_SI) { - proc[N].tb_decoded(ack, 0); - } else { - proc[harq_pid%N].tb_decoded(ack, tb_idx); - } - } - - - void reset() - { - for (uint32_t i=0;igenerate_ack = true; - action->rnti = grant.rnti; - - /* For each subprocess... */ - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - action->default_ack[tb] = false; - action->decode_enabled[tb] = false; - action->phy_grant.dl.tb_en[tb] = grant.tb_en[tb]; - if (grant.tb_en[tb]) { - subproc[tb].new_grant_dl(grant, action); - } - } - } - - int get_current_tbs(uint32_t tb_idx) { return subproc[tb_idx].get_current_tbs(); } - - bool is_sps() { return false; } - - void tb_decoded(bool ack_, uint32_t tb_idx) { - subproc[tb_idx].tb_decoded(ack_); - } + dl_harq_process(); + bool init(int pid, dl_harq_entity* parent); + void reset(void); - private: + void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); + void tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]); - const static int RESET_DUPLICATE_TIMEOUT = 8*6; + bool is_sps(); + + private: + const static int RESET_DUPLICATE_TIMEOUT = 6; class dl_tb_process { public: - dl_tb_process(void) { - is_initiated = false; - ack = false; - bzero(&cur_grant, sizeof(Tgrant)); - payload_buffer_ptr = NULL; - pthread_mutex_init(&mutex, NULL); - } - - ~dl_tb_process() { - if (is_initiated) { - srslte_softbuffer_rx_free(&softbuffer); - } - } - - bool init(uint32_t pid_, dl_harq_entity *parent, uint32_t tb_idx) { - tid = tb_idx; - if (srslte_softbuffer_rx_init(&softbuffer, 110)) { - Error("Error initiating soft buffer\n"); - return false; - } else { - pid = pid_; - is_first_tb = true; - is_initiated = true; - harq_entity = parent; - log_h = harq_entity->log_h; - return true; - } - } - - void reset(bool lock = true) { - if (lock) { - pthread_mutex_lock(&mutex); - } - is_first_tb = true; - ack = false; - n_retx = 0; - if (payload_buffer_ptr) { - if (pid != HARQ_BCCH_PID) { - harq_entity->demux_unit->deallocate(payload_buffer_ptr); - } - payload_buffer_ptr = NULL; - } - bzero(&cur_grant, sizeof(Tgrant)); - if (is_initiated && lock) { - srslte_softbuffer_rx_reset(&softbuffer); - } - if (lock) { - pthread_mutex_unlock(&mutex); - } - } - - void new_grant_dl(Tgrant grant, Taction *action) { - - pthread_mutex_lock(&mutex); - - // Compute RV for BCCH when not specified in PDCCH format - if (pid == HARQ_BCCH_PID && grant.rv[tid] == -1) { - uint32_t k; - if ((grant.tti / 10) % 2 == 0 && grant.tti % 10 == 5) { // This is SIB1, k is different - k = (grant.tti / 20) % 4; - grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; - } else if (grant.rv[tid] == -1) { - k = (grant.tti - harq_entity->si_window_start) % 4; - grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4; - } - } - calc_is_new_transmission(grant); - // If this is a new transmission or the size of the TB has changed - if (is_new_transmission || (cur_grant.n_bytes[tid] != grant.n_bytes[tid])) { - if (!is_new_transmission) { - Warning("DL PID %d: Size of grant changed during a retransmission %d!=%d\n", pid, - cur_grant.n_bytes[tid], grant.n_bytes[tid]); - } - ack = false; - srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8); - n_retx = 0; - } - - // If data has not yet been successfully decoded - if (!ack) { - - // Save grant - grant.last_ndi[tid] = cur_grant.ndi[tid]; - grant.last_tti = cur_grant.tti; - memcpy(&cur_grant, &grant, sizeof(Tgrant)); - - if (payload_buffer_ptr) { - Warning("DL PID %d: Allocating buffer already allocated. Deallocating.\n", pid); - if (pid != HARQ_BCCH_PID) { - harq_entity->demux_unit->deallocate(payload_buffer_ptr); - } - } - - // Instruct the PHY To combine the received data and attempt to decode it - if (pid == HARQ_BCCH_PID) { - payload_buffer_ptr = harq_entity->demux_unit->request_buffer_bcch(cur_grant.n_bytes[tid]); - } else { - payload_buffer_ptr = harq_entity->demux_unit->request_buffer(cur_grant.n_bytes[tid]); - } - action->payload_ptr[tid] = payload_buffer_ptr; - if (!action->payload_ptr[tid]) { - action->decode_enabled[tid] = false; - Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); - pthread_mutex_unlock(&mutex); - return; - } - action->decode_enabled[tid] = true; - action->rv[tid] = cur_grant.rv[tid]; - action->softbuffers[tid] = &softbuffer; - memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); - n_retx++; - - } else { - action->default_ack[tid] = true; - uint32_t interval = srslte_tti_interval(grant.tti, cur_grant.tti); - Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK (grant_tti=%d, ndi=%d, sz=%d, reset=%s)\n", - pid, cur_grant.tti, cur_grant.ndi[tid], cur_grant.n_bytes[tid], interval>RESET_DUPLICATE_TIMEOUT?"yes":"no"); - if (interval > RESET_DUPLICATE_TIMEOUT) { - reset(false); - } - } - - if (pid == HARQ_BCCH_PID || harq_entity->timer_aligment_timer->is_expired()) { - // Do not generate ACK - Debug("Not generating ACK\n"); - action->generate_ack = false; - } else { - if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && !ack) { - // Postpone ACK after contention resolution is resolved - action->generate_ack_callback = harq_entity->generate_ack_callback; - action->generate_ack_callback_arg = harq_entity->demux_unit; - Debug("ACK pending contention resolution\n"); - } else { - Debug("Generating ACK\n"); - } - } - - if (!action->decode_enabled[tid]) { - pthread_mutex_unlock(&mutex); - } - - } - - void tb_decoded(bool ack_) { - ack = ack_; - if (ack) { - if (pid == HARQ_BCCH_PID) { - if (harq_entity->pcap) { - harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes[tid], ack, cur_grant.tti); - } - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu_bcch(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.tti); - } else { - if (harq_entity->pcap) { - harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.rnti, ack, - cur_grant.tti); - } - if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) { - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", - cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]); - } else { - Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]); - harq_entity->demux_unit->push_pdu(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.tti); - - // Compute average number of retransmissions per packet - harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, - harq_entity->nof_pkts++); - } - } - } else if (pid != HARQ_BCCH_PID) { - harq_entity->demux_unit->deallocate(payload_buffer_ptr); - } - - payload_buffer_ptr = NULL; - - Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n", - pid, tid, is_new_transmission ? "newTX" : "reTX ", - cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO", - cur_grant.ndi[tid], cur_grant.last_ndi[tid], cur_grant.tti, cur_grant.last_tti); - - pthread_mutex_unlock(&mutex); - - if (ack && pid == HARQ_BCCH_PID) { - reset(); - } - } - - int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; } + dl_tb_process(void); + ~dl_tb_process(); + + bool init(int pid, dl_harq_entity* parent, uint32_t tb_idx); + void reset(bool lock = true); + + void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); + void tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool* ack_ptr); private: // Determine if it's a new transmission 5.3.2.2 - bool calc_is_new_transmission(Tgrant grant) { - - if (grant.phy_grant.dl.mcs[tid].idx <= 28 && // mcs 29,30,31 always retx regardless of rest - ((grant.ndi[tid] != cur_grant.ndi[tid]) || // 1st condition (NDI has changed) - (pid == HARQ_BCCH_PID && grant.rv[tid] == 0) || // 2nd condition (Broadcast and 1st transmission) - is_first_tb)) - { - is_first_tb = false; - is_new_transmission = true; - Debug("Set HARQ for new transmission\n"); - } else { - is_new_transmission = false; - Debug("Set HARQ for retransmission\n"); - } - - return is_new_transmission; - } + bool calc_is_new_transmission(mac_interface_phy::mac_grant_dl_t grant); pthread_mutex_t mutex; @@ -414,6 +100,7 @@ private: bool is_first_tb; bool is_new_transmission; + bool is_bcch; uint32_t pid; /* HARQ Proccess ID */ uint32_t tid; /* Transport block ID */ uint8_t *payload_buffer_ptr; @@ -421,35 +108,31 @@ private: uint32_t n_retx; - Tgrant cur_grant; + mac_interface_phy::mac_grant_dl_t cur_grant; srslte_softbuffer_rx_t softbuffer; }; /* Transport blocks */ std::vector subproc; }; + // Private members of dl_harq_entity - - static bool generate_ack_callback(void *arg) - { - demux *demux_unit = (demux*) arg; - return demux_unit->get_uecrid_successful(); - } - uint32_t get_harq_sps_pid(uint32_t tti) { return 0; } - + uint32_t get_harq_sps_pid(uint32_t tti); + dl_sps dl_sps_assig; - std::vector proc; + dl_harq_process bcch_proc; srslte::timers::timer *timer_aligment_timer; demux *demux_unit; srslte::log *log_h; - srslte::mac_pcap *pcap; + srslte::mac_pcap* pcap; + mac_interface_rrc::ue_rnti_t* rntis; uint16_t last_temporal_crnti; int si_window_start; - float average_retx; + float average_retx; uint64_t nof_pkts; }; diff --git a/srsue/hdr/mac/dl_sps.h b/srsue/hdr/mac/dl_sps.h index dd6328fdc..55ba15c08 100644 --- a/srsue/hdr/mac/dl_sps.h +++ b/srsue/hdr/mac/dl_sps.h @@ -41,9 +41,8 @@ public: void clear() {} void reset() {} - bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) { - return false; - } + bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_dl_t* grant) { return false; } + private: }; diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index 2853296ba..3060f992b 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -35,7 +35,6 @@ #include "proc_phr.h" #include "proc_ra.h" #include "proc_sr.h" -#include "srslte/asn1/rrc_asn1.h" #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/threads.h" @@ -45,56 +44,60 @@ #include "ul_harq.h" namespace srsue { - -class mac - :public mac_interface_phy - ,public mac_interface_rrc - ,public srslte::timer_callback - ,public srslte::mac_interface_timers - ,public periodic_thread + +class mac : public mac_interface_phy, + public mac_interface_rrc, + public srslte::timer_callback, + public srslte::mac_interface_timers, + public thread, + public mac_interface_demux { public: mac(); - bool init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac* rrc, srslte::log *log_h); + bool init(phy_interface_mac* phy, + rlc_interface_mac* rlc, + rrc_interface_mac* rrc, + srslte::log* log_h, + uint32_t nof_carriers = 1); void stop(); - void get_metrics(mac_metrics_t &m); + void get_metrics(mac_metrics_t m[SRSLTE_MAX_CARRIERS]); - /******** Interface from PHY (PHY -> MAC) ****************/ + /******** Interface from PHY (PHY -> MAC) ****************/ /* see mac_interface.h for comments */ - void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action); - void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action); - void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action); - void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action); - void new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action); - void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid); + void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action); + void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action); + void new_mch_dl(srslte_pdsch_grant_t phy_grant, tb_action_dl_t* action); + void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]); void bch_decoded_ok(uint8_t *payload, uint32_t len); + uint16_t get_dl_sched_rnti(uint32_t tti); + uint16_t get_ul_sched_rnti(uint32_t tti); - void pch_decoded_ok(uint32_t len); - void mch_decoded_ok(uint32_t len); + void mch_decoded(uint32_t len, bool crc); void process_mch_pdu(uint32_t len); void set_mbsfn_config(uint32_t nof_mbsfn_services); - + + void run_tti(const uint32_t tti); + /******** Interface from RRC (RRC -> MAC) ****************/ - void bcch_start_rx(); void bcch_start_rx(int si_window_start, int si_window_length); + void bcch_stop_rx(); void pcch_start_rx(); - void clear_rntis(); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void mch_start_rx(uint32_t lcid); - void reconfiguration(); + void reconfiguration(); void reset(); void wait_uplink(); - /******** set/get MAC configuration ****************/ - void set_config(mac_cfg_t *mac_cfg); - void get_config(mac_cfg_t *mac_cfg); - void set_config_main(asn1::rrc::mac_main_cfg_s* main_cfg); - void set_config_rach(asn1::rrc::rach_cfg_common_s* rach_cfg, uint32_t prach_config_index); - void set_config_sr(asn1::rrc::sched_request_cfg_c* sr_cfg); + /******** set/get MAC configuration ****************/ + void set_config(mac_cfg_t& mac_cfg); void set_contention_id(uint64_t uecri); + /******* interface from demux object ****************/ + void reset_harq(uint32_t cc_idx); + bool contention_resolution_id_rcv(uint64_t id); + void start_noncont_ho(uint32_t preamble_index, uint32_t prach_mask); void start_cont_ho(); @@ -113,13 +116,14 @@ public: void timer_release_id(uint32_t timer_id); uint32_t timer_get_unique_id(); +private: + void run_thread(); + void clear_rntis(); + + bool is_in_window(uint32_t tti, int* start, int* len); -private: - void run_period(); - static const int MAC_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD - static const int MAC_PDU_THREAD_PRIO = DEFAULT_PRIORITY-5; - static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS; + static const int MAC_PDU_THREAD_PRIO = 5; // Interaction with PHY phy_interface_mac *phy_h; @@ -127,23 +131,23 @@ private: rrc_interface_mac *rrc_h; srslte::log *log_h; mac_interface_phy::mac_phy_cfg_mbsfn_t phy_mbsfn_cfg; - - // MAC configuration - mac_cfg_t config; - // UE-specific RNTIs - ue_rnti_t uernti; - - uint32_t tti; + // RNTI search window scheduling + int si_window_length, si_window_start; + int ra_window_length, ra_window_start; + int p_window_start; + + // UE-specific RNTIs + ue_rnti_t uernti; /* Multiplexing/Demultiplexing Units */ - mux mux_unit; - demux demux_unit; - + mux mux_unit; + demux demux_unit; + /* DL/UL HARQ */ - dl_harq_entity dl_harq; - ul_harq_entity ul_harq; - + std::vector dl_harq; + std::vector ul_harq; + /* MAC Uplink-related Procedures */ ra_proc ra_procedure; sr_proc sr_procedure; @@ -160,21 +164,22 @@ private: srslte_softbuffer_rx_t mch_softbuffer; uint8_t mch_payload_buffer[mch_payload_buffer_sz]; srslte::mch_pdu mch_msg; - + // MAC thread + srslte::block_queue tti_sync; + bool running; /* Functions for MAC Timers */ uint32_t timer_alignment; - uint32_t contention_resolution_timer; - void setup_timers(); + void setup_timers(int time_alignment_timer); void timer_alignment_expire(); srslte::timers timers; // pointer to MAC PCAP object srslte::mac_pcap* pcap; - bool is_first_ul_grant; + bool is_first_ul_grant; - mac_metrics_t metrics; + mac_metrics_t metrics[SRSLTE_MAX_CARRIERS]; /* Class to process MAC PDUs from DEMUX unit */ class pdu_process : public thread { diff --git a/srsue/hdr/mac/mux.h b/srsue/hdr/mac/mux.h index 2e621360f..3ea9278a1 100644 --- a/srsue/hdr/mac/mux.h +++ b/srsue/hdr/mac/mux.h @@ -55,14 +55,14 @@ namespace srsue { class mux { public: - mux(uint8_t nof_harq_proc_); + mux(); void reset(); void init(rlc_interface_mac *rlc, srslte::log *log_h, bsr_interface_mux *bsr_procedure, phr_proc *phr_procedure_); bool is_pending_any_sdu(); - bool is_pending_sdu(uint32_t lcid); - - uint8_t* pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32_t pid); + bool is_pending_sdu(uint32_t lcid); + + uint8_t* pdu_get(uint8_t* payload, uint32_t pdu_sz, uint32_t pid); uint8_t* msg3_get(uint8_t* payload, uint32_t pdu_sz); void msg3_flush(); @@ -74,9 +74,8 @@ public: void append_crnti_ce_next_tx(uint16_t crnti); void set_priority(uint32_t lcid, uint32_t priority, int PBR_x_tti, uint32_t BSD); - void clear_lch(uint32_t lch_id); - void pusch_retx(uint32_t tx_tti, uint32_t pid); - + void clear_lch(uint32_t lch_id); + private: int find_lchid(uint32_t lch_id); bool pdu_move_to_msg3(uint32_t pdu_sz); @@ -84,13 +83,10 @@ private: bool sched_sdu(lchid_t *ch, int *sdu_space, int max_sdu_sz); const static int MIN_RLC_SDU_LEN = 0; - const static int MAX_NOF_SUBHEADERS = 20; + const static int MAX_NOF_SUBHEADERS = 20; + + std::vector lch; - std::vector lch; - - // Keep track of the PIDs that transmitted BSR reports - std::vector pid_has_bsr; - // Mutex for exclusive access pthread_mutex_t mutex; @@ -99,8 +95,7 @@ private: bsr_interface_mux *bsr_procedure; phr_proc *phr_procedure; uint16_t pending_crnti_ce; - uint8_t nof_harq_proc; - + /* Msg3 Buffer */ static const uint32_t MSG3_BUFF_SZ = 1024; uint8_t msg3_buff[MSG3_BUFF_SZ]; diff --git a/srsue/hdr/mac/proc_bsr.h b/srsue/hdr/mac/proc_bsr.h index 9592df667..43bfc7128 100644 --- a/srsue/hdr/mac/proc_bsr.h +++ b/srsue/hdr/mac/proc_bsr.h @@ -27,6 +27,7 @@ #ifndef SRSUE_PROC_BSR_H #define SRSUE_PROC_BSR_H +#include #include #include "srslte/common/log.h" @@ -41,44 +42,60 @@ class bsr_proc : public srslte::timer_callback, public bsr_interface_mux { public: bsr_proc(); - void init(rlc_interface_mac *rlc, srslte::log *log_h, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_db); + void init(rlc_interface_mac* rlc, srslte::log* log_h, srslte::timers* timers_db); void step(uint32_t tti); void reset(); - void setup_lcg(uint32_t lcid, uint32_t new_lcg); - void set_priority(uint32_t lcid, uint32_t priority); + void set_config(mac_interface_rrc::bsr_cfg_t& bsr_cfg); + + void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority); void timer_expired(uint32_t timer_id); uint32_t get_buffer_state(); bool need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr); bool generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr); - bool need_to_send_sr(uint32_t tti); - bool need_to_reset_sr(); - void set_tx_tti(uint32_t tti); - + bool need_to_send_sr(uint32_t tti); + bool need_to_reset_sr(); + private: - - const static int QUEUE_STATUS_PERIOD_MS = 500; - + const static int QUEUE_STATUS_PERIOD_MS = 1000; + + pthread_mutex_t mutex; + bool reset_sr; - mac_interface_rrc::mac_cfg_t *mac_cfg; srslte::timers *timers_db; srslte::log *log_h; rlc_interface_mac *rlc; + + mac_interface_rrc::bsr_cfg_t bsr_cfg; + bool initiated; - const static int MAX_LCID = 6; - int lcg[MAX_LCID]; - uint32_t last_pending_data[MAX_LCID]; - int priorities[MAX_LCID]; - uint32_t find_max_priority_lcid(); + + const static int NOF_LCG = 4; + + typedef struct { + int priority; + uint32_t old_buffer; + uint32_t new_buffer; + } lcid_t; + + std::map lcgs[NOF_LCG]; // groups LCID in LCG + + uint32_t find_max_priority_lcg(); typedef enum {NONE, REGULAR, PADDING, PERIODIC} triggered_bsr_type_t; triggered_bsr_type_t triggered_bsr_type; bool sr_is_sent; uint32_t last_print; - uint32_t next_tx_tti; - void update_pending_data(); - bool check_highest_channel(); - bool check_single_channel(); - bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes); + uint32_t current_tti; + uint32_t trigger_tti; + + void set_trigger(triggered_bsr_type_t new_trigger); + void update_new_data(); + void update_buffer_state(); + bool check_highest_channel(); + bool check_new_data(); + bool check_any_channel(); + uint32_t get_buffer_state_lcg(uint32_t lcg); + bool generate_bsr(bsr_t* bsr, uint32_t nof_padding_bytes); char* bsr_type_tostring(triggered_bsr_type_t type); char* bsr_format_tostring(bsr_format_t format); diff --git a/srsue/hdr/mac/proc_phr.h b/srsue/hdr/mac/proc_phr.h index b12280220..3a67307e8 100644 --- a/srsue/hdr/mac/proc_phr.h +++ b/srsue/hdr/mac/proc_phr.h @@ -41,13 +41,14 @@ namespace srsue { class phr_proc : public srslte::timer_callback { public: - phr_proc(); - void init(phy_interface_mac* phy_h, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_db_); - + phr_proc(); + void init(phy_interface_mac* phy_h, srslte::log* log_h_, srslte::timers* timers_db_); + void set_config(mac_interface_rrc::phr_cfg_t& cfg); void step(uint32_t tti); void reset(); bool generate_phr_on_ul_grant(float *phr); + bool is_extended(); void timer_expired(uint32_t timer_id); void start_timer(); @@ -57,13 +58,10 @@ private: bool pathloss_changed(); srslte::log* log_h; - mac_interface_rrc::mac_cfg_t *mac_cfg; - phy_interface_mac* phy_h; + phy_interface_mac* phy_h; srslte::timers* timers_db; + mac_interface_rrc::phr_cfg_t phr_cfg; bool initiated; - int timer_prohibit_value; - int timer_periodic_value; - int dl_pathloss_change; int last_pathloss_db; bool phr_is_triggered; diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h index 5742c2373..63715198a 100644 --- a/srsue/hdr/mac/proc_ra.h +++ b/srsue/hdr/mac/proc_ra.h @@ -58,16 +58,13 @@ public: first_rar_received = false; phy_h = NULL; log_h = NULL; - mac_cfg = NULL; mux_unit = NULL; - demux_unit = NULL; rrc = NULL; transmitted_contention_id = 0; transmitted_crnti = 0; pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; started_by_pdcch = false; rar_grant_nbytes = 0; - rar_grant_tti = 0; msg3_flushed = false; noncontention_enabled = false; @@ -80,67 +77,56 @@ public: ~ra_proc(); - void init(phy_interface_mac *phy_h, - rrc_interface_mac *rrc_, - srslte::log *log_h, - mac_interface_rrc::ue_rnti_t *rntis, - mac_interface_rrc::mac_cfg_t *mac_cfg, - srslte::timers::timer* time_alignment_timer_, - srslte::timers::timer* contention_resolution_timer_, - mux *mux_unit, - demux *demux_unit); + void init(phy_interface_mac* phy_h, + rrc_interface_mac* rrc_, + srslte::log* log_h, + mac_interface_rrc::ue_rnti_t* rntis, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, + mux* mux_unit); + void reset(); + + void set_config(mac_interface_rrc::rach_cfg_t& rach_cfg); + void start_pdcch_order(); void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false); void step(uint32_t tti); - bool is_successful(); - bool is_response_error(); + + bool is_rar_window(int* rar_window_start, int* rar_window_length); bool is_contention_resolution(); void harq_retx(); - bool is_error(); - bool in_progress(); + void harq_max_retx(); void pdcch_to_crnti(bool contains_uplink_grant); void timer_expired(uint32_t timer_id); - - void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action); + void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); void tb_decoded_ok(); void start_noncont(uint32_t preamble_index, uint32_t prach_mask); - + bool contention_resolution_id_received(uint64_t uecri); void start_pcap(srslte::mac_pcap* pcap); -private: - static bool uecrid_callback(void *arg, uint64_t uecri); - bool contention_resolution_id_received(uint64_t uecri); +private: void process_timeadv_cmd(uint32_t ta_cmd); void step_initialization(); void step_resource_selection(); void step_preamble_transmission(); void step_pdcch_setup(); - void step_response_reception(); - void step_response_error(); - void step_backoff_wait(); + void step_response_reception(uint32_t tti); + void step_response_error(uint32_t tti); + void step_backoff_wait(uint32_t tti); void step_contention_resolution(); void step_completition(); // Buffer to receive RAR PDU static const uint32_t MAX_RAR_PDU_LEN = 2048; - uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; - srslte::rar_pdu rar_pdu_msg; + uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; + srslte::rar_pdu rar_pdu_msg; // Random Access parameters provided by higher layers defined in 5.1.1 - uint32_t configIndex; - uint32_t nof_preambles; - uint32_t nof_groupA_preambles; - uint32_t nof_groupB_preambles; - int32_t messagePowerOffsetGroupB; - uint32_t messageSizeGroupA; - uint32_t responseWindowSize; - uint32_t powerRampingStep; - uint32_t preambleTransMax; - int32_t iniReceivedTargetPower; + mac_interface_rrc::rach_cfg_t rach_cfg, new_cfg; + int delta_preamble_db; - uint32_t contentionResolutionTimer; uint32_t maskIndex; int preambleIndex; uint32_t new_ra_msg_len; @@ -177,17 +163,19 @@ private: RA_PROBLEM // Section 5.1.5 last part } state; - typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; + typedef enum { RA_GROUP_A, RA_GROUP_B } ra_group_t; + + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; - ra_group_t last_msg3_group; - bool msg3_transmitted; - bool first_rar_received; - void read_params(); + uint32_t rar_window_st; - phy_interface_mac *phy_h; - srslte::log *log_h; + void read_params(); + + phy_interface_mac* phy_h; + srslte::log* log_h; mux *mux_unit; - demux *demux_unit; srslte::mac_pcap *pcap; rrc_interface_mac *rrc; @@ -195,21 +183,17 @@ private: srslte::timers::timer *contention_resolution_timer; mac_interface_rrc::ue_rnti_t *rntis; - mac_interface_rrc::mac_cfg_t *mac_cfg; uint64_t transmitted_contention_id; uint16_t transmitted_crnti; - enum { - PDCCH_CRNTI_NOT_RECEIVED = 0, - PDCCH_CRNTI_UL_GRANT, - PDCCH_CRNTI_DL_GRANT - } pdcch_to_crnti_received; + pthread_mutex_t mutex; + + enum { PDCCH_CRNTI_NOT_RECEIVED = 0, PDCCH_CRNTI_UL_GRANT, PDCCH_CRNTI_DL_GRANT } pdcch_to_crnti_received; bool ra_is_ho; bool started_by_pdcch; uint32_t rar_grant_nbytes; - uint32_t rar_grant_tti; bool msg3_flushed; bool rar_received; }; diff --git a/srsue/hdr/mac/proc_sr.h b/srsue/hdr/mac/proc_sr.h index 878f92fb5..b3b9f94f7 100644 --- a/srsue/hdr/mac/proc_sr.h +++ b/srsue/hdr/mac/proc_sr.h @@ -40,20 +40,21 @@ class sr_proc { public: sr_proc(); - void init(phy_interface_mac *phy_h, rrc_interface_mac *rrc, srslte::log *log_h, mac_interface_rrc::mac_cfg_t *mac_cfg); - void step(uint32_t tti); + void init(phy_interface_mac* phy_h, rrc_interface_mac* rrc, srslte::log* log_h); + void step(uint32_t tti); + void set_config(mac_interface_rrc::sr_cfg_t& cfg); void reset(); void start(); bool need_random_access(); private: - bool need_tx(uint32_t tti); - - uint32_t sr_counter; - uint32_t dsr_transmax; + bool need_tx(uint32_t tti); + + int sr_counter; bool is_pending_sr; - mac_interface_rrc::mac_cfg_t *mac_cfg; - + + mac_interface_rrc::sr_cfg_t sr_cfg; + rrc_interface_mac *rrc; phy_interface_mac *phy_h; srslte::log *log_h; diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index d62a94aba..69e5021e6 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -32,399 +32,94 @@ #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) -#include "srslte/interfaces/ue_interfaces.h" -#include "srslte/common/log.h" #include "mux.h" -#include "ul_sps.h" +#include "proc_ra.h" +#include "srslte/common/interfaces_common.h" +#include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" -#include "srslte/common/interfaces_common.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "ul_sps.h" -/* Uplink HARQ entity as defined in 5.4.2 of 36.321 */ namespace srsue { -template class ul_harq_entity { public: - static uint32_t pidof(uint32_t tti) { - return (uint32_t) tti % N; - } - - ul_harq_entity() : proc(N) { - contention_timer = NULL; - - pcap = NULL; - mux_unit = NULL; - log_h = NULL; - params = NULL; - rntis = NULL; - average_retx = 0; - nof_pkts = 0; - } + ul_harq_entity(); - bool init(srslte::log *log_h_, - mac_interface_rrc_common::ue_rnti_t *rntis_, - mac_interface_rrc_common::ul_harq_params_t *params_, - srslte::timers::timer *contention_timer_, - mux *mux_unit_) { - log_h = log_h_; - mux_unit = mux_unit_; - params = params_; - rntis = rntis_; - contention_timer = contention_timer_; - for (uint32_t i = 0; i < N; i++) { - if (!proc[i].init(i, this)) { - return false; - } - } - return true; - } + bool init(srslte::log* log_h_, mac_interface_rrc_common::ue_rnti_t* rntis_, ra_proc* ra_proc_h_, mux* mux_unit_); - void reset() { - for (uint32_t i = 0; i < N; i++) { - proc[i].reset(); - } - ul_sps_assig.clear(); - } - - void reset_ndi() { - for (uint32_t i = 0; i < N; i++) { - proc[i].reset_ndi(); - } - } - - void start_pcap(srslte::mac_pcap *pcap_) { - pcap = pcap_; - } + void reset(); + void reset_ndi(); + void set_config(mac_interface_rrc_common::ul_harq_cfg_t& harq_cfg); + void start_pcap(srslte::mac_pcap* pcap_); /***************** PHY->MAC interface for UL processes **************************/ - void new_grant_ul(Tgrant grant, Taction *action) { - new_grant_ul_ack(grant, NULL, action); - } - void new_grant_ul_ack(Tgrant grant, bool *ack, Taction *action) - { - if (grant.rnti_type == SRSLTE_RNTI_USER || - grant.rnti_type == SRSLTE_RNTI_TEMP || - grant.rnti_type == SRSLTE_RNTI_RAR) - { - if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) { - grant.ndi[0] = true; - } - run_tti(grant.tti, &grant, ack, action); - } else if (grant.rnti_type == SRSLTE_RNTI_SPS) { - if (grant.ndi[0]) { - grant.ndi[0] = proc[pidof(grant.tti)].get_ndi(); - run_tti(grant.tti, &grant, ack, action); - } else { - Info("Not implemented\n"); - } - } - } + void new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); - void harq_recv(uint32_t tti, bool ack, Taction *action) - { - run_tti(tti, NULL, &ack, action); - } + int get_current_tbs(uint32_t pid); + float get_average_retx(); - int get_current_tbs(uint32_t tti) - { - int tti_harq = (int) tti-4; - if (tti_harq < 0) { - tti_harq += 10240; - } - uint32_t pid_harq = pidof(tti_harq); - return proc[pid_harq].get_current_tbs(); - } - - float get_average_retx() - { - return average_retx; - } - private: - class ul_harq_process { + class ul_harq_process + { public: - ul_harq_process() { - pid = 0; - harq_feedback = false; - log_h = NULL; - bzero(&softbuffer, sizeof(srslte_softbuffer_tx_t)); - is_msg3 = false; - pdu_ptr = NULL; - current_tx_nb = 0; - current_irv = 0; - is_initiated = false; - is_grant_configured = false; - tti_last_tx = 0; - payload_buffer = NULL; - bzero(&cur_grant, sizeof(Tgrant)); - } - - ~ul_harq_process() - { - if (is_initiated) { - if (payload_buffer) { - free(payload_buffer); - } - srslte_softbuffer_tx_free(&softbuffer); - } - } - - bool init(uint32_t pid_, ul_harq_entity *parent) - { - if (srslte_softbuffer_tx_init(&softbuffer, 110)) { - fprintf(stderr, "Error initiating soft buffer\n"); - return false; - } else { - is_initiated = true; - harq_entity = parent; - log_h = harq_entity->log_h; - pid = pid_; - payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t)); - if (!payload_buffer) { - Error("Allocating memory\n"); - return false; - } - pdu_ptr = payload_buffer; - return true; - } - } - - void reset() - { - current_tx_nb = 0; - current_irv = 0; - tti_last_tx = 0; - is_grant_configured = false; - bzero(&cur_grant, sizeof(Tgrant)); - } + ul_harq_process(); + ~ul_harq_process(); - void reset_ndi() { cur_grant.ndi[0] = false; } + bool init(uint32_t pid_, ul_harq_entity* parent); + void reset(); + void reset_ndi(); - void run_tti(uint32_t tti_tx, Tgrant *grant, bool *ack, Taction* action) - { - if (ack) { - if (grant) { - if (grant->ndi[0] == get_ndi() && grant->phy_grant.ul.mcs.tbs != 0) { - *ack = false; - } - } - harq_feedback = *ack; - } + uint32_t get_rv(); + bool has_grant(); + bool get_ndi(); + bool is_sps(); - // Reset HARQ process if TB has changed - if (harq_feedback && has_grant() && grant) { - if (grant->n_bytes[0] != cur_grant.n_bytes[0] && cur_grant.n_bytes[0] > 0 && grant->n_bytes[0] > 0) { - Debug("UL %d: Reset due to change of grant size last_grant=%d, new_grant=%d\n", - pid, cur_grant.n_bytes[0], grant->n_bytes[0]); - reset(); - } - } + uint32_t get_nof_retx(); + int get_current_tbs(); - // Receive and route HARQ feedbacks - if (grant) { - if (grant->has_cqi_request && grant->phy_grant.ul.mcs.tbs == 0) { - /* Only CQI reporting (without SCH) */ - memcpy(&action->phy_grant.ul, &grant->phy_grant.ul, sizeof(srslte_ra_ul_grant_t)); - //memcpy(&cur_grant, grant, sizeof(Tgrant)); - action->tx_enabled = true; - action->rnti = grant->rnti; - } else if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi() && harq_feedback) || - (grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) || - grant->is_from_rar) - { - // New transmission - reset(); + // Implements Section 5.4.2.1 + void new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); - // Uplink grant in a RAR and there is a PDU in the Msg3 buffer - if (grant->is_from_rar && harq_entity->mux_unit->msg3_is_pending()) { - Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes[0]); - pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes[0]); - if (pdu_ptr) { - generate_new_tx(tti_tx, true, grant, action); - } else { - Warning("UL RAR grant available but no Msg3 on buffer\n"); - } + private: + mac_interface_phy::mac_grant_ul_t cur_grant; - // Normal UL grant - } else { - if (grant->is_from_rar) { - grant->rnti = harq_entity->rntis->crnti; - } - // Request a MAC PDU from the Multiplexing & Assemble Unit - pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes[0], tti_tx, pid); - if (pdu_ptr) { - generate_new_tx(tti_tx, false, grant, action); - } else { - Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n"); - } - } - } else if (has_grant()) { - // Adaptive Re-TX - generate_retx(tti_tx, grant, action); - } else { - Warning("UL %d: Received retransmission but no previous grant available for this PID.\n", pid); - } - } else if (has_grant()) { - // Non-Adaptive Re-Tx - generate_retx(tti_tx, action); - } - if (harq_entity->pcap && grant) { - if (grant->is_from_rar && harq_entity->rntis->temp_rnti) { - grant->rnti = harq_entity->rntis->temp_rnti; - } - harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes[0], grant->rnti, get_nof_retx(), tti_tx); - } - } + uint32_t pid; + uint32_t current_tx_nb; + uint32_t current_irv; + bool harq_feedback; + bool is_grant_configured; + bool is_initiated; - uint32_t get_rv() - { - int rv_of_irv[4] = {0, 2, 3, 1}; - return rv_of_irv[current_irv%4]; - } + srslte::log* log_h; + ul_harq_entity* harq_entity; + srslte_softbuffer_tx_t softbuffer; - bool has_grant() { return is_grant_configured; } - bool get_ndi() { return cur_grant.ndi[0]; } - bool is_sps() { return false; } - uint32_t get_nof_retx() { return current_tx_nb; } - int get_current_tbs() { return cur_grant.n_bytes[0]*8; } - - private: - Tgrant cur_grant; - - uint32_t pid; - uint32_t current_tx_nb; - uint32_t current_irv; - bool harq_feedback; - srslte::log *log_h; - ul_harq_entity *harq_entity; - bool is_grant_configured; - srslte_softbuffer_tx_t softbuffer; - bool is_msg3; - bool is_initiated; - uint32_t tti_last_tx; + const static int payload_buffer_len = 128 * 1024; + uint8_t* payload_buffer; + uint8_t* pdu_ptr; - - const static int payload_buffer_len = 128*1024; - uint8_t *payload_buffer; - uint8_t *pdu_ptr; - - void generate_retx(uint32_t tti_tx, Taction *action) - { - generate_retx(tti_tx, NULL, action); - } - - // Retransmission with or w/o grant (Section 5.4.2.2) - void generate_retx(uint32_t tti_tx, Tgrant *grant, - Taction *action) - { - uint32_t max_retx; - if (is_msg3) { - max_retx = harq_entity->params->max_harq_msg3_tx; - } else { - max_retx = harq_entity->params->max_harq_tx; - } - - if (current_tx_nb >= max_retx) { - Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); - reset(); - action->expect_ack = false; - return; - } - - int irv_of_rv[4] = {0, 3, 1, 2}; - - // HARQ entity requests an adaptive transmission - if (grant) { - if (grant->rv[0]) { - current_irv = irv_of_rv[grant->rv[0]%4]; - } - - Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s, ndi=%d, prev_ndi=%d\n", - pid, current_tx_nb, get_rv(), grant->n_bytes[0], harq_feedback?"ACK":"NACK", grant->ndi[0], cur_grant.ndi[0]); - - memcpy(&cur_grant, grant, sizeof(Tgrant)); - harq_feedback = false; - - generate_tx(tti_tx, action); - - // HARQ entity requests a non-adaptive transmission - } else if (!harq_feedback) { - // Non-adaptive retx are only sent if HI=NACK. If HI=ACK but no grant was received do not reset PID - Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", - pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0], harq_feedback?"ACK":"NACK"); - - generate_tx(tti_tx, action); - } - - // On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5 - if (is_msg3) { - harq_entity->contention_timer->reset(); - } - - harq_entity->mux_unit->pusch_retx(tti_tx, pid); - } - - // New transmission (Section 5.4.2.2) - void generate_new_tx(uint32_t tti_tx, bool is_msg3_, Tgrant *grant, Taction *action) - { - if (grant) { - // Compute average number of retransmissions per packet considering previous packet - harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++); - memcpy(&cur_grant, grant, sizeof(Tgrant)); - harq_feedback = false; - is_grant_configured = true; - current_tx_nb = 0; - current_irv = 0; - is_msg3 = is_msg3_; - - Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n", - pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], - is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti); - generate_tx(tti_tx, action); - } - } - - // Transmission of pending frame (Section 5.4.2.2) - void generate_tx(uint32_t tti_tx, Taction *action) - { - action->current_tx_nb = current_tx_nb; - current_tx_nb++; - action->expect_ack = true; - action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti; - action->rv[0] = cur_grant.rv[0]>0?cur_grant.rv[0]:get_rv(); - action->softbuffers = &softbuffer; - action->tx_enabled = true; - action->payload_ptr[0] = pdu_ptr; - memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); - - current_irv = (current_irv+1)%4; - tti_last_tx = tti_tx; - } + void generate_tx(mac_interface_phy::tb_action_ul_t* action); + void generate_retx(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); + void generate_new_tx(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); }; - // Implements Section 5.4.2.1 - // Called with UL grant - void run_tti(uint32_t tti, Tgrant *grant, bool *ack, Taction* action) - { - uint32_t tti_tx = (tti+action->tti_offset)%10240; - proc[pidof(tti_tx)].run_tti(tti_tx, grant, ack, action); - } - - ul_sps ul_sps_assig; + ul_sps ul_sps_assig; - srslte::timers::timer *contention_timer; - mux *mux_unit; std::vector proc; - srslte::log *log_h; - srslte::mac_pcap *pcap; - mac_interface_rrc_common::ue_rnti_t *rntis; - mac_interface_rrc_common::ul_harq_params_t *params; - - float average_retx; - uint64_t nof_pkts; + mux* mux_unit; + srslte::mac_pcap* pcap; + srslte::log* log_h; + + mac_interface_rrc_common::ue_rnti_t* rntis; + mac_interface_rrc_common::ul_harq_cfg_t harq_cfg; + + float average_retx; + uint64_t nof_pkts; + ra_proc* ra_procedure; }; } // namespace srsue diff --git a/srsue/hdr/mac/ul_sps.h b/srsue/hdr/mac/ul_sps.h index 985b8470f..60f02ff51 100644 --- a/srsue/hdr/mac/ul_sps.h +++ b/srsue/hdr/mac/ul_sps.h @@ -43,7 +43,8 @@ public: void clear() {} void reset(uint32_t tti) {} - bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_t *grant) { return false; } + bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_ul_t* grant) { return false; } + private: }; diff --git a/srsue/hdr/phy/async_scell_recv.h b/srsue/hdr/phy/async_scell_recv.h new file mode 100644 index 000000000..3b7e97183 --- /dev/null +++ b/srsue/hdr/phy/async_scell_recv.h @@ -0,0 +1,175 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSUE_ASYNCH_SCELL_RECV_H +#define SRSUE_ASYNCH_SCELL_RECV_H + +#include + +#include "prach.h" +#include "phy_common.h" +#include "srslte/common/log.h" +#include "srslte/common/thread_pool.h" +#include "srslte/common/threads.h" +#include "srslte/common/tti_sync_cv.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/radio/radio.h" +#include "srslte/srslte.h" + +namespace srsue { + +class async_scell_recv : public thread +{ +public: + async_scell_recv(); + ~async_scell_recv(); + + void init(srslte::radio* _radio_handler, phy_common* _worker_com, srslte::log* _log_h); + void stop(); + + // from chest_feedback_itf + void in_sync(); + void out_of_sync(); + void set_cfo(float cfo); + + // From UE configuration + void set_agc_enable(bool enable); + bool set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell, uint32_t dl_earfcn); + const srslte_cell_t* get_cell() { return &cell; }; + + // Other functions + const static int MUTEX_X_WORKER = 4; + double set_rx_gain(double gain); + int radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time); + bool tti_align(uint32_t tti); + void read_sf(cf_t** dst, srslte_timestamp_t* timestamp); + +private: + class phch_scell_recv_buffer + { + private: + uint32_t tti; + srslte_timestamp_t timestamp; + cf_t* buffer[SRSLTE_MAX_PORTS]; + + public: + phch_scell_recv_buffer() + { + tti = 0; + bzero(×tamp, sizeof(timestamp)); + bzero(buffer, sizeof(buffer)); + } + + ~phch_scell_recv_buffer() + { + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + } + + void init(uint32_t nof_ports) + { + for (uint32_t i = 0; i < nof_ports; i++) { + // It needs to support cell search + buffer[i] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX * 5); + if (!buffer[i]) { + fprintf(stderr, "Error allocating buffer\n"); + } + } + } + + void set_sf(uint32_t _tti, srslte_timestamp_t* _timestamp) + { + tti = _tti; + srslte_timestamp_copy(×tamp, _timestamp); + } + + uint32_t get_tti() { return tti; } + + cf_t** get_buffer_ptr() { return buffer; } + + void get_timestamp(srslte_timestamp_t* _timestamp) { srslte_timestamp_copy(_timestamp, ×tamp); } + }; + + static const uint32_t ASYNC_NOF_BUFFERS = SRSLTE_NOF_SF_X_FRAME; + void reset(); + void radio_error(); + void set_ue_sync_opts(srslte_ue_sync_t* q, float cfo); + void run_thread(); + + void state_decode_mib(); + void state_write_buffer(); + void state_synch_idle(); + + enum receiver_state { DECODE_MIB, WRITE_BUFFER, SYNCH_IDLE } state; + static const uint32_t max_tti_align_timeout_counter = 10; + uint32_t tti_align_timeout_counter; + srslte_cell_t cell; + + bool initiated; + bool running; + + uint32_t tti; + + // Pointers to other classes + srslte::log* log_h; + srslte::radio* radio_h; + phy_common* worker_com; + + // pthread objects + pthread_mutex_t mutex_uesync; + pthread_mutex_t mutex_buffer; + pthread_cond_t cvar_buffer; + + // Object for synchronization of the primary cell + srslte_ue_sync_t ue_sync; + srslte_ue_mib_t ue_mib; + + // Buffer for secondary cell samples + phch_scell_recv_buffer buffers[ASYNC_NOF_BUFFERS]; + uint32_t buffer_write_idx; + uint32_t buffer_read_idx; + + // in-sync / out-of-sync counters + uint32_t out_of_sync_cnt; + uint32_t in_sync_cnt; + + cf_t* sf_buffer[SRSLTE_MAX_PORTS]; + + const static uint32_t NOF_OUT_OF_SYNC_SF = 200; + const static uint32_t NOF_IN_SYNC_SF = 100; + + // This is the secondary cell + bool started; + bool do_agc; + + float ul_dl_factor; + uint32_t current_earfcn[SRSLTE_MAX_PORTS]; + + float dl_freq; + float ul_freq; +}; + +} // namespace srsue + +#endif // SRSUE_ASYNCH_SCELL_RECV_H diff --git a/srsue/hdr/phy/cc_worker.h b/srsue/hdr/phy/cc_worker.h new file mode 100644 index 000000000..926c7206c --- /dev/null +++ b/srsue/hdr/phy/cc_worker.h @@ -0,0 +1,137 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSLTE_CC_WORKER_H +#define SRSLTE_CC_WORKER_H + +#include "phy_common.h" +#include "srslte/srslte.h" + +namespace srsue { + +class cc_worker +{ +public: + cc_worker(uint32_t cc_idx, uint32_t max_prb, phy_common* phy, srslte::log* log); + ~cc_worker(); + void reset(); + + bool set_cell(srslte_cell_t cell); + + /* Functions used by main PHY thread */ + cf_t* get_rx_buffer(uint32_t antenna_idx); + cf_t* get_tx_buffer(uint32_t antenna_idx); + + void set_tti(uint32_t tti); + void set_cfo(float cfo); + float get_ref_cfo(); + + void set_tdd_config(srslte_tdd_config_t config); + void set_pcell_config(phy_interface_rrc::phy_cfg_t* phy_cfg); + void set_scell_config(asn1::rrc::scell_to_add_mod_r10_s* phy_cfg); + void set_crnti(uint16_t rnti); + void enable_pregen_signals(bool enabled); + + bool work_dl_regular(); + bool work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg); + bool work_ul(srslte_uci_data_t* uci_data); + + int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); + int read_pdsch_d(cf_t* pdsch_d); + + void update_measurements(); + +private: + void dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant, + srslte_dci_dl_t* dl_dci, + mac_interface_phy::mac_grant_dl_t* mac_grant); + void ul_phy_to_mac_grant(srslte_pusch_grant_t* phy_grant, + srslte_dci_ul_t* ul_dci, + uint32_t pid, + bool ul_grant_available, + mac_interface_phy::mac_grant_ul_t* mac_grant); + void fill_dci_cfg(srslte_dci_cfg_t* cfg, bool rel10 = false); + + // Cross-carried grants scheduled from PCell + void set_dl_pending_grant(uint32_t cc_idx, srslte_dci_dl_t* dl_dci); + bool get_dl_pending_grant(uint32_t cc_idx, srslte_dci_dl_t* dl_dci); + typedef struct { + bool enable; + srslte_dci_dl_t dl_dci; + } pending_dl_grant_t; + pending_dl_grant_t pending_dl_grant[SRSLTE_MAX_CARRIERS]; // Only for the current TTI + + /* Methods for DL... */ + int decode_pdcch_ul(); + int decode_pdcch_dl(); + + void decode_phich(); + int decode_pdsch(srslte_pdsch_ack_resource_t ack_resource, + mac_interface_phy::tb_action_dl_t* action, + bool acks[SRSLTE_MAX_CODEWORDS]); + int decode_pmch(mac_interface_phy::tb_action_dl_t* action, srslte_mbsfn_cfg_t* mbsfn_cfg); + + /* Methods for UL */ + bool encode_uplink(mac_interface_phy::tb_action_ul_t* action, srslte_uci_data_t* uci_data); + void set_uci_sr(srslte_uci_data_t* uci_data); + void set_uci_periodic_cqi(srslte_uci_data_t* uci_data); + void set_uci_aperiodic_cqi(srslte_uci_data_t* uci_data); + void set_uci_ack(srslte_uci_data_t* uci_data, bool is_grant_available, uint32_t dai_ul, bool is_pusch_available); + float set_power(float tx_power); + uint32_t get_wideband_cqi(); + srslte_cqi_report_mode_t aperiodic_mode(asn1::rrc::cqi_report_mode_aperiodic_e mode); + void parse_antenna_info(asn1::rrc::phys_cfg_ded_s* dedicated); + void parse_pucch_config(phy_interface_rrc::phy_cfg_t* phy_cfg); + + /* Common objects */ + phy_common* phy; + srslte::log* log_h; + + srslte_cell_t cell; + srslte_dl_sf_cfg_t sf_cfg_dl; + srslte_ul_sf_cfg_t sf_cfg_ul; + + uint32_t cc_idx; + bool pregen_enabled; + bool cell_initiated; + cf_t* signal_buffer_rx[SRSLTE_MAX_PORTS]; + cf_t* signal_buffer_tx[SRSLTE_MAX_PORTS]; + + /* Objects for DL */ + srslte_ue_dl_t ue_dl; + srslte_ue_dl_cfg_t ue_dl_cfg; + srslte_pmch_cfg_t pmch_cfg; + + srslte_chest_dl_cfg_t chest_mbsfn_cfg; + srslte_chest_dl_cfg_t chest_default_cfg; + + /* Objects for UL */ + srslte_ue_ul_t ue_ul; + srslte_ue_ul_cfg_t ue_ul_cfg; + + // Metrics + dl_metrics_t dl_metrics; + ul_metrics_t ul_metrics; +}; + +} // namespace srsue + +#endif // SRSLTE_CC_WORKER_H diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h deleted file mode 100644 index 60923adfb..000000000 --- a/srsue/hdr/phy/phch_common.h +++ /dev/null @@ -1,239 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef SRSUE_PHCH_COMMON_H -#define SRSUE_PHCH_COMMON_H - -#define TX_MODE_CONTINUOUS 1 - - -#include -#include -#include -#include -#include "srslte/srslte.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srslte/radio/radio.h" -#include "srslte/common/log.h" -#include "srslte/common/gen_mch_tables.h" -#include "phy_metrics.h" - - -namespace srsue { - -class chest_feedback_itf -{ -public: - virtual void in_sync() = 0; - virtual void out_of_sync() = 0; - virtual void set_cfo(float cfo) = 0; -}; - - -typedef enum{ - SUBFRAME_TYPE_REGULAR = 0, - SUBFRAME_TYPE_MBSFN, - SUBFRAME_TYPE_N_ITEMS, -} subframe_type_t; -static const char subframe_type_text[SUBFRAME_TYPE_N_ITEMS][20] = {"Regular", "MBSFN"}; - -/* Subframe config */ - -typedef struct { - subframe_type_t sf_type; - uint8_t mbsfn_area_id; - uint8_t non_mbsfn_region_length; - uint8_t mbsfn_mcs; - bool mbsfn_decode; - bool is_mcch; -} subframe_cfg_t; - - -/* Subclass that manages variables common to all workers */ - class phch_common { - public: - - /* Common variables used by all phy workers */ - phy_interface_rrc::phy_cfg_t *config; - phy_args_t *args; - rrc_interface_phy *rrc; - mac_interface_phy *mac; - srslte_ue_ul_t ue_ul; - - /* Power control variables */ - float pathloss; - float cur_pathloss; - float p0_preamble; - float cur_radio_power; - float cur_pusch_power; - float avg_rsrp; - float avg_rsrp_cqi; - float avg_rsrp_dbm; - float avg_rsrp_sync_dbm; - float avg_rsrq_db; - float avg_rssi_dbm; - float last_radio_rssi; - float rx_gain_offset; - float avg_snr_db_cqi; - float avg_snr_db_sync; - float avg_ri; - - float avg_noise; - bool pcell_meas_enabled; - - uint32_t pcell_report_period; - bool pcell_first_measurement; - - // Save last TBS for mcs>28 cases - int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; - uint32_t last_dl_tti[2*HARQ_DELAY_MS]; - - int last_ul_tbs[2*HARQ_DELAY_MS]; - uint32_t last_ul_tti[2*HARQ_DELAY_MS]; - srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; - uint32_t last_ul_idx[2*HARQ_DELAY_MS]; - uint8_t last_ri; - uint8_t last_pmi; - - phch_common(uint32_t max_workers); - ~phch_common(); - void init(phy_interface_rrc::phy_cfg_t *config, - phy_args_t *args, - srslte::log *_log, - srslte::radio *_radio, - rrc_interface_phy *rrc, - mac_interface_phy *_mac); - - /* 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 = NULL); - - 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); - bool is_any_pending_ack(); - - void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - - void set_nof_workers(uint32_t nof_workers); - bool sr_enabled; - int sr_last_tx_tti; - - - srslte::radio* get_radio(); - - void set_cell(const srslte_cell_t &c); - uint32_t get_nof_prb(); - void set_dl_metrics(const dl_metrics_t &m); - void get_dl_metrics(dl_metrics_t &m); - void set_ul_metrics(const ul_metrics_t &m); - void get_ul_metrics(ul_metrics_t &m); - void set_sync_metrics(const sync_metrics_t &m); - void get_sync_metrics(sync_metrics_t &m); - - void reset_ul(); - void reset(); - - // MBSFN helpers - void build_mch_table(); - void build_mcch_table(); - void set_mcch(); - void get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti); - void set_mch_period_stop(uint32_t stop); - - private: - - bool have_mtch_stop; - pthread_mutex_t mtch_mutex; - pthread_cond_t mtch_cvar; - - - - std::vector tx_sem; - uint32_t nof_workers; - uint32_t max_workers; - - bool is_first_of_burst; - srslte::radio *radio_h; - float cfo; - srslte::log *log_h; - - - 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[TTIMOD_SZ]; - - bool is_first_tx; - - srslte_cell_t cell; - - dl_metrics_t dl_metrics; - uint32_t dl_metrics_count; - bool dl_metrics_read; - ul_metrics_t ul_metrics; - uint32_t ul_metrics_count; - bool ul_metrics_read; - sync_metrics_t sync_metrics; - uint32_t sync_metrics_count; - bool sync_metrics_read; - - // MBSFN - bool sib13_configured; - bool mcch_configured; - uint32_t mch_period_stop; - uint8_t mch_table[40]; - uint8_t mcch_table[10]; - - bool is_mch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti); - bool is_mcch_subframe(subframe_cfg_t *cfg, uint32_t phy_tti); - }; -} // namespace srsue - -#endif // SRSUE_PDCH_COMMON_H diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h deleted file mode 100644 index 085c9d1ce..000000000 --- a/srsue/hdr/phy/phch_worker.h +++ /dev/null @@ -1,200 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef SRSUE_PHCH_WORKER_H -#define SRSUE_PHCH_WORKER_H - -#include -#include "srslte/srslte.h" -#include "srslte/common/thread_pool.h" -#include "srslte/common/trace.h" -#include "phch_common.h" - -#define LOG_EXECTIME - -namespace srsue { - -class phch_worker : public srslte::thread_pool::worker -{ -public: - - phch_worker(); - ~phch_worker(); - void reset(); - void set_common(phch_common *phy); - void enable_pdsch_coworker(); - bool init(uint32_t max_prb, srslte::log *log, srslte::log *log_phy_lib_h, chest_feedback_itf *chest_loop); - - bool set_cell(srslte_cell_t cell); - - /* Functions used by main PHY thread */ - cf_t* get_buffer(uint32_t antenna_idx); - void set_tti(uint32_t tti, uint32_t tx_worker_cnt); - void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); - void set_prach(cf_t *prach_ptr, float prach_power); - void set_cfo(float cfo); - - void set_ul_params(bool pregen_disabled = false); - void set_crnti(uint16_t rnti); - void enable_pregen_signals(bool enabled); - - void start_trace(); - void write_trace(std::string filename); - - int read_ce_abs(float *ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); - uint32_t get_cell_nof_ports() { - if (cell_initiated) { - return cell.nof_ports; - } else { - return 1; - } - }; - uint32_t get_rx_nof_antennas() { - return ue_dl.nof_rx_antennas; - }; - int read_pdsch_d(cf_t *pdsch_d); - void start_plot(); - - float get_ref_cfo(); - float get_snr(); - float get_rsrp(); - float get_noise(); - float get_cfo(); - -private: - /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ - void work_imp(); - - - /* Internal methods */ - - void compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr); - bool extract_fft_and_pdcch_llr(subframe_cfg_t sf_cfg); - - /* ... 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); - - int decode_pdsch(srslte_ra_dl_grant_t *grant, - uint8_t *payload[SRSLTE_MAX_CODEWORDS], - srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS], - int rv[SRSLTE_MAX_CODEWORDS], - uint16_t rnti, - uint32_t pid, - bool acks[SRSLTE_MAX_CODEWORDS]); - - bool decode_pmch(srslte_ra_dl_grant_t *grant, - uint8_t *payload, - srslte_softbuffer_rx_t* softbuffer, - uint16_t mbsfn_area_id); - - /* ... for UL */ - void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, - uint32_t rv, uint16_t rnti, bool is_from_rar); - void encode_pucch(); - void encode_srs(); - void reset_uci(); - void set_uci_sr(); - void set_uci_periodic_cqi(); - void set_uci_aperiodic_cqi(); - void set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]); - bool srs_is_ready_to_send(); - float set_power(float tx_power); - void setup_tx_gain(); - - void update_measurements(); - - void tr_log_start(); - void tr_log_end(); - struct timeval tr_time[3]; - srslte::trace tr_exec; - bool trace_enabled; - - pthread_mutex_t mutex; - - /* Common objects */ - phch_common *phy; - srslte::log *log_h; - srslte::log *log_phy_lib_h; - chest_feedback_itf *chest_loop; - srslte_cell_t cell; - bool mem_initiated; - bool cell_initiated; - cf_t *signal_buffer[SRSLTE_MAX_PORTS]; - uint32_t tti; - uint32_t tx_tti; - bool pregen_enabled; - uint32_t last_dl_pdcch_ncce; - bool rnti_is_set; - - uint32_t next_offset; - - /* 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; - srslte_cqi_value_t cqi_report; - uint16_t ul_rnti; - - // 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_periodic_cfg_t period_cqi; - srslte_ue_ul_powerctrl_t power_ctrl; - uint32_t I_sr; - bool sr_configured; - float cfo; - bool rar_cqi_request; - cf_t *prach_ptr; - float prach_power; - - uint32_t rssi_read_cnt; - - // Metrics - dl_metrics_t dl_metrics; - ul_metrics_t ul_metrics; - -#ifdef LOG_EXECTIME - struct timeval logtime_start[3]; - bool chest_done; -#endif - -}; - -} // namespace srsue - -#endif // SRSUE_PHCH_WORKER_H - diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 72ba883d8..4e859b860 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -27,17 +27,18 @@ #ifndef SRSUE_PHY_H #define SRSUE_PHY_H -#include "srslte/srslte.h" -#include "srslte/common/log_filter.h" +#include "async_scell_recv.h" +#include "phy_common.h" #include "phy_metrics.h" -#include "phch_recv.h" #include "prach.h" -#include "phch_worker.h" -#include "phch_common.h" -#include "srslte/radio/radio.h" +#include "sf_worker.h" +#include "srslte/common/log_filter.h" #include "srslte/common/task_dispatcher.h" #include "srslte/common/trace.h" #include "srslte/interfaces/ue_interfaces.h" +#include "srslte/radio/radio.h" +#include "srslte/srslte.h" +#include "sync.h" namespace srsue { @@ -50,12 +51,12 @@ class phy { public: phy(); - bool init(srslte::radio_multi *radio_handler, - mac_interface_phy *mac, - rrc_interface_phy *rrc, + bool init(srslte::radio* radio_handler, + mac_interface_phy* mac, + rrc_interface_phy* rrc, std::vector log_vec, - phy_args_t *args = NULL); - + phy_args_t* args = NULL); + void stop(); void wait_initialize(); @@ -65,15 +66,8 @@ public: void get_metrics(phy_metrics_t &m); void srslte_phy_logger(phy_logger_level_t log_level, char *str); - - - static uint32_t tti_to_SFN(uint32_t tti); - static uint32_t tti_to_subf(uint32_t tti); void enable_pregen_signals(bool enable); - - void start_trace(); - void write_trace(std::string filename); void set_earfcn(std::vector earfcns); void force_freq(float dl_freq, float ul_freq); @@ -82,7 +76,6 @@ public: /********** RRC INTERFACE ********************/ void reset(); - void configure_ul_params(bool pregen_disabled = false); cell_search_ret_t cell_search(phy_cell_t *cell); bool cell_select(phy_cell_t *cell); @@ -101,9 +94,9 @@ public: void configure_prach_params(); /* Transmits PRACH in the next opportunity */ - void prach_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = 0.0); - int prach_tx_tti(); - + void prach_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = 0.0); + prach_info_t prach_get_info(); + /* Indicates the transmission of a SR signal in the next opportunity */ void sr_send(); int sr_last_tx_tti(); @@ -111,23 +104,17 @@ public: // Time advance commands void set_timeadv_rar(uint32_t ta_cmd); void set_timeadv(uint32_t ta_cmd); - - /* Sets RAR grant payload */ - void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); - - /* Instruct the PHY to decode PDCCH with the CRC scrambled with given RNTI */ - void pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1); - void pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start = -1, int tti_end = -1); - void pdcch_ul_search_reset(); - void pdcch_dl_search_reset(); - + + /* Activate / Disactivate SCell*/ + void set_activation_deactivation_scell(uint32_t ta_cmd); + + /* Sets RAR dci payload */ + void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti); + /* Get/Set PHY parameters interface from RRC */ - void get_config(phy_cfg_t *phy_cfg); void set_config(phy_cfg_t *phy_cfg); - void set_config_dedicated(asn1::rrc::phys_cfg_ded_s* dedicated); - void set_config_common(phy_cfg_common_t *common); + void set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config); void set_config_tdd(asn1::rrc::tdd_cfg_s* tdd); - void set_config_64qam_en(bool enable); void set_config_mbsfn_sib2(asn1::rrc::sib_type2_s* sib2); void set_config_mbsfn_sib13(asn1::rrc::sib_type13_r9_s* sib13); void set_config_mbsfn_mcch(asn1::rrc::mcch_msg_s* mcch); @@ -146,40 +133,40 @@ public: uint32_t get_current_pci(); void start_plot(); - -private: + const static int MAX_WORKERS = 4; + const static int DEFAULT_WORKERS = 4; + +private: void run_thread(); bool initiated; - uint32_t nof_workers; - uint32_t nof_coworkers; + uint32_t nof_workers; - const static int MAX_WORKERS = 3; - const static int DEFAULT_WORKERS = 2; - const static int SF_RECV_THREAD_PRIO = 1; - const static int WORKERS_THREAD_PRIO = 2; - - srslte::radio_multi *radio_handler; + const static int WORKERS_THREAD_PRIO = 2; + + srslte::radio* radio_handler; std::vector log_vec; - srslte::log *log_h; + srslte::log* log_h; srslte::log *log_phy_lib_h; srsue::mac_interface_phy *mac; srsue::rrc_interface_phy *rrc; - srslte::thread_pool workers_pool; - std::vector workers; - phch_common workers_common; - phch_recv sf_recv; - prach prach_buffer; - - srslte_cell_t cell; - - phy_cfg_t config; - phy_args_t *args; - phy_args_t default_args; - + srslte::thread_pool workers_pool; + std::vector workers; + phy_common common; + sync sfsync; + async_scell_recv scell_sync[SRSLTE_MAX_RADIOS - 1]; + uint32_t scell_earfcn[SRSLTE_MAX_CARRIERS - 1]; + prach prach_buffer; + + srslte_prach_cfg_t prach_cfg; + srslte_tdd_config_t tdd_config; + + phy_args_t* args; + phy_args_t default_args; + /* Current time advance */ uint32_t n_ta; diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h new file mode 100644 index 000000000..78f82f48c --- /dev/null +++ b/srsue/hdr/phy/phy_common.h @@ -0,0 +1,246 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSUE_PHCH_COMMON_H +#define SRSUE_PHCH_COMMON_H + +#define TX_MODE_CONTINUOUS 1 + +#include "phy_metrics.h" +#include "srslte/common/gen_mch_tables.h" +#include "srslte/common/log.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srslte/radio/radio_multi.h" +#include "srslte/srslte.h" +#include +#include +#include +#include + +namespace srsue { + +class chest_feedback_itf +{ +public: + virtual void in_sync() = 0; + + virtual void out_of_sync() = 0; + + virtual void set_cfo(float cfo) = 0; +}; + +/* Subclass that manages variables common to all workers */ +class phy_common +{ +public: + /* Common variables used by all phy workers */ + phy_args_t* args; + rrc_interface_phy* rrc; + mac_interface_phy* mac; + + phy_interface_rrc::phy_cfg_mbsfn_t mbsfn_config; + + /* Power control variables */ + float pathloss[SRSLTE_MAX_CARRIERS]; + float cur_pathloss; + float p0_preamble; + float cur_radio_power; + float cur_pusch_power; + float avg_rsrp[SRSLTE_MAX_CARRIERS]; + float avg_rsrp_dbm[SRSLTE_MAX_CARRIERS]; + float avg_rsrq_db; + float avg_rssi_dbm; + float last_radio_rssi; + float rx_gain_offset; + float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS]; + float avg_snr_db_sync; + + float avg_noise[SRSLTE_MAX_CARRIERS]; + bool pcell_meas_enabled; + + uint32_t pcell_report_period; + bool pcell_first_measurement; + + /* SCell enable for Activation / Deactivation */ + bool scell_configured[SRSLTE_MAX_CARRIERS]; + bool scell_enable[SRSLTE_MAX_CARRIERS]; /* Entry index 0 is reserved, do NOT use it for PCell */ + bool multiple_csi_request_enabled; /* True means cross scheduling enabled */ + bool cif_enabled; /* True means cross scheduling enabled */ + bool srs_request_enabled; + + // Save last TBS for uplink (mcs >= 28) + srslte_ra_tb_t last_ul_tb[SRSLTE_MAX_HARQ_PROC][SRSLTE_MAX_CARRIERS]; + + // Save last TBS for DL (Format1C) + int last_dl_tbs[SRSLTE_MAX_HARQ_PROC][SRSLTE_MAX_CARRIERS][SRSLTE_MAX_CODEWORDS]; + + phy_common(uint32_t max_workers); + + ~phy_common(); + + void + init(phy_args_t* args, srslte::log* _log, srslte::radio* _radio, rrc_interface_phy* rrc, mac_interface_phy* _mac); + + uint32_t ul_pidof(uint32_t tti, srslte_tdd_config_t* tdd_config); + + // Set configurations for lib objects + void set_ue_dl_cfg(srslte_ue_dl_cfg_t* ue_dl_cfg); + void set_ue_ul_cfg(srslte_ue_ul_cfg_t* ue_ul_cfg); + void set_pdsch_cfg(srslte_pdsch_cfg_t* pdsch_cfg); + + void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti, srslte_tdd_config_t tdd_config); + + void set_ul_pending_ack(srslte_ul_sf_cfg_t* sf, + uint32_t cc_idx, + srslte_phich_grant_t phich_grant, + srslte_dci_ul_t* dci_ul); + bool get_ul_pending_ack(srslte_dl_sf_cfg_t* sf, + uint32_t cc_idx, + srslte_phich_grant_t* phich_grant, + srslte_dci_ul_t* dci_ul); + bool is_any_ul_pending_ack(); + + bool get_ul_received_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, bool* ack_value, srslte_dci_ul_t* dci_ul); + void set_ul_received_ack( + srslte_dl_sf_cfg_t* sf, uint32_t cc_idx, bool ack_value, uint32_t I_phich, srslte_dci_ul_t* dci_ul); + + void set_ul_pending_grant(srslte_dl_sf_cfg_t* sf, uint32_t cc_idx, srslte_dci_ul_t* dci); + bool get_ul_pending_grant(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, uint32_t* pid, srslte_dci_ul_t* dci); + + void set_rar_grant_tti(uint32_t tti); + + void set_dl_pending_ack(srslte_dl_sf_cfg_t* sf, + uint32_t cc_idx, + uint8_t value[SRSLTE_MAX_CODEWORDS], + srslte_pdsch_ack_resource_t resource); + bool get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srslte_pdsch_ack_cc_t* ack); + + void worker_end(uint32_t tti, + bool tx_enable, + cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], + uint32_t nof_samples[SRSLTE_MAX_RADIOS], + srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS]); + + void set_nof_workers(uint32_t nof_workers); + + bool sr_enabled; + int sr_last_tx_tti; + + srslte::radio* get_radio(); + + void set_cell(const srslte_cell_t& c); + uint32_t get_nof_prb(); + + void set_dl_metrics(const dl_metrics_t m, uint32_t cc_idx); + void get_dl_metrics(dl_metrics_t m[SRSLTE_MAX_CARRIERS]); + void set_ul_metrics(const ul_metrics_t m, uint32_t cc_idx); + void get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS]); + void set_sync_metrics(const sync_metrics_t& m); + void get_sync_metrics(sync_metrics_t& m); + + void reset(); + + /* SCell Management */ + void enable_scell(uint32_t cc_idx, bool enable); + + void build_mch_table(); + void build_mcch_table(); + void set_mcch(); + bool is_mbsfn_sf(srslte_mbsfn_cfg_t* cfg, uint32_t tti); + void set_mch_period_stop(uint32_t stop); + +private: + bool have_mtch_stop; + pthread_mutex_t mtch_mutex; + pthread_cond_t mtch_cvar; + + std::vector tx_sem; + uint32_t nof_workers; + uint32_t max_workers; + + bool is_first_of_burst[SRSLTE_MAX_RADIOS]; + srslte::radio* radio_h; + float cfo; + srslte::log* log_h; + + int rar_grant_tti; + + typedef struct { + bool enable; + srslte_phich_grant_t phich_grant; + srslte_dci_ul_t dci_ul; + } pending_ul_ack_t; + pending_ul_ack_t pending_ul_ack[TTIMOD_SZ][SRSLTE_MAX_CARRIERS][2]; + pthread_mutex_t pending_ul_ack_mutex; + + typedef struct { + bool hi_value; + bool hi_present; + srslte_dci_ul_t dci_ul; + } received_ul_ack_t; + received_ul_ack_t received_ul_ack[TTIMOD_SZ][SRSLTE_MAX_CARRIERS]; + pthread_mutex_t received_ul_ack_mutex; + + typedef struct { + bool enable; + uint32_t pid; + srslte_dci_ul_t dci; + } pending_ul_grant_t; + pending_ul_grant_t pending_ul_grant[TTIMOD_SZ][SRSLTE_MAX_CARRIERS]; + pthread_mutex_t pending_ul_grant_mutex; + + typedef struct { + bool enable; + uint8_t value[SRSLTE_MAX_CODEWORDS]; // 0/1 or 2 for DTX + srslte_pdsch_ack_resource_t resource; + } received_ack_t; + received_ack_t pending_dl_ack[TTIMOD_SZ][SRSLTE_MAX_CARRIERS]; + uint32_t pending_dl_dai[TTIMOD_SZ][SRSLTE_MAX_CARRIERS]; + pthread_mutex_t pending_dl_ack_mutex; + + bool is_first_tx; + + srslte_cell_t cell; + + dl_metrics_t dl_metrics[SRSLTE_MAX_CARRIERS]; + uint32_t dl_metrics_count; + bool dl_metrics_read; + ul_metrics_t ul_metrics[SRSLTE_MAX_CARRIERS]; + uint32_t ul_metrics_count; + bool ul_metrics_read; + sync_metrics_t sync_metrics; + uint32_t sync_metrics_count; + bool sync_metrics_read; + + // MBSFN + bool sib13_configured; + bool mcch_configured; + uint32_t mch_period_stop; + uint8_t mch_table[40]; + uint8_t mcch_table[10]; + + bool is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); + + bool is_mcch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); +}; +} // namespace srsue + +#endif // SRSUE_PDCH_COMMON_H diff --git a/srsue/hdr/phy/phy_metrics.h b/srsue/hdr/phy/phy_metrics.h index 0b3aa9da6..0ef09fe95 100644 --- a/srsue/hdr/phy/phy_metrics.h +++ b/srsue/hdr/phy/phy_metrics.h @@ -27,6 +27,7 @@ #ifndef SRSUE_PHY_METRICS_H #define SRSUE_PHY_METRICS_H +#include "srslte/phy/common/phy_common.h" namespace srsue { @@ -48,21 +49,20 @@ struct dl_metrics_t float turbo_iters; float mcs; float pathloss; - float mabr_mbps; }; struct ul_metrics_t { float mcs; float power; - float mabr_mbps; }; struct phy_metrics_t { sync_metrics_t sync; - dl_metrics_t dl; - ul_metrics_t ul; + dl_metrics_t dl[SRSLTE_MAX_CARRIERS]; + ul_metrics_t ul[SRSLTE_MAX_CARRIERS]; + uint32_t nof_active_cc; }; } // namespace srsue diff --git a/srsue/hdr/phy/prach.h b/srsue/hdr/phy/prach.h index 51dc7fc56..d024eb1e5 100644 --- a/srsue/hdr/phy/prach.h +++ b/srsue/hdr/phy/prach.h @@ -42,39 +42,35 @@ namespace srsue { bzero(&prach_obj, sizeof(srslte_prach_t)); bzero(&cell, sizeof(srslte_cell_t)); bzero(&cfo_h, sizeof(srslte_cfo_t)); - - args = NULL; - config = NULL; - transmitted_tti = 0; + + transmitted_tti = 0; target_power_dbm = 0; mem_initiated = false; cell_initiated = false; signal_buffer = NULL; } ~prach(); - void init(asn1::rrc::prach_cfg_sib_s* config, uint32_t max_prb, phy_args_t* args, srslte::log* log_h); - bool set_cell(srslte_cell_t cell); + void init(uint32_t max_prb, srslte::log* log_h); + void stop(); + bool set_cell(srslte_cell_t cell, srslte_prach_cfg_t prach_cfg); bool prepare_to_send(uint32_t preamble_idx, int allowed_subframe = -1, float target_power_dbm = -1); bool is_ready_to_send(uint32_t current_tti); bool is_pending(); - int tx_tti(); cf_t* generate(float cfo, uint32_t *nof_sf, float *target_power = NULL); - private: + phy_interface_mac::prach_info_t get_info(); + private: const static int MAX_LEN_SF = 3; - asn1::rrc::prach_cfg_sib_s* config; - phy_args_t* args; - srslte::log *log_h; int preamble_idx; int allowed_subframe; bool mem_initiated; bool cell_initiated; - uint32_t len; - cf_t *buffer[64]; - srslte_prach_t prach_obj; + uint32_t len; + cf_t* buffer[12][64]; + srslte_prach_t prach_obj; int transmitted_tti; srslte_cell_t cell; cf_t *signal_buffer; diff --git a/srsue/hdr/phy/sf_worker.h b/srsue/hdr/phy/sf_worker.h new file mode 100644 index 000000000..7d4b6d61a --- /dev/null +++ b/srsue/hdr/phy/sf_worker.h @@ -0,0 +1,112 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#ifndef SRSUE_PHCH_WORKER_H +#define SRSUE_PHCH_WORKER_H + +#include "cc_worker.h" +#include "phy_common.h" +#include "srslte/common/thread_pool.h" +#include "srslte/srslte.h" +#include + +namespace srsue { + +/** + * The sf_worker class handles the PHY processing, UL and DL procedures associated with 1 subframe. + * It contains multiple cc_worker objects, one for each component carrier which may be executed in + * one or multiple threads. + * + * A sf_worker object is executed by a thread within the thread_pool. + */ + +class sf_worker : public srslte::thread_pool::worker +{ +public: + sf_worker( + uint32_t max_prb, phy_common* phy, srslte::log* log, srslte::log* log_phy_lib_h, chest_feedback_itf* chest_loop); + virtual ~sf_worker(); + void reset(); + + bool set_cell(uint32_t cc_idx, srslte_cell_t cell); + + /* Functions used by main PHY thread */ + cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx); + void set_tti(uint32_t tti, uint32_t tx_worker_cnt); + void set_tx_time(uint32_t radio_idx, srslte_timestamp_t tx_time, int next_offset); + void set_prach(cf_t* prach_ptr, float prach_power); + void set_cfo(float cfo); + + void set_tdd_config(srslte_tdd_config_t config); + void set_pcell_config(phy_interface_rrc::phy_cfg_t* phy_cfg); + void set_scell_config(uint32_t cc_idx, asn1::rrc::scell_to_add_mod_r10_s* scell_config); + void set_crnti(uint16_t rnti); + void enable_pregen_signals(bool enabled); + + int read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna); + uint32_t get_cell_nof_ports() + { + if (cell_initiated) { + return cell.nof_ports; + } else { + return 1; + } + } + uint32_t get_rx_nof_antennas() { return phy->args->nof_rx_ant; } + int read_pdsch_d(cf_t* pdsch_d); + void start_plot(); + +private: + /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ + void work_imp(); + void reset_(); + + void update_measurements(); + void reset_uci(srslte_uci_data_t* uci_data); + + std::vector cc_workers; + + phy_common* phy; + srslte::log* log_h; + srslte::log* log_phy_lib_h; + chest_feedback_itf* chest_loop; + + pthread_mutex_t mutex; + + srslte_cell_t cell; + srslte_tdd_config_t tdd_config; + + bool cell_initiated; + + cf_t* prach_ptr; + float prach_power; + + uint32_t tti; + srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS]; + uint32_t tx_sem_id; + int next_offset[SRSLTE_MAX_RADIOS]; + + uint32_t rssi_read_cnt; +}; + +} // namespace srsue + +#endif // SRSUE_PHCH_WORKER_H diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/sync.h similarity index 79% rename from srsue/hdr/phy/phch_recv.h rename to srsue/hdr/phy/sync.h index e9f1bef5a..23fb6291b 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/sync.h @@ -1,19 +1,14 @@ -/** +/* + * Copyright 2013-2019 Software Radio Systems Limited * - * \section COPYRIGHT + * This file is part of srsLTE. * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify + * 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. * - * srsUE is distributed in the hope that it will be useful, + * 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. @@ -30,31 +25,39 @@ #include #include -#include "srslte/srslte.h" +#include "async_scell_recv.h" +#include "phy_common.h" +#include "prach.h" +#include "sf_worker.h" #include "srslte/common/log.h" -#include "srslte/common/threads.h" #include "srslte/common/thread_pool.h" +#include "srslte/common/threads.h" #include "srslte/common/tti_sync_cv.h" -#include "srslte/radio/radio_multi.h" -#include "prach.h" -#include "phch_worker.h" -#include "phch_common.h" #include "srslte/interfaces/ue_interfaces.h" +#include "srslte/radio/radio_multi.h" +#include "srslte/srslte.h" namespace srsue { typedef _Complex float cf_t; - -class phch_recv : public thread, public chest_feedback_itf +class sync : public thread, public chest_feedback_itf { public: - phch_recv(); - ~phch_recv(); - - void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc, - prach *prach_buffer, srslte::thread_pool *_workers_pool, - phch_common *_worker_com, srslte::log* _log_h, srslte::log *_log_phy_lib_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1); + sync(); + ~sync(); + + void init(srslte::radio* radio_handler, + mac_interface_phy* mac, + rrc_interface_phy* rrc, + prach* prach_buffer, + srslte::thread_pool* _workers_pool, + phy_common* _worker_com, + srslte::log* _log_h, + srslte::log* _log_phy_lib_h, + async_scell_recv* scell_sync_, + uint32_t prio, + int sync_cpu_affinity = -1); void stop(); void radio_overflow(); @@ -85,7 +88,6 @@ public: // Other functions double set_rx_gain(double gain); int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); - int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time); private: @@ -95,15 +97,15 @@ private: typedef enum {CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT} ret_code; ~search(); - void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); + void init(cf_t* buffer[SRSLTE_MAX_PORTS], srslte::log* log_h, uint32_t nof_rx_antennas, sync* parent); void reset(); float get_last_cfo(); void set_agc_enable(bool enable); ret_code run(srslte_cell_t *cell); private: - phch_recv *p; - srslte::log *log_h; + sync* p; + srslte::log* log_h; cf_t *buffer[SRSLTE_MAX_PORTS]; srslte_ue_cellsearch_t cs; srslte_ue_mib_sync_t ue_mib_sync; @@ -116,10 +118,15 @@ private: typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR} ret_code; ~sfn_sync(); - void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES); + void init(srslte_ue_sync_t* ue_sync, + cf_t* buffer[SRSLTE_MAX_PORTS], + srslte::log* log_h, + uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES); void reset(); bool set_cell(srslte_cell_t cell); ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false); + ret_code + decode_mib(srslte_cell_t* cell, uint32_t* tti_cnt, cf_t* ext_buffer[SRSLTE_MAX_PORTS], bool sfidx_only = false); private: const static int SFN_SYNC_NOF_SUBFRAMES = 100; @@ -141,12 +148,14 @@ private: typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; ~measure(); - void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, - uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); + void init(cf_t* buffer[SRSLTE_MAX_PORTS], + srslte::log* log_h, + uint32_t nof_rx_antennas, + phy_common* worker_com, + uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); void reset(); void set_cell(srslte_cell_t cell); ret_code run_subframe(uint32_t sf_idx); - ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); float rssi(); float rsrp(); @@ -155,8 +164,9 @@ private: uint32_t frame_st_idx(); void set_rx_gain_offset(float rx_gain_offset); private: - srslte::log *log_h; + srslte::log* log_h; srslte_ue_dl_t ue_dl; + srslte_ue_dl_cfg_t ue_dl_cfg; cf_t *buffer[SRSLTE_MAX_PORTS]; uint32_t cnt; uint32_t nof_subframes; @@ -177,7 +187,7 @@ private: float rsrq; uint32_t offset; } cell_info_t; - void init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window); + void init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com); void deinit(); void reset(); int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); @@ -201,7 +211,7 @@ private: public: intra_measure(); ~intra_measure(); - void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h); + void init(phy_common* common, rrc_interface_phy* rrc, srslte::log* log_h); void stop(); void add_cell(int pci); void rem_cell(int pci); @@ -214,9 +224,9 @@ private: const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5; scell_recv scell; - rrc_interface_phy *rrc; + rrc_interface_phy* rrc; srslte::log *log_h; - phch_common *common; + phy_common* common; uint32_t current_earfcn; uint32_t current_sflen; srslte_cell_t primary_cell; @@ -251,9 +261,6 @@ private: bool set_frequency(); bool set_cell(); - uint32_t new_earfcn; - srslte_cell_t new_cell; - bool radio_is_overflow; bool radio_overflow_return; bool running; @@ -265,23 +272,23 @@ private: uint32_t current_sflen; int next_offset; - uint32_t nof_rx_antennas; // Pointers to other classes mac_interface_phy *mac; rrc_interface_phy *rrc; srslte::log *log_h; - srslte::log *log_phy_lib_h; - srslte::thread_pool *workers_pool; - srslte::radio_multi *radio_h; - phch_common *worker_com; + srslte::log* log_phy_lib_h; + srslte::thread_pool* workers_pool; + srslte::radio* radio_h; + phy_common* worker_com; prach *prach_buffer; + async_scell_recv* scell_sync; // Object for synchronization of the primary cell - srslte_ue_sync_t ue_sync; + srslte_ue_sync_t ue_sync; - // Buffer for primary cell samples - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; + // Buffer for primary and secondary cell samples + cf_t* sf_buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS]; // Sync metrics sync_metrics_t metrics; @@ -310,8 +317,8 @@ private: pthread_mutex_lock(&inside); cur_state = next_state; if (state_setting) { - state_setting = false; - state_changing = true; + state_setting = false; + state_running = true; } pthread_cond_broadcast(&cvar); pthread_mutex_unlock(&inside); @@ -326,7 +333,7 @@ private: } else { next_state = IDLE; } - state_changing = false; + state_running = false; pthread_cond_broadcast(&cvar); pthread_mutex_unlock(&inside); } @@ -349,13 +356,15 @@ private: void run_cell_search() { pthread_mutex_lock(&outside); go_state(CELL_SEARCH); - wait_state_change(CELL_SEARCH); + wait_state_run(); + wait_state_next(); pthread_mutex_unlock(&outside); } void run_sfn_sync() { pthread_mutex_lock(&outside); go_state(SFN_SYNC); - wait_state_change(SFN_SYNC); + wait_state_run(); + wait_state_next(); pthread_mutex_unlock(&outside); } @@ -388,9 +397,9 @@ private: pthread_mutex_init(&outside, NULL); pthread_cond_init(&cvar, NULL); cur_state = IDLE; - next_state = IDLE; + next_state = IDLE; state_setting = false; - state_changing = false; + state_running = false; } private: @@ -405,15 +414,24 @@ private: } /* Waits until there is a call to set_state() and then run_state(). Returns when run_state() returns */ - void wait_state_change(state_t prev_state) { + void wait_state_run() + { + pthread_mutex_lock(&inside); + while (state_running) { + pthread_cond_wait(&cvar, &inside); + } + pthread_mutex_unlock(&inside); + } + void wait_state_next() + { pthread_mutex_lock(&inside); - while(state_changing) { + while (cur_state != next_state) { pthread_cond_wait(&cvar, &inside); } pthread_mutex_unlock(&inside); } - bool state_changing, state_setting; + bool state_running, state_setting; state_t cur_state, next_state; pthread_mutex_t inside, outside; pthread_cond_t cvar; diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 12072f6f3..e0c44b35d 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -90,7 +90,7 @@ public: private: virtual ~ue(); - srslte::radio_multi radio; + srslte::radio radios[SRSLTE_MAX_RADIOS]; srsue::phy phy; srsue::mac mac; srslte::mac_pcap mac_pcap; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index 2ba136ffb..ed848c413 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -60,26 +60,22 @@ typedef struct { float freq_offset; float rx_gain; float tx_gain; - uint32_t nof_rx_ant; + uint32_t nof_radios; + uint32_t nof_rf_channels; // Number of RF channels per radio + uint32_t nof_rx_ant; // Number of RF channels for MIMO std::string device_name; - std::string device_args; + std::string device_args[SRSLTE_MAX_RADIOS]; std::string time_adv_nsamples; std::string burst_preamble; std::string continuous_tx; -}rf_args_t; +} rf_args_t; typedef struct { bool enable; std::string filename; bool nas_enable; std::string nas_filename; -}pcap_args_t; - -typedef struct { - bool enable; - std::string phy_filename; - std::string radio_filename; -}trace_args_t; +} pcap_args_t; typedef struct { std::string phy_level; @@ -103,7 +99,7 @@ typedef struct { int all_hex_limit; int file_max_size; std::string filename; -}log_args_t; +} log_args_t; typedef struct { bool enable; @@ -119,20 +115,18 @@ typedef struct { bool metrics_csv_enable; std::string metrics_csv_filename; int mbms_service; -}expert_args_t; +} expert_args_t; typedef struct { rf_args_t rf; pcap_args_t pcap; - trace_args_t trace; log_args_t log; gui_args_t gui; usim_args_t usim; rrc_args_t rrc; - std::string ue_category_str; nas_args_t nas; expert_args_t expert; -}all_args_t; +} all_args_t; typedef enum { LTE = 0, diff --git a/srsue/hdr/ue_metrics_interface.h b/srsue/hdr/ue_metrics_interface.h index 968b0de5a..02889aaae 100644 --- a/srsue/hdr/ue_metrics_interface.h +++ b/srsue/hdr/ue_metrics_interface.h @@ -47,7 +47,7 @@ typedef struct { typedef struct { rf_metrics_t rf; phy_metrics_t phy; - mac_metrics_t mac; + mac_metrics_t mac[SRSLTE_MAX_CARRIERS]; srslte::rlc_metrics_t rlc; gw_metrics_t gw; }ue_metrics_t; diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index ce0527a4f..e31777620 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -45,11 +45,21 @@ #define SRSLTE_RRC_N_BANDS 43 typedef struct { - uint32_t ue_category; - uint32_t feature_group; - uint8_t supported_bands[SRSLTE_RRC_N_BANDS]; - uint32_t nof_supported_bands; -}rrc_args_t; + std::string ue_category_str; + uint32_t ue_category; + uint32_t release; + uint32_t feature_group; + uint8_t supported_bands[SRSLTE_RRC_N_BANDS]; + uint32_t nof_supported_bands; + bool support_ca; +} rrc_args_t; + +#define SRSLTE_UE_CATEGORY_DEFAULT "4" +#define SRSLTE_UE_CATEGORY_MIN 1 +#define SRSLTE_UE_CATEGORY_MAX 21 +#define SRSLTE_RELEASE_DEFAULT 8 +#define SRSLTE_RELEASE_MIN 8 +#define SRSLTE_RELEASE_MAX 15 using srslte::byte_buffer_t; @@ -280,15 +290,16 @@ public: rrc(); ~rrc(); - void init(phy_interface_rrc *phy_, - mac_interface_rrc *mac_, - rlc_interface_rrc *rlc_, - pdcp_interface_rrc *pdcp_, - nas_interface_rrc *nas_, - usim_interface_rrc *usim_, - gw_interface_rrc *gw_, - srslte::mac_interface_timers *mac_timers_, - srslte::log *rrc_log_); + void init(phy_interface_rrc* phy_, + mac_interface_rrc* mac_, + rlc_interface_rrc* rlc_, + pdcp_interface_rrc* pdcp_, + nas_interface_rrc* nas_, + usim_interface_rrc* usim_, + gw_interface_rrc* gw_, + srslte::mac_interface_timers* mac_timers_, + srslte::log* rrc_log_, + rrc_args_t* args_); void stop(); @@ -388,8 +399,8 @@ private: uint16_t ho_src_rnti; cell_t ho_src_cell; - phy_interface_rrc::phy_cfg_t previous_phy_cfg; - mac_interface_rrc::mac_cfg_t previous_mac_cfg; + phy_interface_rrc::phy_cfg_t current_phy_cfg, previous_phy_cfg; + mac_interface_rrc::mac_cfg_t current_mac_cfg, previous_mac_cfg; bool pending_mob_reconf; asn1::rrc::rrc_conn_recfg_s mob_reconf; @@ -547,15 +558,19 @@ private: void remove_meas_object(uint32_t object_id); void remove_meas_report(uint32_t report_id); void remove_meas_id(uint32_t measId); - void remove_meas_id(std::map::iterator it); - void calculate_triggers(uint32_t tti); - void update_phy(); + void remove_meas_id(std::map::iterator it); + void calculate_triggers(uint32_t tti); + void update_phy(); void L3_filter(meas_value_t *value, float rsrp[NOF_MEASUREMENTS]); bool find_earfcn_cell(uint32_t earfcn, uint32_t pci, meas_obj_t **object, int *cell_idx); float range_to_value(quantity_t quant, uint8_t range); uint8_t value_to_range(quantity_t quant, float value); - bool process_event(asn1::rrc::eutra_event_s* event, uint32_t tti, bool enter_condition, bool exit_condition, - meas_t* m, meas_value_t* cell); + bool process_event(asn1::rrc::eutra_event_s* event, + uint32_t tti, + bool enter_condition, + bool exit_condition, + meas_t* m, + meas_value_t* cell); void generate_report(uint32_t meas_id); }; @@ -638,15 +653,21 @@ private: void leave_connected(); void stop_timers(); - void apply_rr_config_common_dl(asn1::rrc::rr_cfg_common_s* config); - void apply_rr_config_common_ul(asn1::rrc::rr_cfg_common_s* config); + void log_rr_config_common(); + void log_phy_config_dedicated(); + void log_mac_config_dedicated(); + + void apply_rr_config_common(asn1::rrc::rr_cfg_common_s* config, bool send_lower_layers); + bool apply_rr_config_dedicated(asn1::rrc::rr_cfg_ded_s* cnfg); + void apply_phy_config_dedicated(asn1::rrc::phys_cfg_ded_s* phy_cnfg, bool apply_defaults); + void apply_mac_config_dedicated_default(); + void apply_mac_config_dedicated_explicit(asn1::rrc::mac_main_cfg_s mac_cfg); + void handle_sib1(); void handle_sib2(); void handle_sib3(); void handle_sib13(); - void apply_sib2_configs(asn1::rrc::sib_type2_s* sib2); - void apply_sib13_configs(asn1::rrc::sib_type13_r9_s* sib13); void handle_con_setup(asn1::rrc::rrc_conn_setup_s* setup); void handle_con_reest(asn1::rrc::rrc_conn_reest_s* setup); void handle_rrc_con_reconfig(uint32_t lcid, asn1::rrc::rrc_conn_recfg_s* reconfig); @@ -654,9 +675,6 @@ private: void add_drb(asn1::rrc::drb_to_add_mod_s* drb_cnfg); void release_drb(uint32_t drb_id); void add_mrb(uint32_t lcid, uint32_t port); - bool apply_rr_config_dedicated(asn1::rrc::rr_cfg_ded_s* cnfg); - void apply_phy_config_dedicated(asn1::rrc::phys_cfg_ded_s* phy_cnfg, bool apply_defaults); - void apply_mac_config_dedicated(asn1::rrc::mac_main_cfg_s* mac_cfg, bool apply_defaults); // Helpers for setting default values void set_phy_default_pucch_srs(); diff --git a/srsue/src/mac/demux.cc b/srsue/src/mac/demux.cc index 3c656161d..12bd90805 100644 --- a/srsue/src/mac/demux.cc +++ b/srsue/src/mac/demux.cc @@ -40,19 +40,19 @@ demux::demux() : mac_msg(20), mch_mac_msg(20), pending_mac_msg(20), rlc(NULL) { } -void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer_) +void demux::init(phy_interface_mac_common* phy_h, + rlc_interface_mac* rlc, + mac_interface_demux* mac, + srslte::log* log_h, + srslte::timers::timer* time_alignment_timer) { - phy_h = phy_h_; - log_h = log_h_; - rlc = rlc_; - time_alignment_timer = time_alignment_timer_; + this->phy_h = phy_h; + this->log_h = log_h; + this->rlc = rlc; + this->mac = mac; + this->time_alignment_timer = time_alignment_timer; pdus.init(this, log_h); - bzero(&mch_lcids, SRSLTE_N_MCH_LCIDS); -} - -void demux::set_uecrid_callback(bool (*callback)(void*,uint64_t), void *arg) { - uecrid_callback = callback; - uecrid_callback_arg = arg; + bzero(&mch_lcids, SRSLTE_N_MCH_LCIDS); } bool demux::get_uecrid_successful() { @@ -94,13 +94,13 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes) // Unpack DLSCH MAC PDU pending_mac_msg.init_rx(nof_bytes); pending_mac_msg.parse_packet(buff); - - // Look for Contention Resolution UE ID - is_uecrid_successful = false; + + // Look for Contention Resolution UE ID + is_uecrid_successful = false; while(pending_mac_msg.next() && !is_uecrid_successful) { if (pending_mac_msg.get()->ce_type() == srslte::sch_subh::CON_RES_ID) { Debug("Found Contention Resolution ID CE\n"); - is_uecrid_successful = uecrid_callback(uecrid_callback_arg, pending_mac_msg.get()->get_con_res_id()); + is_uecrid_successful = mac->contention_resolution_id_rcv(pending_mac_msg.get()->get_con_res_id()); } } @@ -118,21 +118,28 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes) * This function enqueues the packet and returns quickly because ACK * deadline is important here. */ -void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { - return pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH, tstamp); +void demux::push_pdu(uint8_t* buff, uint32_t nof_bytes) +{ + + // Process Real-Time PDUs + process_sch_pdu_rt(buff, nof_bytes); + + return pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH); } /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through -* the MAC in transparent mode. -*/ -void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { - pdus.push(buff, nof_bytes, srslte::pdu_queue::BCH, tstamp); + * the MAC in transparent mode. + */ +void demux::push_pdu_bcch(uint8_t* buff, uint32_t nof_bytes) +{ + pdus.push(buff, nof_bytes, srslte::pdu_queue::BCH); } -void demux::push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { +void demux::push_pdu_mch(uint8_t* buff, uint32_t nof_bytes) +{ uint8_t *mch_buffer_ptr = request_buffer(nof_bytes); memcpy(mch_buffer_ptr, buff, nof_bytes); - pdus.push(mch_buffer_ptr, nof_bytes, srslte::pdu_queue::MCH, tstamp); + pdus.push(mch_buffer_ptr, nof_bytes, srslte::pdu_queue::MCH); mch_buffer_ptr = NULL; } @@ -141,7 +148,7 @@ bool demux::process_pdus() return pdus.process_pdus(); } -void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp) +void demux::process_pdu(uint8_t* mac_pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel) { Debug("Processing MAC PDU channel %d\n", channel); switch(channel) { @@ -165,6 +172,25 @@ void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, srslte::pdu_queue: } } +void demux::process_sch_pdu_rt(uint8_t* buff, uint32_t nof_bytes) +{ + srslte::sch_pdu mac_msg_rt(20); + + mac_msg_rt.init_rx(nof_bytes); + mac_msg_rt.parse_packet(buff); + + while (mac_msg_rt.next()) { + if (mac_msg_rt.get()->is_sdu()) { + // Ignore SDU + } else { + // Process MAC Control Element + if (!process_ce(mac_msg_rt.get())) { + Warning("Received Subheader with invalid or unknown LCID\n"); + } + } + } +} + void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg) { while(pdu_msg->next()) { @@ -177,13 +203,15 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg) sum += x[i]; } if (sum == 0) { - route_pdu = false; + route_pdu = false; Warning("Received all zero PDU\n"); } } // Route logical channel if (route_pdu) { - Info("Delivering PDU for lcid=%d, %d bytes\n", pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_payload_size()); + Info("Delivering PDU for lcid=%d, %d bytes\n", + pdu_msg->get()->get_sdu_lcid(), + pdu_msg->get()->get_payload_size()); if (pdu_msg->get()->get_payload_size() < MAX_PDU_LEN) { rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_payload_size()); } else { @@ -194,10 +222,7 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg) } } } else { - // Process MAC Control Element - if (!process_ce(pdu_msg->get())) { - Warning("Received Subheader with invalid or unkonwn LCID\n"); - } + // Ignore MAC Control Element } } } @@ -238,6 +263,7 @@ void demux::mch_start_rx(uint32_t lcid) } bool demux::process_ce(srslte::sch_subh *subh) { + uint32_t cc_idx = 0; switch(subh->ce_type()) { case srslte::sch_subh::CON_RES_ID: // Do nothing @@ -251,6 +277,11 @@ bool demux::process_ce(srslte::sch_subh *subh) { time_alignment_timer->run(); } break; + case srslte::sch_subh::SCELL_ACTIVATION: + cc_idx = (uint32_t)subh->get_activation_deactivation_cmd(); + phy_h->set_activation_deactivation_scell(cc_idx); + mac->reset_harq(cc_idx); + break; case srslte::sch_subh::PADDING: break; default: diff --git a/srsue/src/mac/dl_harq.cc b/srsue/src/mac/dl_harq.cc new file mode 100644 index 000000000..0fcb5d773 --- /dev/null +++ b/srsue/src/mac/dl_harq.cc @@ -0,0 +1,402 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) + +#include "srsue/hdr/mac/dl_harq.h" +#include "srslte/common/log.h" +#include "srslte/common/mac_pcap.h" +#include "srslte/common/timers.h" +#include "srslte/interfaces/ue_interfaces.h" + +namespace srsue { + +dl_harq_entity::dl_harq_entity() : proc(SRSLTE_MAX_HARQ_PROC) +{ + pcap = NULL; + demux_unit = NULL; + log_h = NULL; + timer_aligment_timer = NULL; + si_window_start = 0; + last_temporal_crnti = 0; + average_retx = 0; +} + +bool dl_harq_entity::init(srslte::log* log_h, + mac_interface_rrc::ue_rnti_t* rntis, + srslte::timers::timer* timer_aligment_timer, + demux* demux_unit) +{ + this->timer_aligment_timer = timer_aligment_timer; + this->demux_unit = demux_unit; + this->log_h = log_h; + this->rntis = rntis; + + for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) { + if (!proc[i].init(i, this)) { + return false; + } + } + bcch_proc.init(-1, this); + return true; +} + +/***************** PHY->MAC interface for DL processes **************************/ +void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action) +{ + bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); + + if (grant.rnti != rntis->sps_rnti) { + // Set BCCH PID for SI RNTI + dl_harq_process* proc_ptr = NULL; + if (grant.rnti == SRSLTE_SIRNTI) { + proc_ptr = &bcch_proc; + } else { + if (grant.pid >= SRSLTE_MAX_HARQ_PROC) { + Error("Invalid PID: %d\n", grant.pid); + return; + } + proc_ptr = &proc[grant.pid]; + } + if (grant.rnti == rntis->temp_rnti && last_temporal_crnti != rntis->temp_rnti) { + grant.tb[0].ndi = true; + last_temporal_crnti = rntis->temp_rnti; + Info("Set NDI=1 for Temp-RNTI DL dci\n"); + } + if (grant.rnti == rntis->crnti && proc_ptr->is_sps()) { + grant.tb[0].ndi = true; + Info("Set NDI=1 for C-RNTI DL dci\n"); + } + proc_ptr->new_grant_dl(grant, action); + } else { + Error("SPS not supported\n"); + } +} + +void dl_harq_entity::tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) +{ + if (grant.rnti == SRSLTE_SIRNTI) { + bcch_proc.tb_decoded(grant, ack); + } else { + if (grant.pid >= SRSLTE_MAX_HARQ_PROC) { + Error("Invalid PID: %d\n", grant.pid); + return; + } + proc[grant.pid].tb_decoded(grant, ack); + } +} + +void dl_harq_entity::reset() +{ + for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) { + proc[i].reset(); + } + bcch_proc.reset(); + dl_sps_assig.clear(); +} + +void dl_harq_entity::start_pcap(srslte::mac_pcap* pcap_) +{ + pcap = pcap_; +} + +void dl_harq_entity::set_si_window_start(int si_window_start_) +{ + si_window_start = si_window_start_; +} + +float dl_harq_entity::get_average_retx() +{ + return average_retx; +} + +dl_harq_entity::dl_harq_process::dl_harq_process() : subproc(SRSLTE_MAX_TB) {} + +bool dl_harq_entity::dl_harq_process::init(int pid, dl_harq_entity* parent) +{ + bool ret = true; + + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + ret &= subproc[tb].init(pid, parent, tb); + } + return ret; +} + +void dl_harq_entity::dl_harq_process::reset(void) +{ + for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + subproc[tb].reset(); + } +} + +void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, + mac_interface_phy::tb_action_dl_t* action) +{ + bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); + /* For each subprocess... */ + for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) { + if (grant.tb[i].tbs) { + subproc[i].new_grant_dl(grant, action); + } + } +} + +void dl_harq_entity::dl_harq_process::tb_decoded(mac_interface_phy::mac_grant_dl_t grant, + bool ack[SRSLTE_MAX_CODEWORDS]) +{ + /* For each subprocess... */ + for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) { + subproc[i].tb_decoded(grant, &ack[i]); + } +} + +bool dl_harq_entity::dl_harq_process::is_sps() +{ + return false; +} + +dl_harq_entity::dl_harq_process::dl_tb_process::dl_tb_process() +{ + is_initiated = false; + ack = false; + bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_dl_t)); + payload_buffer_ptr = NULL; + pthread_mutex_init(&mutex, NULL); +} + +dl_harq_entity::dl_harq_process::dl_tb_process::~dl_tb_process() +{ + if (is_initiated) { + srslte_softbuffer_rx_free(&softbuffer); + } +} + +bool dl_harq_entity::dl_harq_process::dl_tb_process::init(int pid, dl_harq_entity* parent, uint32_t tb_idx) +{ + if (srslte_softbuffer_rx_init(&softbuffer, 110)) { + Error("Error initiating soft buffer\n"); + return false; + } + + if (pid < 0) { + is_bcch = true; + this->pid = 0; + } else { + this->pid = (uint32_t)pid; + is_bcch = false; + } + + tid = tb_idx; + is_first_tb = true; + is_initiated = true; + harq_entity = parent; + log_h = harq_entity->log_h; + return true; +} + +void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock) +{ + if (lock) { + pthread_mutex_lock(&mutex); + } + + bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_dl_t)); + is_first_tb = true; + ack = false; + n_retx = 0; + + if (payload_buffer_ptr) { + if (!is_bcch) { + harq_entity->demux_unit->deallocate(payload_buffer_ptr); + } + payload_buffer_ptr = NULL; + } + + if (is_initiated && lock) { + srslte_softbuffer_rx_reset(&softbuffer); + } + + if (lock) { + pthread_mutex_unlock(&mutex); + } +} + +void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, + mac_interface_phy::tb_action_dl_t* action) +{ + + pthread_mutex_lock(&mutex); + + // Compute RV for BCCH when not specified in PDCCH format + if (is_bcch && grant.tb[tid].rv == -1) { + uint32_t k; + if ((grant.pid / 10) % 2 == 0 && grant.pid % 10 == 5) { // This is SIB1, k is different + k = (grant.pid / 20) % 4; + grant.tb[tid].rv = ((uint32_t)ceilf((float)1.5 * k)) % 4; + } else { + k = (grant.pid - harq_entity->si_window_start) % 4; + grant.tb[tid].rv = ((uint32_t)ceilf((float)1.5 * k)) % 4; + } + } + + calc_is_new_transmission(grant); + + // If this is a new transmission or the size of the TB has changed + if (is_new_transmission || (cur_grant.tb[tid].tbs != grant.tb[tid].tbs)) { + if (!is_new_transmission) { + Warning("DL PID %d: Size of dci changed during a retransmission %d!=%d\n", + pid, + cur_grant.tb[tid].tbs, + grant.tb[tid].tbs); + } + ack = false; + n_retx = 0; + srslte_softbuffer_rx_reset_tbs(&softbuffer, grant.tb[tid].tbs * 8); + } + + n_retx++; + + // If data has not yet been successfully decoded + if (!ack) { + + // Save dci + cur_grant = grant; + + if (payload_buffer_ptr) { + Warning("DL PID %d: Allocating buffer already allocated. Deallocating.\n", pid); + if (!is_bcch) { + harq_entity->demux_unit->deallocate(payload_buffer_ptr); + } + } + + // Instruct the PHY To combine the received data and attempt to decode it + if (is_bcch) { + payload_buffer_ptr = harq_entity->demux_unit->request_buffer_bcch(cur_grant.tb[tid].tbs); + } else { + payload_buffer_ptr = harq_entity->demux_unit->request_buffer(cur_grant.tb[tid].tbs); + } + + action->tb[tid].payload = payload_buffer_ptr; + if (!action->tb[tid].payload) { + Error("Can't get a buffer for TBS=%d\n", cur_grant.tb[tid].tbs); + return; + } + + action->tb[tid].enabled = true; + action->tb[tid].rv = cur_grant.tb[tid].rv; + action->tb[tid].softbuffer.rx = &softbuffer; + } else { + Warning("DL PID %d: Received duplicate TB%d. Discarting and retransmitting ACK (n_retx=%d, reset=%s)\n", + pid, + tid, + n_retx, + n_retx > RESET_DUPLICATE_TIMEOUT ? "yes" : "no"); + if (n_retx > RESET_DUPLICATE_TIMEOUT) { + reset(false); + } + } + + if (is_bcch || harq_entity->timer_aligment_timer->is_expired()) { + // Do not generate ACK + action->generate_ack = false; + } else { + action->generate_ack = true; + } +} + +void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool* ack_ptr) +{ + if (payload_buffer_ptr) { + this->ack = *ack_ptr; + if (ack) { + if (is_bcch) { + if (harq_entity->pcap) { + harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.tb[tid].tbs, ack, 0); + } + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.tb[tid].tbs); + harq_entity->demux_unit->push_pdu_bcch(payload_buffer_ptr, cur_grant.tb[tid].tbs); + } else { + if (harq_entity->pcap) { + harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.tb[tid].tbs, cur_grant.rnti, ack, 0); + } + if (cur_grant.rnti == harq_entity->rntis->temp_rnti) { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.tb[tid].tbs); + harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.tb[tid].tbs); + + // If T-CRNTI, update ack value with result from contention resolution + *ack_ptr = harq_entity->demux_unit->get_uecrid_successful(); + + } else { + Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.tb[tid].tbs); + harq_entity->demux_unit->push_pdu(payload_buffer_ptr, cur_grant.tb[tid].tbs); + + // Compute average number of retransmissions per packet + harq_entity->average_retx = SRSLTE_VEC_CMA((float)n_retx, harq_entity->average_retx, harq_entity->nof_pkts++); + } + } + + } else if (!is_bcch) { + harq_entity->demux_unit->deallocate(payload_buffer_ptr); + } + + payload_buffer_ptr = NULL; + + Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d\n", + pid, + tid, + is_new_transmission ? "newTX" : "reTX ", + cur_grant.tb[tid].tbs, + cur_grant.tb[tid].rv, + ack ? "OK" : "KO", + cur_grant.tb[tid].ndi); + } + + pthread_mutex_unlock(&mutex); + + if (ack && is_bcch) { + reset(); + } +} + +// Determine if it's a new transmission 5.3.2.2 +bool dl_harq_entity::dl_harq_process::dl_tb_process::calc_is_new_transmission(mac_interface_phy::mac_grant_dl_t grant) +{ + + if (((grant.tb[tid].ndi_present && + grant.tb[tid].ndi != cur_grant.tb[tid].ndi) || // 1st condition (NDI provided and has changed) + (is_bcch && grant.tb[tid].rv == 0) || // 2nd condition (Broadcast and 1st transmission) + is_first_tb)) // 3rd condition (is first tx for this tb) + { + is_first_tb = false; + is_new_transmission = true; + } else { + is_new_transmission = false; + } + + Debug("Set HARQ for %stransmission\n", is_new_transmission ? "new " : "re"); + + return is_new_transmission; +} + +} // namespace srsue diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index f558da255..dc56b26d7 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -42,47 +42,49 @@ using namespace asn1::rrc; namespace srsue { -mac::mac() : timers(64), - mux_unit(MAC_NOF_HARQ_PROC), - pdu_process_thread(&demux_unit), - mch_msg(10) +mac::mac() : + timers(64), + pdu_process_thread(&demux_unit), + mch_msg(10), + dl_harq(SRSLTE_MAX_CARRIERS), + ul_harq(SRSLTE_MAX_CARRIERS), + running(false), + pcap(NULL) { - tti = 0; - pcap = NULL; bzero(&metrics, sizeof(mac_metrics_t)); - bzero(&config, sizeof(mac_cfg_t)); + clear_rntis(); } -bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_) +bool mac::init( + phy_interface_mac* phy, rlc_interface_mac* rlc, rrc_interface_mac* rrc, srslte::log* log_h_, uint32_t nof_carriers) { phy_h = phy; rlc_h = rlc; rrc_h = rrc; log_h = log_h_; - tti = 0; srslte_softbuffer_rx_init(&pch_softbuffer, 100); srslte_softbuffer_rx_init(&mch_softbuffer, 100); - timer_alignment = timers.get_unique_id(); - contention_resolution_timer = timers.get_unique_id(); + timer_alignment = timers.get_unique_id(); + uint32_t contention_resolution_timer = timers.get_unique_id(); - log_h->debug("Timer Timing Alignment ID 0x%x\n", timer_alignment); - log_h->debug("Timer Contention Resolution ID 0x%x\n", - contention_resolution_timer); + bsr_procedure.init(rlc_h, log_h, &timers); + phr_procedure.init(phy_h, log_h, &timers); + mux_unit.init(rlc_h, log_h, &bsr_procedure, &phr_procedure); + demux_unit.init(phy_h, rlc_h, this, log_h, timers.get(timer_alignment)); + ra_procedure.init( + phy_h, rrc, log_h, &uernti, timers.get(timer_alignment), timers.get(contention_resolution_timer), &mux_unit); + sr_procedure.init(phy_h, rrc, log_h); - bsr_procedure.init( rlc_h, log_h, &config, &timers); - phr_procedure.init(phy_h, log_h, &config, &timers); - mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure); - demux_unit.init (phy_h, rlc_h, log_h, timers.get(timer_alignment)); - ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, timers.get(timer_alignment), timers.get(contention_resolution_timer), &mux_unit, &demux_unit); - sr_procedure.init (phy_h, rrc, log_h, &config); - ul_harq.init ( log_h, &uernti, &config.ul_harq_params, timers.get(contention_resolution_timer), &mux_unit); - dl_harq.init ( log_h, timers.get(timer_alignment), &demux_unit); + for (uint32_t r = 0; r < nof_carriers; r++) { + ul_harq[r].init(log_h, &uernti, &ra_procedure, &mux_unit); + dl_harq[r].init(log_h, &uernti, timers.get(timer_alignment), &demux_unit); + } reset(); - start_periodic(1000, MAC_MAIN_THREAD_PRIO); + start(MAC_MAIN_THREAD_PRIO); return true; } @@ -93,15 +95,19 @@ void mac::stop() srslte_softbuffer_rx_free(&mch_softbuffer); pdu_process_thread.stop(); - stop_thread(); + running = false; wait_thread_finish(); } void mac::start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; - dl_harq.start_pcap(pcap); - ul_harq.start_pcap(pcap); + for (uint32_t r = 0; r < dl_harq.size(); r++) { + dl_harq[r].start_pcap(pcap); + } + for (uint32_t r = 0; r < ul_harq.size(); r++) { + ul_harq[r].start_pcap(pcap); + } ra_procedure.start_pcap(pcap); } @@ -128,9 +134,15 @@ void mac::reset() Info("Resetting MAC\n"); timers.get(timer_alignment)->stop(); - timers.get(contention_resolution_timer)->stop(); - ul_harq.reset_ndi(); + timer_alignment_expire(); + + for (uint32_t r = 0; r < dl_harq.size(); r++) { + dl_harq[r].reset(); + } + for (uint32_t r = 0; r < ul_harq.size(); r++) { + ul_harq[r].reset(); + } mux_unit.msg3_flush(); mux_unit.reset(); @@ -140,167 +152,280 @@ void mac::reset() bsr_procedure.reset(); phr_procedure.reset(); - dl_harq.reset(); - phy_h->pdcch_dl_search_reset(); - phy_h->pdcch_ul_search_reset(); - + // Setup default LCID 0 and LCID1 + setup_lcid(0, 0, 99, -1, -1); + setup_lcid(1, 0, 98, -1, -1); is_first_ul_grant = true; - bzero(&uernti, sizeof(ue_rnti_t)); + clear_rntis(); } -void mac::run_period() { - - /* Warning: Here order of invocation of procedures is important!! */ +void mac::run_tti(const uint32_t tti_) +{ + tti_sync.push(tti_); +} - tti = phy_h->get_current_tti(); +void mac::run_thread() +{ + running = true; - log_h->step(tti); + while (running) { + // Wait for next TTI + uint32_t tti = tti_sync.wait_pop(); - // Step all procedures - bsr_procedure.step(tti); - phr_procedure.step(tti); + log_h->step(tti); - // Check if BSR procedure need to start SR + /* Warning: Here order of invocation of procedures is important!! */ - if (bsr_procedure.need_to_send_sr(tti)) { - Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); - sr_procedure.start(); - } - if (bsr_procedure.need_to_reset_sr()) { - Debug("Resetting SR procedure by BSR request\n"); - sr_procedure.reset(); - } - sr_procedure.step(tti); + // Step all procedures + Debug("Running MAC tti=%d\n", tti); + bsr_procedure.step(tti); + phr_procedure.step(tti); - // Check SR if we need to start RA - if (sr_procedure.need_random_access()) { - ra_procedure.start_mac_order(); - } + // Check if BSR procedure need to start SR + if (bsr_procedure.need_to_send_sr(tti)) { + Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); + sr_procedure.start(); + } + if (bsr_procedure.need_to_reset_sr()) { + Debug("Resetting SR procedure by BSR request\n"); + sr_procedure.reset(); + } + sr_procedure.step(tti); - ra_procedure.step(tti); - timers.step_all(); - rrc_h->run_tti(tti); -} + // Check SR if we need to start RA + if (sr_procedure.need_random_access()) { + ra_procedure.start_mac_order(); + } -void mac::bcch_start_rx() -{ - bcch_start_rx(tti, -1); + ra_procedure.step(tti); + ra_window_start = 0; + ra_procedure.is_rar_window(&ra_window_start, &ra_window_length); + timers.step_all(); + rrc_h->run_tti(tti); + } } void mac::bcch_start_rx(int si_window_start, int si_window_length) { if (si_window_length >= 0 && si_window_start >= 0) { - dl_harq.set_si_window_start(si_window_start); - phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start, si_window_start+si_window_length); + for (uint32_t r = 0; r < dl_harq.size(); r++) { + dl_harq[r].set_si_window_start(si_window_start); + } + this->si_window_length = si_window_length; + this->si_window_start = si_window_start; } else { - phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start); + this->si_window_length = 0; + this->si_window_start = 0; } - Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); + Info("SCHED: Searching for DL dci for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); +} + +void mac::bcch_stop_rx() +{ + bcch_start_rx(-1, -1); } void mac::pcch_start_rx() { - phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); - Info("SCHED: Searching for DL grant for P-RNTI\n"); + this->p_window_start = 1; } void mac::clear_rntis() { - phy_h->pdcch_dl_search_reset(); + p_window_start = 0; + si_window_start = 0; + ra_window_start = 0; + bzero(&uernti, sizeof(ue_rnti_t)); } -void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) +void mac::get_rntis(ue_rnti_t* rntis) { - // Send MIB to RLC - rlc_h->write_pdu_bcch_bch(payload, len); + if (rntis) { + *rntis = uernti; + } +} +void mac::set_ho_rnti(uint16_t crnti, uint16_t target_pci) +{ + uernti.crnti = crnti; if (pcap) { - pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti()); + pcap->set_ue_id(target_pci); } } -void mac::pch_decoded_ok(uint32_t len) +uint16_t mac::get_ul_sched_rnti(uint32_t tti) { - // Send PCH payload to RLC - rlc_h->write_pdu_pcch(pch_payload_buffer, len); + if (uernti.temp_rnti && !uernti.crnti) { + return uernti.temp_rnti; + } + if (uernti.crnti) { + return uernti.crnti; + } + return 0; +} - if (pcap) { - pcap->write_dl_pch(pch_payload_buffer, len, true, phy_h->get_current_tti()); +bool mac::is_in_window(uint32_t tti, int* start, int* len) +{ + uint32_t st = (uint32_t)*start; + uint32_t l = (uint32_t)*len; + + if (srslte_tti_interval(tti, st) < l + 5) { + if (tti > st) { + if (tti <= st + l) { + return true; + } else { + *start = 0; + *len = 0; + return false; + } + } else { + if (tti <= (st + l) % 10240) { + return true; + } else { + *start = 0; + *len = 0; + return false; + } + } } + return false; } -void mac::mch_decoded_ok(uint32_t len) +uint16_t mac::get_dl_sched_rnti(uint32_t tti) { - // Parse MAC header - mch_msg.init_rx(len); - - mch_msg.parse_packet(mch_payload_buffer); - while(mch_msg.next()) { - for(uint32_t i = 0; i < phy_mbsfn_cfg.nof_mbsfn_services;i++) { - if(srslte::mch_subh::MCH_SCHED_INFO == mch_msg.get()->ce_type()) { - uint16_t stop; - uint8_t lcid; - if(mch_msg.get()->get_next_mch_sched_info(&lcid, &stop)) { - phy_h->set_mch_period_stop(stop); - Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti()); + // Priority: SI-RNTI, P-RNTI, RA-RNTI, Temp-RNTI, CRNTI + if (si_window_start > 0) { + if (is_in_window(tti, &si_window_start, &si_window_length)) { + // FIXME: This scheduling decision belongs to RRC + if (si_window_length > 1) { // This is not a SIB1 + if ((tti / 10) % 2 == 0 && (tti % 10) == 5) { // Skip subframe #5 for which SFN mod 2 = 0 + return 0; } } + Debug("SCHED: Searching SI-RNTI, tti=%d, window start=%d, length=%d\n", tti, si_window_start, si_window_length); + return SRSLTE_SIRNTI; } } - - demux_unit.push_pdu_mch(mch_payload_buffer, len, 0); - pdu_process_thread.notify(); + if (ra_window_start > 0 && ra_window_length > 0 && is_in_window(tti, &ra_window_start, &ra_window_length)) { + Debug("SCHED: Searching RAR-RNTI=0x%x, tti=%d\n", uernti.rar_rnti, tti); + return uernti.rar_rnti; + } + if (uernti.temp_rnti && !uernti.crnti) { + Debug("SCHED: Searching Temp-RNTI=0x%x\n", uernti.temp_rnti); + return uernti.temp_rnti; + } + if (uernti.crnti) { + Debug("SCHED: Searching C-RNTI=0x%x\n", uernti.crnti); + return uernti.crnti; + } + if (p_window_start > 0) { + Debug("SCHED: Searching P-RNTI\n"); + return SRSLTE_PRNTI; + } + return 0; +} + +void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) +{ + // Send MIB to RLC + rlc_h->write_pdu_bcch_bch(payload, len); + if (pcap) { - pcap->write_dl_mch(mch_payload_buffer, len, true, phy_h->get_current_tti()); + pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti()); } +} + +void mac::mch_decoded(uint32_t len, bool crc) +{ + // Parse MAC header + if (crc) { + mch_msg.init_rx(len); + mch_msg.parse_packet(mch_payload_buffer); + while (mch_msg.next()) { + for (uint32_t i = 0; i < phy_mbsfn_cfg.nof_mbsfn_services; i++) { + if (srslte::mch_subh::MCH_SCHED_INFO == mch_msg.get()->ce_type()) { + uint16_t stop; + uint8_t lcid; + if (mch_msg.get()->get_next_mch_sched_info(&lcid, &stop)) { + phy_h->set_mch_period_stop(stop); + Info("MCH Sched Info: LCID: %d, Stop: %d, tti is %d \n", lcid, stop, phy_h->get_current_tti()); + } + } + } + } - metrics.rx_brate += len*8; + demux_unit.push_pdu_mch(mch_payload_buffer, len); + pdu_process_thread.notify(); + if (pcap) { + pcap->write_dl_mch(mch_payload_buffer, len, true, phy_h->get_current_tti()); + } + metrics[0].rx_brate += len * 8; + } else { + metrics[0].rx_errors++; + } + metrics[0].rx_pkts++; } -void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) +void mac::tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) { - if (rnti_type == SRSLTE_RNTI_RAR) { - if (ack) { + if (SRSLTE_RNTI_ISRAR(grant.rnti)) { + if (ack[0]) { ra_procedure.tb_decoded_ok(); } + } else if (grant.rnti == SRSLTE_PRNTI) { + // Send PCH payload to RLC + rlc_h->write_pdu_pcch(pch_payload_buffer, grant.tb[0].tbs); + + if (pcap) { + pcap->write_dl_pch(pch_payload_buffer, grant.tb[0].tbs, true, phy_h->get_current_tti()); + } } else { - dl_harq.tb_decoded(ack, tb_idx, rnti_type, harq_pid); - if (ack) { - pdu_process_thread.notify(); - metrics.rx_brate += dl_harq.get_current_tbs(harq_pid, tb_idx); - } else { - metrics.rx_errors++; + + dl_harq[cc_idx].tb_decoded(grant, ack); + pdu_process_thread.notify(); + + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (grant.tb[tb].tbs) { + if (ack[tb]) { + metrics[cc_idx].rx_brate += grant.tb[tb].tbs * 8; + } else { + metrics[cc_idx].rx_errors++; + } + metrics[cc_idx].rx_pkts++; + } } - metrics.rx_pkts++; } } -void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action) +void mac::new_grant_dl(uint32_t cc_idx, + mac_interface_phy::mac_grant_dl_t grant, + mac_interface_phy::tb_action_dl_t* action) { - if (grant.rnti_type == SRSLTE_RNTI_RAR) { + if (SRSLTE_RNTI_ISRAR(grant.rnti)) { ra_procedure.new_grant_dl(grant, action); - } else if (grant.rnti_type == SRSLTE_RNTI_PCH) { - - action->phy_grant = grant.phy_grant; - action->generate_ack = false; - action->decode_enabled[0] = true; - action->decode_enabled[1] = false; - srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); - action->payload_ptr[0] = pch_payload_buffer; - action->softbuffers[0] = &pch_softbuffer; - action->rnti = grant.rnti; - action->rv[0] = grant.rv[0]; - if (grant.n_bytes[0] > pch_payload_buffer_sz) { - Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes[0], pch_payload_buffer_sz); - action->decode_enabled[0] = false; + } else if (grant.rnti == SRSLTE_PRNTI) { + + bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); + if (grant.tb[0].tbs > pch_payload_buffer_sz) { + Error("Received dci for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.tb[0].tbs, pch_payload_buffer_sz); + action->tb[0].enabled = false; + } else { + action->tb[0].enabled = true; + action->tb[0].payload = pch_payload_buffer; + action->tb[0].softbuffer.rx = &pch_softbuffer; + action->tb[0].rv = grant.tb[0].rv; + srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); } - } else { + } else if (!(grant.rnti == SRSLTE_SIRNTI && cc_idx != 0)) { // If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it - if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { + if (grant.rnti == uernti.crnti && ra_procedure.is_contention_resolution()) { ra_procedure.pdcch_to_crnti(false); } - dl_harq.new_grant_dl(grant, action); + dl_harq[cc_idx].new_grant_dl(grant, action); + } else { + /* Discard */ + Info("Discarding dci in CC %d, RNTI=0x%x\n", cc_idx, grant.rnti); } } @@ -309,76 +434,58 @@ uint32_t mac::get_current_tti() return phy_h->get_current_tti(); } -void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action) +void mac::reset_harq(uint32_t cc_idx) { - /* Start PHR Periodic timer on first UL grant */ - if (is_first_ul_grant) { - is_first_ul_grant = false; - phr_procedure.start_timer(); + if (cc_idx < dl_harq.size()) { + dl_harq[cc_idx].reset(); + ul_harq[cc_idx].reset(); } - if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { - ra_procedure.pdcch_to_crnti(true); - } - ul_harq.new_grant_ul(grant, action); - metrics.tx_pkts++; } -void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action) +bool mac::contention_resolution_id_rcv(uint64_t id) { - int tbs = ul_harq.get_current_tbs(tti); - ul_harq.new_grant_ul_ack(grant, &ack, action); - if (!ack) { - metrics.tx_errors++; - } else { - metrics.tx_brate += tbs; - } - metrics.tx_pkts++; - if (!ack && ra_procedure.is_contention_resolution()) { - ra_procedure.harq_retx(); - } - if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { - ra_procedure.pdcch_to_crnti(true); - } + return ra_procedure.contention_resolution_id_received(id); } -void mac::new_mch_dl(srslte_ra_dl_grant_t phy_grant, tb_action_dl_t *action) +void mac::new_grant_ul(uint32_t cc_idx, + mac_interface_phy::mac_grant_ul_t grant, + mac_interface_phy::tb_action_ul_t* action) { - action->phy_grant.dl = phy_grant; - action->generate_ack = false; - action->decode_enabled[0] = true; - srslte_softbuffer_rx_reset_cb(&mch_softbuffer, 1); - action->payload_ptr[0] = mch_payload_buffer; - action->softbuffers[0] = &mch_softbuffer; + /* Start PHR Periodic timer on first UL dci */ + if (is_first_ul_grant) { + is_first_ul_grant = false; + phr_procedure.start_timer(); + } + ul_harq[cc_idx].new_grant_ul(grant, action); + metrics[cc_idx].tx_pkts++; + + if (grant.phich_available) { + if (!grant.hi_value) { + metrics[cc_idx].tx_errors++; + } else { + metrics[cc_idx].tx_brate += ul_harq[cc_idx].get_current_tbs(grant.pid) * 8; + } + } } -void mac::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action) +void mac::new_mch_dl(srslte_pdsch_grant_t phy_grant, tb_action_dl_t* action) { - int tbs = ul_harq.get_current_tbs(tti); - ul_harq.harq_recv(tti, ack, action); - if (!ack) { - metrics.tx_errors++; - metrics.tx_pkts++; - } else { - metrics.tx_brate += tbs; - } - if (!ack && ra_procedure.is_contention_resolution()) { - ra_procedure.harq_retx(); - } + action->generate_ack = false; + action->tb[0].enabled = true; + action->tb[0].payload = mch_payload_buffer; + action->tb[0].softbuffer.rx = &mch_softbuffer; + srslte_softbuffer_rx_reset_cb(&mch_softbuffer, 1); } -void mac::setup_timers() +void mac::setup_timers(int time_alignment_timer) { // stop currently running time alignment timer if (timers.get(timer_alignment)->is_running()) { timers.get(timer_alignment)->stop(); - log_h->debug("Stop running MAC Time Alignment Timer with ID 0x%x\n", - timer_alignment); } - int value = config.main.time_align_timer_ded.to_number(); - log_h->info("Set MAC Time Alignment Timer (0x%x) to %d \n", timer_alignment, value); - if (value > 0) { - timers.get(timer_alignment)->set(this, value); + if (time_alignment_timer > 0) { + timers.get(timer_alignment)->set(this, time_alignment_timer); } } @@ -392,27 +499,14 @@ void mac::timer_expired(uint32_t timer_id) } /* Function called on expiry of TimeAlignmentTimer */ -void mac::timer_alignment_expire() { - log_h->console("TimeAlignment timer has expired value=%d ms\n", - timers.get(timer_alignment)->get_timeout()); - log_h->warning("TimeAlignment timer has expired value=%d ms\n", - timers.get(timer_alignment)->get_timeout()); - rrc_h->release_pucch_srs(); - dl_harq.reset(); - ul_harq.reset(); -} - -void mac::get_rntis(ue_rnti_t* rntis) +void mac::timer_alignment_expire() { - *rntis = uernti; -} - -void mac::set_ho_rnti(uint16_t crnti, uint16_t target_pci) { - phy_h->pdcch_dl_search_reset(); - phy_h->pdcch_ul_search_reset(); - uernti.crnti = crnti; - if (pcap) { - pcap->set_ue_id(target_pci); + rrc_h->release_pucch_srs(); + for (uint32_t r = 0; r < dl_harq.size(); r++) { + dl_harq[r].reset(); + } + for (uint32_t r = 0; r < ul_harq.size(); r++) { + ul_harq[r].reset(); } } @@ -431,39 +525,23 @@ void mac::start_cont_ho() ra_procedure.start_mac_order(56, true); } -void mac::get_config(mac_cfg_t* mac_cfg) -{ - *mac_cfg = config; -} - void mac::set_mbsfn_config(uint32_t nof_mbsfn_services) { - //cfg->nof_mbsfn_services = config.mbsfn.mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size; + // ul_cfg->nof_mbsfn_services = config.mbsfn.mcch.pmch_infolist_r9[0].mbms_sessioninfolist_r9_size; phy_mbsfn_cfg.nof_mbsfn_services = nof_mbsfn_services; } - -void mac::set_config(mac_cfg_t* mac_cfg) -{ - config = *mac_cfg; - setup_timers(); -} - -void mac::set_config_main(mac_main_cfg_s* main_cfg) -{ - config.main = *main_cfg; - setup_timers(); -} - -void mac::set_config_rach(rach_cfg_common_s* rach_cfg, uint32_t prach_config_index) +void mac::set_config(mac_cfg_t& mac_cfg) { - config.rach = *rach_cfg; - config.prach_config_index = prach_config_index; -} - -void mac::set_config_sr(sched_request_cfg_c* sr_cfg) -{ - config.sr = *sr_cfg; + // Set configuration for each module in MAC + bsr_procedure.set_config(mac_cfg.get_bsr_cfg()); + phr_procedure.set_config(mac_cfg.get_phr_cfg()); + sr_procedure.set_config(mac_cfg.get_sr_cfg()); + ra_procedure.set_config(mac_cfg.get_rach_cfg()); + for (uint32_t i = 0; i < ul_harq.size(); i++) { + ul_harq[i].set_config(mac_cfg.get_harq_cfg()); + } + setup_timers(mac_cfg.get_time_alignment_timer()); } void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) @@ -471,8 +549,7 @@ void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_t Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", lcid, lcg, priority, PBR_x_tti, BSD); mux_unit.set_priority(lcid, priority, PBR_x_tti, BSD); - bsr_procedure.setup_lcg(lcid, lcg); - bsr_procedure.set_priority(lcid, priority); + bsr_procedure.setup_lcid(lcid, lcg, priority); } void mac::mch_start_rx(uint32_t lcid) @@ -480,19 +557,49 @@ void mac::mch_start_rx(uint32_t lcid) demux_unit.mch_start_rx(lcid); } -void mac::get_metrics(mac_metrics_t &m) -{ - Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n", - metrics.rx_pkts?((float) 100*metrics.rx_errors/metrics.rx_pkts):0.0, - dl_harq.get_average_retx(), - metrics.tx_pkts?((float) 100*metrics.tx_errors/metrics.tx_pkts):0.0, - ul_harq.get_average_retx()); - - metrics.ul_buffer = (int) bsr_procedure.get_buffer_state(); - metrics.dl_retx_avg = dl_harq.get_average_retx(); - metrics.ul_retx_avg = ul_harq.get_average_retx(); - m = metrics; - bzero(&metrics, sizeof(mac_metrics_t)); +void mac::get_metrics(mac_metrics_t m[SRSLTE_MAX_CARRIERS]) +{ + int tx_pkts = 0; + int tx_errors = 0; + int tx_brate = 0; + int rx_pkts = 0; + int rx_errors = 0; + int rx_brate = 0; + int ul_buffer = 0; + float dl_avg_ret = 0; + float ul_avg_ret = 0; + int dl_avg_ret_count = 0; + int ul_avg_ret_count = 0; + + for (uint32_t r = 0; r < SRSLTE_MAX_CARRIERS; r++) { + tx_pkts += metrics[r].tx_pkts; + tx_errors += metrics[r].tx_errors; + tx_brate += metrics[r].tx_brate; + rx_pkts += metrics[r].rx_pkts; + rx_errors += metrics[r].rx_errors; + rx_brate += metrics[r].rx_brate; + ul_buffer += metrics[r].ul_buffer; + + if (metrics[r].rx_pkts) { + dl_avg_ret += dl_harq[r].get_average_retx(); + dl_avg_ret_count++; + } + } + + if (dl_avg_ret_count) { + dl_avg_ret /= dl_avg_ret_count; + } + + Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n", + rx_pkts ? ((float)100 * rx_errors / rx_pkts) : 0.0f, + dl_avg_ret, + tx_pkts ? ((float)100 * tx_errors / tx_pkts) : 0.0f, + ul_harq[0].get_average_retx()); + + metrics[0].ul_buffer = (int)bsr_procedure.get_buffer_state(); + memcpy(m, metrics, sizeof(mac_metrics_t) * SRSLTE_MAX_CARRIERS); + m = metrics; + bzero(&metrics, sizeof(mac_metrics_t) * SRSLTE_MAX_CARRIERS); } diff --git a/srsue/src/mac/mux.cc b/srsue/src/mac/mux.cc index 36ec7ff97..ba5e3ffe2 100644 --- a/srsue/src/mac/mux.cc +++ b/srsue/src/mac/mux.cc @@ -37,7 +37,7 @@ namespace srsue { -mux::mux(uint8_t nof_harq_proc_) : pdu_msg(MAX_NOF_SUBHEADERS), pid_has_bsr(nof_harq_proc_), nof_harq_proc(nof_harq_proc_) +mux::mux() : pdu_msg(MAX_NOF_SUBHEADERS) { pthread_mutex_init(&mutex, NULL); @@ -143,15 +143,8 @@ srslte::sch_subh::cetype bsr_format_convert(bsr_proc::bsr_format_t format) { } } -void mux::pusch_retx(uint32_t tx_tti, uint32_t pid) -{ - if (pid_has_bsr[pid%nof_harq_proc]) { - bsr_procedure->set_tx_tti(tx_tti); - } -} - // Multiplexing and logical channel priorization as defined in Section 5.4.3 -uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32_t pid) +uint8_t* mux::pdu_get(uint8_t* payload, uint32_t pdu_sz, uint32_t pid) { pthread_mutex_lock(&mutex); @@ -188,13 +181,11 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 bsr_proc::bsr_t bsr; bool regular_bsr = bsr_procedure->need_to_send_bsr_on_ul_grant(pdu_msg.rem_size(), &bsr); - bool bsr_is_inserted = false; - + // MAC control element for BSR, with exception of BSR included for padding; if (regular_bsr) { if (pdu_msg.new_subh()) { pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format)); - bsr_is_inserted = true; } } @@ -233,7 +224,7 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 } } - // Maximize the grant utilization + // Maximize the dci utilization if (lch.size() > 0) { for (int i=(int)lch.size()-1;i>=0;i--) { if (lch[i].sched_len > 0) { @@ -254,8 +245,7 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 if (bsr_procedure->generate_padding_bsr(pdu_msg.rem_size(), &bsr)) { if (pdu_msg.new_subh()) { pdu_msg.get()->set_bsr(bsr.buff_size, bsr_format_convert(bsr.format)); - bsr_is_inserted = true; - } + } } } @@ -264,14 +254,8 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32 /* Generate MAC PDU and save to buffer */ uint8_t *ret = pdu_msg.write_packet(log_h); - pid_has_bsr[pid%nof_harq_proc] = bsr_is_inserted; - if (bsr_is_inserted) { - bsr_procedure->set_tx_tti(tx_tti); - } - pthread_mutex_unlock(&mutex); - return ret; } @@ -368,7 +352,7 @@ uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz) { if (pdu_sz < MSG3_BUFF_SZ - 32) { if (!msg3_buff_start_pdu) { - msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); + msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0); if (!msg3_buff_start_pdu) { Error("Moving PDU from Mux unit to Msg3 buffer\n"); return NULL; diff --git a/srsue/src/mac/proc_bsr.cc b/srsue/src/mac/proc_bsr.cc index ed13111aa..357a30f07 100644 --- a/srsue/src/mac/proc_bsr.cc +++ b/srsue/src/mac/proc_bsr.cc @@ -33,31 +33,24 @@ #include "srsue/hdr/mac/mac.h" #include "srsue/hdr/mac/mux.h" +namespace srsue { - namespace srsue { - bsr_proc::bsr_proc() { log_h = NULL; - initiated = false; - last_print = 0; - next_tx_tti = 0; - triggered_bsr_type=NONE; - - for (int i=0;iget_unique_id(); @@ -67,6 +60,12 @@ void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_ initiated = true; } +void bsr_proc::set_trigger(srsue::bsr_proc::triggered_bsr_type_t new_trigger) +{ + triggered_bsr_type = new_trigger; + trigger_tti = current_tti; +} + void bsr_proc::reset() { timers_db->get(timer_periodic_id)->stop(); @@ -77,124 +76,165 @@ void bsr_proc::reset() reset_sr = false; sr_is_sent = false; triggered_bsr_type = NONE; - next_tx_tti = 0; + + trigger_tti = 0; +} + +void bsr_proc::set_config(srsue::mac_interface_rrc::bsr_cfg_t& bsr_cfg) +{ + pthread_mutex_lock(&mutex); + + this->bsr_cfg = bsr_cfg; + + timers_db->get(timer_periodic_id)->stop(); + timers_db->get(timer_retx_id)->stop(); + + if (bsr_cfg.periodic_timer > 0) { + timers_db->get(timer_periodic_id)->set(this, bsr_cfg.periodic_timer); + Info("BSR: Configured timer periodic %d ms\n", bsr_cfg.periodic_timer); + } + if (bsr_cfg.retx_timer > 0) { + timers_db->get(timer_retx_id)->set(this, bsr_cfg.retx_timer); + Info("BSR: Configured timer reTX %d ms\n", bsr_cfg.retx_timer); + } + pthread_mutex_unlock(&mutex); } /* Process Periodic BSR */ void bsr_proc::timer_expired(uint32_t timer_id) { - if(timer_id == timer_periodic_id) { + pthread_mutex_lock(&mutex); + // periodicBSR-Timer + if (timer_id == timer_periodic_id) { if (triggered_bsr_type == NONE) { - // Check condition 4 in Sec 5.4.5 - triggered_bsr_type = PERIODIC; + set_trigger(PERIODIC); Debug("BSR: Triggering Periodic BSR\n"); } + // retxBSR-Timer } else if (timer_id == timer_retx_id) { // Enable reTx of SR only if periodic timer is not infinity - int periodic = mac_cfg->main.ul_sch_cfg.periodic_bsr_timer.to_number(); - if (periodic >= 0) { - triggered_bsr_type = REGULAR; - Debug("BSR: Triggering BSR reTX\n"); - sr_is_sent = false; + if (bsr_cfg.periodic_timer >= 0) { + // Triger Regular BSR if UE has available data for transmission on any channel + if (check_any_channel()) { + set_trigger(REGULAR); + Debug("BSR: Triggering BSR reTX\n"); + sr_is_sent = false; + } } } + pthread_mutex_unlock(&mutex); } -// Checks if data is available for a a channel with higher priority than others +uint32_t bsr_proc::get_buffer_state() +{ + uint32_t buffer = 0; + for (int i = 0; i < NOF_LCG; i++) { + buffer += get_buffer_state_lcg(i); + } + return buffer; +} + +// Checks if data is available for a a channel with higher priority than others bool bsr_proc::check_highest_channel() { - int pending_data_lcid = -1; - - for (int i=0;i= 0) { - if (rlc->has_data(i)) { - pending_data_lcid = i; - for (int j=0;jhas_data(j)) { - if (priorities[j] > priorities[i]) { - pending_data_lcid = -1; + + for (int i = 0; i < NOF_LCG; i++) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + // If new data available + if (iter->second.new_buffer > iter->second.old_buffer) { + // Check if this lcid has higher priority than any other LCID in the group + bool is_max_priority = true; + for (int j = 0; j < NOF_LCG; j++) { + for (std::map::iterator iter2 = lcgs[j].begin(); iter2 != lcgs[j].end(); ++iter2) { + if (iter2->second.priority > iter->second.priority && iter2->second.old_buffer) { + is_max_priority = false; } } } - } - } - } - if (pending_data_lcid >= 0) { - // If there is new data available for this logical channel - uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid); - if (nbytes > last_pending_data[pending_data_lcid]) - { - if (triggered_bsr_type != REGULAR) { - Debug("BSR: Triggered REGULAR BSR for Max Priority LCID=%d\n", pending_data_lcid); + if (is_max_priority) { + Debug("BSR: New data for lcid=%d with maximum priority in lcg=%d\n", iter->first, i); + return true; + } } - triggered_bsr_type = REGULAR; - return true; - } + } } - return false; + return false; } -uint32_t bsr_proc::get_buffer_state() { - uint32_t buffer = 0; - for (int i=0;i= 0) { - buffer += rlc->get_buffer_state(i); +bool bsr_proc::check_any_channel() +{ + for (int i = 0; i < NOF_LCG; i++) { + if (get_buffer_state_lcg(i)) { + return true; } } - return buffer; + return false; } - + // Checks if only one logical channel has data avaiable for Tx -bool bsr_proc::check_single_channel() { - uint32_t pending_data_lcid = 0; - uint32_t nof_nonzero_lcid = 0; - - for (int i=0;i= 0) { - if (rlc->has_data(i)) { - pending_data_lcid = i; - nof_nonzero_lcid++; +bool bsr_proc::check_new_data() +{ + for (int i = 0; i < NOF_LCG; i++) { + // If there was no data available in any LCID belonging to this LCG + if (!get_buffer_state_lcg(i)) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + if (iter->second.new_buffer > 0) { + Debug("BSR: New data available for lcid=%d\n", iter->first); + return true; + } } } } - if (nof_nonzero_lcid == 1) { - uint32_t nbytes = rlc->get_buffer_state(pending_data_lcid); - // If there is new data available for this logical channel - if (nbytes > last_pending_data[pending_data_lcid]) { - triggered_bsr_type = REGULAR; - Debug("BSR: Triggered REGULAR BSR for single LCID=%d\n", pending_data_lcid); - return true; - } - } return false; } -void bsr_proc::update_pending_data() { - for (int i=0;iget_buffer_state(i); +void bsr_proc::update_new_data() +{ + for (int i = 0; i < NOF_LCG; i++) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + iter->second.new_buffer = rlc->get_buffer_state(iter->first); + } } } -bool bsr_proc::generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes) { - bool ret = false; - uint32_t nof_lcg=0; - bzero(bsr, sizeof(bsr_t)); - for (int i=0;i= 0) { - uint32_t n = rlc->get_buffer_state(i); - bsr->buff_size[lcg[i]] += n; - if (n > 0) { - nof_lcg++; - ret = true; - } +void bsr_proc::update_buffer_state() +{ + for (int i = 0; i < NOF_LCG; i++) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + iter->second.old_buffer = iter->second.new_buffer; } } - if (triggered_bsr_type == PADDING) { +} + +uint32_t bsr_proc::get_buffer_state_lcg(uint32_t lcg) +{ + uint32_t n = 0; + for (std::map::iterator iter = lcgs[lcg].begin(); iter != lcgs[lcg].end(); ++iter) { + n += iter->second.old_buffer; + } + return n; +} + +bool bsr_proc::generate_bsr(bsr_t* bsr, uint32_t nof_padding_bytes) +{ + bool ret = false; + uint32_t nof_lcg = 0; + bzero(bsr, sizeof(bsr_t)); + + // Calculate buffer size for each LCG + for (int i = 0; i < NOF_LCG; i++) { + bsr->buff_size[i] = get_buffer_state_lcg(i); + if (bsr->buff_size[i] > 0) { + nof_lcg++; + ret = true; + } + } + if (triggered_bsr_type == PADDING) { if (nof_padding_bytes < 4) { - // If space only for short + // If space only for short if (nof_lcg > 1) { - bsr->format = TRUNC_BSR; - uint32_t max_prio_ch = find_max_priority_lcid(); - for (int i=0;i<4;i++) { - if (lcg[max_prio_ch] != i) { + bsr->format = TRUNC_BSR; + uint32_t max_prio_lcg = find_max_priority_lcg(); + for (uint32_t i = 0; i < NOF_LCG; i++) { + if (max_prio_lcg != i) { bsr->buff_size[i] = 0; } } @@ -215,53 +255,43 @@ bool bsr_proc::generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes) { bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), bsr->buff_size[0], bsr->buff_size[1], bsr->buff_size[2], bsr->buff_size[3]); - return ret; + return ret; } -// Checks if Regular BSR must be assembled, as defined in 5.4.5 -// Padding BSR is assembled when called by mux_unit when UL grant is received -// Periodic BSR is triggered by the expiration of the timers +// Checks if Regular BSR must be assembled, as defined in 5.4.5 +// Padding BSR is assembled when called by mux_unit when UL dci is received +// Periodic BSR is triggered by the expiration of the timers void bsr_proc::step(uint32_t tti) { if (!initiated) { return; } - int periodic = mac_cfg->main.ul_sch_cfg.periodic_bsr_timer.to_number(); - if (periodic > 0 && (uint32_t)periodic != timers_db->get(timer_periodic_id)->get_timeout()) - { - timers_db->get(timer_periodic_id)->set(this, periodic); - timers_db->get(timer_periodic_id)->run(); - Info("BSR: Configured timer periodic %d ms\n", periodic); - } - int retx = mac_cfg->main.ul_sch_cfg.retx_bsr_timer.to_number(); - if (retx > 0 && (uint32_t)retx != timers_db->get(timer_retx_id)->get_timeout()) - { - timers_db->get(timer_retx_id)->set(this, retx); - timers_db->get(timer_retx_id)->run(); - Info("BSR: Configured timer reTX %d ms\n", retx); - } + pthread_mutex_lock(&mutex); + current_tti = tti; + + update_new_data(); - // Check condition 1 in Sec 5.4.5 - if (triggered_bsr_type == NONE) { - check_single_channel(); + // Regular BSR triggered if new data arrives or channel with high priority has new data + if (check_new_data() || check_highest_channel()) { + set_trigger(REGULAR); } - // Higher priority channel is reported regardless of a BSR being already triggered - check_highest_channel(); - - update_pending_data(); - - - if ((tti - last_print)%10240 > QUEUE_STATUS_PERIOD_MS) { + + update_buffer_state(); + + if ((tti - last_print) % 10240 > QUEUE_STATUS_PERIOD_MS) { char str[128]; - bzero(str, 128); - for (int i=0;iget_buffer_state(i), last_pending_data[i]); + str[0] = '\0'; + int n = 0; + for (int i = 0; i < NOF_LCG; i++) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + n = srslte_print_check(str, 128, n, "%d: %d ", iter->first, iter->second.old_buffer); + } } - Info("BSR: QUEUE status: %s\n", str); + Info("BSR: triggered_bsr_type=%d, LCID QUEUE status: %s\n", triggered_bsr_type, str); last_print = tti; } - + pthread_mutex_unlock(&mutex); } char* bsr_proc::bsr_type_tostring(triggered_bsr_type_t type) { @@ -290,121 +320,135 @@ char* bsr_proc::bsr_format_tostring(bsr_format_t format) { } } -bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) +bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t* bsr) { - bool ret = false; + bool ret = false; + + pthread_mutex_lock(&mutex); - uint32_t bsr_sz = 0; + uint32_t bsr_sz = 0; if (triggered_bsr_type == PERIODIC || triggered_bsr_type == REGULAR) { - /* Check if grant + MAC SDU headers is enough to accomodate all pending data */ - int total_data = 0; - for (int i=0;iget_buffer_state(i))+rlc->get_buffer_state(i); + /* Check if dci + MAC SDU headers is enough to accomodate all pending data */ + int total_data = 0; + for (int i = 0; i < NOF_LCG; i++) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + total_data += srslte::sch_pdu::size_header_sdu(iter->second.old_buffer) + iter->second.old_buffer; + } } - total_data--; // Because last SDU has no size header - - /* All triggered BSRs shall be cancelled in case the UL grant can accommodate all pending data available for transmission - but is not sufficient to additionally accommodate the BSR MAC control element plus its subheader. + total_data--; // Because last SDU has no size header + + /* All triggered BSRs shall be cancelled in case the UL dci can accommodate all pending data available for + transmission but is not sufficient to additionally accommodate the BSR MAC control element plus its subheader. */ generate_bsr(bsr, 0); bsr_sz = bsr->format==LONG_BSR?3:1; if (total_data <= (int)grant_size && total_data + 1 + bsr_sz > grant_size) { Debug("Grant is not enough to accommodate the BSR MAC CE\n"); } else { - Debug("BSR: Including Regular BSR: grant_size=%d, total_data=%d, bsr_sz=%d\n", - grant_size, total_data, bsr_sz); - ret = true; - } + Debug("BSR: Including Regular BSR: grant_size=%d, total_data=%d, bsr_sz=%d\n", grant_size, total_data, bsr_sz); + ret = true; + } + // Restart or Start Periodic timer if (timers_db->get(timer_periodic_id)->get_timeout() && bsr->format != TRUNC_BSR) { timers_db->get(timer_periodic_id)->reset(); timers_db->get(timer_periodic_id)->run(); + Debug("BSR: Started periodicBSR-Timer\n"); } } - // Cancel all triggered BSR and SR - triggered_bsr_type = NONE; - reset_sr = true; - // Restart or Start ReTX timer + // Cancel all triggered BSR and SR + set_trigger(NONE); + reset_sr = true; + // Restart or Start ReTX timer upon indication of a grant if (timers_db->get(timer_retx_id)->get_timeout()) { timers_db->get(timer_retx_id)->reset(); timers_db->get(timer_retx_id)->run(); + Debug("BSR: Started retxBSR-Timer\n"); } - return ret; + pthread_mutex_unlock(&mutex); + return ret; } -bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) +bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t* bsr) { - bool ret = false; + bool ret = false; + + pthread_mutex_lock(&mutex); if (triggered_bsr_type != NONE || nof_padding_bytes >= 2) { - if (triggered_bsr_type == NONE) { - triggered_bsr_type = PADDING; - } generate_bsr(bsr, nof_padding_bytes); - ret = true; + ret = true; if (timers_db->get(timer_periodic_id)->get_timeout() && bsr->format != TRUNC_BSR) { timers_db->get(timer_periodic_id)->reset(); timers_db->get(timer_periodic_id)->run(); - } - + Debug("BSR: Started periodicBSR-Timer\n"); + } } - return ret; -} -void bsr_proc::set_tx_tti(uint32_t tti) { - Debug("BSR: Set next_tx_tti=%d\n", tti); - next_tx_tti = tti; + pthread_mutex_unlock(&mutex); + + return ret; } bool bsr_proc::need_to_reset_sr() { + bool ret = false; + pthread_mutex_lock(&mutex); if (reset_sr) { - reset_sr = false; - sr_is_sent = false; + reset_sr = false; + sr_is_sent = false; Debug("BSR: SR reset. sr_is_sent and reset_rs false\n"); - return true; - } else { - return false; + ret = true; } + pthread_mutex_unlock(&mutex); + return ret; } bool bsr_proc::need_to_send_sr(uint32_t tti) { + bool ret = false; + pthread_mutex_lock(&mutex); if (!sr_is_sent && triggered_bsr_type == REGULAR) { - if (srslte_tti_interval(tti,next_tx_tti)>0 && srslte_tti_interval(tti,next_tx_tti) < 10240-HARQ_DELAY_MS) { - reset_sr = false; - sr_is_sent = true; - Debug("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, next_tx_tti=%d\n", tti, next_tx_tti); - return true; - } else { - Debug("BSR: Not sending SR because tti=%d, next_tx_tti=%d\n", tti, next_tx_tti); - } - } - return false; + reset_sr = false; + sr_is_sent = true; + Info("BSR: Need to send sr: sr_is_sent=true, reset_sr=false, tti=%d, trigger_tti=%d\n", tti, trigger_tti); + ret = true; + } + pthread_mutex_unlock(&mutex); + return ret; } -void bsr_proc::setup_lcg(uint32_t lcid, uint32_t new_lcg) +void bsr_proc::setup_lcid(uint32_t lcid, uint32_t new_lcg, uint32_t priority) { - if (lcid < MAX_LCID && new_lcg < 4) { - lcg[lcid] = new_lcg; - } -} - -void bsr_proc::set_priority(uint32_t lcid, uint32_t priority) { - if (lcid < MAX_LCID) { - priorities[lcid] = priority; + if (new_lcg < NOF_LCG) { + pthread_mutex_lock(&mutex); + // First see if it already exists and eliminate it + for (int i = 0; i < NOF_LCG; i++) { + if (lcgs[i].count(lcid)) { + lcgs[i].erase(lcid); + } + } + // Now add it + lcgs[new_lcg][lcid].priority = priority; + lcgs[new_lcg][lcid].old_buffer = 0; + pthread_mutex_unlock(&mutex); + } else { + Error("BSR: Invalid lcg=%d for lcid=%d\n", new_lcg, lcid); } } -uint32_t bsr_proc::find_max_priority_lcid() { - int32_t max_prio = 0; - uint32_t max_idx = 0; - for (int i=0;i max_prio) { - max_prio = priorities[i]; - max_idx = i; +uint32_t bsr_proc::find_max_priority_lcg() +{ + int32_t max_prio = 0; + uint32_t max_idx = 0; + for (int i = 0; i < NOF_LCG; i++) { + for (std::map::iterator iter = lcgs[i].begin(); iter != lcgs[i].end(); ++iter) { + if (iter->second.priority > max_prio) { + max_prio = iter->second.priority; + max_idx = i; + } } } - return max_idx; + return max_idx; } } diff --git a/srsue/src/mac/proc_phr.cc b/srsue/src/mac/proc_phr.cc index 7635968df..a25f682d3 100644 --- a/srsue/src/mac/proc_phr.cc +++ b/srsue/src/mac/proc_phr.cc @@ -34,20 +34,20 @@ #include "srsue/hdr/mac/mux.h" #include "srslte/interfaces/ue_interfaces.h" +namespace srsue { - namespace srsue { - phr_proc::phr_proc() { - initiated = false; + initiated = false; + last_pathloss_db = 0; + ZERO_OBJECT(phr_cfg); } -void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_db_) +void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, srslte::timers* timers_db_) { phy_h = phy_h_; - log_h = log_h_; - mac_cfg = mac_cfg_; - timers_db = timers_db_; + log_h = log_h_; + timers_db = timers_db_; initiated = true; timer_periodic_id = timers_db->get_unique_id(); @@ -61,34 +61,59 @@ void phr_proc::reset() timers_db->get(timer_periodic_id)->stop(); timers_db->get(timer_prohibit_id)->stop(); phr_is_triggered = false; - timer_periodic_value = -2; - timer_prohibit_value = -2; - dl_pathloss_change = -2; +} + +void phr_proc::set_config(srsue::mac_interface_rrc::phr_cfg_t& cfg) +{ + phr_cfg = cfg; + + // First stop timers. If enabled==false or value is Inf, won't be re-started + timers_db->get(timer_periodic_id)->stop(); + timers_db->get(timer_prohibit_id)->stop(); + + if (cfg.enabled) { + // Setup timers and trigger PHR when configuration changed by higher layers + if (phr_cfg.periodic_timer > 0) { + timers_db->get(timer_periodic_id)->set(this, phr_cfg.periodic_timer); + timers_db->get(timer_periodic_id)->run(); + phr_is_triggered = true; + Info("PHR: Configured timer periodic %d ms\n", phr_cfg.periodic_timer); + } + + if (phr_cfg.prohibit_timer > 0) { + timers_db->get(timer_prohibit_id)->set(this, phr_cfg.prohibit_timer); + timers_db->get(timer_prohibit_id)->run(); + Info("PHR: Configured timer prohibit %d ms\n", phr_cfg.prohibit_timer); + phr_is_triggered = true; + } + } } bool phr_proc::pathloss_changed() { - if (not mac_cfg->main.phr_cfg_present or mac_cfg->main.phr_cfg.type() == asn1::rrc::setup_e::release) { - log_h->error("Pathloss has changed but phr_cfg is not present.\n"); + if (!phr_cfg.enabled) { return false; } - int min_change = mac_cfg->main.phr_cfg.setup().dl_pathloss_change.to_number(); - int cur_pathloss_db = (int) phy_h->get_pathloss_db(); - - if (abs(cur_pathloss_db - last_pathloss_db) > min_change && min_change > 0) { + int cur_pathloss_db = (int)phy_h->get_pathloss_db(); + + if (abs(cur_pathloss_db - last_pathloss_db) > phr_cfg.db_pathloss_change && phr_cfg.db_pathloss_change > 0) { last_pathloss_db = cur_pathloss_db; - return true; + return true; } else { return false; } } - + void phr_proc::start_timer() { timers_db->get(timer_periodic_id)->run(); } /* Trigger PHR when timers exires */ void phr_proc::timer_expired(uint32_t timer_id) { + if (!phr_cfg.enabled) { + Warning("PHR: Timer triggered but PHR has been disabled\n"); + return; + } if (timer_id == timer_periodic_id) { timers_db->get(timer_periodic_id)->reset(); timers_db->get(timer_periodic_id)->run(); @@ -106,35 +131,7 @@ void phr_proc::timer_expired(uint32_t timer_id) { void phr_proc::step(uint32_t tti) { - if (!initiated) { - return; - } - - if (mac_cfg->main.phr_cfg.type() == asn1::rrc::setup_e::setup) { - int cfg_timer_periodic = mac_cfg->main.phr_cfg.setup().periodic_phr_timer.to_number(); - - // Setup timers and trigger PHR when configuration changed by higher layers - if (timer_periodic_value != cfg_timer_periodic && cfg_timer_periodic > 0) - { - timer_periodic_value = cfg_timer_periodic; - timers_db->get(timer_periodic_id)->set(this, timer_periodic_value); - timers_db->get(timer_periodic_id)->run(); - phr_is_triggered = true; - Info("PHR: Configured timer periodic %d ms\n", timer_periodic_value); - } - - } - - if (mac_cfg->main.phr_cfg_present) { - int cfg_timer_prohibit = mac_cfg->main.phr_cfg.setup().prohibit_phr_timer.to_number(); - - if (timer_prohibit_value != cfg_timer_prohibit && cfg_timer_prohibit > 0) { - timer_prohibit_value = cfg_timer_prohibit; - timers_db->get(timer_prohibit_id)->set(this, timer_prohibit_value); - timers_db->get(timer_prohibit_id)->run(); - Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit_value); - phr_is_triggered = true; - } + if (phr_cfg.enabled && initiated) { if (pathloss_changed() && timers_db->get(timer_prohibit_id)->is_expired()) { Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%d\n", last_pathloss_db); phr_is_triggered = true; @@ -165,4 +162,8 @@ bool phr_proc::generate_phr_on_ul_grant(float *phr) } } +bool phr_proc::is_extended() +{ + return phr_cfg.extended; +} } diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 8a4bbb47e..4995a0ca2 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -49,43 +49,41 @@ uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480 // Table 7.6-1: DELTA_PREAMBLE values. int delta_preamble_db_table[5] = {0, 0, -3, -3, 8}; -void ra_proc::init(phy_interface_mac* phy_h_, - rrc_interface_mac *rrc_, - srslte::log* log_h_, - mac_interface_rrc::ue_rnti_t *rntis_, - mac_interface_rrc::mac_cfg_t *mac_cfg_, - srslte::timers::timer* time_alignment_timer_, - srslte::timers::timer* contention_resolution_timer_, - mux* mux_unit_, - demux* demux_unit_) +void ra_proc::init(phy_interface_mac* phy_h_, + rrc_interface_mac* rrc_, + srslte::log* log_h_, + mac_interface_rrc::ue_rnti_t* rntis_, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, + mux* mux_unit_) { phy_h = phy_h_; log_h = log_h_; - mac_cfg = mac_cfg_; rntis = rntis_; - mux_unit = mux_unit_; - demux_unit= demux_unit_; + mux_unit = mux_unit_; rrc = rrc_; time_alignment_timer = time_alignment_timer_; contention_resolution_timer = contention_resolution_timer_; srslte_softbuffer_rx_init(&softbuffer_rar, 10); - - // Tell demux to call us when a UE CRID is received - demux_unit->set_uecrid_callback(uecrid_callback, this); + + pthread_mutex_init(&mutex, NULL); reset(); } ra_proc::~ra_proc() { + pthread_mutex_destroy(&mutex); srslte_softbuffer_rx_free(&softbuffer_rar); } void ra_proc::reset() { state = IDLE; msg3_transmitted = false; - started_by_pdcch = false; + started_by_pdcch = false; + contention_resolution_timer->stop(); + contention_resolution_timer->reset(); } void ra_proc::start_pcap(srslte::mac_pcap* pcap_) @@ -93,10 +91,20 @@ void ra_proc::start_pcap(srslte::mac_pcap* pcap_) pcap = pcap_; } -void ra_proc::read_params() { - +void ra_proc::set_config(srsue::mac_interface_rrc::rach_cfg_t& rach_cfg) +{ + pthread_mutex_lock(&mutex); + new_cfg = rach_cfg; + pthread_mutex_unlock(&mutex); +} + +void ra_proc::read_params() +{ + pthread_mutex_lock(&mutex); + rach_cfg = new_cfg; + pthread_mutex_unlock(&mutex); + // Read initialization parameters - configIndex = mac_cfg->prach_config_index; if (noncontention_enabled) { preambleIndex = next_preamble_idx; maskIndex = next_prach_mask; @@ -105,57 +113,23 @@ void ra_proc::read_params() { preambleIndex = 0; // pass when called from higher layers for non-contention based RA maskIndex = 0; // same } - nof_preambles = mac_cfg->rach.preamb_info.nof_ra_preambs.to_number(); - if (mac_cfg->rach.preamb_info.preambs_group_a_cfg_present) { - nof_groupA_preambles = mac_cfg->rach.preamb_info.preambs_group_a_cfg.size_of_ra_preambs_group_a.to_number(); - } else { - nof_groupA_preambles = nof_preambles; - } - if (nof_groupA_preambles > nof_preambles) { - nof_groupA_preambles = nof_preambles; + if (rach_cfg.nof_groupA_preambles == 0) { + rach_cfg.nof_groupA_preambles = rach_cfg.nof_preambles; } - nof_groupB_preambles = nof_preambles - nof_groupA_preambles; - if (nof_groupB_preambles) { - messagePowerOffsetGroupB = mac_cfg->rach.preamb_info.preambs_group_a_cfg.msg_pwr_offset_group_b.to_number(); - messageSizeGroupA = mac_cfg->rach.preamb_info.preambs_group_a_cfg.msg_size_group_a.to_number(); - } - responseWindowSize = mac_cfg->rach.ra_supervision_info.ra_resp_win_size.to_number(); - powerRampingStep = mac_cfg->rach.pwr_ramp_params.pwr_ramp_step.to_number(); - preambleTransMax = mac_cfg->rach.ra_supervision_info.preamb_trans_max.to_number(); - iniReceivedTargetPower = mac_cfg->rach.pwr_ramp_params.preamb_init_rx_target_pwr.to_number(); - contentionResolutionTimer = mac_cfg->rach.ra_supervision_info.mac_contention_resolution_timer.to_number(); + phy_interface_mac::prach_info_t prach_info = phy_h->prach_get_info(); + delta_preamble_db = delta_preamble_db_table[prach_info.preamble_format % 5]; - delta_preamble_db = delta_preamble_db_table[configIndex%5]; - - if (contentionResolutionTimer > 0) { - contention_resolution_timer->set(this, contentionResolutionTimer); + if (rach_cfg.contentionResolutionTimer > 0) { + contention_resolution_timer->set(this, rach_cfg.contentionResolutionTimer); } - -} - -bool ra_proc::in_progress() -{ - return (state > IDLE && state != COMPLETION_DONE); -} - -bool ra_proc::is_successful() { - return state == COMPLETION_DONE; -} - -bool ra_proc::is_response_error() { - return state == RESPONSE_ERROR; } bool ra_proc::is_contention_resolution() { return state == CONTENTION_RESOLUTION; } -bool ra_proc::is_error() { - return state == RA_PROBLEM; -} - const char* state_str[12] = {"Idle", "RA: INIT: ", "RA: Select: ", @@ -201,7 +175,7 @@ void ra_proc::process_timeadv_cmd(uint32_t ta) { void ra_proc::step_initialization() { read_params(); - pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; + pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; transmitted_contention_id = 0; preambleTransmissionCounter = 1; first_rar_received = true; @@ -220,8 +194,14 @@ void ra_proc::step_initialization() { state = RESOURCE_SELECTION; } -void ra_proc::step_resource_selection() { - ra_group_t sel_group; +void ra_proc::step_resource_selection() +{ + ra_group_t sel_group; + + uint32_t nof_groupB_preambles = 0; + if (rach_cfg.nof_groupA_preambles > 0) { + nof_groupB_preambles = rach_cfg.nof_preambles - rach_cfg.nof_groupA_preambles; + } if (preambleIndex > 0) { // Preamble is chosen by Higher layers (ie Network) @@ -230,19 +210,20 @@ void ra_proc::step_resource_selection() { } else { // Preamble is chosen by MAC UE if (!msg3_transmitted) { - if (nof_groupB_preambles > 0 && new_ra_msg_len > messageSizeGroupA) { // Check also pathloss (Pcmax,deltaPreamble and powerOffset) + if (nof_groupB_preambles && + new_ra_msg_len > rach_cfg.messageSizeGroupA) { // Check also pathloss (Pcmax,deltaPreamble and powerOffset) sel_group = RA_GROUP_B; } else { sel_group = RA_GROUP_A; } last_msg3_group = sel_group; } else { - sel_group = last_msg3_group; + sel_group = last_msg3_group; } if (sel_group == RA_GROUP_A) { - if (nof_groupA_preambles) { + if (rach_cfg.nof_groupA_preambles) { // randomly choose preamble from [0 nof_groupA_preambles) - sel_preamble = rand() % nof_groupA_preambles; + sel_preamble = rand() % rach_cfg.nof_groupA_preambles; } else { rError("Selected group preamble A but nof_groupA_preambles=0\n"); state = RA_PROBLEM; @@ -251,7 +232,7 @@ void ra_proc::step_resource_selection() { } else { if (nof_groupB_preambles) { // randomly choose preamble from [nof_groupA_preambles nof_groupB_preambles) - sel_preamble = nof_groupA_preambles + rand() % nof_groupB_preambles; + sel_preamble = rach_cfg.nof_groupA_preambles + rand() % nof_groupB_preambles; } else { rError("Selected group preamble B but nof_groupA_preambles=0\n"); state = RA_PROBLEM; @@ -261,62 +242,79 @@ void ra_proc::step_resource_selection() { sel_maskIndex = 0; } - rDebug("Selected preambleIndex=%d maskIndex=%d GroupA=%d, GroupB=%d\n", - sel_preamble, sel_maskIndex,nof_groupA_preambles, nof_groupB_preambles); + rDebug("Selected preambleIndex=%d maskIndex=%d GroupA=%d, GroupB=%d\n", + sel_preamble, + sel_maskIndex, + rach_cfg.nof_groupA_preambles, + nof_groupB_preambles); state = PREAMBLE_TRANSMISSION; } void ra_proc::step_preamble_transmission() { - received_target_power_dbm = iniReceivedTargetPower + - delta_preamble_db + - (preambleTransmissionCounter-1)*powerRampingStep; - - rar_received = false; - phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm); + + received_target_power_dbm = rach_cfg.iniReceivedTargetPower + delta_preamble_db + + (preambleTransmissionCounter - 1) * rach_cfg.powerRampingStep; + + rar_received = false; + phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm); state = PDCCH_SETUP; } -void ra_proc::step_pdcch_setup() { - - int ra_tti = phy_h->prach_tx_tti(); - if (ra_tti > 0) { - ra_rnti = 1+ra_tti%10; - rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d\n", sel_preamble, ra_rnti, ra_tti); +bool ra_proc::is_rar_window(int* rar_window_start, int* rar_window_length) +{ + if (state == RESPONSE_RECEPTION) { + if (rar_window_length) { + *rar_window_length = rach_cfg.responseWindowSize; + } + if (rar_window_start) { + *rar_window_start = rar_window_st; + } + return true; + } else { + if (rar_window_length) { + *rar_window_length = -1; + } + return false; + } +} + +void ra_proc::step_pdcch_setup() +{ + + phy_interface_mac::prach_info_t info = phy_h->prach_get_info(); + if (info.is_transmitted) { + ra_rnti = 1 + info.tti_ra % 10 + info.f_id; + rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d, f_id=%d\n", sel_preamble, ra_rnti, info.tti_ra, info.f_id); log_h->console("Random Access Transmission: seq=%d, ra-rnti=0x%x\n", sel_preamble, ra_rnti); - phy_h->pdcch_dl_search(SRSLTE_RNTI_RAR, ra_rnti, ra_tti+3, ra_tti+3+responseWindowSize); - state = RESPONSE_RECEPTION; + rar_window_st = info.tti_ra + 3; + rntis->rar_rnti = ra_rnti; + state = RESPONSE_RECEPTION; } } -void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action) +void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action) { - if (grant.n_bytes[0] < MAX_RAR_PDU_LEN) { - rDebug("DL grant found RA-RNTI=%d\n", ra_rnti); - action->decode_enabled[0] = true; - action->decode_enabled[1] = false; - action->default_ack[0] = false; - action->generate_ack = false; - action->payload_ptr[0] = rar_pdu_buffer; - action->rnti = grant.rnti; - memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->rv[0] = grant.rv[0]; - action->softbuffers[0] = &softbuffer_rar; - rar_grant_nbytes = grant.n_bytes[0]; - rar_grant_tti = grant.tti; - if (action->rv[0] == 0) { + bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); + + if (grant.tb[0].tbs < MAX_RAR_PDU_LEN) { + rDebug("DL dci found RA-RNTI=%d\n", ra_rnti); + action->tb[0].enabled = true; + action->tb[0].payload = rar_pdu_buffer; + action->tb[0].rv = grant.tb[0].rv; + action->tb[0].softbuffer.rx = &softbuffer_rar; + rar_grant_nbytes = grant.tb[0].tbs; + if (action->tb[0].rv == 0) { srslte_softbuffer_rx_reset(&softbuffer_rar); } } else { - rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes[0], MAX_RAR_PDU_LEN); - action->decode_enabled[0] = false; - action->decode_enabled[1] = false; + rError("Received RAR dci exceeds buffer length (%d>%d)\n", grant.tb[0].tbs, MAX_RAR_PDU_LEN); state = RESPONSE_ERROR; } } void ra_proc::tb_decoded_ok() { if (pcap) { - pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, rar_grant_tti); + pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, 0); } rDebug("RAR decoded successfully TBS=%d\n", rar_grant_nbytes); @@ -344,14 +342,16 @@ void ra_proc::tb_decoded_ok() { uint8_t grant[srslte::rar_subh::RAR_GRANT_LEN]; rar_pdu_msg.get()->get_sched_grant(grant); - phy_h->pdcch_dl_search_reset(); - - phy_h->set_rar_grant(rar_grant_tti, grant); - + rntis->rar_rnti = 0; + phy_h->set_rar_grant(grant, rar_pdu_msg.get()->get_temp_crnti()); + current_ta = rar_pdu_msg.get()->get_ta_cmd(); - - rInfo("RAPID=%d, TA=%d\n", sel_preamble, rar_pdu_msg.get()->get_ta_cmd()); - + + rInfo("RAPID=%d, TA=%d, T-CRNTI=0x%x\n", + sel_preamble, + rar_pdu_msg.get()->get_ta_cmd(), + rar_pdu_msg.get()->get_temp_crnti()); + if (preambleIndex > 0) { // Preamble selected by Network state = COMPLETION; @@ -359,40 +359,40 @@ void ra_proc::tb_decoded_ok() { // Preamble selected by UE MAC mux_unit->msg3_prepare(); rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti(); - phy_h->pdcch_dl_search(SRSLTE_RNTI_TEMP, rar_pdu_msg.get()->get_temp_crnti()); - + if (first_rar_received) { - first_rar_received = false; - - // Save transmitted C-RNTI (if any) + first_rar_received = false; + + // Save transmitted C-RNTI (if any) transmitted_crnti = rntis->crnti; - + // If we have a C-RNTI, tell Mux unit to append C-RNTI CE if no CCCH SDU transmission if (transmitted_crnti) { rInfo("Appending C-RNTI MAC CE 0x%x in next transmission\n", transmitted_crnti); mux_unit->append_crnti_ce_next_tx(transmitted_crnti); - phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, transmitted_crnti); - phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, transmitted_crnti); - } - } + rntis->crnti = transmitted_crnti; + } + } rDebug("Going to Contention Resolution state\n"); state = CONTENTION_RESOLUTION; - - // Start contention resolution timer + + // Start contention resolution timer + rInfo("Starting ContentionResolutionTimer=%d ms\n", contention_resolution_timer->get_timeout()); contention_resolution_timer->reset(); contention_resolution_timer->run(); - } + } } else { rInfo("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid()); } } } -void ra_proc::step_response_reception() { +void ra_proc::step_response_reception(uint32_t tti) +{ // do nothing. Processing done in tb_decoded_ok() - int ra_tti = phy_h->prach_tx_tti(); - if (ra_tti >= 0 && !rar_received) { - uint32_t interval = srslte_tti_interval(phy_h->get_current_tti(), ra_tti+3+responseWindowSize); + phy_interface_mac::prach_info_t prach_info = phy_h->prach_get_info(); + if (prach_info.is_transmitted && !rar_received) { + uint32_t interval = srslte_tti_interval(tti, prach_info.tti_ra + 3 + rach_cfg.responseWindowSize); if (interval > 1 && interval < 100) { Error("RA response not received within the response window\n"); state = RESPONSE_ERROR; @@ -400,43 +400,40 @@ void ra_proc::step_response_reception() { } } -void ra_proc::step_response_error() +void ra_proc::step_response_error(uint32_t tti) { preambleTransmissionCounter++; - if (preambleTransmissionCounter >= preambleTransMax + 1) { - rError("Maximum number of transmissions reached (%d)\n", preambleTransMax); + if (preambleTransmissionCounter >= rach_cfg.preambleTransMax + 1) { + rError("Maximum number of transmissions reached (%d)\n", rach_cfg.preambleTransMax); rrc->ra_problem(); state = RA_PROBLEM; if (ra_is_ho) { rrc->ho_ra_completed(false); } } else { - backoff_interval_start = phy_h->get_current_tti(); + backoff_interval_start = tti; if (backoff_param_ms) { - backoff_inteval = rand()%backoff_param_ms; + backoff_inteval = rand() % backoff_param_ms; } else { backoff_inteval = 0; } if (backoff_inteval) { rDebug("Backoff wait interval %d\n", backoff_inteval); - state = BACKOFF_WAIT; + state = BACKOFF_WAIT; } else { - rDebug("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, preambleTransMax); + rDebug("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, rach_cfg.preambleTransMax); state = RESOURCE_SELECTION; } } } -void ra_proc::step_backoff_wait() { - if (srslte_tti_interval(phy_h->get_current_tti(), backoff_interval_start) >= backoff_inteval) { +void ra_proc::step_backoff_wait(uint32_t tti) +{ + if (srslte_tti_interval(tti, backoff_interval_start) >= backoff_inteval) { state = RESOURCE_SELECTION; } } -bool ra_proc::uecrid_callback(void *arg, uint64_t uecri) { - return ((ra_proc*) arg)->contention_resolution_id_received(uecri); -} - // Random Access initiated by RRC by the transmission of CCCH SDU bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) { bool uecri_successful = false; @@ -449,40 +446,35 @@ bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) { if (transmitted_contention_id == rx_contention_id) { // UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3 - rntis->crnti = rntis->temp_rnti; - // finish the disassembly and demultiplexing of the MAC PDU uecri_successful = true; state = COMPLETION; } else { rInfo("Transmitted UE Contention Id differs from received Contention ID (0x%" PRIu64 " != 0x%" PRIu64 ")\n", transmitted_contention_id, rx_contention_id); - // Discard MAC PDU + // Discard MAC PDU uecri_successful = false; // Contention Resolution not successfully is like RAR not successful // FIXME: Need to flush Msg3 HARQ buffer. Why? - state = RESPONSE_ERROR; - } - rntis->temp_rnti = 0; - + state = RESPONSE_ERROR; + } + return uecri_successful; } void ra_proc::step_contention_resolution() { // If Msg3 has been sent if (mux_unit->msg3_is_transmitted()) - { - msg3_transmitted = true; - if (transmitted_crnti) - { + { + msg3_transmitted = true; + if (transmitted_crnti) { // Random Access with transmission of MAC C-RNTI CE if ((!started_by_pdcch && pdcch_to_crnti_received == PDCCH_CRNTI_UL_GRANT) || (started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)) { rDebug("PDCCH for C-RNTI received\n"); contention_resolution_timer->stop(); - rntis->temp_rnti = 0; - state = COMPLETION; + state = COMPLETION; } pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; } else { @@ -496,19 +488,24 @@ void ra_proc::step_contention_resolution() { } else { rDebug("Msg3 not yet transmitted\n"); } - } -void ra_proc::step_completition() { +void ra_proc::step_completition() +{ + + // Start looking for PDCCH CRNTI + if (!transmitted_crnti) { + rntis->crnti = rntis->temp_rnti; + } + rntis->temp_rnti = 0; + log_h->console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta); rInfo("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta); + if (!msg3_flushed) { mux_unit->msg3_flush(); msg3_flushed = true; } - // Configure PHY to look for UL C-RNTI grants - phy_h->pdcch_ul_search(SRSLTE_RNTI_USER, rntis->crnti); - phy_h->pdcch_dl_search(SRSLTE_RNTI_USER, rntis->crnti); phy_h->set_crnti(rntis->crnti); @@ -529,22 +526,22 @@ void ra_proc::step(uint32_t tti_) break; case RESOURCE_SELECTION: step_resource_selection(); - break; + break; case PREAMBLE_TRANSMISSION: step_preamble_transmission(); - break; - case PDCCH_SETUP: + break; + case PDCCH_SETUP: step_pdcch_setup(); - break; - case RESPONSE_RECEPTION: - step_response_reception(); - break; + break; + case RESPONSE_RECEPTION: + step_response_reception(tti_); + break; case RESPONSE_ERROR: - step_response_error(); - break; + step_response_error(tti_); + break; case BACKOFF_WAIT: - step_backoff_wait(); - break; + step_backoff_wait(tti_); + break; case CONTENTION_RESOLUTION: step_contention_resolution(); break; @@ -587,13 +584,12 @@ void ra_proc::start_pdcch_order() void ra_proc::timer_expired(uint32_t timer_id) { rInfo("Contention Resolution Timer expired. Stopping PDCCH Search and going to Response Error\n"); - rntis->temp_rnti = 0; + bzero(rntis, sizeof(mac_interface_rrc::ue_rnti_t)); state = RESPONSE_ERROR; - phy_h->pdcch_dl_search_reset(); } void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) { - rDebug("PDCCH to C-RNTI received %s UL grant\n", contains_uplink_grant?"with":"without"); + rDebug("PDCCH to C-RNTI received %s UL dci\n", contains_uplink_grant ? "with" : "without"); if (contains_uplink_grant) { pdcch_to_crnti_received = PDCCH_CRNTI_UL_GRANT; } else if (pdcch_to_crnti_received == PDCCH_CRNTI_NOT_RECEIVED) { @@ -606,5 +602,11 @@ void ra_proc::harq_retx() contention_resolution_timer->reset(); } +void ra_proc::harq_max_retx() +{ + Warning("Contention Resolution is considered not successful. Stopping PDCCH Search and going to Response Error\n"); + bzero(rntis, sizeof(mac_interface_rrc::ue_rnti_t)); + state = RESPONSE_ERROR; +} } diff --git a/srsue/src/mac/proc_sr.cc b/srsue/src/mac/proc_sr.cc index e699b7611..3e8552ea6 100644 --- a/srsue/src/mac/proc_sr.cc +++ b/srsue/src/mac/proc_sr.cc @@ -35,17 +35,15 @@ namespace srsue { sr_proc::sr_proc() { - initiated = false; + initiated = false; } - -void sr_proc::init(phy_interface_mac* phy_h_, rrc_interface_mac *rrc_, srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_) + +void sr_proc::init(phy_interface_mac* phy_h_, rrc_interface_mac* rrc_, srslte::log* log_h_) { log_h = log_h_; rrc = rrc_; - mac_cfg = mac_cfg_; phy_h = phy_h_; initiated = true; - dsr_transmax = 0; sr_counter = 0; do_ra = false; } @@ -73,12 +71,17 @@ bool sr_proc::need_tx(uint32_t tti) return false; } +void sr_proc::set_config(srsue::mac_interface_rrc::sr_cfg_t& cfg) +{ + sr_cfg = cfg; +} + void sr_proc::step(uint32_t tti) { if (initiated) { if (is_pending_sr) { - if (mac_cfg->sr.type() == asn1::rrc::setup_e::setup) { - if (sr_counter < dsr_transmax) { + if (sr_cfg.enabled) { + if (sr_counter < sr_cfg.dsr_transmax) { if (sr_counter == 0 || need_tx(tti)) { sr_counter++; Info("SR: Signalling PHY sr_counter=%d\n", sr_counter); @@ -86,8 +89,9 @@ void sr_proc::step(uint32_t tti) } } else { if (need_tx(tti)) { - Info("SR: Releasing PUCCH/SRS resources, sr_counter=%d, dsr_transmax=%d\n", - sr_counter, dsr_transmax); + Info("SR: Releasing PUCCH/SRS resources, sr_counter=%d, dsr_transmax=%d\n", + sr_counter, + sr_cfg.dsr_transmax); log_h->console("Scheduling request failed: releasing RRC connection...\n"); rrc->release_pucch_srs(); do_ra = true; @@ -120,11 +124,10 @@ void sr_proc::start() if (initiated) { if (!is_pending_sr) { sr_counter = 0; - is_pending_sr = true; + is_pending_sr = true; } - if (mac_cfg->sr.type() == asn1::rrc::setup_e::setup) { - dsr_transmax = mac_cfg->sr.setup().dsr_trans_max.to_number(); - Info("SR: Starting Procedure. dsrTransMax=%d\n", dsr_transmax); + if (sr_cfg.enabled) { + Info("SR: Starting Procedure. dsrTransMax=%d\n", sr_cfg.dsr_transmax); } } } diff --git a/srsue/src/mac/ul_harq.cc b/srsue/src/mac/ul_harq.cc new file mode 100644 index 000000000..5810e62b8 --- /dev/null +++ b/srsue/src/mac/ul_harq.cc @@ -0,0 +1,401 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/. + * + */ + +#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) + +#include "srsue/hdr/mac/ul_harq.h" +#include "srslte/common/interfaces_common.h" +#include "srslte/common/log.h" +#include "srslte/common/mac_pcap.h" +#include "srslte/common/timers.h" +#include "srslte/interfaces/ue_interfaces.h" + +namespace srsue { + +ul_harq_entity::ul_harq_entity() : proc(SRSLTE_MAX_HARQ_PROC) +{ + pcap = NULL; + mux_unit = NULL; + ra_procedure = NULL; + log_h = NULL; + rntis = NULL; + average_retx = 0; + nof_pkts = 0; +} + +bool ul_harq_entity::init(srslte::log* log_h_, + mac_interface_rrc_common::ue_rnti_t* rntis_, + ra_proc* ra_procedure_, + mux* mux_unit_) +{ + log_h = log_h_; + mux_unit = mux_unit_; + ra_procedure = ra_procedure_; + rntis = rntis_; + + for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) { + if (!proc[i].init(i, this)) { + return false; + } + } + return true; +} + +void ul_harq_entity::reset() +{ + for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) { + proc[i].reset(); + } + ul_sps_assig.clear(); +} + +void ul_harq_entity::reset_ndi() +{ + for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) { + proc[i].reset_ndi(); + } +} + +void ul_harq_entity::set_config(srsue::mac_interface_rrc_common::ul_harq_cfg_t& harq_cfg) +{ + this->harq_cfg = harq_cfg; +} + +void ul_harq_entity::start_pcap(srslte::mac_pcap* pcap_) +{ + pcap = pcap_; +} + +/***************** PHY->MAC interface for UL processes **************************/ +void ul_harq_entity::new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action) +{ + bzero(action, sizeof(mac_interface_phy::tb_action_ul_t)); + + if (grant.pid >= SRSLTE_MAX_HARQ_PROC) { + Error("Invalid PID: %d\n", grant.pid); + return; + } + if (grant.rnti == rntis->crnti || grant.rnti == rntis->temp_rnti || SRSLTE_RNTI_ISRAR(grant.rnti)) { + if (grant.rnti == rntis->crnti && proc[grant.pid].is_sps()) { + grant.tb.ndi = true; + } + proc[grant.pid].new_grant_ul(grant, action); + } else if (grant.rnti == rntis->sps_rnti) { + if (grant.tb.ndi) { + grant.tb.ndi = proc[grant.pid].get_ndi(); + proc[grant.pid].new_grant_ul(grant, action); + } else { + Info("Not implemented\n"); + } + } else { + Warning("Received grant for unknnown rnti=0x%x\n", grant.rnti); + } +} + +int ul_harq_entity::get_current_tbs(uint32_t pid) +{ + if (pid >= SRSLTE_MAX_HARQ_PROC) { + Error("Invalid PID: %d\n", pid); + return 0; + } + return proc[pid].get_current_tbs(); +} + +float ul_harq_entity::get_average_retx() +{ + return average_retx; +} + +ul_harq_entity::ul_harq_process::ul_harq_process() +{ + log_h = NULL; + pdu_ptr = NULL; + payload_buffer = NULL; + + bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_ul_t)); + + harq_feedback = false; + is_initiated = false; + is_grant_configured = false; + + pid = 0; + current_tx_nb = 0; + current_irv = 0; +} + +ul_harq_entity::ul_harq_process::~ul_harq_process() +{ + if (is_initiated) { + if (payload_buffer) { + free(payload_buffer); + } + srslte_softbuffer_tx_free(&softbuffer); + } +} + +bool ul_harq_entity::ul_harq_process::init(uint32_t pid, ul_harq_entity* parent) +{ + if (srslte_softbuffer_tx_init(&softbuffer, 110)) { + ERROR("Error initiating soft buffer\n"); + return false; + } + + harq_entity = parent; + log_h = harq_entity->log_h; + is_initiated = true; + this->pid = pid; + + payload_buffer = (uint8_t*)srslte_vec_malloc(payload_buffer_len * sizeof(uint8_t)); + if (!payload_buffer) { + Error("Allocating memory\n"); + return false; + } + pdu_ptr = payload_buffer; + return true; +} + +void ul_harq_entity::ul_harq_process::reset() +{ + current_tx_nb = 0; + current_irv = 0; + is_grant_configured = false; + bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_ul_t)); +} + +void ul_harq_entity::ul_harq_process::reset_ndi() +{ + cur_grant.tb.ndi = false; +} + +#define grant_is_rar() (grant.rnti == harq_entity->rntis->temp_rnti) + +void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, + mac_interface_phy::tb_action_ul_t* action) +{ + if (grant.phich_available) { + if (grant.tb.ndi_present && (grant.tb.ndi == get_ndi()) && (grant.tb.tbs != 0)) { + harq_feedback = false; + } else { + harq_feedback = grant.hi_value; + } + + if (grant.rnti == harq_entity->rntis->crnti && harq_entity->ra_procedure->is_contention_resolution()) { + harq_entity->ra_procedure->pdcch_to_crnti(true); + } + + // Get maximum retransmissions + uint32_t max_retx; + if (grant_is_rar()) { + max_retx = harq_entity->harq_cfg.max_harq_msg3_tx; + } else { + max_retx = harq_entity->harq_cfg.max_harq_tx; + } + + // Check maximum retransmissions, do not consider last retx ACK + if (current_tx_nb >= max_retx && !grant.hi_value) { + Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx); + if (grant_is_rar()) { + harq_entity->ra_procedure->harq_max_retx(); + } + reset(); + } else if (grant_is_rar()) { + harq_entity->ra_procedure->harq_retx(); + } + } + + // Reset HARQ process if TB has changed + if (harq_feedback && has_grant() && grant.tb.ndi_present) { + if (grant.tb.tbs != cur_grant.tb.tbs && cur_grant.tb.tbs > 0 && grant.tb.tbs > 0) { + Debug( + "UL %d: Reset due to change of dci size last_grant=%d, new_grant=%d\n", pid, cur_grant.tb.tbs, grant.tb.tbs); + reset(); + } + } + // Receive and route HARQ feedbacks + if (grant.tb.ndi_present) { + /* If TBS != 0, it's a CQI request, don't read PDU from RLC */ + if (grant.tb.tbs == 0) { + action->tb.enabled = true; + + } else if ((grant.rnti == harq_entity->rntis->crnti && // If C-RNTI + ((grant.tb.ndi != get_ndi()) || !has_grant())) || // if NDI toggled or is first dci is a new tx + grant_is_rar()) // If T-CRNTI received in RAR has no RV information + { + // New transmission + reset(); + + // Check buffer size + if (grant.tb.tbs > payload_buffer_len) { + Error("Grant size exceeds payload buffer size (%d > %d)\n", grant.tb.tbs, payload_buffer_len); + return; + } + + // Uplink dci in a RAR and there is a PDU in the Msg3 buffer + if (grant_is_rar()) { + if (harq_entity->mux_unit->msg3_is_pending()) { + Debug("Getting Msg3 buffer payload, dci size=%d bytes\n", grant.tb.tbs); + pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant.tb.tbs); + if (pdu_ptr) { + generate_new_tx(grant, action); + } else { + Warning("UL RAR dci available but no Msg3 on buffer\n"); + } + } else { + Warning("UL RAR available but no Msg3 pending on buffer\n"); + } + // Normal UL dci + } else { + // Request a MAC PDU from the Multiplexing & Assemble Unit + pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant.tb.tbs, pid); + if (pdu_ptr) { + generate_new_tx(grant, action); + } else { + Warning("Uplink dci but no MAC PDU in Multiplex Unit buffer\n"); + } + } + } else if (has_grant()) { + // Adaptive Re-TX + generate_retx(grant, action); + } else { + Warning("UL %d: Received retransmission but no previous dci available for this PID.\n", pid); + } + if (harq_entity->pcap) { + uint16_t rnti; + if (grant_is_rar() && harq_entity->rntis->temp_rnti) { + rnti = harq_entity->rntis->temp_rnti; + } else { + rnti = harq_entity->rntis->crnti; + } + harq_entity->pcap->write_ul_crnti(pdu_ptr, grant.tb.tbs, rnti, get_nof_retx(), 0); + } + } else if (has_grant()) { + // Non-Adaptive Re-Tx + generate_retx(grant, action); + } +} + +uint32_t ul_harq_entity::ul_harq_process::get_rv() +{ + int rv_of_irv[4] = {0, 2, 3, 1}; + return rv_of_irv[current_irv % 4]; +} + +bool ul_harq_entity::ul_harq_process::has_grant() +{ + return is_grant_configured; +} + +bool ul_harq_entity::ul_harq_process::get_ndi() +{ + return cur_grant.tb.ndi; +} + +bool ul_harq_entity::ul_harq_process::is_sps() +{ + return false; +} + +uint32_t ul_harq_entity::ul_harq_process::get_nof_retx() +{ + return current_tx_nb; +} + +int ul_harq_entity::ul_harq_process::get_current_tbs() +{ + return cur_grant.tb.tbs; +} + +// Retransmission with or w/o dci (Section 5.4.2.2) +void ul_harq_entity::ul_harq_process::generate_retx(mac_interface_phy::mac_grant_ul_t grant, + mac_interface_phy::tb_action_ul_t* action) +{ + int irv_of_rv[4] = {0, 3, 1, 2}; + + // HARQ entity requests an adaptive transmission + if (grant.tb.ndi_present) { + if (grant.tb.rv) { + current_irv = irv_of_rv[grant.tb.rv % 4]; + } + + Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d, HI=%s, ndi=%d, prev_ndi=%d\n", + pid, + current_tx_nb, + get_rv(), + grant.tb.tbs, + harq_feedback ? "ACK" : "NACK", + grant.tb.ndi, + cur_grant.tb.ndi); + + cur_grant = grant; + harq_feedback = false; + + generate_tx(action); + + // HARQ entity requests a non-adaptive transmission + } else if (!harq_feedback) { + // Non-adaptive retx are only sent if HI=NACK. If HI=ACK but no dci was received do not reset PID + Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d, HI=%s\n", + pid, + current_tx_nb, + get_rv(), + cur_grant.tb.tbs, + harq_feedback ? "ACK" : "NACK"); + + generate_tx(action); + } +} + +// New transmission (Section 5.4.2.2) +void ul_harq_entity::ul_harq_process::generate_new_tx(mac_interface_phy::mac_grant_ul_t grant, + mac_interface_phy::tb_action_ul_t* action) +{ + // Compute average number of retransmissions per packet considering previous packet + harq_entity->average_retx = SRSLTE_VEC_CMA((float)current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++); + cur_grant = grant; + harq_feedback = false; + is_grant_configured = true; + current_tx_nb = 0; + current_irv = 0; + + Info("UL %d: New TX%s, RV=%d, TBS=%d\n", pid, grant_is_rar() ? " for Msg3" : "", get_rv(), cur_grant.tb.tbs); + generate_tx(action); +} + +// Transmission of pending frame (Section 5.4.2.2) +void ul_harq_entity::ul_harq_process::generate_tx(mac_interface_phy::tb_action_ul_t* action) +{ + current_tx_nb++; + + action->current_tx_nb = current_tx_nb; + action->expect_ack = true; + + action->tb.rv = cur_grant.tb.rv > 0 ? cur_grant.tb.rv : get_rv(); + action->tb.enabled = true; + action->tb.payload = pdu_ptr; + action->tb.softbuffer.tx = &softbuffer; + + current_irv = (current_irv + 1) % 4; +} + +} // namespace srsue diff --git a/srsue/src/main.cc b/srsue/src/main.cc index f23bd3b08..8a3329bf5 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -45,6 +45,9 @@ #include "srslte/common/metrics_hub.h" #include "srslte/version.h" +extern uint32_t zero_tti; +extern bool simulate_rlf; + using namespace std; using namespace srsue; namespace bpo = boost::program_options; @@ -74,17 +77,22 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("rf.ul_freq", bpo::value(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") ("rf.rx_gain", bpo::value(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") ("rf.tx_gain", bpo::value(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") - ("rf.nof_rx_ant", bpo::value(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas") + ("rf.nof_radios", bpo::value(&args->rf.nof_radios)->default_value(1), "Number of available RF devices") + ("rf.nof_rf_channels", bpo::value(&args->rf.nof_rf_channels)->default_value(1), "Number of RF channels per radio") + ("rf.nof_rx_ant", bpo::value(&args->rf.nof_rx_ant)->default_value(1), "Number of RX antennas per channel") ("rf.device_name", bpo::value(&args->rf.device_name)->default_value("auto"), "Front-end device name") - ("rf.device_args", bpo::value(&args->rf.device_args)->default_value("auto"), "Front-end device arguments") + ("rf.device_args", bpo::value(&args->rf.device_args[0])->default_value("auto"), "Front-end device arguments") + ("rf.device_args_2", bpo::value(&args->rf.device_args[1])->default_value("auto"), "Front-end device 2 arguments") + ("rf.device_args_3", bpo::value(&args->rf.device_args[2])->default_value("auto"), "Front-end device 3 arguments") ("rf.time_adv_nsamples", bpo::value(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance") ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") ("rf.continuous_tx", bpo::value(&args->rf.continuous_tx)->default_value("auto"), "Transmit samples continuously to the radio or on bursts (auto/yes/no). Default is auto (yes for UHD, no for rest)") ("rrc.feature_group", bpo::value(&args->rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the" "UECapabilityInformation message. Default 0xe6041000") - ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") + ("rrc.ue_category", bpo::value(&args->rrc.ue_category_str)->default_value(SRSLTE_UE_CATEGORY_DEFAULT), "UE Category (1 to 10)") + ("rrc.release", bpo::value(&args->rrc.release)->default_value(8), "UE Release (8 to 10)") ("nas.apn", bpo::value(&args->nas.apn_name)->default_value(""), "Set Access Point Name (APN) for data services") ("nas.apn_protocol", bpo::value(&args->nas.apn_protocol)->default_value(""), "Set Access Point Name (APN) protocol for data services") @@ -98,11 +106,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") ("pcap.nas_enable", bpo::value(&args->pcap.nas_enable)->default_value(false), "Enable NAS packet captures for wireshark") ("pcap.nas_filename", bpo::value(&args->pcap.nas_filename)->default_value("ue_nas.pcap"), "NAS layer capture filename (useful when NAS encryption is enabled)") - - ("trace.enable", bpo::value(&args->trace.enable)->default_value(false), "Enable PHY and radio timing traces") - ("trace.phy_filename", bpo::value(&args->trace.phy_filename)->default_value("ue.phy_trace"), "PHY timing traces filename") - ("trace.radio_filename", bpo::value(&args->trace.radio_filename)->default_value("ue.radio_trace"), "Radio timing traces filename") - + ("gui.enable", bpo::value(&args->gui.enable)->default_value(false), "Enable GUI plots") ("log.phy_level", bpo::value(&args->log.phy_level), "PHY log level") @@ -220,12 +224,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) bpo::value(&args->expert.phy.pdsch_max_its)->default_value(8), "Maximum number of turbo decoder iterations") - ("expert.attach_enable_64qam", - bpo::value(&args->expert.phy.attach_enable_64qam)->default_value(false), - "PUSCH 64QAM modulation before attachment") - ("expert.nof_phy_threads", - bpo::value(&args->expert.phy.nof_phy_threads)->default_value(2), + bpo::value(&args->expert.phy.nof_phy_threads)->default_value(3), "Number of PHY threads") ("expert.equalizer_mode", @@ -251,7 +251,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.cfo_correct_tol_hz", bpo::value(&args->expert.phy.cfo_correct_tol_hz)->default_value(1.0), - "Tolerance (in Hz) for digital CFO compensation (needs to be low if average_subframe_enabled=true.") + "Tolerance (in Hz) for digital CFO compensation (needs to be low if interpolate_subframe_enabled=true.") ("expert.cfo_pss_ema", bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(DEFAULT_CFO_EMA_TRACK), @@ -286,9 +286,9 @@ void parse_args(all_args_t* args, int argc, char* argv[]) bpo::value(&args->expert.phy.sic_pss_enabled)->default_value(false), "Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.") - ("expert.average_subframe_enabled", - bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(true), - "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") + ("expert.interpolate_subframe_enabled", + bpo::value(&args->expert.phy.interpolate_subframe_enabled)->default_value(false), + "Interpolates in the time domain the channel estimates within 1 subframe.") ("expert.estimator_fil_auto", bpo::value(&args->expert.phy.estimator_fil_auto)->default_value(false), @@ -302,6 +302,10 @@ void parse_args(all_args_t* args, int argc, char* argv[]) bpo::value(&args->expert.phy.estimator_fil_order)->default_value(4), "Sets the channel estimator smooth gaussian filter order (even values perform better).") + ("expert.snr_to_cqi_offset", + bpo::value(&args->expert.phy.snr_to_cqi_offset)->default_value(0), + "Sets an offset in the SNR to CQI table. This is used to adjust the reported CQI.") + ("expert.sss_algorithm", bpo::value(&args->expert.phy.sss_algorithm)->default_value("full"), "Selects the SSS estimation algorithm.") @@ -457,7 +461,7 @@ void sig_int_handler(int signo) { sigcnt++; running = false; - printf("Stopping srsUE... Press Ctrl+C %d more times to force stop\n", 10 - sigcnt); + cout << "Stopping srsUE... Press Ctrl+C " << (10 - sigcnt) << " more times to force stop" << endl; if (sigcnt >= 10) { exit(-1); } @@ -480,6 +484,12 @@ void* input_loop(void* m) cout << "Enter t to restart trace." << endl; } metrics_screen.toggle_print(do_metrics); + } else if (0 == key.compare("rlf")) { + simulate_rlf = true; + cout << "Sending Radio Link Failure" << endl; + } else if (0 == key.find("zeros ")) { + zero_tti = std::stoi(key.substr(6)); + cout << "Receiving zeros for " << zero_tti << " ms" << endl; } else if (0 == key.compare("q")) { running = false; } else if (0 == key.compare("mbms")) { @@ -544,15 +554,15 @@ int main(int argc, char* argv[]) pthread_t input; pthread_create(&input, NULL, &input_loop, &args); - printf("Attaching UE...\n"); + cout << "Attaching UE..." << endl; while (!ue->switch_on() && running) { sleep(1); } if (running) { if (args.expert.pregenerate_signals) { - printf("Pre-generating signals...\n"); + cout << "Pre-generating signals..." << endl; ue->pregenerate_signals(true); - printf("Done pregenerating signals.\n"); + cout << "Done pregenerating signals." << endl; } if (args.gui.enable) { ue->start_plot(); diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc index 2199a253d..3bfb44bc4 100644 --- a/srsue/src/metrics_csv.cc +++ b/srsue/src/metrics_csv.cc @@ -79,28 +79,61 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec) if(n_reports == 0) { file << "time;rsrp;pl;cfo;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;ul_ta;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;is_attached\n"; } - file << (metrics_report_period*n_reports) << ";"; - file << float_to_string(metrics.phy.dl.rsrp, 2); - file << float_to_string(metrics.phy.dl.pathloss, 2); + + file << (metrics_report_period * n_reports) << ";"; + + // Print PHY metrics for first CC + file << float_to_string(metrics.phy.dl[0].rsrp, 2); + file << float_to_string(metrics.phy.dl[0].pathloss, 2); file << float_to_string(metrics.phy.sync.cfo, 2); - file << float_to_string(metrics.phy.dl.mcs, 2); - file << float_to_string(metrics.phy.dl.sinr, 2); - file << float_to_string(metrics.phy.dl.turbo_iters, 2); - file << float_to_string((float) metrics.mac.rx_brate/period_usec*1e6, 2); - if (metrics.mac.rx_pkts > 0) { - file << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1); + file << float_to_string(metrics.phy.dl[0].mcs, 2); + file << float_to_string(metrics.phy.dl[0].sinr, 2); + file << float_to_string(metrics.phy.dl[0].turbo_iters, 2); + + // Sum DL rate for all CCs + float rx_brate = 0; + for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { + rx_brate += metrics.mac[r].rx_brate; + } + file << float_to_string(rx_brate / period_usec * 1e6, 2); + + // Sum BLER for all CCs + int rx_pkts = 0; + int rx_errors = 0; + for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { + rx_pkts += metrics.mac[r].rx_pkts; + rx_errors += metrics.mac[r].rx_errors; + } + if (rx_pkts > 0) { + file << float_to_string((float)100 * rx_errors / rx_pkts, 1); } else { file << float_to_string(0, 2); } + file << float_to_string(metrics.phy.sync.ta_us, 2); - file << float_to_string(metrics.phy.ul.mcs, 2); - file << float_to_string((float) metrics.mac.ul_buffer, 2); - file << float_to_string((float) metrics.mac.tx_brate/period_usec*1e6, 2); - if (metrics.mac.tx_pkts > 0) { - file << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1); + file << float_to_string(metrics.phy.ul[0].mcs, 2); + file << float_to_string((float)metrics.mac[0].ul_buffer, 2); + + // Sum UL rate for all CCs + float tx_brate = 0; + for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { + tx_brate += metrics.mac[r].tx_brate; + } + file << float_to_string(tx_brate / period_usec * 1e6, 2); + + // Sum UL BLER for all CCs + int tx_pkts = 0; + int tx_errors = 0; + for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { + tx_pkts += metrics.mac[r].tx_pkts; + tx_errors += metrics.mac[r].tx_errors; + } + if (tx_pkts > 0) { + file << float_to_string((float)100 * tx_errors / tx_pkts, 1); } else { file << float_to_string(0, 2); } + file << float_to_string(metrics.rf.rf_o, 2); file << float_to_string(metrics.rf.rf_u, 2); file << float_to_string(metrics.rf.rf_l, 2); @@ -109,7 +142,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec) n_reports++; } else { - std::cout << "Error, couldn't write CSV file." << std::endl; + std::cout << "couldn't write CSV file." << std::endl; } pthread_mutex_unlock(&mutex); } diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc index aa38390fb..340df8c29 100644 --- a/srsue/src/metrics_stdout.cc +++ b/srsue/src/metrics_stdout.cc @@ -78,33 +78,39 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us { n_reports = 0; cout << endl; - cout << "--Signal--------------DL------------------------------UL----------------------" << endl; - cout << " rsrp pl cfo mcs snr turbo brate bler ta_us mcs buff brate bler" << endl; + cout << "----Signal--------------DL-------------------------------------UL----------------------" << endl; + cout << "cc rsrp pl cfo mcs snr turbo brate bler ta_us mcs buff brate bler" << endl; } - cout << float_to_string(metrics.phy.dl.rsrp, 2); - cout << float_to_string(metrics.phy.dl.pathloss, 2); - cout << float_to_eng_string(metrics.phy.sync.cfo, 2); - cout << float_to_string(metrics.phy.dl.mcs, 2); - cout << float_to_string(metrics.phy.dl.sinr, 2); - cout << float_to_string(metrics.phy.dl.turbo_iters, 2); - cout << float_to_eng_string((float) metrics.mac.rx_brate/period_usec*1e6, 2); - if (metrics.mac.rx_pkts > 0) { - cout << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1) << "%"; - } else { - cout << float_to_string(0, 1) << "%"; - } - cout << float_to_string(metrics.phy.sync.ta_us, 2); - cout << float_to_string(metrics.phy.ul.mcs, 2); - cout << float_to_eng_string((float) metrics.mac.ul_buffer, 2); - cout << float_to_eng_string((float) metrics.mac.tx_brate/period_usec*1e6, 2); - if (metrics.mac.tx_pkts > 0) { - cout << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1) << "%"; - } else { - cout << float_to_string(0, 1) << "%"; + for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { + cout << " " << r; + cout << float_to_string(metrics.phy.dl[r].rsrp, 2); + cout << float_to_string(metrics.phy.dl[r].pathloss, 2); + cout << float_to_eng_string(metrics.phy.sync.cfo, 2); + cout << float_to_string(metrics.phy.dl[r].mcs, 2); + cout << float_to_string(metrics.phy.dl[r].sinr, 2); + cout << float_to_string(metrics.phy.dl[r].turbo_iters, 2); + + cout << float_to_eng_string((float)metrics.mac[r].rx_brate / period_usec * 1e6, 2); + if (metrics.mac[r].rx_pkts > 0) { + cout << float_to_string((float)100 * metrics.mac[r].rx_errors / metrics.mac[r].rx_pkts, 1) << "%"; + } else { + cout << float_to_string(0, 1) << "%"; + } + + cout << float_to_string(metrics.phy.sync.ta_us, 2); + + cout << float_to_string(metrics.phy.ul[r].mcs, 2); + cout << float_to_eng_string((float)metrics.mac[r].ul_buffer, 2); + cout << float_to_eng_string((float)metrics.mac[r].tx_brate / period_usec * 1e6, 2); + if (metrics.mac[r].tx_pkts > 0) { + cout << float_to_string((float)100 * metrics.mac[r].tx_errors / metrics.mac[r].tx_pkts, 1) << "%"; + } else { + cout << float_to_string(0, 1) << "%"; + } + cout << endl; } - cout << endl; - if(metrics.rf.rf_error) { + if (metrics.rf.rf_error) { printf("RF status: O=%d, U=%d, L=%d\n", metrics.rf.rf_o, metrics.rf.rf_u, metrics.rf.rf_l); } } @@ -112,7 +118,7 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us std::string metrics_stdout::float_to_string(float f, int digits) { std::ostringstream os; - const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON; + const int precision = SRSLTE_MIN((int)((f == 0.0f) ? digits - 1 : digits - log10f(fabsf(f)) - 2 * FLT_EPSILON), 3); os << std::setw(6) << std::fixed << std::setprecision(precision) << f; return os.str(); } diff --git a/srsue/src/phy/async_scell_recv.cc b/srsue/src/phy/async_scell_recv.cc new file mode 100644 index 000000000..80a07f69d --- /dev/null +++ b/srsue/src/phy/async_scell_recv.cc @@ -0,0 +1,583 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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 "srsue/hdr/phy/async_scell_recv.h" +#include "srsue/hdr/phy/phy_common.h" +#include +#include +#include +#include +#include + +#define LOG_PREABLE "[scell_recv] " + +#define LOG_ALL_CONSOLE 0 + +#if LOG_ALL_CONSOLE +#define Error(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->console(LOG_PREABLE fmt, ##__VA_ARGS__) +#else +#define Error(fmt, ...) log_h->error(LOG_PREABLE fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) log_h->warning(LOG_PREABLE fmt, ##__VA_ARGS__) +#define Info(fmt, ...) log_h->info(LOG_PREABLE fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) log_h->debug(LOG_PREABLE fmt, ##__VA_ARGS__) +#endif + +namespace srsue { + +async_scell_recv::async_scell_recv() +{ + initiated = false; + buffer_write_idx = 0; + buffer_read_idx = 0; + dl_freq = -1; + ul_freq = -1; + bzero(&cell, sizeof(srslte_cell_t)); + bzero(sf_buffer, sizeof(sf_buffer)); + running = false; +} + +async_scell_recv::~async_scell_recv() +{ + if (initiated) { + srslte_ue_sync_free(&ue_sync); + } + + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + } +} + +static int radio_recv_callback(void* obj, cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) +{ + return ((async_scell_recv*)obj)->radio_recv_fnc(data, nsamples, rx_time); +} + +static double callback_set_rx_gain(void* h, double gain) +{ + return ((async_scell_recv*)h)->set_rx_gain(gain); +} + +void async_scell_recv::init(srslte::radio* _radio_handler, phy_common* _worker_com, srslte::log* _log_h) +{ + // Get handlers + radio_h = _radio_handler; + worker_com = _worker_com; + log_h = _log_h; + + // Calculate number of RF channels + uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; + + // Initialise buffers + for (uint32_t s = 0; s < ASYNC_NOF_BUFFERS; s++) { + buffers[s].init(nof_rf_channels); + } + + for (uint32_t i = 0; i < nof_rf_channels; i++) { + sf_buffer[i] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX * 5); + if (!sf_buffer[i]) { + fprintf(stderr, "Error allocating buffer\n"); + return; + } + } + + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rf_channels, this)) { + fprintf(stderr, "SYNC: Initiating ue_sync\n"); + return; + } + + if (srslte_ue_mib_init(&ue_mib, sf_buffer, SRSLTE_MAX_PRB)) { + fprintf(stderr, "Error initaiting UE MIB decoder\n"); + return; + } + + if (pthread_cond_init(&cvar_buffer, NULL)) { + fprintf(stderr, "Initiating condition var\n"); + return; + } + + reset(); + running = false; + initiated = true; +} + +void async_scell_recv::stop() +{ + running = false; + wait_thread_finish(); + + pthread_mutex_destroy(&mutex_buffer); + pthread_mutex_destroy(&mutex_uesync); + pthread_cond_destroy(&cvar_buffer); +} + +void async_scell_recv::in_sync() +{ + in_sync_cnt++; + // Send RRC in-sync signal after 100 ms consecutive subframes + if (in_sync_cnt == NOF_IN_SYNC_SF) { + in_sync_cnt = 0; + out_of_sync_cnt = 0; + } +} +void async_scell_recv::out_of_sync() +{ + // Send RRC out-of-sync signal after 200 ms consecutive subframes + Info("Out-of-sync %d/%d\n", out_of_sync_cnt, NOF_OUT_OF_SYNC_SF); + out_of_sync_cnt++; + if (out_of_sync_cnt == NOF_OUT_OF_SYNC_SF) { + Info("Sending to RRC\n"); + out_of_sync_cnt = 0; + in_sync_cnt = 0; + } +} + +void async_scell_recv::set_cfo(float cfo) +{ + srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); +} + +void async_scell_recv::set_agc_enable(bool enable) +{ + do_agc = enable; + if (do_agc) { + if (radio_h) { + srslte_rf_info_t* rf_info = radio_h->get_info(); + srslte_ue_sync_start_agc( + &ue_sync, callback_set_rx_gain, rf_info->min_rx_gain, rf_info->max_rx_gain, radio_h->get_rx_gain()); + } else { + fprintf(stderr, "Error setting Secondary cell AGC: PHY not initiated\n"); + } + } else { + fprintf(stderr, "Error stopping AGC: not implemented\n"); + } +} + +double async_scell_recv::set_rx_gain(double gain) +{ + return radio_h->set_rx_gain_th((float)gain); +} + +int async_scell_recv::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) +{ + int ret = 0; + + if (running) { + if (radio_h->rx_now(data, nsamples, rx_time)) { + log_h->debug("SYNC: received %d samples from radio\n", nsamples); + ret = nsamples; + } else { + ret = SRSLTE_ERROR; + } + } + + return ret; +} + +void async_scell_recv::reset() +{ + in_sync_cnt = 0; + out_of_sync_cnt = 0; + + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + current_earfcn[i] = UINT32_MAX; + } +} + +void async_scell_recv::radio_error() +{ + log_h->error("SYNC: Receiving from radio.\n"); + // Need to find a method to effectively reset radio, reloading the driver does not work + radio_h->reset(); +} + +void async_scell_recv::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo) +{ + if (worker_com->args->cfo_integer_enabled) { + srslte_ue_sync_set_cfo_i_enable(q, true); + } + + srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_pss_ema); + srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz); + srslte_ue_sync_set_cfo_loop_bw(q, + worker_com->args->cfo_loop_bw_pss, + worker_com->args->cfo_loop_bw_ref, + worker_com->args->cfo_loop_pss_tol, + worker_com->args->cfo_loop_ref_min, + worker_com->args->cfo_loop_pss_tol, + worker_com->args->cfo_loop_pss_conv); + + q->strack.pss.chest_on_filter = worker_com->args->sic_pss_enabled; + + // Disable CP based CFO estimation during find + if (cfo != 0) { + q->cfo_current_value = cfo / 15000; + q->cfo_is_copied = true; + q->cfo_correct_enable_find = true; + srslte_sync_set_cfo_cp_enable(&q->sfind, false, 0); + } + + // Set SFO ema and correct period + srslte_ue_sync_set_sfo_correct_period(q, worker_com->args->sfo_correct_period); + srslte_ue_sync_set_sfo_ema(q, worker_com->args->sfo_ema); + + srslte_sync_set_sss_algorithm(&q->strack, SSS_FULL); + srslte_sync_set_sss_algorithm(&q->sfind, SSS_FULL); +} + +bool async_scell_recv::set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell, uint32_t dl_earfcn) +{ + bool ret = true; + bool reset_ue_sync = false; + + Info("Set cell:{nof_prb=%d; cp=%s; id=%d} dl_earfcn=%d\n", + _cell->nof_prb, + srslte_cp_string(_cell->cp), + _cell->id, + dl_earfcn); + + // Lock mutex + pthread_mutex_lock(&mutex_uesync); + + // Get transceiver mapping + carrier_map_t* m = &worker_com->args->carrier_map[carrier_idx]; + uint32_t channel_idx = m->channel_idx; + + // Set radio frequency if frequency changed + if (current_earfcn[channel_idx] != dl_earfcn && ret) { + dl_freq = srslte_band_fd(dl_earfcn) * 1e6f; + ul_freq = srslte_band_fu(srslte_band_ul_earfcn(dl_earfcn)) * 1e6f; + radio_h->set_rx_freq(channel_idx, dl_freq); + radio_h->set_tx_freq(channel_idx, ul_freq); + Info("Setting DL: %.1f MHz; UL %.1fMHz; Radio/Chan: %d/%d\n", + dl_freq / 1e6, + ul_freq / 1e6, + m->radio_idx, + m->channel_idx); + ul_dl_factor = ul_freq / dl_freq; + current_earfcn[channel_idx] = dl_earfcn; + reset_ue_sync = true; + } + + // Detect change in cell configuration + if (memcmp(&cell, &_cell, sizeof(srslte_cell_t)) != 0) { + + // Set sampling rate, if number of PRB changed + if (cell.nof_prb != _cell->nof_prb && ret) { + double srate = srslte_sampling_freq_hz(_cell->nof_prb); + if (srate < 10e6) { + radio_h->set_master_clock_rate(4 * srate); + } else { + radio_h->set_master_clock_rate(srate); + } + radio_h->set_rx_srate(srate); + radio_h->set_tx_srate(srate); + Info("Setting SRate to %.2f MHz\n", srate / 1e6); + } + + // Copy cell + memcpy(&cell, _cell, sizeof(srslte_cell_t)); + reset_ue_sync = true; + + // Set cell in ue sync + if (srslte_ue_sync_set_cell(&ue_sync, cell)) { + Error("SYNC: Setting cell: initiating ue_sync\n"); + ret = false; + } + + // Set cell in MIB decoder + if (srslte_ue_mib_set_cell(&ue_mib, cell)) { + fprintf(stderr, "Error setting cell in UE MIB decoder\n"); + ret = false; + } + + srslte_ue_mib_reset(&ue_mib); + } + + // Reset ue_sync and set CFO/gain from search procedure + if (reset_ue_sync) { + srslte_ue_sync_reset(&ue_sync); + } + + // Reset thread state + state = DECODE_MIB; + + // If not running start! + if (!running) { + // Start main thread + start(1); + running = true; + } + + pthread_mutex_unlock(&mutex_uesync); + + return ret; +} + +void async_scell_recv::state_decode_mib() +{ + int sfn_offset = 0; + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync); + + if (sfidx == 0) { + // Run only for sub-frame index 0 + int n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); + + if (n < SRSLTE_SUCCESS) { + // Error decoding MIB, log error + Error("Error decoding UE MIB (%d)\n", n); + } else if (n == SRSLTE_UE_MIB_FOUND) { + // MIB Found + uint32_t sfn = 0; + srslte_pbch_mib_unpack(bch_payload, &cell, &sfn); + + Info("SCell MIB synchronised (SNR=%.2fdB)\n", ue_mib.chest_res.snr_db); + + // Set sub-frame index + tti = ((sfn + sfn_offset) % 1024) * 10; + + // Change state, reset ring buffer and go to Synchronized but idle + buffer_write_idx = 0; + buffer_read_idx = 0; + state = SYNCH_IDLE; + } else { + // MIB Not found + // Do nothing. Keep going. + } + } else { + // Do nothing. Keep going. + } +} + +void async_scell_recv::state_write_buffer() +{ + if (tti % SRSLTE_NOF_SF_X_FRAME != srslte_ue_sync_get_sfidx(&ue_sync) || ue_sync.state != SF_TRACK) { + // Real-time failure, go to decode MIB + Info("Detected Real-Time failure; Going to search MIB (from WRITE)\n"); + state = DECODE_MIB; + } else { + // Normal operation, try to write buffer + phch_scell_recv_buffer* buffer = &buffers[buffer_write_idx]; + srslte_timestamp_t rx_time = {}; + + // Lock mutex + pthread_mutex_lock(&mutex_buffer); + + // Copy last timestamp + srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); + + // Extract essential information + buffer->set_sf(tti, &rx_time); + + // Increment write index + buffer_write_idx = (buffer_write_idx + 1) % ASYNC_NOF_BUFFERS; + + // Detect overflow + if (buffer_write_idx == buffer_read_idx) { + // Reset buffer and goto synchronized IDLE + Info("Detected overflow; reseting ring buffer and going to IDLE...\n"); + buffer_write_idx = 0; + buffer_read_idx = 0; + state = SYNCH_IDLE; + } + + // Unlock mutex and inform that data was received + pthread_cond_broadcast(&cvar_buffer); + pthread_mutex_unlock(&mutex_buffer); + } +} + +void async_scell_recv::state_synch_idle() +{ + if (tti % SRSLTE_NOF_SF_X_FRAME != srslte_ue_sync_get_sfidx(&ue_sync)) { + // Real-time failure, go to decode MIB + Debug("Detected Real-Time failure; Going to search MIB (from IDLE)\n"); + state = DECODE_MIB; + } else { + // Do nothing + } +} + +void async_scell_recv::run_thread() +{ + Info("Starting asynchronous scell reception...\n"); + while (running) { + phch_scell_recv_buffer* buffer = &buffers[buffer_write_idx]; + + // Lock ue_sync + pthread_mutex_lock(&mutex_uesync); + + // Get RF base-band + int ret = srslte_ue_sync_zerocopy(&ue_sync, (state == DECODE_MIB) ? sf_buffer : buffer->get_buffer_ptr()); + if (ret < 0) { + fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); + } + + // Unlock ue_sync + pthread_mutex_unlock(&mutex_uesync); + + if (ret == 1) { + // Synchronized + switch (state) { + case DECODE_MIB: + state_decode_mib(); + break; + case WRITE_BUFFER: + state_write_buffer(); + break; + case SYNCH_IDLE: + state_synch_idle(); + break; + } + + // Increment tti + tti = (tti + 1) % 10240; + } else if (ret == 0) { + // Error in synchronization + // Warning("SYNC: Out-of-sync detected in PSS/SSS\n"); + // out_of_sync(); + } + + if (ret < 0) { + // Radio error + radio_error(); + } + } +} + +bool async_scell_recv::tti_align(uint32_t tti) +{ + bool ret = false; + + if (state == SYNCH_IDLE) { + // Enable Writing in buffer + Debug("Start writing in buffer\n"); + state = WRITE_BUFFER; + } else if (state == DECODE_MIB) { + // Debug("SCell not ready for reading\n"); + return false; + } + + pthread_mutex_lock(&mutex_buffer); + + // Stage 1: Flush buffers if the tti is not available + // While data is available and no tti match, discard + while ((buffer_write_idx != buffer_read_idx) && (buffers[buffer_read_idx].get_tti() != tti)) { + // Discard buffer + Error("Expected TTI %d. Discarding tti %d.\n", tti, buffers[buffer_read_idx].get_tti()); + buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS; + } + + if ((buffers[buffer_read_idx].get_tti() == tti)) { + // tti match + ret = true; + } + + // Stage 2: If the tti is not found and the latest tti was -1; wait + // Get time and set timeout time + if (!ret) { + bool timedout = false; + + while (!ret && !timedout && buffer_write_idx == buffer_read_idx && running) { + struct timespec timeToWait; + struct timeval now; + + gettimeofday(&now, NULL); + timeToWait.tv_sec = now.tv_sec; + timeToWait.tv_nsec = (now.tv_usec + 1000UL) * 1000UL; + + int rt = pthread_cond_timedwait(&cvar_buffer, &mutex_buffer, &timeToWait); + switch (rt) { + case ETIMEDOUT: + case EPERM: + // Consider all errors timed out, exit loop + timedout = true; + Error("Expected TTI %04d. timeout (%d).\n", tti, rt); + tti_align_timeout_counter++; + if (tti_align_timeout_counter > max_tti_align_timeout_counter) { + Error("Maximum number of timeouts reached (%d). Going back to decode MIB.\n", + max_tti_align_timeout_counter); + state = DECODE_MIB; + } + break; + default: + if ((buffers[buffer_read_idx].get_tti() == tti)) { + // tti match + ret = true; + } + break; + } + } + } + + pthread_mutex_unlock(&mutex_buffer); + + return ret; +} + +void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp) +{ + pthread_mutex_lock(&mutex_buffer); + + // Block until data is filled + while (buffer_write_idx == buffer_read_idx && running) { + pthread_cond_wait(&cvar_buffer, &mutex_buffer); + } + + // Exit condition detected + if (!running) { + pthread_mutex_unlock(&mutex_buffer); + return; + } + + // Get reading buffer + phch_scell_recv_buffer* buffer = &buffers[buffer_read_idx]; + + if (dst) { + // Get data pointer + cf_t** buff = buffer->get_buffer_ptr(); + + uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; + + // Copy data + for (uint32_t i = 0; i < nof_rf_channels; i++) { + if (dst[i]) { + // Check pointer is allocated + memcpy(dst[i], buff[i], sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + } + } + + buffer->get_timestamp(timestamp); + + // Increment read index + buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS; + + pthread_mutex_unlock(&mutex_buffer); +} + +} // namespace srsue diff --git a/srsue/src/phy/cc_worker.cc b/srsue/src/phy/cc_worker.cc new file mode 100644 index 000000000..116315fb7 --- /dev/null +++ b/srsue/src/phy/cc_worker.cc @@ -0,0 +1,1419 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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 "srsue/hdr/phy/cc_worker.h" +#include "srslte/interfaces/ue_interfaces.h" + +#define Error(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->debug(fmt, ##__VA_ARGS__) + +#define CURRENT_TTI (sf_cfg_dl.tti) +#define CURRENT_SFIDX (sf_cfg_dl.tti % 10) +#define CURRENT_TTI_TX (sf_cfg_ul.tti) + +using namespace asn1::rrc; + +namespace srsue { + +/************ + * + * Common Functions + * + */ + +cc_worker::cc_worker(uint32_t cc_idx, uint32_t max_prb, srsue::phy_common* phy, srslte::log* log_h) +{ + ZERO_OBJECT(signal_buffer_rx); + ZERO_OBJECT(signal_buffer_tx); + ZERO_OBJECT(pending_dl_grant); + ZERO_OBJECT(cell); + ZERO_OBJECT(sf_cfg_dl); + ZERO_OBJECT(sf_cfg_ul); + ZERO_OBJECT(ue_dl); + ZERO_OBJECT(ue_dl_cfg); + ZERO_OBJECT(ue_dl_cfg.cfg.pdsch); + ZERO_OBJECT(pmch_cfg); + ZERO_OBJECT(chest_mbsfn_cfg); + ZERO_OBJECT(chest_default_cfg); + ZERO_OBJECT(ue_ul); + ZERO_OBJECT(ue_ul_cfg); + ZERO_OBJECT(dl_metrics); + ZERO_OBJECT(ul_metrics); + + cell_initiated = false; + + this->cc_idx = cc_idx; + this->phy = phy; + this->log_h = log_h; + + for (uint32_t i = 0; i < phy->args->nof_rx_ant; i++) { + signal_buffer_rx[i] = (cf_t*)srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); + if (!signal_buffer_rx[i]) { + Error("Allocating memory\n"); + return; + } + signal_buffer_tx[i] = (cf_t*)srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); + if (!signal_buffer_tx[i]) { + Error("Allocating memory\n"); + return; + } + } + + if (srslte_ue_dl_init(&ue_dl, signal_buffer_rx, max_prb, phy->args->nof_rx_ant)) { + Error("Initiating UE DL\n"); + return; + } + + if (srslte_ue_ul_init(&ue_ul, signal_buffer_tx[0], max_prb)) { + Error("Initiating UE UL\n"); + return; + } + + phy->set_ue_dl_cfg(&ue_dl_cfg); + phy->set_ue_ul_cfg(&ue_ul_cfg); + phy->set_pdsch_cfg(&ue_dl_cfg.cfg.pdsch); + phy->set_pdsch_cfg(&pmch_cfg.pdsch_cfg); // set same config in PMCH decoder + + // Define MBSFN subframes channel estimation and save default one + chest_mbsfn_cfg.filter_type = SRSLTE_CHEST_FILTER_TRIANGLE; + chest_mbsfn_cfg.filter_coef[0] = 0.1; + chest_mbsfn_cfg.interpolate_subframe = true; + chest_mbsfn_cfg.noise_alg = SRSLTE_NOISE_ALG_PSS; + + chest_default_cfg = ue_dl_cfg.chest_cfg; + + if (phy->args->pdsch_8bit_decoder) { + ue_dl.pdsch.llr_is_8bit = true; + ue_dl.pdsch.dl_sch.llr_is_8bit = true; + } +} + +cc_worker::~cc_worker() +{ + for (uint32_t i = 0; i < phy->args->nof_rx_ant; i++) { + if (signal_buffer_tx[i]) { + free(signal_buffer_tx[i]); + } + if (signal_buffer_rx[i]) { + free(signal_buffer_rx[i]); + } + } + srslte_ue_dl_free(&ue_dl); + srslte_ue_ul_free(&ue_ul); +} + +void cc_worker::reset() +{ + bzero(&dl_metrics, sizeof(dl_metrics_t)); + bzero(&ul_metrics, sizeof(ul_metrics_t)); + + phy_interface_rrc::phy_cfg_t empty_cfg = {}; + // defaults + empty_cfg.common.pucch_cnfg.delta_pucch_shift.value = pucch_cfg_common_s::delta_pucch_shift_opts::ds1; + empty_cfg.common.ul_pwr_ctrl.alpha.value = alpha_r12_opts::al0; + empty_cfg.common.ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format1.value = + delta_flist_pucch_s::delta_f_pucch_format1_opts::delta_f0; + empty_cfg.common.ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format1b.value = + delta_flist_pucch_s::delta_f_pucch_format1b_opts::delta_f1; + empty_cfg.common.ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2.value = + delta_flist_pucch_s::delta_f_pucch_format2_opts::delta_f0; + empty_cfg.common.ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2a.value = + delta_flist_pucch_s::delta_f_pucch_format2a_opts::delta_f0; + empty_cfg.common.ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2b.value = + delta_flist_pucch_s::delta_f_pucch_format2b_opts::delta_f0; + set_pcell_config(&empty_cfg); +} + +bool cc_worker::set_cell(srslte_cell_t cell) +{ + if (this->cell.id != cell.id || !cell_initiated) { + this->cell = cell; + + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + Error("Initiating UE DL\n"); + return false; + } + + if (srslte_ue_dl_set_mbsfn_area_id(&ue_dl, 1)) { + Error("Setting mbsfn id\n"); + } + + if (srslte_ue_ul_set_cell(&ue_ul, cell)) { + Error("Initiating UE UL\n"); + return false; + } + + if (cell.frame_type == SRSLTE_TDD && !ue_dl_cfg.chest_cfg.interpolate_subframe) { + ue_dl_cfg.chest_cfg.interpolate_subframe = true; + log_h->console("Enabling subframe interpolation for TDD cells (recommended setting)\n"); + } + + cell_initiated = true; + } + return true; +} + +cf_t* cc_worker::get_rx_buffer(uint32_t antenna_idx) +{ + return signal_buffer_rx[antenna_idx]; +} + +cf_t* cc_worker::get_tx_buffer(uint32_t antenna_idx) +{ + return signal_buffer_tx[antenna_idx]; +} + +void cc_worker::set_tti(uint32_t tti) +{ + sf_cfg_dl.tti = tti; + sf_cfg_ul.tti = TTI_TX(tti); + sf_cfg_ul.shortened = false; +} + +void cc_worker::set_cfo(float cfo) +{ + ue_ul_cfg.cfo_value = cfo; +} + +float cc_worker::get_ref_cfo() +{ + return ue_dl.chest_res.cfo; +} + +void cc_worker::set_crnti(uint16_t rnti) +{ + srslte_ue_dl_set_rnti(&ue_dl, rnti); + srslte_ue_ul_set_rnti(&ue_ul, rnti); +} + +void cc_worker::set_tdd_config(srslte_tdd_config_t config) +{ + sf_cfg_dl.tdd_config = config; + sf_cfg_ul.tdd_config = config; +} + +void cc_worker::enable_pregen_signals(bool enabled) +{ + this->pregen_enabled = enabled; +} + +void cc_worker::fill_dci_cfg(srslte_dci_cfg_t* cfg, bool rel10) +{ + bzero(cfg, sizeof(srslte_dci_cfg_t)); + if (rel10 && phy->cif_enabled) { + cfg->cif_enabled = phy->cif_enabled; + } + cfg->multiple_csi_request_enabled = phy->multiple_csi_request_enabled; + cfg->srs_request_enabled = phy->srs_request_enabled; +} + +void cc_worker::set_dl_pending_grant(uint32_t cc_idx, srslte_dci_dl_t* dl_dci) +{ + if (!pending_dl_grant[cc_idx].enable) { + pending_dl_grant[cc_idx].dl_dci = *dl_dci; + pending_dl_grant[cc_idx].enable = true; + } else { + Warning("set_dl_pending_grant: cc=%d already exists\n", cc_idx); + } +} + +bool cc_worker::get_dl_pending_grant(uint32_t cc_idx, srslte_dci_dl_t* dl_dci) +{ + if (pending_dl_grant[cc_idx].enable) { + *dl_dci = pending_dl_grant[cc_idx].dl_dci; + pending_dl_grant[cc_idx].enable = false; + return true; + } else { + return false; + } +} + +/************ + * + * Downlink Functions + * + */ + +bool cc_worker::work_dl_regular() +{ + bool dl_ack[SRSLTE_MAX_CODEWORDS]; + + mac_interface_phy::tb_action_dl_t dl_action; + + bool found_dl_grant = false; + + sf_cfg_dl.sf_type = SRSLTE_SF_NORM; + + // Set default channel estimation + ue_dl_cfg.chest_cfg = chest_default_cfg; + + /* For TDD, when searching for SIB1, the ul/dl configuration is unknown and need to do blind search over + * the possible mi values + */ + uint32_t mi_set_len; + if (cell.frame_type == SRSLTE_TDD && !sf_cfg_dl.tdd_config.configured) { + mi_set_len = 3; + } else { + mi_set_len = 1; + } + + // Blind search PHICH mi value + for (uint32_t i = 0; i < mi_set_len && !found_dl_grant; i++) { + + if (mi_set_len == 1) { + srslte_ue_dl_set_mi_auto(&ue_dl); + } else { + srslte_ue_dl_set_mi_manual(&ue_dl, i); + } + + /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg_dl, &ue_dl_cfg) < 0) { + Error("Getting PDCCH FFT estimate\n"); + return false; + } + + /* Look for DL and UL dci(s) if this is PCell, or no cross-carrier scheduling is enabled */ + if ((cc_idx == 0) || (!phy->cif_enabled)) { + found_dl_grant = decode_pdcch_dl() > 0; + decode_pdcch_ul(); + } + } + + srslte_dci_dl_t dci_dl; + bool has_dl_grant = get_dl_pending_grant(cc_idx, &dci_dl); + + // If found a dci for this carrier, generate a grant, pass it to MAC and decode the associated PDSCH + if (has_dl_grant) { + + // Read last TB from last retx for this pid + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + ue_dl_cfg.cfg.pdsch.grant.last_tbs[i] = phy->last_dl_tbs[dci_dl.pid][cc_idx][i]; + } + // Generate PHY grant + if (srslte_ue_dl_dci_to_pdsch_grant(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, &dci_dl, &ue_dl_cfg.cfg.pdsch.grant)) { + Error("Converting DCI message to DL dci\n"); + return -1; + } + + // Save TB for next retx + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + phy->last_dl_tbs[dci_dl.pid][cc_idx][i] = ue_dl_cfg.cfg.pdsch.grant.last_tbs[i]; + } + + // Set RNTI + ue_dl_cfg.cfg.pdsch.rnti = dci_dl.rnti; + + // Generate MAC grant + mac_interface_phy::mac_grant_dl_t mac_grant; + dl_phy_to_mac_grant(&ue_dl_cfg.cfg.pdsch.grant, &dci_dl, &mac_grant); + + // Save ACK resource configuration + srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce}; + + // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC + phy->mac->new_grant_dl(cc_idx, mac_grant, &dl_action); + decode_pdsch(ack_resource, &dl_action, dl_ack); + phy->mac->tb_decoded(cc_idx, mac_grant, dl_ack); + } + + /* Decode PHICH */ + decode_phich(); + + return true; +} + +bool cc_worker::work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg) +{ + mac_interface_phy::tb_action_dl_t dl_action; + + // Configure MBSFN settings + srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_cfg.mbsfn_area_id); + srslte_ue_dl_set_non_mbsfn_region(&ue_dl, mbsfn_cfg.non_mbsfn_region_length); + + sf_cfg_dl.sf_type = SRSLTE_SF_MBSFN; + + // Set MBSFN channel estimation + chest_mbsfn_cfg.mbsfn_area_id = mbsfn_cfg.mbsfn_area_id; + ue_dl_cfg.chest_cfg = chest_mbsfn_cfg; + + /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg_dl, &ue_dl_cfg) < 0) { + Error("Getting PDCCH FFT estimate\n"); + return false; + } + + decode_pdcch_ul(); + + if (mbsfn_cfg.enable) { + srslte_configure_pmch(&pmch_cfg, &cell, &mbsfn_cfg); + srslte_ra_dl_compute_nof_re(&cell, &sf_cfg_dl, &pmch_cfg.pdsch_cfg.grant); + + // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC + phy->mac->new_mch_dl(pmch_cfg.pdsch_cfg.grant, &dl_action); + bool mch_decoded = true; + if (!decode_pmch(&dl_action, &mbsfn_cfg)) { + mch_decoded = false; + } + phy->mac->mch_decoded((uint32_t)pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8, mch_decoded); + } else if (mbsfn_cfg.is_mcch) { + // release lock in phy_common + phy->set_mch_period_stop(0); + } + + /* Decode PHICH */ + decode_phich(); + + return true; +} + +void cc_worker::dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant, + srslte_dci_dl_t* dl_dci, + srsue::mac_interface_phy::mac_grant_dl_t* mac_grant) +{ + /* Fill MAC dci structure */ + mac_grant->pid = dl_dci->pid; + mac_grant->rnti = dl_dci->rnti; + + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + mac_grant->tb[i].ndi = dl_dci->tb[i].ndi; + mac_grant->tb[i].ndi_present = (dl_dci->tb[i].mcs_idx <= 28); + mac_grant->tb[i].tbs = phy_grant->tb[i].enabled ? (phy_grant->tb[i].tbs / (uint32_t)8) : 0; + mac_grant->tb[i].rv = phy_grant->tb[i].rv; + } + + // If SIB dci, use PID to signal TTI to obtain RV from higher layers + if (mac_grant->rnti == SRSLTE_SIRNTI) { + mac_grant->pid = CURRENT_TTI; + } +} + +int cc_worker::decode_pdcch_dl() +{ + int nof_grants = 0; + + srslte_dci_dl_t dci[SRSLTE_MAX_CARRIERS]; + ZERO_OBJECT(dci); + + uint16_t dl_rnti = phy->mac->get_dl_sched_rnti(CURRENT_TTI); + if (dl_rnti) { + + /* Blind search first without cross scheduling then with it if enabled */ + for (int i = 0; i < (phy->cif_enabled ? 2 : 1) && !nof_grants; i++) { + fill_dci_cfg(&ue_dl_cfg.dci_cfg, i > 0); + Debug("PDCCH looking for rnti=0x%x\n", dl_rnti); + nof_grants = srslte_ue_dl_find_dl_dci(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, dl_rnti, dci); + if (nof_grants < 0) { + Error("Looking for DL grants\n"); + return -1; + } + } + + // If RAR dci, save TTI + if (nof_grants > 0 && SRSLTE_RNTI_ISRAR(dl_rnti)) { + phy->set_rar_grant_tti(CURRENT_TTI); + } + + for (int k = 0; k < nof_grants; k++) { + // Save dci to CC index + set_dl_pending_grant(dci[k].cif_present ? dci[k].cif : cc_idx, &dci[k]); + + // Logging + char str[512]; + srslte_dci_dl_info(&dci[k], str, 512); + Info("PDCCH: cc=%d, %s, snr=%.1f dB\n", cc_idx, str, ue_dl.chest_res.snr_db); + } + } + return nof_grants; +} + +int cc_worker::decode_pdsch(srslte_pdsch_ack_resource_t ack_resource, + mac_interface_phy::tb_action_dl_t* action, + bool mac_acks[SRSLTE_MAX_CODEWORDS]) +{ + + srslte_pdsch_res_t pdsch_dec[SRSLTE_MAX_CODEWORDS]; + ZERO_OBJECT(pdsch_dec); + + // See if at least 1 codeword needs to be decoded. If not need to be decode, resend ACK + bool decode_enable = false; + bool tb_enable[SRSLTE_MAX_CODEWORDS]; + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + tb_enable[tb] = ue_dl_cfg.cfg.pdsch.grant.tb[tb].enabled; + if (action->tb[tb].enabled) { + decode_enable = true; + + // Prepare I/O based on action + pdsch_dec[tb].payload = action->tb[tb].payload; + ue_dl_cfg.cfg.pdsch.softbuffers.rx[tb] = action->tb[tb].softbuffer.rx; + } else { + // If this TB is duplicate, indicate PDSCH to skip it + ue_dl_cfg.cfg.pdsch.grant.tb[tb].enabled = false; + } + } + + // Run PDSCH decoder + if (decode_enable) { + if (srslte_ue_dl_decode_pdsch(&ue_dl, &sf_cfg_dl, &ue_dl_cfg.cfg.pdsch, pdsch_dec)) { + Error("ERROR: Decoding PDSCH\n"); + } + } + + // Generate ACKs for MAC and PUCCH + uint8_t pending_acks[SRSLTE_MAX_CODEWORDS]; + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + // For MAC, set to true if it's a duplicate + mac_acks[tb] = action->tb[tb].enabled ? pdsch_dec[tb].crc : true; + + // For PUCCH feedback, need to send even if duplicate, but only those CW that were enabled before disabling in th + // grant + pending_acks[tb] = tb_enable[tb] ? mac_acks[tb] : 2; + } + + if (action->generate_ack && ue_dl_cfg.cfg.pdsch.grant.nof_tb > 0) { + phy->set_dl_pending_ack(&sf_cfg_dl, cc_idx, pending_acks, ack_resource); + } + + if (decode_enable) { + // Metrics + dl_metrics.mcs = ue_dl_cfg.cfg.pdsch.grant.tb[0].mcs_idx; + dl_metrics.turbo_iters = pdsch_dec->avg_iterations_block / 2; + + // Logging + char str[512]; + srslte_pdsch_rx_info(&ue_dl_cfg.cfg.pdsch, pdsch_dec, str, 512); + Info("PDSCH: cc=%d, %s, snr=%.1f dB\n", cc_idx, str, ue_dl.chest_res.snr_db); + } + + return SRSLTE_SUCCESS; +} + +int cc_worker::decode_pmch(mac_interface_phy::tb_action_dl_t* action, srslte_mbsfn_cfg_t* mbsfn_cfg) +{ + srslte_pdsch_res_t pmch_dec; + + pmch_cfg.area_id = mbsfn_cfg->mbsfn_area_id; + pmch_cfg.pdsch_cfg.softbuffers.rx[0] = action->tb[0].softbuffer.rx; + pmch_dec.payload = action->tb[0].payload; + + if (action->tb[0].enabled) { + + srslte_softbuffer_rx_reset_tbs(pmch_cfg.pdsch_cfg.softbuffers.rx[0], pmch_cfg.pdsch_cfg.grant.tb[0].tbs); + + if (srslte_ue_dl_decode_pmch(&ue_dl, &sf_cfg_dl, &pmch_cfg, &pmch_dec)) { + Error("Decoding PMCH\n"); + return -1; + } + + // Store metrics + dl_metrics.mcs = pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx; + + Info("PMCH: l_crb=%2d, tbs=%d, mcs=%d, crc=%s, snr=%.1f dB, n_iter=%.1f\n", + pmch_cfg.pdsch_cfg.grant.nof_prb, + pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8, + pmch_cfg.pdsch_cfg.grant.tb[0].mcs_idx, + pmch_dec.crc ? "OK" : "KO", + ue_dl.chest_res.snr_db, + pmch_dec.avg_iterations_block); + + + if (pmch_dec.crc) { + return 1; + } + + } else { + Warning("Received dci for TBS=0\n"); + } + return 0; +} + +void cc_worker::decode_phich() +{ + srslte_dci_ul_t dci_ul = {}; + srslte_phich_grant_t phich_grant = {}; + srslte_phich_res_t phich_res = {}; + + // Receive PHICH, in TDD might be more than one + for (uint32_t I_phich = 0; I_phich < 2; I_phich++) { + phich_grant.I_phich = I_phich; + if (phy->get_ul_pending_ack(&sf_cfg_dl, cc_idx, &phich_grant, &dci_ul)) { + if (srslte_ue_dl_decode_phich(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, &phich_grant, &phich_res)) { + Error("Decoding PHICH\n"); + } + phy->set_ul_received_ack(&sf_cfg_dl, cc_idx, phich_res.ack_value, I_phich, &dci_ul); + Info("PHICH: hi=%d, corr=%.1f, I_lowest=%d, n_dmrs=%d, I_phich=%d\n", + phich_res.ack_value, + phich_res.distance, + phich_grant.n_prb_lowest, + phich_grant.n_dmrs, + I_phich); + } + } +} + +void cc_worker::update_measurements() +{ + float snr_ema_coeff = phy->args->snr_ema_coeff; + + // In TDD, ignore special subframes without PDSCH + if (srslte_sfidx_tdd_type(sf_cfg_dl.tdd_config, CURRENT_SFIDX) == SRSLTE_TDD_SF_S && + srslte_sfidx_tdd_nof_dw(sf_cfg_dl.tdd_config) < 4) { + return; + } + + // Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC + float rsrq_db = ue_dl.chest_res.rsrq_db; + if (std::isnormal(rsrq_db)) { + if (!(CURRENT_TTI % phy->pcell_report_period) || !phy->avg_rsrq_db) { + phy->avg_rsrq_db = rsrq_db; + } else { + phy->avg_rsrq_db = SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db, CURRENT_TTI % phy->pcell_report_period); + } + } + + // Average RSRP taken from CRS + float rsrp_lin = ue_dl.chest_res.rsrp; + if (std::isnormal(rsrp_lin)) { + if (!phy->avg_rsrp[cc_idx] && !std::isnan(phy->avg_rsrp[cc_idx])) { + phy->avg_rsrp[cc_idx] = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp[cc_idx], snr_ema_coeff); + } else { + phy->avg_rsrp[cc_idx] = rsrp_lin; + } + } + + /* Correct absolute power measurements by RX gain offset */ + float rsrp_dbm = ue_dl.chest_res.rsrp_dbm - phy->rx_gain_offset; + + // Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC + if (std::isnormal(rsrp_dbm)) { + if (!(CURRENT_TTI % phy->pcell_report_period) || !phy->avg_rsrp_dbm) { + phy->avg_rsrp_dbm[cc_idx] = rsrp_dbm; + } else { + phy->avg_rsrp_dbm[cc_idx] = + SRSLTE_VEC_CMA(rsrp_dbm, phy->avg_rsrp_dbm[cc_idx], CURRENT_TTI % phy->pcell_report_period); + } + } + + // Compute PL + float tx_crs_power = ue_dl_cfg.cfg.pdsch.rs_power; + phy->pathloss[cc_idx] = tx_crs_power - phy->avg_rsrp_dbm[cc_idx]; + + // Average noise + float cur_noise = ue_dl.chest_res.noise_estimate; + if (std::isnormal(cur_noise)) { + if (!phy->avg_noise) { + phy->avg_noise[cc_idx] = cur_noise; + } else { + phy->avg_noise[cc_idx] = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise[cc_idx], snr_ema_coeff); + } + } + + // Average snr in the log domain + if (std::isnormal(ue_dl.chest_res.snr_db)) { + if (!phy->avg_noise) { + phy->avg_snr_db_cqi[cc_idx] = ue_dl.chest_res.snr_db; + } else { + phy->avg_snr_db_cqi[cc_idx] = SRSLTE_VEC_EMA(ue_dl.chest_res.snr_db, phy->avg_snr_db_cqi[cc_idx], snr_ema_coeff); + } + } + + // Store metrics + dl_metrics.n = phy->avg_noise[cc_idx]; + dl_metrics.rsrp = phy->avg_rsrp_dbm[cc_idx]; + dl_metrics.rsrq = phy->avg_rsrq_db; + dl_metrics.rssi = phy->avg_rssi_dbm; + dl_metrics.pathloss = phy->pathloss[cc_idx]; + dl_metrics.sinr = phy->avg_snr_db_cqi[cc_idx]; + + phy->set_dl_metrics(dl_metrics, cc_idx); + phy->set_ul_metrics(ul_metrics, cc_idx); +} + +/************ + * + * Uplink Functions + * + */ + +bool cc_worker::work_ul(srslte_uci_data_t* uci_data) +{ + + bool signal_ready; + + srslte_dci_ul_t dci_ul = {}; + mac_interface_phy::mac_grant_ul_t ul_mac_grant = {}; + mac_interface_phy::tb_action_ul_t ul_action = {}; + uint32_t pid = 0; + + bool ul_grant_available = phy->get_ul_pending_grant(&sf_cfg_ul, cc_idx, &pid, &dci_ul); + ul_mac_grant.phich_available = + phy->get_ul_received_ack(&sf_cfg_ul, cc_idx, &ul_mac_grant.hi_value, ul_grant_available ? NULL : &dci_ul); + + // If there is no grant, pid is from current TX TTI + if (!ul_grant_available) { + pid = phy->ul_pidof(CURRENT_TTI_TX, &sf_cfg_ul.tdd_config); + } + + /* Generate CQI reports if required, note that in case both aperiodic + * and periodic ones present, only aperiodic is sent (36.213 section 7.2) */ + if (ul_grant_available && dci_ul.cqi_request) { + set_uci_aperiodic_cqi(uci_data); + } else { + /* Check PCell and enabled secondary cells */ + if (cc_idx == 0 || phy->scell_enable[cc_idx]) { + set_uci_periodic_cqi(uci_data); + } + } + + /* Send UL dci or HARQ information (from PHICH) to MAC and receive actions*/ + if (ul_grant_available || ul_mac_grant.phich_available) { + + // Read last TB info from last retx for this PID + ue_ul_cfg.ul_cfg.pusch.grant.last_tb = phy->last_ul_tb[pid][cc_idx]; + + // Generate PHY grant + if (srslte_ue_ul_dci_to_pusch_grant(&ue_ul, &sf_cfg_ul, &ue_ul_cfg, &dci_ul, &ue_ul_cfg.ul_cfg.pusch.grant)) { + Error("Converting DCI message to UL dci\n"); + } + + // Save TBS info for next retx + phy->last_ul_tb[pid][cc_idx] = ue_ul_cfg.ul_cfg.pusch.grant.tb; + + // Fill MAC dci + ul_phy_to_mac_grant(&ue_ul_cfg.ul_cfg.pusch.grant, &dci_ul, pid, ul_grant_available, &ul_mac_grant); + + phy->mac->new_grant_ul(cc_idx, ul_mac_grant, &ul_action); + + // Calculate PUSCH Hopping procedure + ue_ul_cfg.ul_cfg.hopping.current_tx_nb = ul_action.current_tx_nb; + srslte_ue_ul_pusch_hopping(&ue_ul, &sf_cfg_ul, &ue_ul_cfg, &ue_ul_cfg.ul_cfg.pusch.grant); + } + + // Set UL RNTI + if (ul_grant_available || ul_mac_grant.phich_available) { + ue_ul_cfg.ul_cfg.pusch.rnti = dci_ul.rnti; + } else { + ue_ul_cfg.ul_cfg.pucch.rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI_TX); + } + + // PCell sends SR and ACK + if (cc_idx == 0) { + set_uci_sr(uci_data); + // This must be called after set_uci_sr() and set_uci_*_cqi + set_uci_ack(uci_data, ul_grant_available, dci_ul.dai, ul_action.tb.enabled); + } + + // Generate uplink signal, include uci data on only PCell + signal_ready = encode_uplink(&ul_action, (cc_idx == 0) ? uci_data : NULL); + + // Prepare to receive ACK through PHICH + if (ul_action.expect_ack) { + srslte_phich_grant_t phich_grant = {}; + phich_grant.I_phich = 0; + if (cell.frame_type == SRSLTE_TDD && sf_cfg_ul.tdd_config.sf_config == 0) { + if ((sf_cfg_ul.tti % 10) == 4 || (sf_cfg_ul.tti % 10) == 9) { + phich_grant.I_phich = 1; + } + } + phich_grant.n_prb_lowest = ue_ul_cfg.ul_cfg.pusch.grant.n_prb_tilde[0]; + phich_grant.n_dmrs = ue_ul_cfg.ul_cfg.pusch.grant.n_dmrs; + + phy->set_ul_pending_ack(&sf_cfg_ul, cc_idx, phich_grant, &dci_ul); + } + + return signal_ready; +} + +void cc_worker::ul_phy_to_mac_grant(srslte_pusch_grant_t* phy_grant, + srslte_dci_ul_t* dci_ul, + uint32_t pid, + bool ul_grant_available, + srsue::mac_interface_phy::mac_grant_ul_t* mac_grant) +{ + if (mac_grant->phich_available && !dci_ul->rnti) { + mac_grant->rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI); + } else { + mac_grant->rnti = dci_ul->rnti; + } + mac_grant->tb.ndi = dci_ul->tb.ndi; + mac_grant->tb.ndi_present = ul_grant_available; + mac_grant->tb.tbs = phy_grant->tb.tbs / (uint32_t)8; + mac_grant->tb.rv = phy_grant->tb.rv; + mac_grant->pid = pid; +} + +int cc_worker::decode_pdcch_ul() +{ + int nof_grants = 0; + + srslte_dci_ul_t dci[SRSLTE_MAX_CARRIERS]; + ZERO_OBJECT(dci); + + uint16_t ul_rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI); + + if (ul_rnti) { + /* Blind search first without cross scheduling then with it if enabled */ + for (int i = 0; i < (phy->cif_enabled ? 2 : 1) && !nof_grants; i++) { + fill_dci_cfg(&ue_dl_cfg.dci_cfg, i > 0); + nof_grants = srslte_ue_dl_find_ul_dci(&ue_dl, &sf_cfg_dl, &ue_dl_cfg, ul_rnti, dci); + if (nof_grants < 0) { + Error("Looking for UL grants\n"); + return -1; + } + } + + /* Convert every DCI message to UL dci */ + for (int k = 0; k < nof_grants; k++) { + + // If the DCI does not have Carrier Indicator Field then indicate in which carrier the dci was found + uint32_t cc_idx_grant = dci[k].cif_present ? dci[k].cif : cc_idx; + + // Save DCI + phy->set_ul_pending_grant(&sf_cfg_dl, cc_idx_grant, &dci[k]); + + // Logging + char str[512]; + srslte_dci_ul_info(&dci[k], str, 512); + Info("PDCCH: cc=%d, %s, snr=%.1f dB\n", cc_idx_grant, str, ue_dl.chest_res.snr_db); + } + } + + return nof_grants; +} + +bool cc_worker::encode_uplink(mac_interface_phy::tb_action_ul_t* action, srslte_uci_data_t* uci_data) +{ + srslte_pusch_data_t data = {}; + ue_ul_cfg.cc_idx = cc_idx; + + // Setup input data + if (action) { + data.ptr = action->tb.payload; + ue_ul_cfg.ul_cfg.pusch.softbuffers.tx = action->tb.softbuffer.tx; + } + + // Set UCI data and configuration + if (uci_data) { + data.uci = uci_data->value; + ue_ul_cfg.ul_cfg.pusch.uci_cfg = uci_data->cfg; + ue_ul_cfg.ul_cfg.pucch.uci_cfg = uci_data->cfg; + } else { + ZERO_OBJECT(ue_ul_cfg.ul_cfg.pusch.uci_cfg); + ZERO_OBJECT(ue_ul_cfg.ul_cfg.pucch.uci_cfg); + } + + // Use RV from higher layers + ue_ul_cfg.ul_cfg.pusch.grant.tb.rv = action->tb.rv; + + // Setup PUSCH grant + ue_ul_cfg.grant_available = action->tb.enabled; + + // Set UL RNTI + ue_ul_cfg.ul_cfg.pucch.rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI_TX); + + // Encode signal + int ret = srslte_ue_ul_encode(&ue_ul, &sf_cfg_ul, &ue_ul_cfg, &data); + if (ret < 0) { + Error("Encoding UL cc=%d\n", cc_idx); + } + + // Store metrics + if (action->tb.enabled) { + ul_metrics.mcs = ue_ul_cfg.ul_cfg.pusch.grant.tb.mcs_idx; + } + + // Logging + char str[512]; + if (srslte_ue_ul_info(&ue_ul_cfg, &sf_cfg_ul, &data.uci, str, 512)) { + Info("%s\n", str); + } + + return ret > 0; +} + +void cc_worker::set_uci_sr(srslte_uci_data_t* uci_data) +{ + if (srslte_ue_ul_gen_sr(&ue_ul_cfg, &sf_cfg_ul, uci_data, phy->sr_enabled)) { + if (phy->sr_enabled) { + phy->sr_last_tx_tti = CURRENT_TTI_TX; + phy->sr_enabled = false; + } + } +} + +uint32_t cc_worker::get_wideband_cqi() +{ + int cqi_fixed = phy->args->cqi_fixed; + int cqi_max = phy->args->cqi_max; + + uint32_t wb_cqi_value = srslte_cqi_from_snr(phy->avg_snr_db_cqi[cc_idx] + ue_dl_cfg.snr_to_cqi_offset); + + if (cqi_fixed >= 0) { + wb_cqi_value = cqi_fixed; + } else if (cqi_max >= 0 && wb_cqi_value > (uint32_t)cqi_max) { + wb_cqi_value = cqi_max; + } + + return wb_cqi_value; +} + +void cc_worker::set_uci_periodic_cqi(srslte_uci_data_t* uci_data) +{ + srslte_ue_dl_gen_cqi_periodic(&ue_dl, &ue_dl_cfg, get_wideband_cqi(), CURRENT_TTI_TX, uci_data); +} + +void cc_worker::set_uci_aperiodic_cqi(srslte_uci_data_t* uci_data) +{ + if (ue_dl_cfg.cfg.cqi_report.aperiodic_configured) { + srslte_ue_dl_gen_cqi_aperiodic(&ue_dl, &ue_dl_cfg, get_wideband_cqi(), uci_data); + } else { + Warning("Received CQI request but aperiodic mode is not configured\n"); + } +} + +void cc_worker::set_uci_ack(srslte_uci_data_t* uci_data, + bool is_grant_available, + uint32_t V_dai_ul, + bool is_pusch_available) +{ + + srslte_pdsch_ack_t ack_info = {}; + uint32_t nof_configured_carriers = 0; + + // Only PCell generates ACK for all SCell + for (uint32_t cc_idx = 0; cc_idx < phy->args->nof_carriers; cc_idx++) { + if (cc_idx == 0 || phy->scell_configured[cc_idx]) { + phy->get_dl_pending_ack(&sf_cfg_ul, cc_idx, &ack_info.cc[cc_idx]); + nof_configured_carriers++; + } + } + + // Set ACK length for CA (default value is set to DTX) + if (ue_ul_cfg.ul_cfg.pucch.ack_nack_feedback_mode != SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL) { + if (ue_dl_cfg.cfg.tm > SRSLTE_TM2) { + /* TM3, TM4 */ + uci_data->cfg.ack.nof_acks = nof_configured_carriers * SRSLTE_MAX_CODEWORDS; + } else { + /* TM1, TM2 */ + uci_data->cfg.ack.nof_acks = nof_configured_carriers; + } + } + + // Configure ACK parameters + ack_info.is_grant_available = is_grant_available; + ack_info.is_pusch_available = is_pusch_available; + ack_info.V_dai_ul = V_dai_ul; + ack_info.tdd_ack_bundle = ue_ul_cfg.ul_cfg.pucch.tdd_ack_bundle; + ack_info.simul_cqi_ack = ue_ul_cfg.ul_cfg.pucch.simul_cqi_ack; + ack_info.ack_nack_feedback_mode = ue_ul_cfg.ul_cfg.pucch.ack_nack_feedback_mode; + ack_info.nof_cc = nof_configured_carriers; + ack_info.transmission_mode = ue_dl_cfg.cfg.tm; + + // Generate ACK/NACK bits + srslte_ue_dl_gen_ack(&ue_dl, &sf_cfg_dl, &ack_info, uci_data); +} + +float cc_worker::set_power(float tx_power) +{ + float gain = 0; + /* Check if UL power control is enabled */ + if (phy->args->ul_pwr_ctrl_en) { + /* Adjust maximum power if it changes significantly */ + if (tx_power < phy->cur_radio_power - 5 || tx_power > phy->cur_radio_power + 5) { + phy->cur_radio_power = tx_power; + float radio_tx_power = phy->cur_radio_power; + gain = phy->get_radio()->set_tx_power(radio_tx_power); + } + } + return gain; +} + +/************ + * + * Configuration Functions + * + */ + +srslte_cqi_report_mode_t cc_worker::aperiodic_mode(cqi_report_mode_aperiodic_e mode) +{ + switch (mode) { + case cqi_report_mode_aperiodic_e::rm12: + return SRSLTE_CQI_MODE_12; + case cqi_report_mode_aperiodic_e::rm20: + return SRSLTE_CQI_MODE_20; + case cqi_report_mode_aperiodic_e::rm22: + return SRSLTE_CQI_MODE_22; + case cqi_report_mode_aperiodic_e::rm30: + return SRSLTE_CQI_MODE_30; + case cqi_report_mode_aperiodic_e::rm31: + return SRSLTE_CQI_MODE_31; + case cqi_report_mode_aperiodic_e::rm10_v1310: + case cqi_report_mode_aperiodic_e::rm11_v1310: + case cqi_report_mode_aperiodic_e::rm32_v1250: + fprintf(stderr, "Aperiodic mode %s not handled\n", mode.to_string().c_str()); + default: + return SRSLTE_CQI_MODE_NA; + } +} + +void cc_worker::parse_antenna_info(phys_cfg_ded_s* dedicated) +{ + if (dedicated->ant_info_r10_present) { + // Parse Release 10 + ant_info_ded_r10_s::tx_mode_r10_e_::options tx_mode = + dedicated->ant_info_r10->explicit_value_r10().tx_mode_r10.value; + if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) { + ue_dl_cfg.cfg.tm = (srslte_tm_t)tx_mode; + } else { + fprintf(stderr, + "Transmission mode (R10) %s is not supported\n", + dedicated->ant_info_r10->explicit_value_r10().tx_mode_r10.to_string().c_str()); + } + } else if (dedicated->ant_info_present && + dedicated->ant_info.type() == phys_cfg_ded_s::ant_info_c_::types::explicit_value) { + // Parse Release 8 + ant_info_ded_s::tx_mode_e_::options tx_mode = dedicated->ant_info.explicit_value().tx_mode.value; + if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) { + ue_dl_cfg.cfg.tm = (srslte_tm_t)tx_mode; + } else { + fprintf(stderr, + "Transmission mode (R8) %s is not supported\n", + dedicated->ant_info.explicit_value().tx_mode.to_string().c_str()); + } + } else { + if (cell.nof_ports == 1) { + // No antenna info provided + ue_dl_cfg.cfg.tm = SRSLTE_TM1; + } else { + // No antenna info provided + ue_dl_cfg.cfg.tm = SRSLTE_TM2; + } + } +} + +void cc_worker::parse_pucch_config(phy_interface_rrc::phy_cfg_t* phy_cfg) +{ + phy_interface_rrc::phy_cfg_common_t* common = &phy_cfg->common; + phys_cfg_ded_s* dedicated = &phy_cfg->dedicated; + + /* PUCCH configuration */ + bzero(&ue_ul_cfg.ul_cfg.pucch, sizeof(srslte_pucch_cfg_t)); + ue_ul_cfg.ul_cfg.pucch.delta_pucch_shift = common->pucch_cnfg.delta_pucch_shift.to_number(); + ue_ul_cfg.ul_cfg.pucch.N_cs = common->pucch_cnfg.n_cs_an; + ue_ul_cfg.ul_cfg.pucch.n_rb_2 = common->pucch_cnfg.n_rb_cqi; + + /* PUCCH Scheduling configuration */ + ue_ul_cfg.ul_cfg.pucch.n_pucch_1[0] = 0; // TODO: n_pucch_1 for SPS + ue_ul_cfg.ul_cfg.pucch.n_pucch_1[1] = 0; + ue_ul_cfg.ul_cfg.pucch.n_pucch_1[2] = 0; + ue_ul_cfg.ul_cfg.pucch.n_pucch_1[3] = 0; + ue_ul_cfg.ul_cfg.pucch.N_pucch_1 = common->pucch_cnfg.n1_pucch_an; + if (dedicated->cqi_report_cfg.cqi_report_periodic_present and + dedicated->cqi_report_cfg.cqi_report_periodic.type().value == setup_e::setup) { + ue_ul_cfg.ul_cfg.pucch.n_pucch_2 = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx; + ue_ul_cfg.ul_cfg.pucch.simul_cqi_ack = dedicated->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi; + } else { + // FIXME: put is_pucch_configured flag here? + ue_ul_cfg.ul_cfg.pucch.n_pucch_2 = 0; + ue_ul_cfg.ul_cfg.pucch.simul_cqi_ack = false; + } + + /* SR configuration */ + if (dedicated->sched_request_cfg_present and dedicated->sched_request_cfg.type() == setup_e::setup) { + ue_ul_cfg.ul_cfg.pucch.I_sr = dedicated->sched_request_cfg.setup().sr_cfg_idx; + ue_ul_cfg.ul_cfg.pucch.n_pucch_sr = dedicated->sched_request_cfg.setup().sr_pucch_res_idx; + ue_ul_cfg.ul_cfg.pucch.sr_configured = true; + } else { + ue_ul_cfg.ul_cfg.pucch.I_sr = 0; + ue_ul_cfg.ul_cfg.pucch.n_pucch_sr = 0; + ue_ul_cfg.ul_cfg.pucch.sr_configured = false; + } + + if (dedicated->pucch_cfg_ded.tdd_ack_nack_feedback_mode_present) { + ue_ul_cfg.ul_cfg.pucch.tdd_ack_bundle = + dedicated->pucch_cfg_ded.tdd_ack_nack_feedback_mode == pucch_cfg_ded_s::tdd_ack_nack_feedback_mode_e_::bundling; + } else { + ue_ul_cfg.ul_cfg.pucch.tdd_ack_bundle = false; + } + + if (dedicated->pucch_cfg_ded_v1020_present) { + pucch_cfg_ded_v1020_s* pucch_cfg_ded = dedicated->pucch_cfg_ded_v1020.get(); + + if (pucch_cfg_ded->pucch_format_r10_present) { + + typedef pucch_cfg_ded_v1020_s::pucch_format_r10_c_ pucch_format_r10_t; + pucch_format_r10_t* pucch_format_r10 = &pucch_cfg_ded->pucch_format_r10; + + if (pucch_format_r10->type() == pucch_format_r10_t::types::format3_r10) { + // Select feedback mode + ue_ul_cfg.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3; + + pucch_format3_conf_r13_s* format3_r13 = &pucch_format_r10->format3_r10(); + for (uint32_t n = 0; n < SRSLTE_MIN(format3_r13->n3_pucch_an_list_r13.size(), SRSLTE_PUCCH_SIZE_AN_CS); n++) { + ue_ul_cfg.ul_cfg.pucch.n3_pucch_an_list[n] = format3_r13->n3_pucch_an_list_r13[n]; + } + if (format3_r13->two_ant_port_activ_pucch_format3_r13_present) { + if (format3_r13->two_ant_port_activ_pucch_format3_r13.type() == setup_e::setup) { + // TODO: UL MIMO Configure PUCCH two antenna port + } else { + // TODO: UL MIMO Disable two antenna port + } + } + } else if (pucch_format_r10->type() == pucch_cfg_ded_v1020_s::pucch_format_r10_c_::types::ch_sel_r10) { + + typedef pucch_format_r10_t::ch_sel_r10_s_ ch_sel_r10_t; + ch_sel_r10_t* ch_sel_r10 = &pucch_format_r10->ch_sel_r10(); + + if (ch_sel_r10->n1_pucch_an_cs_r10_present) { + typedef ch_sel_r10_t::n1_pucch_an_cs_r10_c_ n1_pucch_an_cs_r10_t; + n1_pucch_an_cs_r10_t* n1_pucch_an_cs_r10 = &ch_sel_r10->n1_pucch_an_cs_r10; + + if (n1_pucch_an_cs_r10->type() == setup_e::setup) { + // Select feedback mode + ue_ul_cfg.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS; + + typedef n1_pucch_an_cs_r10_t::setup_s_::n1_pucch_an_cs_list_r10_l_ n1_pucch_an_cs_list_r10_t; + n1_pucch_an_cs_list_r10_t n1_pucch_an_cs_list = + ch_sel_r10->n1_pucch_an_cs_r10.setup().n1_pucch_an_cs_list_r10; + for (uint32_t i = 0; i < SRSLTE_MIN(n1_pucch_an_cs_list.size(), SRSLTE_PUCCH_NOF_AN_CS); i++) { + n1_pucch_an_cs_r10_l n1_pucch_an_cs = n1_pucch_an_cs_list[i]; + for (uint32_t j = 0; j < SRSLTE_PUCCH_SIZE_AN_CS; j++) { + ue_ul_cfg.ul_cfg.pucch.n1_pucch_an_cs[j][i] = n1_pucch_an_cs[j]; + } + } + } else { + ue_ul_cfg.ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL; + } + } + } else { + // Do nothing + } + } + } +} + +/* Translates RRC structs into PHY structs + */ +void cc_worker::set_pcell_config(phy_interface_rrc::phy_cfg_t* phy_cfg) +{ + phy_interface_rrc::phy_cfg_common_t* common = &phy_cfg->common; + phys_cfg_ded_s* dedicated = &phy_cfg->dedicated; + + // Configure PDSCH + if (dedicated->pdsch_cfg_ded_present && common->pdsch_cnfg.p_b < 4) { + ue_dl_cfg.cfg.pdsch.p_a = dedicated->pdsch_cfg_ded.p_a.to_number(); + ue_dl_cfg.cfg.pdsch.p_b = common->pdsch_cnfg.p_b; + ue_dl_cfg.cfg.pdsch.power_scale = true; + } else { + ue_dl_cfg.cfg.pdsch.power_scale = false; + } + ue_dl_cfg.cfg.pdsch.rs_power = (float)common->pdsch_cnfg.ref_sig_pwr; + parse_antenna_info(dedicated); + + // Configure PUSCH + ue_ul_cfg.ul_cfg.pusch.enable_64qam = + phy->args->ue_category >= 5 && phy_cfg->common.pusch_cnfg.pusch_cfg_basic.enable64_qam; + + /* PUSCH DMRS signal configuration */ + bzero(&ue_ul_cfg.ul_cfg.dmrs, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); + ue_ul_cfg.ul_cfg.dmrs.group_hopping_en = common->pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled; + ue_ul_cfg.ul_cfg.dmrs.sequence_hopping_en = common->pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled; + ue_ul_cfg.ul_cfg.dmrs.cyclic_shift = common->pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift; + ue_ul_cfg.ul_cfg.dmrs.delta_ss = common->pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch; + + /* PUSCH Hopping configuration */ + bzero(&ue_ul_cfg.ul_cfg.hopping, sizeof(srslte_pusch_hopping_cfg_t)); + ue_ul_cfg.ul_cfg.hopping.n_sb = common->pusch_cnfg.pusch_cfg_basic.n_sb; + ue_ul_cfg.ul_cfg.hopping.hop_mode = + common->pusch_cnfg.pusch_cfg_basic.hop_mode.value == + pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame + ? ue_ul_cfg.ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF + : ue_ul_cfg.ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF; + ue_ul_cfg.ul_cfg.hopping.hopping_offset = common->pusch_cnfg.pusch_cfg_basic.pusch_hop_offset; + + /* PUSCH UCI configuration */ + bzero(&ue_ul_cfg.ul_cfg.pusch.uci_offset, sizeof(srslte_uci_offset_cfg_t)); + ue_ul_cfg.ul_cfg.pusch.uci_offset.I_offset_ack = dedicated->pusch_cfg_ded.beta_offset_ack_idx; + ue_ul_cfg.ul_cfg.pusch.uci_offset.I_offset_cqi = dedicated->pusch_cfg_ded.beta_offset_cqi_idx; + ue_ul_cfg.ul_cfg.pusch.uci_offset.I_offset_ri = dedicated->pusch_cfg_ded.beta_offset_ri_idx; + + parse_pucch_config(phy_cfg); + + /* SRS Configuration */ + bzero(&ue_ul_cfg.ul_cfg.srs, sizeof(srslte_refsignal_srs_cfg_t)); + ue_ul_cfg.ul_cfg.srs.configured = dedicated->srs_ul_cfg_ded_present and + dedicated->srs_ul_cfg_ded.type() == setup_e::setup and + common->srs_ul_cnfg.type() == setup_e::setup; + if (ue_ul_cfg.ul_cfg.srs.configured) { + ue_ul_cfg.ul_cfg.srs.I_srs = dedicated->srs_ul_cfg_ded.setup().srs_cfg_idx; + ue_ul_cfg.ul_cfg.srs.B = dedicated->srs_ul_cfg_ded.setup().srs_bw; + ue_ul_cfg.ul_cfg.srs.b_hop = dedicated->srs_ul_cfg_ded.setup().srs_hop_bw; + ue_ul_cfg.ul_cfg.srs.n_rrc = dedicated->srs_ul_cfg_ded.setup().freq_domain_position; + ue_ul_cfg.ul_cfg.srs.k_tc = dedicated->srs_ul_cfg_ded.setup().tx_comb; + ue_ul_cfg.ul_cfg.srs.n_srs = dedicated->srs_ul_cfg_ded.setup().cyclic_shift; + ue_ul_cfg.ul_cfg.srs.simul_ack = common->srs_ul_cnfg.setup().ack_nack_srs_simul_tx; + ue_ul_cfg.ul_cfg.srs.bw_cfg = common->srs_ul_cnfg.setup().srs_bw_cfg.to_number(); + ue_ul_cfg.ul_cfg.srs.subframe_config = common->srs_ul_cnfg.setup().srs_sf_cfg.to_number(); + } + + /* UL power control configuration */ + bzero(&ue_ul_cfg.ul_cfg.power_ctrl, sizeof(srslte_ue_ul_powerctrl_t)); + ue_ul_cfg.ul_cfg.power_ctrl.p0_nominal_pusch = common->ul_pwr_ctrl.p0_nominal_pusch; + ue_ul_cfg.ul_cfg.power_ctrl.alpha = common->ul_pwr_ctrl.alpha.to_number(); + ue_ul_cfg.ul_cfg.power_ctrl.p0_nominal_pucch = common->ul_pwr_ctrl.p0_nominal_pucch; + ue_ul_cfg.ul_cfg.power_ctrl.delta_f_pucch[0] = + common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format1.to_number(); + ue_ul_cfg.ul_cfg.power_ctrl.delta_f_pucch[1] = + common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format1b.to_number(); + ue_ul_cfg.ul_cfg.power_ctrl.delta_f_pucch[2] = + common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2.to_number(); + ue_ul_cfg.ul_cfg.power_ctrl.delta_f_pucch[3] = + common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2a.to_number(); + ue_ul_cfg.ul_cfg.power_ctrl.delta_f_pucch[4] = + common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2b.to_number(); + + ue_ul_cfg.ul_cfg.power_ctrl.delta_preamble_msg3 = common->ul_pwr_ctrl.delta_preamb_msg3; + + ue_ul_cfg.ul_cfg.power_ctrl.p0_ue_pusch = dedicated->ul_pwr_ctrl_ded.p0_ue_pusch; + ue_ul_cfg.ul_cfg.power_ctrl.delta_mcs_based = + dedicated->ul_pwr_ctrl_ded.delta_mcs_enabled == ul_pwr_ctrl_ded_s::delta_mcs_enabled_e_::en0; + ue_ul_cfg.ul_cfg.power_ctrl.acc_enabled = dedicated->ul_pwr_ctrl_ded.accumulation_enabled; + ue_ul_cfg.ul_cfg.power_ctrl.p0_ue_pucch = dedicated->ul_pwr_ctrl_ded.p0_ue_pucch; + ue_ul_cfg.ul_cfg.power_ctrl.p_srs_offset = dedicated->ul_pwr_ctrl_ded.p_srs_offset; + + /* CQI configuration */ + bzero(&ue_dl_cfg.cfg.cqi_report, sizeof(srslte_cqi_report_cfg_t)); + ue_dl_cfg.cfg.cqi_report.periodic_configured = dedicated->cqi_report_cfg.cqi_report_periodic_present and + dedicated->cqi_report_cfg.cqi_report_periodic.type() == setup_e::setup; + if (ue_dl_cfg.cfg.cqi_report.periodic_configured) { + ue_dl_cfg.cfg.cqi_report.pmi_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx; + ue_dl_cfg.cfg.cqi_report.format_is_subband = + dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().value == + cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::subband_cqi; + if (ue_dl_cfg.cfg.cqi_report.format_is_subband) { + ue_dl_cfg.cfg.cqi_report.subband_size = + dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.subband_cqi().k; + } + if (dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) { + if (cell.nof_ports > 1) { + log_h->error("Warning: Received Rank Indication report configuration but only 1 antenna is available\n"); + } + ue_dl_cfg.cfg.cqi_report.ri_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx; + ue_dl_cfg.cfg.cqi_report.ri_idx_present = true; + } else { + ue_dl_cfg.cfg.cqi_report.ri_idx_present = false; + } + } + + if (dedicated->cqi_report_cfg.cqi_report_mode_aperiodic_present) { + ue_dl_cfg.cfg.cqi_report.aperiodic_configured = true; + ue_dl_cfg.cfg.cqi_report.aperiodic_mode = aperiodic_mode(dedicated->cqi_report_cfg.cqi_report_mode_aperiodic); + } + + if (pregen_enabled) { + Info("Pre-generating UL signals...\n"); + srslte_ue_ul_pregen_signals(&ue_ul, &ue_ul_cfg); + Info("Done pre-generating signals worker...\n"); + } +} + +void cc_worker::set_scell_config(asn1::rrc::scell_to_add_mod_r10_s* phy_cfg) +{ + if (phy_cfg->rr_cfg_common_scell_r10_present) { + rr_cfg_common_scell_r10_s* rr_cfg_common_scell_r10 = &phy_cfg->rr_cfg_common_scell_r10; + + if (rr_cfg_common_scell_r10->ul_cfg_r10_present) { + typedef rr_cfg_common_scell_r10_s::ul_cfg_r10_s_ ul_cfg_r10_t; + ul_cfg_r10_t* ul_cfg_r10 = &rr_cfg_common_scell_r10->ul_cfg_r10; + + // Parse Power control + ul_pwr_ctrl_common_scell_r10_s* ul_pwr_ctrl_common_scell_r10 = &ul_cfg_r10->ul_pwr_ctrl_common_scell_r10; + bzero(&ue_ul_cfg.ul_cfg.power_ctrl, sizeof(srslte_ue_ul_powerctrl_t)); + ue_ul_cfg.ul_cfg.power_ctrl.p0_nominal_pusch = ul_pwr_ctrl_common_scell_r10->p0_nominal_pusch_r10; + ue_ul_cfg.ul_cfg.power_ctrl.alpha = ul_pwr_ctrl_common_scell_r10->alpha_r10.to_number(); + + // Parse SRS + typedef srs_ul_cfg_common_c::setup_s_ srs_ul_cfg_common_t; + if (ul_cfg_r10->srs_ul_cfg_common_r10.type() == setup_e::setup) { + srs_ul_cfg_common_t* srs_ul_cfg_common = &ul_cfg_r10->srs_ul_cfg_common_r10.setup(); + ue_ul_cfg.ul_cfg.srs.configured = true; + ue_ul_cfg.ul_cfg.srs.simul_ack = srs_ul_cfg_common->ack_nack_srs_simul_tx; + ue_ul_cfg.ul_cfg.srs.bw_cfg = srs_ul_cfg_common->srs_bw_cfg.to_number(); + ue_ul_cfg.ul_cfg.srs.subframe_config = srs_ul_cfg_common->srs_sf_cfg.to_number(); + } else { + ue_ul_cfg.ul_cfg.srs.configured = false; + } + + // Parse PUSCH + pusch_cfg_common_s* pusch_cfg_common = &ul_cfg_r10->pusch_cfg_common_r10; + bzero(&ue_ul_cfg.ul_cfg.hopping, sizeof(srslte_pusch_hopping_cfg_t)); + ue_ul_cfg.ul_cfg.hopping.n_sb = pusch_cfg_common->pusch_cfg_basic.n_sb; + ue_ul_cfg.ul_cfg.hopping.hop_mode = + pusch_cfg_common->pusch_cfg_basic.hop_mode.value == + pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame + ? ue_ul_cfg.ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF + : ue_ul_cfg.ul_cfg.hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF; + ue_ul_cfg.ul_cfg.hopping.hopping_offset = pusch_cfg_common->pusch_cfg_basic.pusch_hop_offset; + } + } + + if (phy_cfg->rr_cfg_ded_scell_r10_present) { + rr_cfg_ded_scell_r10_s* rr_cfg_ded_scell_r10 = &phy_cfg->rr_cfg_ded_scell_r10; + if (rr_cfg_ded_scell_r10->phys_cfg_ded_scell_r10_present) { + phys_cfg_ded_scell_r10_s* phys_cfg_ded_scell_r10 = &rr_cfg_ded_scell_r10->phys_cfg_ded_scell_r10; + + // Parse nonUL Configuration + if (phys_cfg_ded_scell_r10->non_ul_cfg_r10_present) { + + typedef phys_cfg_ded_scell_r10_s::non_ul_cfg_r10_s_ non_ul_cfg_t; + non_ul_cfg_t* non_ul_cfg = &phys_cfg_ded_scell_r10->non_ul_cfg_r10; + + // Parse Transmission mode + if (non_ul_cfg->ant_info_r10_present) { + ant_info_ded_r10_s::tx_mode_r10_e_::options tx_mode = non_ul_cfg->ant_info_r10.tx_mode_r10.value; + if ((srslte_tm_t)tx_mode < SRSLTE_TMINV) { + ue_dl_cfg.cfg.tm = (srslte_tm_t)tx_mode; + } else { + fprintf(stderr, + "Transmission mode (R10) %s is not supported\n", + non_ul_cfg->ant_info_r10.tx_mode_r10.to_string().c_str()); + } + } + + // Parse Cross carrier scheduling + if (non_ul_cfg->cross_carrier_sched_cfg_r10_present) { + typedef cross_carrier_sched_cfg_r10_s::sched_cell_info_r10_c_ sched_info_t; + + typedef sched_info_t::types cross_carrier_type_e; + sched_info_t* sched_info = &non_ul_cfg->cross_carrier_sched_cfg_r10.sched_cell_info_r10; + + cross_carrier_type_e cross_carrier_type = sched_info->type(); + if (cross_carrier_type == cross_carrier_type_e::own_r10) { + ue_dl_cfg.dci_cfg.cif_enabled = sched_info->own_r10().cif_presence_r10; + } else { + ue_dl_cfg.dci_cfg.cif_enabled = false; // This CC does not have Carrier Indicator Field + // ue_dl_cfg.blablabla = sched_info->other_r10().pdsch_start_r10; + // ue_dl_cfg.blablabla = sched_info->other_r10().sched_cell_id_r10; + } + } + + // Parse pdsch config dedicated + if (non_ul_cfg->pdsch_cfg_ded_r10_present) { + ue_dl_cfg.cfg.pdsch.p_b = phy_cfg->rr_cfg_common_scell_r10.non_ul_cfg_r10.pdsch_cfg_common_r10.p_b; + ue_dl_cfg.cfg.pdsch.p_a = non_ul_cfg->pdsch_cfg_ded_r10.p_a.to_number(); + ue_dl_cfg.cfg.pdsch.power_scale = true; + } + } + + // Parse UL Configuration + if (phys_cfg_ded_scell_r10->ul_cfg_r10_present) { + typedef phys_cfg_ded_scell_r10_s::ul_cfg_r10_s_ ul_cfg_t; + ul_cfg_t* ul_cfg = &phys_cfg_ded_scell_r10->ul_cfg_r10; + + // Parse CQI param + if (ul_cfg->cqi_report_cfg_scell_r10_present) { + cqi_report_cfg_scell_r10_s* cqi_report_cfg = &ul_cfg->cqi_report_cfg_scell_r10; + + // Aperiodic report + if (cqi_report_cfg->cqi_report_mode_aperiodic_r10_present) { + ue_dl_cfg.cfg.cqi_report.aperiodic_configured = true; + ue_dl_cfg.cfg.cqi_report.aperiodic_mode = aperiodic_mode(cqi_report_cfg->cqi_report_mode_aperiodic_r10); + } + + // Periodic report + if (cqi_report_cfg->cqi_report_periodic_scell_r10_present) { + if (cqi_report_cfg->cqi_report_periodic_scell_r10.type() == setup_e::setup) { + typedef cqi_report_periodic_r10_c::setup_s_ cqi_cfg_t; + cqi_cfg_t cqi_cfg = cqi_report_cfg->cqi_report_periodic_scell_r10.setup(); + ue_dl_cfg.cfg.cqi_report.periodic_configured = true; + ue_dl_cfg.cfg.cqi_report.pmi_idx = cqi_cfg.cqi_pmi_cfg_idx; + ue_dl_cfg.cfg.cqi_report.format_is_subband = + cqi_cfg.cqi_format_ind_periodic_r10.type().value == + cqi_cfg_t::cqi_format_ind_periodic_r10_c_::types::subband_cqi_r10; + if (ue_dl_cfg.cfg.cqi_report.format_is_subband) { + ue_dl_cfg.cfg.cqi_report.subband_size = cqi_cfg.cqi_format_ind_periodic_r10.subband_cqi_r10().k; + } + if (cqi_cfg.ri_cfg_idx_present) { + ue_dl_cfg.cfg.cqi_report.ri_idx = cqi_cfg.ri_cfg_idx; + ue_dl_cfg.cfg.cqi_report.ri_idx_present = true; + } else { + ue_dl_cfg.cfg.cqi_report.ri_idx_present = false; + } + } else { + // Release, disable periodic reporting + ue_dl_cfg.cfg.cqi_report.periodic_configured = false; + } + } + } + + if (ul_cfg->srs_ul_cfg_ded_r10_present) { + // Sounding reference signals + if (ul_cfg->srs_ul_cfg_ded_r10.type() == setup_e::setup) { + srs_ul_cfg_ded_c::setup_s_* srs_ul_cfg_ded_r10 = &ul_cfg->srs_ul_cfg_ded_r10.setup(); + ue_ul_cfg.ul_cfg.srs.bw_cfg = srs_ul_cfg_ded_r10->srs_bw.to_number(); + ue_ul_cfg.ul_cfg.srs.I_srs = srs_ul_cfg_ded_r10->srs_cfg_idx; + ue_ul_cfg.ul_cfg.srs.B = srs_ul_cfg_ded_r10->srs_bw; + ue_ul_cfg.ul_cfg.srs.b_hop = srs_ul_cfg_ded_r10->srs_hop_bw; + ue_ul_cfg.ul_cfg.srs.n_rrc = srs_ul_cfg_ded_r10->freq_domain_position; + ue_ul_cfg.ul_cfg.srs.k_tc = srs_ul_cfg_ded_r10->tx_comb; + ue_ul_cfg.ul_cfg.srs.n_srs = srs_ul_cfg_ded_r10->cyclic_shift; + ue_ul_cfg.ul_cfg.srs.bw_cfg = 0; + } else { + ue_ul_cfg.ul_cfg.srs.configured = false; + } + } + } + } + } +} + +int cc_worker::read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna) +{ + uint32_t i = 0; + int sz = srslte_symbol_sz(cell.nof_prb); + bzero(ce_abs, sizeof(float) * sz); + int g = (sz - 12 * cell.nof_prb) / 2; + for (i = 0; i < 12 * cell.nof_prb; i++) { + ce_abs[g + i] = 20 * log10f(cabsf(ue_dl.chest_res.ce[tx_antenna][rx_antenna][i])); + if (std::isinf(ce_abs[g + i])) { + ce_abs[g + i] = -80; + } + } + return sz; +} + +int cc_worker::read_pdsch_d(cf_t* pdsch_d) +{ + memcpy(pdsch_d, ue_dl.pdsch.d[0], ue_dl_cfg.cfg.pdsch.grant.nof_re * sizeof(cf_t)); + return ue_dl_cfg.cfg.pdsch.grant.nof_re; +} + +} // namespace srsue diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc deleted file mode 100644 index ec38b8f4b..000000000 --- a/srsue/src/phy/phch_common.cc +++ /dev/null @@ -1,565 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include "srsue/hdr/phy/phch_common.h" -#include "srslte/asn1/rrc_asn1.h" -#include "srslte/srslte.h" -#include -#include -#include - -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) - -using namespace asn1::rrc; - -namespace srsue { - -cf_t zeros[50000]; - -phch_common::phch_common(uint32_t max_workers) : tx_sem(max_workers) -{ - config = NULL; - args = NULL; - log_h = NULL; - radio_h = NULL; - mac = NULL; - this->max_workers = max_workers; - rx_gain_offset = 0; - last_ri = 0; - last_pmi = 0; - avg_noise = 0; - //have_mtch_stop = false; - - bzero(&dl_metrics, sizeof(dl_metrics_t)); - dl_metrics_read = true; - dl_metrics_count = 0; - bzero(&ul_metrics, sizeof(ul_metrics_t)); - ul_metrics_read = true; - ul_metrics_count = 0; - bzero(&sync_metrics, sizeof(sync_metrics_t)); - sync_metrics_read = true; - sync_metrics_count = 0; - - bzero(zeros, 50000*sizeof(cf_t)); - - for (uint32_t i=0;inof_workers = nof_workers; -} - -void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) -{ - log_h = _log; - radio_h = _radio; - rrc = _rrc; - mac = _mac; - config = _config; - args = _args; - is_first_tx = true; - sr_last_tx_tti = -1; -} - -bool phch_common::ul_rnti_active(uint32_t tti) { - if ((((int)tti >= ul_rnti_start && ul_rnti_start >= 0) || ul_rnti_start < 0) && - (((int)tti < ul_rnti_end && ul_rnti_end >= 0) || ul_rnti_end < 0)) - { - return true; - } else { - return false; - } -} - -bool phch_common::dl_rnti_active(uint32_t tti) { - Debug("tti=%d, dl_rnti_start=%d, dl_rnti_end=%d, dl_rnti=0x%x\n", tti, dl_rnti_start, dl_rnti_end, dl_rnti); - if ((((int)tti >= dl_rnti_start && dl_rnti_start >= 0) || dl_rnti_start < 0) && - (((int)tti < dl_rnti_end && dl_rnti_end >= 0) || dl_rnti_end < 0)) - { - bool ret = true; - // FIXME: This scheduling decision belongs to RRC - if (dl_rnti_type == SRSLTE_RNTI_SI) { - if (dl_rnti_end - dl_rnti_start > 1) { // This is not a SIB1 - if ((tti/10)%2 == 0 && (tti%10) == 5) { // Skip subframe #5 for which SFN mod 2 = 0 - ret = false; - } - } - } - return ret; - } else { - return false; - } -} - -srslte::radio* phch_common::get_radio() -{ - return radio_h; -} - -// Unpack RAR grant as defined in Section 6.2 of 36.213 -void phch_common::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) -{ - srslte_dci_rar_grant_unpack(&rar_grant, grant_payload); - rar_grant_pending = true; - if (MSG3_DELAY_MS < 0) { - fprintf(stderr, "Error MSG3_DELAY_MS can't be negative\n"); - } - if (rar_grant.ul_delay) { - rar_grant_tti = (tti + MSG3_DELAY_MS + 1) % 10240; - } else { - rar_grant_tti = (tti + MSG3_DELAY_MS) % 10240; - } -} - -bool phch_common::get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant_) -{ - if (rar_grant_pending && tti >= rar_grant_tti) { - if (rar_grant_) { - rar_grant_pending = false; - *rar_grant_ = rar_grant; - } - return true; - } - return false; -} - -/* Common variables used by all phy workers */ -uint16_t phch_common::get_ul_rnti(uint32_t tti) { - if (ul_rnti_active(tti)) { - return ul_rnti; - } else { - return 0; - } -} -srslte_rnti_type_t phch_common::get_ul_rnti_type() { - return ul_rnti_type; -} -void phch_common::set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) { - ul_rnti = rnti_value; - ul_rnti_type = type; - ul_rnti_start = tti_start; - ul_rnti_end = tti_end; -} -uint16_t phch_common::get_dl_rnti(uint32_t tti) { - if (dl_rnti_active(tti)) { - return dl_rnti; - } else { - return 0; - } -} -srslte_rnti_type_t phch_common::get_dl_rnti_type() { - return dl_rnti_type; -} -void phch_common::set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start, int tti_end) { - dl_rnti = rnti_value; - dl_rnti_type = type; - dl_rnti_start = tti_start; - dl_rnti_end = tti_end; - if (log_h) { - Debug("Set DL rnti: start=%d, end=%d, value=0x%x\n", tti_start, tti_end, rnti_value); - } -} - -void phch_common::reset_pending_ack(uint32_t tti) { - pending_ack[TTIMOD(tti)].enabled = false; -} - -void phch_common::set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs) { - pending_ack[TTIMOD(tti)].enabled = true; - pending_ack[TTIMOD(tti)].I_lowest = I_lowest; - pending_ack[TTIMOD(tti)].n_dmrs = n_dmrs; - Debug("Set pending ACK for tti=%d I_lowest=%d, n_dmrs=%d\n", tti, I_lowest, n_dmrs); -} - -bool phch_common::get_pending_ack(uint32_t tti) { - return get_pending_ack(tti, NULL, NULL); -} - -bool phch_common::get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs) { - if (I_lowest) { - *I_lowest = pending_ack[TTIMOD(tti)].I_lowest; - } - if (n_dmrs) { - *n_dmrs = pending_ack[TTIMOD(tti)].n_dmrs; - } - return pending_ack[TTIMOD(tti)].enabled; -} - -bool phch_common::is_any_pending_ack() { - for (int i=0;iset_tti(tti); - if (tx_enable) { - radio_h->tx_single(buffer, nof_samples, tx_time); - is_first_of_burst = false; - } else { - if (radio_h->is_continuous_tx()) { - if (!is_first_of_burst) { - radio_h->tx_single(zeros, nof_samples, tx_time); - } - } else { - if (!is_first_of_burst) { - radio_h->tx_end(); - is_first_of_burst = true; - } - } - } - - // Allow next TTI to transmit - sem_post(&tx_sem[(tti+1)%nof_workers]); -} - - -void phch_common::set_cell(const srslte_cell_t &c) { - cell = c; -} - -uint32_t phch_common::get_nof_prb() { - return cell.nof_prb; -} - -void phch_common::set_dl_metrics(const dl_metrics_t &m) { - if(dl_metrics_read) { - dl_metrics = m; - dl_metrics_count = 1; - dl_metrics_read = false; - } else { - dl_metrics_count++; - dl_metrics.mcs = dl_metrics.mcs + (m.mcs - dl_metrics.mcs)/dl_metrics_count; - dl_metrics.n = dl_metrics.n + (m.n - dl_metrics.n)/dl_metrics_count; - dl_metrics.rsrp = dl_metrics.rsrp + (m.rsrp - dl_metrics.rsrp)/dl_metrics_count; - dl_metrics.rsrq = dl_metrics.rsrq + (m.rsrq - dl_metrics.rsrq)/dl_metrics_count; - dl_metrics.rssi = dl_metrics.rssi + (m.rssi - dl_metrics.rssi)/dl_metrics_count; - dl_metrics.sinr = dl_metrics.sinr + (m.sinr - dl_metrics.sinr)/dl_metrics_count; - dl_metrics.pathloss = dl_metrics.pathloss + (m.pathloss - dl_metrics.pathloss)/dl_metrics_count; - dl_metrics.turbo_iters = dl_metrics.turbo_iters + (m.turbo_iters - dl_metrics.turbo_iters)/dl_metrics_count; - } -} - -void phch_common::get_dl_metrics(dl_metrics_t &m) { - m = dl_metrics; - dl_metrics_read = true; -} - -void phch_common::set_ul_metrics(const ul_metrics_t &m) { - if(ul_metrics_read) { - ul_metrics = m; - ul_metrics_count = 1; - ul_metrics_read = false; - } else { - ul_metrics_count++; - ul_metrics.mcs = ul_metrics.mcs + (m.mcs - ul_metrics.mcs)/ul_metrics_count; - ul_metrics.power = ul_metrics.power + (m.power - ul_metrics.power)/ul_metrics_count; - } -} - -void phch_common::get_ul_metrics(ul_metrics_t &m) { - m = ul_metrics; - ul_metrics_read = true; -} - -void phch_common::set_sync_metrics(const sync_metrics_t &m) { - - if(sync_metrics_read) { - sync_metrics = m; - sync_metrics_count = 1; - sync_metrics_read = false; - } else { - sync_metrics_count++; - sync_metrics.cfo = sync_metrics.cfo + (m.cfo - sync_metrics.cfo)/sync_metrics_count; - sync_metrics.sfo = sync_metrics.sfo + (m.sfo - sync_metrics.sfo)/sync_metrics_count; - } -} - -void phch_common::get_sync_metrics(sync_metrics_t &m) { - m = sync_metrics; - sync_metrics_read = true; -} - -void phch_common::reset() { - sr_enabled = false; - is_first_of_burst = true; - is_first_tx = true; - rar_grant_pending = false; - pathloss = 0; - cur_pathloss = 0; - cur_pusch_power = 0; - p0_preamble = 0; - cur_radio_power = 0; - sr_last_tx_tti = -1; - cur_pusch_power = 0; - avg_snr_db_cqi = 0; - avg_rsrp = 0; - avg_rsrp_dbm = 0; - avg_rsrq_db = 0; - avg_ri = 0; - avg_noise = 0; - - pcell_report_period = 20; - - bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ); - -} - -void phch_common::reset_ul() -{ - /* - is_first_tx = true; - is_first_of_burst = true; - - for (uint32_t i=0;itx_end(); - */ -} - -/* Convert 6-bit maps to 10-element subframe tables - bitmap = |0|0|0|0|0|0| - subframe index = |1|2|3|6|7|8| -*/ -void phch_common::build_mch_table() -{ - // First reset tables - bzero(&mch_table[0], sizeof(uint8_t)*40); - - // 40 element table represents 4 frames (40 subframes) - if (config->mbsfn.mbsfn_subfr_cnfg.sf_alloc.type() == mbsfn_sf_cfg_s::sf_alloc_c_::types::one_frame) { - generate_mch_table(&mch_table[0], (uint32_t)config->mbsfn.mbsfn_subfr_cnfg.sf_alloc.one_frame().to_number(), 1u); - } else if (config->mbsfn.mbsfn_subfr_cnfg.sf_alloc.type() == mbsfn_sf_cfg_s::sf_alloc_c_::types::four_frames) { - generate_mch_table(&mch_table[0], (uint32_t)config->mbsfn.mbsfn_subfr_cnfg.sf_alloc.four_frames().to_number(), 4u); - } else { - log_h->error("The subframe config has not been set for MBSFN\n"); - } - // Debug - - - std::stringstream ss; - ss << "|"; - for(uint32_t j=0; j<40; j++) { - ss << (int) mch_table[j] << "|"; - } - Info("MCH table: %s\n", ss.str().c_str()); -} - -void phch_common::build_mcch_table() -{ - // First reset tables - bzero(&mcch_table[0], sizeof(uint8_t)*10); - generate_mcch_table(&mcch_table[0], (uint32_t)config->mbsfn.mbsfn_area_info.mcch_cfg_r9.sf_alloc_info_r9.to_number()); - // Debug - std::stringstream ss; - ss << "|"; - for(uint32_t j=0; j<10; j++) { - ss << (int) mcch_table[j] << "|"; - } - Info("MCCH table: %s\n", ss.str().c_str()); - sib13_configured = true; -} - -void phch_common::set_mcch() -{ - mcch_configured = true; -} - -void phch_common::set_mch_period_stop(uint32_t stop) -{ - pthread_mutex_lock(&mtch_mutex); - have_mtch_stop = true; - mch_period_stop = stop; - pthread_cond_broadcast(&mtch_cvar); - pthread_mutex_unlock(&mtch_mutex); - -} - -bool phch_common::is_mch_subframe(subframe_cfg_t* cfg, uint32_t phy_tti) -{ - uint32_t sfn; // System Frame Number - uint8_t sf; // Subframe - uint8_t offset; - uint8_t period; - - sfn = phy_tti / 10; - sf = phy_tti % 10; - - // Set some defaults - cfg->mbsfn_area_id = 0; - cfg->non_mbsfn_region_length = 1; - cfg->mbsfn_mcs = 2; - cfg->mbsfn_decode = false; - cfg->is_mcch = false; - // Check for MCCH - if (is_mcch_subframe(cfg, phy_tti)) { - cfg->is_mcch = true; - return true; - } - - // Not MCCH, check for MCH - mbsfn_sf_cfg_s* subfr_cnfg = &config->mbsfn.mbsfn_subfr_cnfg; - mbsfn_area_info_r9_s* area_info = &config->mbsfn.mbsfn_area_info; - offset = subfr_cnfg->radioframe_alloc_offset; - period = subfr_cnfg->radioframe_alloc_period.to_number(); - - if (subfr_cnfg->sf_alloc.type() == mbsfn_sf_cfg_s::sf_alloc_c_::types::one_frame) { - if ((sfn % period == offset) && (mch_table[sf] > 0)) { - if (sib13_configured) { - cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; - cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); - if (mcch_configured) { - // Iterate through PMCH configs to see which one applies in the current frame - mbsfn_area_cfg_r9_s* mcch = &config->mbsfn.mcch.msg.c1().mbsfn_area_cfg_r9(); - uint32_t mbsfn_per_frame = mcch->pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9 / - mcch->pmch_info_list_r9[0].pmch_cfg_r9.mch_sched_period_r9.to_number(); - uint32_t frame_alloc_idx = sfn % mcch->common_sf_alloc_period_r9.to_number(); - uint32_t sf_alloc_idx = frame_alloc_idx * mbsfn_per_frame + ((sf < 4) ? sf - 1 : sf - 3); - pthread_mutex_lock(&mtch_mutex); - while (!have_mtch_stop) { - pthread_cond_wait(&mtch_cvar, &mtch_mutex); - } - pthread_mutex_unlock(&mtch_mutex); - - for (uint32_t i = 0; i < mcch->pmch_info_list_r9.size(); i++) { - if (sf_alloc_idx <= mch_period_stop) { - // trigger conditional variable, has ot be untriggered by mtch stop location - cfg->mbsfn_mcs = mcch->pmch_info_list_r9[i].pmch_cfg_r9.data_mcs_r9; - cfg->mbsfn_decode = true; - } else { - // have_mtch_stop = false; - } - } - Debug("MCH subframe TTI:%d\n", phy_tti); - } - } - return true; - } - } else if (subfr_cnfg->sf_alloc.type() == mbsfn_sf_cfg_s::sf_alloc_c_::types::four_frames) { - uint8_t idx = sfn % period; - if ((idx >= offset) && (idx < offset + 4)) { - if (mch_table[(idx * 10) + sf] > 0) { - if (sib13_configured) { - cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; - cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); - // TODO: check for MCCH configuration, set MCS and decode - } - return true; - } - } - } else { - log_h->error("The subframe allocation type is not yet configured\n"); - } - - return false; -} - -bool phch_common::is_mcch_subframe(subframe_cfg_t* cfg, uint32_t phy_tti) -{ - uint32_t sfn; // System Frame Number - uint8_t sf; // Subframe - uint8_t offset; - uint16_t period; - - sfn = phy_tti / 10; - sf = (uint8_t)(phy_tti % 10); - - if (sib13_configured) { - mbsfn_area_info_r9_s* area_info = &config->mbsfn.mbsfn_area_info; - - offset = area_info->mcch_cfg_r9.mcch_offset_r9; - period = area_info->mcch_cfg_r9.mcch_repeat_period_r9.to_number(); - - if ((sfn % period == offset) && mcch_table[sf] > 0) { - cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; - cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); - cfg->mbsfn_mcs = area_info->mcch_cfg_r9.sig_mcs_r9.to_number(); - cfg->mbsfn_decode = true; - have_mtch_stop = false; - Debug("MCCH subframe TTI:%d\n", phy_tti); - return true; - } - } - return false; -} - -void phch_common::get_sf_config(subframe_cfg_t *cfg, uint32_t phy_tti) -{ - cfg->sf_type = SUBFRAME_TYPE_REGULAR; - if (sib13_configured) { - if (is_mch_subframe(cfg, phy_tti)) { - cfg->sf_type = SUBFRAME_TYPE_MBSFN; - } - } -} - -} diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc deleted file mode 100644 index 8f782f355..000000000 --- a/srsue/src/phy/phch_worker.cc +++ /dev/null @@ -1,1851 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include -#include -#include "srsue/hdr/phy/phch_worker.h" -#include "srslte/srslte.h" -#include "srslte/interfaces/ue_interfaces.h" - -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) - - -/* This is to visualize the channel response */ -#ifdef ENABLE_GUI -#include "srsgui/srsgui.h" -#include - -void init_plots(srsue::phch_worker *worker); -pthread_t plot_thread; -sem_t plot_sem; -static int plot_worker_id = -1; -#else -#warning Compiling without srsGUI support -#endif -/*********************************************/ - -using namespace asn1::rrc; - -namespace srsue { - - -phch_worker::phch_worker() : tr_exec(10240) -{ - phy = NULL; - chest_loop = NULL; - - bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - ZERO_OBJECT(cell); - - mem_initiated = false; - cell_initiated = false; - pregen_enabled = false; - trace_enabled = false; - - pthread_mutex_init(&mutex, NULL); - - reset(); -} - - -phch_worker::~phch_worker() -{ - if (mem_initiated) { - for (uint32_t i=0;iargs->nof_rx_ant;i++) { - if (signal_buffer[i]) { - free(signal_buffer[i]); - } - } - srslte_ue_dl_free(&ue_dl); - srslte_ue_ul_free(&ue_ul); - mem_initiated = false; - } - - pthread_mutex_destroy(&mutex); -} - -void phch_worker::reset() -{ - pthread_mutex_lock(&mutex); - bzero(&dl_metrics, sizeof(dl_metrics_t)); - bzero(&ul_metrics, sizeof(ul_metrics_t)); - bzero(&dmrs_cfg, sizeof(srslte_refsignal_dmrs_pusch_cfg_t)); - bzero(&pusch_hopping, sizeof(srslte_pusch_hopping_cfg_t)); - bzero(&uci_cfg, sizeof(srslte_uci_cfg_t)); - bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); - bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); - bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); - sr_configured = false; - rnti_is_set = false; - rar_cqi_request = false; - I_sr = 0; - cfi = 0; - rssi_read_cnt = 0; - pthread_mutex_unlock(&mutex); -} - -void phch_worker::enable_pdsch_coworker() { - srslte_pdsch_enable_coworker(&ue_dl.pdsch); -} - -void phch_worker::set_common(phch_common* phy_) -{ - phy = phy_; -} - -bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_phy_lib_h , chest_feedback_itf *chest_loop) -{ - this->log_h = log_h; - this->log_phy_lib_h = log_phy_lib_h; - this->chest_loop = chest_loop; - - // ue_sync in phy.cc requires a buffer for 3 subframes - for (uint32_t i=0;iargs->nof_rx_ant;i++) { - signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); - if (!signal_buffer[i]) { - Error("Allocating memory\n"); - return false; - } - } - - if (srslte_ue_dl_init(&ue_dl, signal_buffer, max_prb, phy->args->nof_rx_ant)) { - Error("Initiating UE DL\n"); - return false; - } - - if (srslte_ue_ul_init(&ue_ul, signal_buffer[0], max_prb)) { - Error("Initiating UE UL\n"); - return false; - } - - if (phy->args->pdsch_8bit_decoder) { - ue_dl.pdsch.llr_is_8bit = true; - ue_dl.pdsch.dl_sch.llr_is_8bit = true; - } - - srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true); - srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled); - srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask); - srslte_ue_ul_set_normalization(&ue_ul, true); - srslte_ue_ul_set_cfo_enable(&ue_ul, true); - srslte_pdsch_enable_csi(&ue_dl.pdsch, phy->args->pdsch_csi_enabled); - - mem_initiated = true; - - return true; -} - -bool phch_worker::set_cell(srslte_cell_t cell_) -{ - bool ret = false; - pthread_mutex_lock(&mutex); - if (cell.id != cell_.id || !cell_initiated) { - memcpy(&cell, &cell_, sizeof(srslte_cell_t)); - - if (srslte_ue_dl_set_cell(&ue_dl, cell)) { - Error("Initiating UE DL\n"); - goto unlock; - } - - if(srslte_ue_dl_set_mbsfn_area_id(&ue_dl, 1)){ - Error("Setting mbsfn id\n"); - } - - if (srslte_ue_ul_set_cell(&ue_ul, cell)) { - Error("Initiating UE UL\n"); - goto unlock; - } - srslte_ue_ul_set_normalization(&ue_ul, true); - srslte_ue_ul_set_cfo_enable(&ue_ul, true); - - cell_initiated = true; - } - ret = true; -unlock: - pthread_mutex_unlock(&mutex); - return ret; -} - -cf_t* phch_worker::get_buffer(uint32_t antenna_idx) -{ - return signal_buffer[antenna_idx]; -} - -void phch_worker::set_tti(uint32_t tti_, uint32_t tx_worker_cnt) -{ - tti = tti_; - tx_tti = tx_worker_cnt; - log_h->step(tti); - if (log_phy_lib_h) { - log_phy_lib_h->step(tti); - } -} - -void phch_worker::set_prach(cf_t *prach_ptr, float prach_power) { - this->prach_ptr = prach_ptr; - this->prach_power = prach_power; -} - -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); - rnti_is_set = true; -} - -float phch_worker::get_ref_cfo() -{ - return srslte_chest_dl_get_cfo(&ue_dl.chest); -} - -float phch_worker::get_snr() -{ - return 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); -} - -float phch_worker::get_rsrp() -{ - return 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)); -} - -float phch_worker::get_noise() -{ - return 10*log10(srslte_chest_dl_get_noise_estimate(&ue_dl.chest)); -} - - -float phch_worker::get_cfo() -{ - return cfo; -} - -void phch_worker::work_imp() -{ - if (!cell_initiated) { - return; - } - - pthread_mutex_lock(&mutex); - - Debug("TTI %d running\n", tti); - -#ifdef LOG_EXECTIME - gettimeofday(&logtime_start[1], NULL); -#endif - - tr_log_start(); - - reset_uci(); - - subframe_cfg_t sf_cfg; - phy->get_sf_config(&sf_cfg, tti); - Debug("TTI: %d, Subframe type: %s\n", tti, subframe_type_text[sf_cfg.sf_type]); - - bool dl_grant_available = false; - bool ul_grant_available = false; - bool dl_ack[SRSLTE_MAX_CODEWORDS] = {false}; - - mac_interface_phy::mac_grant_t dl_mac_grant; - mac_interface_phy::tb_action_dl_t dl_action; - - mac_interface_phy::mac_grant_t ul_mac_grant; - mac_interface_phy::tb_action_ul_t ul_action; - - ZERO_OBJECT(dl_mac_grant); - ZERO_OBJECT(dl_action); - ZERO_OBJECT(ul_mac_grant); - ZERO_OBJECT(ul_action); - - /** Calculate RSSI on the input signal before generating the output */ - - // Average RSSI over all symbols (make sure SF length is non-zero) - float rssi_dbm = SRSLTE_SF_LEN_PRB(cell.nof_prb) > 0 ? (10*log10(srslte_vec_avg_power_cf(signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb))) + 30) : 0; - if (std::isnormal(rssi_dbm)) { - phy->avg_rssi_dbm = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm, phy->args->snr_ema_coeff); - } - - bool mch_decoded = false; - srslte_ra_dl_grant_t mch_grant; - - - // Call feedback loop for chest - if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { - chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest)); - } - bool chest_ok = false; - bool snr_th_ok = false; - - /***** Downlink Processing *******/ - - - if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) { - /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ - chest_ok = extract_fft_and_pdcch_llr(sf_cfg); - - snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; - - if (chest_ok && snr_th_ok) { - - /***** Downlink Processing *******/ - - /* PDCCH DL + PDSCH */ - dl_grant_available = decode_pdcch_dl(&dl_mac_grant); - if(dl_grant_available) { - /* Send grant to MAC and get action for this TB */ - phy->mac->new_grant_dl(dl_mac_grant, &dl_action); - - /* Set DL ACKs to default */ - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - dl_ack[tb] = dl_action.default_ack[tb]; - } - - /* Decode PDSCH if instructed to do so */ - if (dl_action.decode_enabled[0] || dl_action.decode_enabled[1]) { - decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, - dl_action.softbuffers, dl_action.rv, dl_action.rnti, - dl_mac_grant.pid, dl_ack); - } - if (dl_action.generate_ack_callback) { - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (dl_action.decode_enabled[tb]) { - phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); - dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); - Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]); - } - } - } - Debug("dl_ack={%d, %d}, generate_ack=%d\n", dl_ack[0], dl_ack[1], dl_action.generate_ack); - if (dl_action.generate_ack) { - set_uci_ack(dl_ack, dl_mac_grant.tb_en); - } - } - } - - } else if(SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type) { - srslte_ue_dl_set_non_mbsfn_region(&ue_dl, sf_cfg.non_mbsfn_region_length); - - /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ - if (extract_fft_and_pdcch_llr(sf_cfg)) { - - dl_grant_available = decode_pdcch_dl(&dl_mac_grant); - phy->mac->new_grant_dl(dl_mac_grant, &dl_action); - - /* Set DL ACKs to default */ - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - dl_ack[tb] = dl_action.default_ack[tb]; - } - if(sf_cfg.mbsfn_decode) { - - mch_grant.sf_type = SRSLTE_SF_MBSFN; - mch_grant.mcs[0].idx = sf_cfg.mbsfn_mcs; - mch_grant.tb_en[0] = true; - for(uint32_t i=1;imac->new_mch_dl(mch_grant, &dl_action); - srslte_softbuffer_rx_reset_tbs(dl_action.softbuffers[0], mch_grant.mcs[0].tbs); - Debug("TBS=%d, Softbuffer max_cb=%d\n", mch_grant.mcs[0].tbs, dl_action.softbuffers[0]->max_cb); - if(dl_action.decode_enabled[0]) { - mch_decoded = decode_pmch(&mch_grant, dl_action.payload_ptr[0], dl_action.softbuffers[0], sf_cfg.mbsfn_area_id); - } - } - } - } - - // Process RAR before UL to enable zero-delay Msg3 - bool rar_delivered = false; - if (HARQ_DELAY_MS == MSG3_DELAY_MS && dl_mac_grant.rnti_type == SRSLTE_RNTI_RAR) { - rar_delivered = true; - phy->mac->tb_decoded(dl_ack[0], 0, dl_mac_grant.rnti_type, dl_mac_grant.pid); - } - - // Decode PHICH - bool ul_ack = false; - bool ul_ack_available = decode_phich(&ul_ack); - - - /***** Uplink Processing + Transmission *******/ - - bool signal_ready = false; - cf_t *signal_ptr = NULL; - - /* Transmit PRACH if pending, or PUSCH/PUCCH otherwise */ - if (prach_ptr) { - signal_ready = true; - signal_ptr = prach_ptr; - } else { - /* Generate SR if required*/ - set_uci_sr(); - - /* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */ - ul_grant_available = decode_pdcch_ul(&ul_mac_grant); - - /* Generate CQI reports if required, note that in case both aperiodic - and periodic ones present, only aperiodic is sent (36.213 section 7.2) */ - if (ul_grant_available && ul_mac_grant.has_cqi_request) { - set_uci_aperiodic_cqi(); - } else { - set_uci_periodic_cqi(); - } - - /* TTI offset for UL */ - ul_action.tti_offset = HARQ_DELAY_MS; - - /* 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_ack, &ul_action); - } else if (ul_grant_available && !ul_ack_available) { - phy->mac->new_grant_ul(ul_mac_grant, &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 */ - if (ul_action.tx_enabled) { - encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb, - &ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); - signal_ready = true; - if (ul_action.expect_ack) { - phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs); - } - - } else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) { - encode_pucch(); - signal_ready = true; - } else if (srs_is_ready_to_send()) { - encode_srs(); - signal_ready = true; - } - signal_ptr = signal_buffer[0]; - } - - - tr_log_end(); - - - if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type) { - if (!dl_action.generate_ack_callback) { - if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { - if (dl_ack[0]) { - phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); - } - } else if (!rar_delivered) { - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (dl_action.decode_enabled[tb]) { - phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); - } - } - } - } - } else if (SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type && sf_cfg.mbsfn_decode) { - if(mch_decoded) { - phy->mac->mch_decoded_ok(mch_grant.mcs[0].tbs/8); - } else if(sf_cfg.is_mcch) { - //release lock in phch_common - phy->set_mch_period_stop(0); - } - } - - if (next_offset > 0) { - phy->worker_end(tx_tti, signal_ready, signal_ptr, SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); - } else { - phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); - } - - if(SUBFRAME_TYPE_REGULAR == sf_cfg.sf_type){ - update_measurements(); - } - - if (chest_ok) { - if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db_cqi > -6.0) { - log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n", - phy->avg_snr_db_cqi, phy->avg_rsrp_dbm); - chest_loop->in_sync(); - } else { - log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n", - phy->avg_snr_db_cqi, phy->avg_rsrp_dbm); - chest_loop->out_of_sync(); - } - } - - pthread_mutex_unlock(&mutex); - - /* Tell the plotting thread to draw the plots */ -#ifdef ENABLE_GUI - if ((int) get_id() == plot_worker_id) { - sem_post(&plot_sem); - } -#endif -} - -void phch_worker::compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr) { - if (phy->config->dedicated.ant_info.explicit_value().tx_mode == asn1::rrc::ant_info_ded_s::tx_mode_e_::tm3) { - if (ue_dl.nof_rx_antennas > 1) { - /* If 2 ort more receiving antennas, select RI */ - float cn = 0.0f; - srslte_ue_dl_ri_select(&ue_dl, ri, &cn); - if (ri) { - Debug("TM3 RI select %d layers, κ=%fdB\n", (*ri) + 1, cn); - } - } else { - /* If only one receiving antenna, force RI for 1 layer */ - if (ri) { - *ri = 0; - } - } - uci_data.uci_ri_len = 1; - } else if (phy->config->dedicated.ant_info.explicit_value().tx_mode == asn1::rrc::ant_info_ded_s::tx_mode_e_::tm4) { - if (sinr) { - srslte_ue_dl_ri_pmi_select(&ue_dl, ri, pmi, sinr); - Debug("TM4 ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]])); - } - } -} - - - -bool phch_worker::extract_fft_and_pdcch_llr(subframe_cfg_t sf_cfg) { - bool decode_pdcch = true; - - // Do always channel estimation to keep track of out-of-sync and send measurements to RRC - - // Setup estimator filter - srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest, - phy->args->estimator_fil_order, - phy->args->estimator_fil_stddev); - srslte_chest_dl_set_smooth_filter_auto(&ue_dl.chest, phy->args->estimator_fil_auto); - - if (!phy->args->snr_estim_alg.compare("refs")) { - srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS); - } else if (!phy->args->snr_estim_alg.compare("empty")) { - srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY); - } else { - srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); - } - - - int decode_fft = 0; - if(SUBFRAME_TYPE_MBSFN == sf_cfg.sf_type) { - srslte_ue_dl_set_non_mbsfn_region(&ue_dl, sf_cfg.non_mbsfn_region_length); - decode_fft = srslte_ue_dl_decode_fft_estimate_mbsfn(&ue_dl, tti%10, &cfi, SRSLTE_SF_MBSFN); - }else{ - decode_fft = srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi); - } - if (decode_fft < 0) { - Error("Getting PDCCH FFT estimate\n"); - return false; - } - - chest_done = true; - - - if (chest_done && decode_pdcch) { /* and not in DRX mode */ - - float noise_estimate = phy->avg_noise; - - if (!phy->args->equalizer_mode.compare("zf")) { - noise_estimate = 0; - } - - if (srslte_pdcch_extract_llr_multi(&ue_dl.pdcch, ue_dl.sf_symbols_m, ue_dl.ce_m, noise_estimate, 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(srsue::mac_interface_phy::mac_grant_t* grant) -{ - dl_rnti = phy->get_dl_rnti(tti); - if (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 (type == SRSLTE_RNTI_RAR) { - Debug("Looking for RNTI=0x%x\n", dl_rnti); - } - - if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.ant_info.explicit_value().tx_mode, cfi, tti % 10, - dl_rnti, type, &dci_msg) != 1) { - if (type == SRSLTE_RNTI_RAR) { - Debug("RAR not found, SNR=%.1f dB, tti=%d, cfi=%d, tx_mode=%d, cell_id=%d\n", - 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), tti, cfi, - phy->config->dedicated.ant_info.explicit_value().tx_mode.value, cell.id); - } - return false; - } - - if (srslte_dci_msg_to_dl_grant(&dci_msg, dl_rnti, cell.nof_prb, cell.nof_ports, &dci_unpacked, &grant->phy_grant.dl)) { - Error("Converting DCI message to DL grant\n"); - return false; - } - - grant->pid = ASYNC_DL_SCHED?dci_unpacked.harq_process:(UL_PIDOF(TTI_TX(tti))); - - // Set last TBS for this TB (pid) in case of mcs>28 (7.1.7.2 of 36.213) - for (int i=0;iphy_grant.dl.mcs[i].idx > 28) { - grant->phy_grant.dl.mcs[i].tbs = phy->last_dl_tbs[grant->pid][i]; - } - if(grant->phy_grant.dl.mcs[i].tbs < 0) { - Info("Invalid TBS size for PDSCH grant\n"); - grant->phy_grant.dl.mcs[i].tbs = 0; - } - // save it - phy->last_dl_tbs[grant->pid][i] = grant->phy_grant.dl.mcs[i].tbs; - } - - /* Fill MAC grant structure */ - grant->ndi[0] = dci_unpacked.ndi; - grant->ndi[1] = dci_unpacked.ndi_1; - grant->n_bytes[0] = grant->phy_grant.dl.mcs[0].tbs / (uint32_t) 8; - grant->n_bytes[1] = grant->phy_grant.dl.mcs[1].tbs / (uint32_t) 8; - grant->tti = tti; - grant->rv[0] = dci_unpacked.rv_idx; - grant->rv[1] = dci_unpacked.rv_idx_1; - grant->rnti = dl_rnti; - grant->rnti_type = type; - grant->last_tti = 0; - grant->tb_en[0] = dci_unpacked.tb_en[0]; - grant->tb_en[1] = dci_unpacked.tb_en[1]; - grant->tb_cw_swap = dci_unpacked.tb_cw_swap; // FIXME: tb_cw_swap not supported - - last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl); - - char hexstr[512]; - hexstr[0]='\0'; - if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { - srslte_vec_sprint_hex(hexstr, sizeof(hexstr), dci_msg.data, dci_msg.nof_bits); - } - Info("PDCCH: DL DCI %s cce_index=%2d, L=%d, n_data_bits=%d, tpc_pucch=%d, hex=%s\n", srslte_dci_format_string(dci_msg.format), - last_dl_pdcch_ncce, (1<tb_en[tb] && (rv[tb] < 0 || rv[tb] > 3)) { - valid_config = false; - Error("Wrong RV (%d) for TB index %d\n", rv[tb], tb); - } - } - - uint32_t nof_tb = SRSLTE_RA_DL_GRANT_NOF_TB(grant); - switch (phy->config->dedicated.ant_info.explicit_value().tx_mode.value) { - /* Implemented Tx Modes */ - case ant_info_ded_s::tx_mode_e_::tm1: - mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - if (nof_tb != 1) { - Error("Wrong number of transport blocks (%d) for single antenna.", nof_tb); - valid_config = false; - } - break; - case ant_info_ded_s::tx_mode_e_::tm2: - if (cell.nof_ports > 1) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else { - mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } - if (nof_tb != 1) { - Error("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); - valid_config = false; - } - break; - case ant_info_ded_s::tx_mode_e_::tm3: - if (nof_tb == 1) { - mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) { - mimo_type = SRSLTE_MIMO_TYPE_CDD; - } else { - Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, - nof_tb); - valid_config = false; - } - break; - case ant_info_ded_s::tx_mode_e_::tm4: - if (nof_tb == 1) { - mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (ue_dl.nof_rx_antennas > 1 && nof_tb == 2) { - mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else { - Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM4\n", ue_dl.nof_rx_antennas, - nof_tb); - valid_config = false; - } - break; - - /* Not implemented cases */ - case ant_info_ded_s::tx_mode_e_::tm5: - case ant_info_ded_s::tx_mode_e_::tm6: - case ant_info_ded_s::tx_mode_e_::tm7: - case ant_info_ded_s::tx_mode_e_::tm8_v920: - Error("Not implemented Tx mode (%d)\n", phy->config->dedicated.ant_info.explicit_value().tx_mode.value); - break; - - /* Error cases */ - default: - Error("Wrong Tx mode (%d)\n", phy->config->dedicated.ant_info.explicit_value().tx_mode.value); - valid_config = false; - } - - /* Set power allocation according to 3GPP 36.213 clause 5.2 Downlink power allocation */ - float rho_a = 1.0f, rho_b = 1.0f; - if (phy->config->dedicated.pdsch_cfg_ded_present) { - float rho_a_db = phy->config->dedicated.pdsch_cfg_ded.p_a.to_number(); - rho_a = powf(10.0f, rho_a_db / 20.0f) * ((cell.nof_ports == 1) ? 1.0f : sqrtf(2.0f)); - } - if (phy->config->common.pdsch_cnfg.p_b < 4) { - uint32_t idx0 = (cell.nof_ports == 1) ? 0 : 1; - float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][phy->config->common.pdsch_cnfg.p_b]; - rho_b = sqrtf(cell_specific_ratio); - } - srslte_ue_dl_set_power_alloc(&ue_dl, rho_a, rho_b); - - Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti); - - /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ - if (valid_config) { - if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) { - if ((ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) || - (ue_dl.pdsch_cfg.grant.mcs[1].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[1].tbs >= 0)) { - - float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); - - if (!phy->args->equalizer_mode.compare("zf")) { - noise_estimate = 0; - } - - /* Set decoder iterations */ - if (phy->args->pdsch_max_its > 0) { - srslte_pdsch_set_max_noi(&ue_dl.pdsch, phy->args->pdsch_max_its); - } - - - #ifdef LOG_EXECTIME - struct timeval t[3]; - gettimeofday(&t[1], NULL); - #endif - ret = srslte_pdsch_decode(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m, - ue_dl.ce_m, noise_estimate, rnti, payload, acks); - if (ret) { - Error("ERROR: Decoding PDSCH\n"); - } - #ifdef LOG_EXECTIME - gettimeofday(&t[2], NULL); - get_time_interval(t); - snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); - #endif - - char pinfo_str[16] = {0}; - if (phy->config->dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - snprintf(pinfo_str, 15, ", pinfo=%x", grant->pinfo); - } - - snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB, tx_scheme=%s%s", grant->nof_prb, harq_pid, - 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), srslte_mimotype2str(mimo_type), pinfo_str); - - for (int i=0;itb_en[i]) { - snprintf(tbstr[i], 128, ", CW%d: tbs=%d, mcs=%d, rv=%d, crc=%s, it=%d", - i, grant->mcs[i].tbs/8, grant->mcs[i].idx, rv[i], acks[i] ? "OK" : "KO", - srslte_pdsch_last_noi_cw(&ue_dl.pdsch, i)); - } - } - - Info("%s%s%s%s\n", commonstr, grant->tb_en[0]?tbstr[0]:"", grant->tb_en[1]?tbstr[1]:"", timestr); - - // Store metrics - dl_metrics.mcs = grant->mcs[0].idx; - float niters = srslte_pdsch_last_noi(&ue_dl.pdsch); - if (niters) { - dl_metrics.turbo_iters = niters; - } - } else { - Warning("Received grant for TBS=0\n"); - } - } else { - Error("Error configuring DL grant\n"); - ret = SRSLTE_ERROR; - } - } else { - Error("Error invalid DL config\n"); - ret = SRSLTE_ERROR; - } - return ret; -} - -bool phch_worker::decode_pmch(srslte_ra_dl_grant_t *grant, uint8_t *payload, - srslte_softbuffer_rx_t* softbuffer, uint16_t mbsfn_area_id) -{ - char timestr[64]; - timestr[0]='\0'; - - Debug("DL Buffer TTI %d: Decoding PMCH\n", tti); - /* Setup PMCH configuration */ - srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_area_id); - - if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) { - if (ue_dl.pmch_cfg.grant.mcs[0].mod > 0 && ue_dl.pmch_cfg.grant.mcs[0].tbs >= 0) { - - Debug("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n", - ue_dl.pmch_cfg.sf_idx, mbsfn_area_id, srslte_mod_string(ue_dl.pmch_cfg.grant.mcs[0].mod), ue_dl.pmch_cfg.grant.mcs[0].tbs, ue_dl.pmch_cfg.nbits[0].nof_re, - ue_dl.pmch_cfg.nbits[0].nof_bits, 0, ue_dl.pmch_cfg.grant.nof_prb, ue_dl.pmch_cfg.nbits[0].lstart-1); - - float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); - - if (!phy->args->equalizer_mode.compare("zf")) { - noise_estimate = 0; - } - - /* Set decoder iterations */ - // TODO: Add separate arg for pmch_max_its - if (phy->args->pdsch_max_its > 0) { - srslte_sch_set_max_noi(&ue_dl.pmch.dl_sch, phy->args->pdsch_max_its); - } - -#ifdef LOG_EXECTIME - struct timeval t[3]; - gettimeofday(&t[1], NULL); -#endif - - bool ack = srslte_pmch_decode_multi(&ue_dl.pmch, &ue_dl.pmch_cfg, softbuffer, ue_dl.sf_symbols_m, - ue_dl.ce_m, noise_estimate, mbsfn_area_id, payload) == 0; - -#ifdef LOG_EXECTIME - gettimeofday(&t[2], NULL); - get_time_interval(t); - snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); -#endif - - Info("PMCH: l_crb=%2d, tbs=%d, mcs=%d, crc=%s, snr=%.1f dB, n_iter=%d%s\n", - grant->nof_prb, - grant->mcs[0].tbs/8, grant->mcs[0].idx, - ack?"OK":"KO", - 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), - srslte_pmch_last_noi(&ue_dl.pmch), - timestr); - - //printf("tti=%d, cfo=%f\n", tti, cfo*15000); - //srslte_vec_save_file("pdsch", signal_buffer, sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); - - // Store metrics - dl_metrics.mcs = grant->mcs[0].idx; - - return ack; - } 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); - Info("PHICH: hi=%d, I_lowest=%d, n_dmrs=%d\n", *ack, I_lowest, n_dmrs); - } - phy->reset_pending_ack(tti); - 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_RX_ACK(tti)); - - 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)) - { - Error("Converting RAR message to UL grant\n"); - return false; - } - grant->rnti_type = SRSLTE_RNTI_TEMP; - grant->is_from_rar = true; - grant->has_cqi_request = false; // In contention-based Random Access CQI request bit is reserved - Debug("RAR grant found for TTI=%d\n", tti); - ret = true; - } else { - ul_rnti = phy->get_ul_rnti(tti); - if (ul_rnti) { - if (srslte_ue_dl_find_ul_dci(&ue_dl, cfi, tti%10, ul_rnti, &dci_msg) != 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, tti)) - { - Error("Converting DCI message to UL grant\n"); - return false; - } - grant->rnti_type = type; - grant->is_from_rar = false; - grant->has_cqi_request = dci_unpacked.cqi_request; - ret = true; - - char hexstr[512]; - hexstr[0]='\0'; - if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { - srslte_vec_sprint_hex(hexstr, sizeof(hexstr), dci_msg.data, dci_msg.nof_bits); - } - // Change to last_location_ul - Info("PDCCH: UL DCI Format0 cce_index=%d, L=%d, n_data_bits=%d, tpc_pusch=%d, hex=%s\n", - ue_dl.last_location_ul.ncce, (1<phy_grant.ul.mcs.tbs==0) { - Info("Received PUSCH grant with empty data\n"); - } - } - } - - - // Handle Format0 adaptive retx - if (ret) { - // Use last TBS for this TB in case of mcs>28 - if (grant->phy_grant.ul.mcs.idx > 28 && grant->phy_grant.ul.mcs.mod == SRSLTE_MOD_LAST) { - // Make sure we received a grant in the previous TTI for this PID - grant->phy_grant.ul.mcs.tbs = phy->last_ul_tbs[UL_PIDOF(TTI_TX(tti))]; - grant->phy_grant.ul.mcs.mod = phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))]; - grant->phy_grant.ul.mcs.idx = phy->last_ul_idx[UL_PIDOF(TTI_TX(tti))]; - grant->phy_grant.ul.Qm = srslte_mod_bits_x_symbol(grant->phy_grant.ul.mcs.mod); - } - } - if (ret) { - phy->last_ul_tbs[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.tbs; - phy->last_ul_mod[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.mod; - phy->last_ul_idx[UL_PIDOF(TTI_TX(tti))] = grant->phy_grant.ul.mcs.idx; - phy->last_ul_tti[UL_PIDOF(TTI_TX(tti))] = TTI_RX_ACK(tti); - /* Limit UL modulation if not supported by the UE or disabled by higher layers */ - if (!phy->config->enable_64qam) { - if (grant->phy_grant.ul.mcs.mod >= SRSLTE_MOD_64QAM) { - grant->phy_grant.ul.mcs.mod = SRSLTE_MOD_16QAM; - grant->phy_grant.ul.Qm = 4; - } - } - } - - /* Make sure the grant is valid */ - if (ret && !srslte_dft_precoding_valid_prb(grant->phy_grant.ul.L_prb) && grant->phy_grant.ul.L_prb <= cell.nof_prb) { - Warning("Received invalid UL grant. L=%d\n", grant->phy_grant.ul.L_prb); - ret = false; - } - - if (ret) { - grant->ndi[0] = dci_unpacked.ndi; - grant->pid = 0; // This is computed by MAC from TTI - grant->n_bytes[0] = grant->phy_grant.ul.mcs.tbs / (uint32_t) 8; - grant->tti = tti; - grant->rnti = ul_rnti; - grant->rv[0] = dci_unpacked.rv_idx; - if (SRSLTE_VERBOSE_ISINFO()) { - srslte_ra_pusch_fprint(stdout, &dci_unpacked, cell.nof_prb); - } - } - - return ret; -} - -void phch_worker::reset_uci() -{ - ZERO_OBJECT(uci_data); - ZERO_OBJECT(cqi_report); -} - -void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) -{ - /* Map ACK according to 3GPP 36.212 clause 5.2.3.1 */ - uint32_t nof_ack = 0; - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - if (tb_en[tb]) { - ((nof_ack == 0)?uci_data.uci_ack:uci_data.uci_ack_2) = (uint8_t)(ack[tb]?1:0); - nof_ack++; - } - } - uci_data.uci_ack_len = nof_ack; -} - -void phch_worker::set_uci_sr() -{ - uci_data.scheduling_request = false; - if (phy->sr_enabled && sr_configured) { - uint32_t sr_tx_tti = TTI_TX(tti); - // Get I_sr parameter - if (srslte_ue_ul_sr_send_tti(I_sr, sr_tx_tti)) { - Info("PUCCH: SR transmission at TTI=%d, I_sr=%d\n", sr_tx_tti, I_sr); - uci_data.scheduling_request = true; - phy->sr_last_tx_tti = sr_tx_tti; - phy->sr_enabled = false; - } - } -} - -void phch_worker::set_uci_periodic_cqi() -{ - int cqi_fixed = phy->args->cqi_fixed; - int cqi_max = phy->args->cqi_max; - - float sinr = ue_dl.sinr[phy->last_ri & SRSLTE_MAX_LAYERS][phy->last_pmi % SRSLTE_MAX_CODEBOOKS]; - - if (period_cqi.configured && rnti_is_set) { - if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) { - /* Compute RI, PMI and SINR */ - compute_ri(&phy->last_ri, &phy->last_pmi, &sinr); - uci_data.uci_ri = phy->last_ri; - uci_data.uci_ri_len = 1; - uci_data.ri_periodic_report = true; - Debug("PUCCH: Periodic ri=%d, SINR=%.1f\n", phy->last_ri, sinr); - } else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { - compute_ri(NULL, NULL, NULL); - phy->last_pmi = (uint8_t) ue_dl.pmi[phy->last_ri % SRSLTE_MAX_LAYERS]; - - ZERO_OBJECT(cqi_report); - - if (period_cqi.format_is_subband) { - // TODO: Implement subband periodic reports - cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND; - cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db_cqi); - cqi_report.subband.subband_label = 0; - log_h->console("Warning: Subband CQI periodic reports not implemented\n"); - Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db_cqi); - } else { - cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND; - if (cqi_fixed >= 0) { - cqi_report.wideband.wideband_cqi = cqi_fixed; - } else { - cqi_report.wideband.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db_cqi); - } - if (cqi_max >= 0 && cqi_report.wideband.wideband_cqi > cqi_max) { - cqi_report.wideband.wideband_cqi = cqi_max; - } - if (phy->config->dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - cqi_report.wideband.pmi_present = true; - cqi_report.wideband.pmi = phy->last_pmi; - cqi_report.wideband.rank_is_not_one = (phy->last_ri != 0); - } - Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db_cqi); - } - uci_data.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); - uci_data.uci_ri = phy->last_ri; - uci_data.uci_ri_len = 0; - rar_cqi_request = false; - } - } -} - -void phch_worker::set_uci_aperiodic_cqi() -{ - float sinr_db = ue_dl.sinr[phy->last_ri % SRSLTE_MAX_LAYERS][phy->last_pmi%SRSLTE_MAX_CODEBOOKS]; - - if (phy->config->dedicated.cqi_report_cfg.cqi_report_mode_aperiodic_present) { - /* Compute RI, PMI and SINR */ - compute_ri(&phy->last_ri, &phy->last_pmi, &sinr_db); - - switch (phy->config->dedicated.cqi_report_cfg.cqi_report_mode_aperiodic.value) { - case cqi_report_mode_aperiodic_e::rm30: - /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 - - A UE shall report a wideband CQI value which is calculated assuming transmission on set S subbands - - The UE shall also report one subband CQI value for each set S subband. The subband CQI - value is calculated assuming transmission only in the subband - - Both the wideband and subband CQI represent channel quality for the first codeword, - even when RI>1 - - For transmission mode 3 the reported CQI values are calculated conditioned on the - reported RI. For other transmission modes they are reported conditioned on rank 1. - */ - if (rnti_is_set) { - ZERO_OBJECT(cqi_report); - - cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db_cqi); - - // TODO: implement subband CQI properly - cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands - cqi_report.subband_hl.N = (cell.nof_prb > 7) ? (uint32_t) srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0; - - int cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); - if (cqi_len < 0) { - Error("Error packing CQI value (Aperiodic reporting mode RM30)."); - return; - } - uci_data.uci_cqi_len = (uint32_t) cqi_len; - - char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = {0}; - srslte_cqi_to_str(uci_data.uci_cqi, uci_data.uci_cqi_len, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); - - /* Set RI = 1 */ - if (phy->config->dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm3 || - phy->config->dedicated.ant_info.explicit_value().tx_mode == ant_info_ded_s::tx_mode_e_::tm4) { - uci_data.uci_ri = phy->last_ri; - uci_data.uci_ri_len = 1; - } else { - uci_data.uci_ri_len = 0; - } - - Info("PUSCH: Aperiodic RM30 CQI=%s, %sSNR=%.1f dB, for %d subbands\n", - cqi_str, (uci_data.uci_ri_len)?((uci_data.uci_ri == 0)?"ri=0, ":"ri=1, "):"", phy->avg_snr_db_cqi, cqi_report.subband_hl.N); - } - break; - case cqi_report_mode_aperiodic_e::rm31: - /* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1 - - A single precoding matrix is selected from the codebook subset assuming transmission on set S subbands - - A UE shall report one subband CQI value per codeword for each set S subband which are calculated assuming - the use of the single precoding matrix in all subbands and assuming transmission in the corresponding - subband. - - A UE shall report a wideband CQI value per codeword which is calculated assuming the use of the single - precoding matrix in all subbands and transmission on set S subbands - - The UE shall report the single selected precoding matrix indicator. - - For transmission mode 4 the reported PMI and CQI values are calculated conditioned on the reported RI. For - other transmission modes they are reported conditioned on rank 1. - */ - if (rnti_is_set) { - /* Fill CQI Report */ - srslte_cqi_value_t cqi_report; - ZERO_OBJECT(cqi_report); - - cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; - - cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(sinr_db); - cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands - - if (phy->last_ri > 0) { - cqi_report.subband_hl.rank_is_not_one = true; - cqi_report.subband_hl.wideband_cqi_cw1 = srslte_cqi_from_snr(sinr_db); - cqi_report.subband_hl.subband_diff_cqi_cw1 = 0; // Always report zero offset on all subbands - } - - cqi_report.subband_hl.pmi = phy->last_pmi; - cqi_report.subband_hl.pmi_present = true; - cqi_report.subband_hl.four_antenna_ports = (cell.nof_ports == 4); - - // TODO: implement subband CQI properly - cqi_report.subband_hl.N = (uint32_t) ((cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell.nof_prb) : 0); - - int cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); - if (cqi_len < 0) { - Error("Error packing CQI value (Aperiodic reporting mode RM31)."); - return; - } - uci_data.uci_cqi_len = (uint32_t) cqi_len; - uci_data.uci_ri_len = 1; - uci_data.uci_ri = phy->last_ri; - - char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = {0}; - srslte_cqi_to_str(uci_data.uci_cqi, uci_data.uci_cqi_len, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); - - if (cqi_report.subband_hl.rank_is_not_one) { - Info("PUSCH: Aperiodic RM31 ri~1, CQI=%02d/%02d, SINR=%2.1f/%2.1fdB, pmi=%d for %d subbands\n", - cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1, - sinr_db, sinr_db, phy->last_pmi, cqi_report.subband_hl.N); - } else { - Info("PUSCH: Aperiodic RM31 ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n", - cqi_report.subband_hl.wideband_cqi_cw0, - sinr_db, phy->last_pmi, cqi_report.subband_hl.N); - } - } - break; - default: - Warning("Received CQI request but mode %s is not supported\n", - phy->config->dedicated.cqi_report_cfg.cqi_report_mode_aperiodic.to_string().c_str()); - break; - } - } else { - Warning("Received CQI request but aperiodic mode is not configured\n"); - } -} - -bool phch_worker::srs_is_ready_to_send() { - if (srs_cfg.configured) { - if (srslte_refsignal_srs_send_cs(srs_cfg.subframe_config, TTI_TX(tti)%10) == 1 && - srslte_refsignal_srs_send_ue(srs_cfg.I_srs, TTI_TX(tti)) == 1) - { - return true; - } - } - return false; -} - -void phch_worker::set_tx_time(srslte_timestamp_t _tx_time, uint32_t next_offset) -{ - this->next_offset = next_offset; - memcpy(&tx_time, &_tx_time, sizeof(srslte_timestamp_t)); -} - -void phch_worker::encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, - srslte_softbuffer_tx_t* softbuffer, uint32_t rv, uint16_t rnti, bool is_from_rar) -{ - char timestr[64]; - timestr[0]='\0'; - - /* Check input values ranges */ - if (rnti == 0) { - Warning("Encode PUSCH: Invalid RNTI (= 0)\n"); - return; - } else if (rv > 3) { - Warning("Encode PUSCH: Invalid RV (= %ud)\n", rv); - return; - } else if (payload == NULL) { - Warning("Encode PUSCH: NULL payload\n"); - return; - } else if (softbuffer == NULL) { - Warning("Encode PUSCH: NULL softbuffer\n"); - return; - } - - /* Configure and encode */ - if (srslte_ue_ul_cfg_grant(&ue_ul, grant, TTI_TX(tti), rv, current_tx_nb)) { - Error("Configuring UL grant\n"); - } - - if (srslte_ue_ul_pusch_encode_rnti_softbuffer(&ue_ul, - payload, uci_data, - softbuffer, - rnti, - signal_buffer[0])) - { - Error("Encoding PUSCH\n"); - } - - float p0_preamble = 0; - if (is_from_rar) { - p0_preamble = phy->p0_preamble; - } - float tx_power = srslte_ue_ul_pusch_power(&ue_ul, phy->pathloss, p0_preamble); - float gain = set_power(tx_power); - - // Save PUSCH power for PHR calculation - phy->cur_pusch_power = tx_power; - -#ifdef LOG_EXECTIME - gettimeofday(&logtime_start[2], NULL); - get_time_interval(logtime_start); - snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); -#endif - - char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = ""; - if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { - srslte_cqi_value_tostring(&cqi_report, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); - } - - uint8_t dummy[2] = {0,0}; - log_h->info_hex(payload, grant->mcs.tbs/8, - "PUSCH: tti_tx=%d, amp=%.2f, alloc=(%d,%d), tbs=%d, mcs=%d, rv=%d%s%s%s, cfo=%.1f KHz%s%s\n", - (tti + HARQ_DELAY_MS) % 10240, srslte_ue_ul_get_last_amplitude(&ue_ul), - grant->n_prb[0], grant->n_prb[0] + grant->L_prb, - grant->mcs.tbs / 8, grant->mcs.idx, rv, - uci_data.uci_ack_len > 0 ? (uci_data.uci_ack ? ", ack=1" : ", ack=0") : "", - uci_data.uci_ack_len > 1 ? (uci_data.uci_ack_2 ? "1" : "0") : "", - uci_data.uci_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "", - cfo * 15, timestr, - uci_data.uci_cqi_len > 0 ? cqi_str : ""); - - // Store metrics - ul_metrics.mcs = grant->mcs.idx; - ul_metrics.power = tx_power; - phy->set_ul_metrics(ul_metrics); -} - -void phch_worker::encode_pucch() -{ - char timestr[64]; - timestr[0]='\0'; - - if (uci_data.scheduling_request || uci_data.uci_ack_len > 0 || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) - { - - // Drop CQI if there is collision with ACK - if (!period_cqi.simul_cqi_ack && uci_data.uci_ack_len > 0 && uci_data.uci_cqi_len > 0) { - uci_data.uci_cqi_len = 0; - } - -#ifdef LOG_EXECTIME - struct timeval t[3]; - gettimeofday(&t[1], NULL); -#endif - - if (srslte_ue_ul_pucch_encode(&ue_ul, uci_data, last_dl_pdcch_ncce, TTI_TX(tti), signal_buffer[0])) { - Error("Encoding PUCCH\n"); - } - -#ifdef LOG_EXECTIME - gettimeofday(&logtime_start[2], NULL); - memcpy(&t[2], &logtime_start[2], sizeof(struct timeval)); - get_time_interval(logtime_start); - get_time_interval(t); - snprintf(timestr, 64, ", pucch_time=%d us, tot_time=%d us", (int) t[0].tv_usec, (int) logtime_start[0].tv_usec); -#endif - - float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len); - float gain = set_power(tx_power); - - char cqi_str[SRSLTE_CQI_STR_MAX_CHAR] = ""; - if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { - srslte_cqi_value_tostring(&cqi_report, cqi_str, SRSLTE_CQI_STR_MAX_CHAR); - } - - Info("PUCCH: tti_tx=%d, amp=%.2f, n_pucch=%d, n_prb=%d, ack=%s%s%s%s, sr=%s, cfo=%.1f KHz%s\n", - (tti + 4) % 10240, srslte_ue_ul_get_last_amplitude(&ue_ul), - ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, - uci_data.uci_ack_len > 0 ? (uci_data.uci_ack ? "1" : "0") : "no", - uci_data.uci_ack_len > 1 ? (uci_data.uci_ack_2 ? "1" : "0") : "", - uci_data.uci_ri_len > 0 ? (uci_data.uci_ri ? ", ri=1" : ", ri=0") : "", - uci_data.uci_cqi_len > 0 ? cqi_str : "", - uci_data.scheduling_request ? "yes" : "no", - cfo * 15, timestr); - } - - if (uci_data.scheduling_request) { - phy->sr_enabled = false; - } -} - -void phch_worker::encode_srs() -{ - char timestr[64]; - timestr[0]='\0'; - - if (srslte_ue_ul_srs_encode(&ue_ul, TTI_TX(tti), signal_buffer[0])) - { - Error("Encoding SRS\n"); - } - -#ifdef LOG_EXECTIME - gettimeofday(&logtime_start[2], NULL); - get_time_interval(logtime_start); - snprintf(timestr, 64, ", tot_time=%4d us", (int) logtime_start[0].tv_usec); -#endif - - float tx_power = srslte_ue_ul_srs_power(&ue_ul, phy->pathloss); - float gain = set_power(tx_power); - - Info("SRS: power=%.2f dBm, amp=%.2f, tti_tx=%d%s\n", tx_power, srslte_ue_ul_get_last_amplitude(&ue_ul), TTI_TX(tti), timestr); -} - -void phch_worker::enable_pregen_signals(bool enabled) -{ - pregen_enabled = enabled; - if (enabled) { - Info("Pre-generating UL signals worker=%d\n", get_id()); - srslte_ue_ul_pregen_signals(&ue_ul); - Info("Done pre-generating signals worker=%d\n", get_id()); - } -} - -void phch_worker::set_ul_params(bool pregen_disabled) -{ - pthread_mutex_lock(&mutex); - - phy_interface_rrc::phy_cfg_common_t* common = &phy->config->common; - phys_cfg_ded_s* dedicated = &phy->config->dedicated; - - Info("Setting new params worker_id=%d, pregen_disabled=%d\n", get_id(), pregen_disabled); - - /* PUSCH DMRS signal configuration */ - dmrs_cfg.group_hopping_en = common->pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled; - dmrs_cfg.sequence_hopping_en = common->pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled; - dmrs_cfg.cyclic_shift = common->pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift; - dmrs_cfg.delta_ss = common->pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch; - - /* PUSCH Hopping configuration */ - pusch_hopping.n_sb = common->pusch_cnfg.pusch_cfg_basic.n_sb; - pusch_hopping.hop_mode = common->pusch_cnfg.pusch_cfg_basic.hop_mode.value == - pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame - ? pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTRA_SF - : pusch_hopping.SRSLTE_PUSCH_HOP_MODE_INTER_SF; - pusch_hopping.hopping_offset = common->pusch_cnfg.pusch_cfg_basic.pusch_hop_offset; - - /* PUSCH UCI configuration */ - uci_cfg.I_offset_ack = dedicated->pusch_cfg_ded.beta_offset_ack_idx; - uci_cfg.I_offset_cqi = dedicated->pusch_cfg_ded.beta_offset_cqi_idx; - uci_cfg.I_offset_ri = dedicated->pusch_cfg_ded.beta_offset_ri_idx; - - /* PUCCH configuration */ - bzero(&pucch_cfg, sizeof(srslte_pucch_cfg_t)); - pucch_cfg.delta_pucch_shift = common->pucch_cnfg.delta_pucch_shift.to_number(); - pucch_cfg.N_cs = common->pucch_cnfg.n_cs_an; - pucch_cfg.n_rb_2 = common->pucch_cnfg.n_rb_cqi; - pucch_cfg.srs_configured = dedicated->srs_ul_cfg_ded_present and - dedicated->srs_ul_cfg_ded.type() == setup_e::setup and - common->srs_ul_cnfg.type().value == setup_e::setup; - if (pucch_cfg.srs_configured) { - pucch_cfg.srs_cs_subf_cfg = common->srs_ul_cnfg.setup().srs_sf_cfg.to_number(); - pucch_cfg.srs_simul_ack = common->srs_ul_cnfg.setup().ack_nack_srs_simul_tx; - } - - /* PUCCH Scheduling configuration */ - bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); - pucch_sched.n_pucch_1[0] = 0; // TODO: n_pucch_1 for SPS - pucch_sched.n_pucch_1[1] = 0; - pucch_sched.n_pucch_1[2] = 0; - pucch_sched.n_pucch_1[3] = 0; - pucch_sched.N_pucch_1 = common->pucch_cnfg.n1_pucch_an; - if (dedicated->cqi_report_cfg.cqi_report_periodic_present and - dedicated->cqi_report_cfg.cqi_report_periodic.type().value == setup_e::setup) { - pucch_sched.n_pucch_2 = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx; - } else { - // FIXME: put is_pucch_configured flag here? - pucch_sched.n_pucch_2 = 0; - } - - /* SR configuration */ - if (dedicated->sched_request_cfg_present and dedicated->sched_request_cfg.type() == setup_e::setup) { - I_sr = dedicated->sched_request_cfg.setup().sr_cfg_idx; - pucch_sched.n_pucch_sr = dedicated->sched_request_cfg.setup().sr_pucch_res_idx; - sr_configured = true; - } else { - pucch_sched.n_pucch_sr = 0; - sr_configured = false; - } - - /* SRS Configuration */ - bzero(&srs_cfg, sizeof(srslte_refsignal_srs_cfg_t)); - srs_cfg.configured = dedicated->srs_ul_cfg_ded_present and dedicated->srs_ul_cfg_ded.type() == setup_e::setup and - common->srs_ul_cnfg.type() == setup_e::setup; - if (srs_cfg.configured) { - srs_cfg.subframe_config = common->srs_ul_cnfg.setup().srs_sf_cfg.to_number(); - srs_cfg.bw_cfg = common->srs_ul_cnfg.setup().srs_bw_cfg.to_number(); - srs_cfg.I_srs = dedicated->srs_ul_cfg_ded.setup().srs_cfg_idx; - srs_cfg.B = dedicated->srs_ul_cfg_ded.setup().srs_bw; - srs_cfg.b_hop = dedicated->srs_ul_cfg_ded.setup().srs_hop_bw; - srs_cfg.n_rrc = dedicated->srs_ul_cfg_ded.setup().freq_domain_position; - srs_cfg.k_tc = dedicated->srs_ul_cfg_ded.setup().tx_comb; - srs_cfg.n_srs = dedicated->srs_ul_cfg_ded.setup().cyclic_shift; - } - - /* UL power control configuration */ - bzero(&power_ctrl, sizeof(srslte_ue_ul_powerctrl_t)); - power_ctrl.p0_nominal_pusch = common->ul_pwr_ctrl.p0_nominal_pusch; - power_ctrl.alpha = common->ul_pwr_ctrl.alpha.to_number(); - power_ctrl.p0_nominal_pucch = common->ul_pwr_ctrl.p0_nominal_pucch; - power_ctrl.delta_f_pucch[0] = common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format1.to_number(); - power_ctrl.delta_f_pucch[1] = common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format1b.to_number(); - power_ctrl.delta_f_pucch[2] = common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2.to_number(); - power_ctrl.delta_f_pucch[3] = common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2a.to_number(); - power_ctrl.delta_f_pucch[4] = common->ul_pwr_ctrl.delta_flist_pucch.delta_f_pucch_format2b.to_number(); - - power_ctrl.delta_preamble_msg3 = common->ul_pwr_ctrl.delta_preamb_msg3; - - power_ctrl.p0_ue_pusch = dedicated->ul_pwr_ctrl_ded.p0_ue_pusch; - power_ctrl.delta_mcs_based = - dedicated->ul_pwr_ctrl_ded.delta_mcs_enabled == ul_pwr_ctrl_ded_s::delta_mcs_enabled_e_::en0; - power_ctrl.acc_enabled = dedicated->ul_pwr_ctrl_ded.accumulation_enabled; - power_ctrl.p0_ue_pucch = dedicated->ul_pwr_ctrl_ded.p0_ue_pucch; - power_ctrl.p_srs_offset = dedicated->ul_pwr_ctrl_ded.p_srs_offset; - - srslte_ue_ul_set_cfg(&ue_ul, &dmrs_cfg, &srs_cfg, &pucch_cfg, &pucch_sched, &uci_cfg, &pusch_hopping, &power_ctrl); - - /* CQI configuration */ - bzero(&period_cqi, sizeof(srslte_cqi_periodic_cfg_t)); - period_cqi.configured = dedicated->cqi_report_cfg.cqi_report_periodic_present and - dedicated->cqi_report_cfg.cqi_report_periodic.type() == setup_e::setup; - if (period_cqi.configured) { - period_cqi.pmi_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx; - period_cqi.simul_cqi_ack = dedicated->cqi_report_cfg.cqi_report_periodic.setup().simul_ack_nack_and_cqi; - period_cqi.format_is_subband = - dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().value == - cqi_report_periodic_c::setup_s_::cqi_format_ind_periodic_c_::types::subband_cqi; - if (period_cqi.format_is_subband) { - period_cqi.subband_size = - dedicated->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.subband_cqi().k; - } - if (dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx_present) { - period_cqi.ri_idx = dedicated->cqi_report_cfg.cqi_report_periodic.setup().ri_cfg_idx; - period_cqi.ri_idx_present = true; - } else { - period_cqi.ri_idx_present = false; - } - } - - pthread_mutex_unlock(&mutex); - - if (pregen_enabled && !pregen_disabled) { - Info("Pre-generating UL signals worker=%d\n", get_id()); - srslte_ue_ul_pregen_signals(&ue_ul); - Info("Done pre-generating signals worker=%d\n", get_id()); - } -} - -float phch_worker::set_power(float tx_power) { - float gain = 0; - /* Check if UL power control is enabled */ - if(phy->args->ul_pwr_ctrl_en) { - /* Adjust maximum power if it changes significantly */ - if (tx_power < phy->cur_radio_power - 5 || tx_power > phy->cur_radio_power + 5) { - phy->cur_radio_power = tx_power; - float radio_tx_power = phy->cur_radio_power; - gain = phy->get_radio()->set_tx_power(radio_tx_power); - } - } - return gain; -} - -void phch_worker::start_plot() { -#ifdef ENABLE_GUI - if (plot_worker_id == -1) { - plot_worker_id = get_id(); - log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); - init_plots(this); - } else { - log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); - } -#else - log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); -#endif -} - -int phch_worker::read_ce_abs(float *ce_abs, uint32_t tx_antenna, uint32_t rx_antenna) { - uint32_t i=0; - int sz = srslte_symbol_sz(cell.nof_prb); - bzero(ce_abs, sizeof(float)*sz); - int g = (sz - 12*cell.nof_prb)/2; - for (i = 0; i < 12*cell.nof_prb; i++) { - ce_abs[g+i] = 20 * log10f(std::abs(std::complex(ue_dl.ce_m[tx_antenna][rx_antenna][i]))); - if (std::isinf(ce_abs[g + i])) { - ce_abs[g+i] = -80; - } - } - return sz; -} - -int phch_worker::read_pdsch_d(cf_t* pdsch_d) -{ - - memcpy(pdsch_d, ue_dl.pdsch.d[0], ue_dl.pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); - return ue_dl.pdsch_cfg.nbits[0].nof_re; -} - - - -/**************************** Measurements **************************/ - -void phch_worker::update_measurements() -{ - float snr_ema_coeff = phy->args->snr_ema_coeff; - if (chest_done) { - - /* Only worker 0 reads the RSSI sensor every ~1-nof_cores s */ - if (get_id() == 0) { - if (!rssi_read_cnt) { - if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { - phy->last_radio_rssi = phy->get_radio()->get_rssi(); - phy->rx_gain_offset = phy->avg_rssi_dbm - phy->last_radio_rssi + 30; - } else { - phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset; - } - } - rssi_read_cnt++; - if (rssi_read_cnt == 1000) { - rssi_read_cnt = 0; - } - } - - // Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC - float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); - if (std::isnormal(rsrq_db)) { - if (!(tti%phy->pcell_report_period) || !phy->avg_rsrq_db) { - phy->avg_rsrq_db = rsrq_db; - } else { - phy->avg_rsrq_db = SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db, tti%phy->pcell_report_period); - } - } - - // Average RSRP taken from CRS - float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest); - if (std::isnormal(rsrp_lin)) { - if (!phy->avg_rsrp) { - phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff); - } else { - phy->avg_rsrp = rsrp_lin; - } - } - - /* Correct absolute power measurements by RX gain offset */ - float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->rx_gain_offset; - - // Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC - if (std::isnormal(rsrp_dbm)) { - if (!(tti%phy->pcell_report_period) || !phy->avg_rsrp_dbm) { - phy->avg_rsrp_dbm = rsrp_dbm; - } else { - phy->avg_rsrp_dbm = SRSLTE_VEC_CMA(rsrp_dbm, phy->avg_rsrp_dbm, tti%phy->pcell_report_period); - } - } - - // Send PCell measurement - if ((tti%phy->pcell_report_period) == phy->pcell_report_period-1) { - phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti); - } - - // Compute PL - float tx_crs_power = phy->config->common.pdsch_cnfg.ref_sig_pwr; - phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm; - - // Average noise - float cur_noise = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); - if (std::isnormal(cur_noise)) { - if (!phy->avg_noise) { - phy->avg_noise = cur_noise; - } else { - phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff); - } - } - - // Average RI - if (!phy->avg_ri) { - phy->avg_ri = SRSLTE_VEC_EMA(phy->last_ri, phy->avg_ri, 0.1); - } else { - phy->avg_ri = phy->last_ri; - } - - phy->avg_snr_db_cqi = 10*log10(phy->avg_rsrp/phy->avg_noise); - - // Store metrics - dl_metrics.n = phy->avg_noise; - dl_metrics.rsrp = phy->avg_rsrp_dbm; - dl_metrics.rsrq = phy->avg_rsrq_db; - dl_metrics.rssi = phy->avg_rssi_dbm; - dl_metrics.pathloss = phy->pathloss; - dl_metrics.sinr = phy->avg_snr_db_cqi; - dl_metrics.ri = phy->avg_ri; - phy->set_dl_metrics(dl_metrics); - - } -} - - -/********** Execution time trace function ************/ - -void phch_worker::start_trace() { - trace_enabled = true; -} - -void phch_worker::write_trace(std::string filename) { - tr_exec.writeToBinary(filename + ".exec"); -} - -void phch_worker::tr_log_start() -{ - if (trace_enabled) { - gettimeofday(&tr_time[1], NULL); - } -} - -void phch_worker::tr_log_end() -{ - if (trace_enabled) { - gettimeofday(&tr_time[2], NULL); - get_time_interval(tr_time); - tr_exec.push(tti, tr_time[0].tv_usec); - } -} - -} - - - - - - - - -/*********************************************************** - * - * PLOT TO VISUALIZE THE CHANNEL RESPONSEE - * - ***********************************************************/ - - -#ifdef ENABLE_GUI -plot_real_t pce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; -plot_scatter_t pconst; -#define SCATTER_PDSCH_BUFFER_LEN (20*6*SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)) -#define SCATTER_PDSCH_PLOT_LEN 4000 -float tmp_plot[SCATTER_PDSCH_BUFFER_LEN]; -cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; - -#define CFO_PLOT_LEN 0 /* Set to non zero for enabling CFO plot */ -#if CFO_PLOT_LEN > 0 -static plot_real_t pcfo; -static uint32_t icfo = 0; -static float cfo_buffer[CFO_PLOT_LEN]; -#endif /* CFO_PLOT_LEN > 0 */ - -void *plot_thread_run(void *arg) { - srsue::phch_worker *worker = (srsue::phch_worker*) arg; - - sdrgui_init(); - for (uint32_t tx = 0; tx < worker->get_cell_nof_ports(); tx++) { - for (uint32_t rx = 0; rx < worker->get_rx_nof_antennas(); rx++) { - char str_buf[64]; - snprintf(str_buf, 64, "|H%d%d|", rx, tx); - plot_real_init(&pce[tx][rx]); - plot_real_setTitle(&pce[tx][rx], str_buf); - plot_real_setLabels(&pce[tx][rx], (char *) "Index", (char *) "dB"); - plot_real_setYAxisScale(&pce[tx][rx], -40, 40); - - plot_real_addToWindowGrid(&pce[tx][rx], (char*)"srsue", tx, rx); - } - } - - plot_scatter_init(&pconst); - plot_scatter_setTitle(&pconst, (char*) "PDSCH - Equalized Symbols"); - plot_scatter_setXAxisScale(&pconst, -4, 4); - plot_scatter_setYAxisScale(&pconst, -4, 4); - - plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, worker->get_rx_nof_antennas()); - -#if CFO_PLOT_LEN > 0 - plot_real_init(&pcfo); - plot_real_setTitle(&pcfo, (char*) "CFO (Hz)"); - plot_real_setLabels(&pcfo, (char *) "Time", (char *) "Hz"); - plot_real_setYAxisScale(&pcfo, -4000, 4000); - - plot_scatter_addToWindowGrid(&pcfo, (char*)"srsue", 1, worker->get_rx_nof_antennas()); -#endif /* CFO_PLOT_LEN > 0 */ - - int n; - int readed_pdsch_re=0; - while(1) { - sem_wait(&plot_sem); - - if (readed_pdsch_re < SCATTER_PDSCH_PLOT_LEN) { - n = worker->read_pdsch_d(&tmp_plot2[readed_pdsch_re]); - readed_pdsch_re += n; - } else { - for (uint32_t tx = 0; tx < worker->get_cell_nof_ports(); tx++) { - for (uint32_t rx = 0; rx < worker->get_rx_nof_antennas(); rx++) { - n = worker->read_ce_abs(tmp_plot, tx, rx); - if (n > 0) { - plot_real_setNewData(&pce[tx][rx], tmp_plot, n); - } - } - } - if (readed_pdsch_re > 0) { - plot_scatter_setNewData(&pconst, tmp_plot2, readed_pdsch_re); - } - readed_pdsch_re = 0; - } - -#if CFO_PLOT_LEN > 0 - cfo_buffer[icfo] = worker->get_cfo() * 15000.0f; - icfo = (icfo + 1)%CFO_PLOT_LEN; - plot_real_setNewData(&pcfo, cfo_buffer, CFO_PLOT_LEN); -#endif /* CFO_PLOT_LEN > 0 */ - - } - return NULL; -} - - -void init_plots(srsue::phch_worker *worker) { - - if (sem_init(&plot_sem, 0, 0)) { - perror("sem_init"); - exit(-1); - } - - pthread_attr_t attr; - struct sched_param param; - param.sched_priority = 0; - pthread_attr_init(&attr); - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); - pthread_attr_setschedpolicy(&attr, SCHED_OTHER); - pthread_attr_setschedparam(&attr, ¶m); - if (pthread_create(&plot_thread, &attr, plot_thread_run, worker)) { - perror("pthread_create"); - exit(-1); - } -} -#endif - diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 52ce4dc8f..2e0e3dc68 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -33,7 +33,6 @@ #include #include "srslte/srslte.h" - #include "srslte/common/threads.h" #include "srslte/common/log.h" #include "srsue/hdr/phy/phy.h" @@ -48,12 +47,13 @@ using namespace asn1::rrc; namespace srsue { -phy::phy() : workers_pool(MAX_WORKERS), - workers(MAX_WORKERS), - workers_common(MAX_WORKERS),nof_coworkers(0) +phy::phy() : workers_pool(MAX_WORKERS), workers(0), common(MAX_WORKERS) { - ZERO_OBJECT(config); - ZERO_OBJECT(cell); + ZERO_OBJECT(tdd_config); + ZERO_OBJECT(prach_cfg); + ZERO_OBJECT(default_args); + ZERO_OBJECT(scell_earfcn); + n_ta = 0; } static void srslte_phy_handler(phy_logger_level_t log_level, void *ctx, char *str) { @@ -63,14 +63,14 @@ static void srslte_phy_handler(phy_logger_level_t log_level, void *ctx, char *st void phy::srslte_phy_logger(phy_logger_level_t log_level, char *str) { if (log_phy_lib_h) { - switch(log_level){ - case LOG_LEVEL_INFO: + switch (log_level) { + case LOG_LEVEL_INFO_S: log_phy_lib_h->info(" %s", str); break; - case LOG_LEVEL_DEBUG: + case LOG_LEVEL_DEBUG_S: log_phy_lib_h->debug(" %s", str); break; - case LOG_LEVEL_ERROR: + case LOG_LEVEL_ERROR_S: log_phy_lib_h->error(" %s", str); break; default: @@ -91,7 +91,6 @@ void phy::set_default_args(phy_args_t *args) args->snr_ema_coeff = 0.1; args->snr_estim_alg = "refs"; args->pdsch_max_its = 4; - args->attach_enable_64qam = false; args->nof_phy_threads = DEFAULT_WORKERS; args->equalizer_mode = "mmse"; args->cfo_integer_enabled = false; @@ -102,9 +101,9 @@ void phy::set_default_args(phy_args_t *args) args->estimator_fil_order = 4; } -bool phy::check_args(phy_args_t *args) +bool phy::check_args(phy_args_t* args) { - if (args->nof_phy_threads > MAX_WORKERS * 2) { + if (args->nof_phy_threads > MAX_WORKERS) { log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n"); return false; } @@ -115,8 +114,12 @@ bool phy::check_args(phy_args_t *args) return true; } -bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_interface_phy *rrc, - std::vector log_vec, phy_args_t *phy_args) { +bool phy::init(srslte::radio* radio_handler, + mac_interface_phy* mac, + rrc_interface_phy* rrc, + std::vector log_vec, + phy_args_t* phy_args) +{ mlockall(MCL_CURRENT | MCL_FUTURE); @@ -139,12 +142,8 @@ bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_i } nof_workers = args->nof_phy_threads; - if (nof_workers > MAX_WORKERS) { - nof_coworkers = SRSLTE_MIN(nof_workers - MAX_WORKERS, MAX_WORKERS); - nof_workers = MAX_WORKERS; - } if (log_vec[nof_workers]) { - this->log_phy_lib_h = (srslte::log*) log_vec[nof_workers]; + this->log_phy_lib_h = (srslte::log*)log_vec[0]; srslte_phy_log_register_handler(this, srslte_phy_handler); } else { this->log_phy_lib_h = NULL; @@ -158,22 +157,34 @@ bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_i // Initializes PHY in a thread void phy::run_thread() { - prach_buffer.init(&config.common.prach_cnfg, SRSLTE_MAX_PRB, args, log_h); - workers_common.init(&config, args, (srslte::log*) log_vec[0], radio_handler, rrc, mac); + prach_buffer.init(SRSLTE_MAX_PRB, log_h); + common.init(args, (srslte::log*)log_vec[0], radio_handler, rrc, mac); // Add workers to workers pool and start threads for (uint32_t i=0;iworker_cpu_mask); + sf_worker* w = + new sf_worker(SRSLTE_MAX_PRB, &common, (srslte::log*)log_vec[i], (srslte::log*)log_vec[nof_workers], &sfsync); + workers.push_back(w); + workers_pool.init_worker(i, w, WORKERS_THREAD_PRIO, args->worker_cpu_mask); } - for (uint32_t i=0;inof_radios - 1; i++) { + scell_sync[i].init(&radio_handler[i + 1], &common, log_h); } // Warning this must be initialized after all workers have been added to the pool - sf_recv.init(radio_handler, mac, rrc, &prach_buffer, &workers_pool, &workers_common, log_h, log_phy_lib_h, args->nof_rx_ant, SF_RECV_THREAD_PRIO, args->sync_cpu_affinity); + sfsync.init(radio_handler, + mac, + rrc, + &prach_buffer, + &workers_pool, + &common, + log_h, + log_phy_lib_h, + scell_sync, + SF_RECV_THREAD_PRIO, + args->sync_cpu_affinity); // Disable UL signal pregeneration until the attachment enable_pregen_signals(false); @@ -185,269 +196,307 @@ void phy::wait_initialize() { wait_thread_finish(); } -bool phy::is_initiated() { +bool phy::is_initiated() +{ return initiated; } void phy::set_agc_enable(bool enabled) { - sf_recv.set_agc_enable(enabled); -} - -void phy::start_trace() -{ - for (uint32_t i=0;inof_radios - 1; i++) { + scell_sync[i].set_agc_enable(enabled); } } -void phy::write_trace(std::string filename) +void phy::stop() { - for (uint32_t i=0;i( &(ostringstream() << i) )->str(); - workers[i].write_trace(filename + "_" + i_str); + sfsync.stop(); + for (uint32_t i = 0; i < args->nof_radios - 1; i++) { + scell_sync[i].stop(); } -} -void phy::stop() -{ - sf_recv.stop(); workers_pool.stop(); + prach_buffer.stop(); + for (uint32_t i = 0; i < nof_workers; i++) { + delete ((sf_worker*)workers[i]); + } } void phy::get_metrics(phy_metrics_t &m) { - workers_common.get_dl_metrics(m.dl); - workers_common.get_ul_metrics(m.ul); - workers_common.get_sync_metrics(m.sync); - int dl_tbs = srslte_ra_tbs_from_idx(srslte_ra_dl_tbs_idx_from_mcs(m.dl.mcs), workers_common.get_nof_prb()); - int ul_tbs = srslte_ra_tbs_from_idx(srslte_ra_ul_tbs_idx_from_mcs(m.ul.mcs), workers_common.get_nof_prb()); - m.dl.mabr_mbps = dl_tbs/1000.0; // TBS is bits/ms - convert to mbps - m.ul.mabr_mbps = ul_tbs/1000.0; // TBS is bits/ms - convert to mbps - Info("PHY: MABR estimates. DL: %4.6f Mbps. UL: %4.6f Mbps.\n", m.dl.mabr_mbps, m.ul.mabr_mbps); + common.get_dl_metrics(m.dl); + common.get_ul_metrics(m.ul); + common.get_sync_metrics(m.sync); + m.nof_active_cc = args->nof_carriers; } void phy::set_timeadv_rar(uint32_t ta_cmd) { n_ta = srslte_N_ta_new_rar(ta_cmd); - sf_recv.set_time_adv_sec(((float) n_ta)*SRSLTE_LTE_TS); + sfsync.set_time_adv_sec(((float)n_ta) * SRSLTE_LTE_TS); Info("PHY: Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float) n_ta)*SRSLTE_LTE_TS*1e6); } void phy::set_timeadv(uint32_t ta_cmd) { uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd); - sf_recv.set_time_adv_sec(((float) new_nta)*SRSLTE_LTE_TS); - Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n", ta_cmd, new_nta, n_ta, ((float) new_nta)*SRSLTE_LTE_TS*1e6); + sfsync.set_time_adv_sec(((float)new_nta) * SRSLTE_LTE_TS); + Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n", + ta_cmd, + new_nta, + n_ta, + ((float)new_nta) * SRSLTE_LTE_TS * 1e6); n_ta = new_nta; } -void phy::configure_prach_params() +void phy::set_activation_deactivation_scell(uint32_t cmd) { - Debug("Configuring PRACH parameters\n"); - srslte_cell_t cell; - sf_recv.get_current_cell(&cell); - if (!prach_buffer.set_cell(cell)) { - Error("Configuring PRACH parameters\n"); + Info("Received SCell Activation / Deactivation command: 0x%x\n", cmd); + + /* Implements 3GPP 36.321 section 6.1.3.8. Activation/Deactivation MAC Control Element*/ + log_h->console("SCELL Activation / Deactivation CMD: %x\n", cmd); + + for (uint32_t i = 1; i < SRSLTE_MAX_CARRIERS; i++) { + bool activated = ((cmd >> i) & 0x1) == 0x1; + + /* Enable actual cell */ + common.enable_scell(i, activated); } } -void phy::configure_ul_params(bool pregen_disabled) +void phy::configure_prach_params() { - Info("PHY: Configuring UL parameters\n"); - if (is_initiated()) { - for (uint32_t i=0;iget_max_tx_power() - workers_common.cur_pusch_power; + float phr = radio_handler->get_max_tx_power() - common.cur_pusch_power; return phr; } float phy::get_pathloss_db() { - return workers_common.cur_pathloss; + return common.cur_pathloss; } -void phy::pdcch_ul_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end) +void phy::get_current_cell(srslte_cell_t* cell, uint32_t* current_earfcn) { - workers_common.set_ul_rnti(rnti_type, rnti, tti_start, tti_end); -} - -void phy::pdcch_dl_search(srslte_rnti_type_t rnti_type, uint16_t rnti, int tti_start, int tti_end) -{ - workers_common.set_dl_rnti(rnti_type, rnti, tti_start, tti_end); -} - -void phy::pdcch_dl_search_reset() -{ - workers_common.set_dl_rnti(SRSLTE_RNTI_USER, 0); -} - -void phy::pdcch_ul_search_reset() -{ - workers_common.set_ul_rnti(SRSLTE_RNTI_USER, 0); -} - -void phy::get_current_cell(srslte_cell_t *cell, uint32_t *current_earfcn) -{ - sf_recv.get_current_cell(cell, current_earfcn); + sfsync.get_current_cell(cell, current_earfcn); } uint32_t phy::get_current_pci() { srslte_cell_t cell; - sf_recv.get_current_cell(&cell); + sfsync.get_current_cell(&cell); return cell.id; } uint32_t phy::get_current_earfcn() { uint32_t earfcn; - sf_recv.get_current_cell(NULL, &earfcn); + sfsync.get_current_cell(NULL, &earfcn); return earfcn; } void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm) { - + sfsync.set_time_adv_sec(0.0f); if (!prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm)) { Error("Preparing PRACH to send\n"); } } -int phy::prach_tx_tti() +phy_interface_mac::prach_info_t phy::prach_get_info() { - return prach_buffer.tx_tti(); + return prach_buffer.get_info(); } // Handle the case of a radio overflow. Resynchronise inmediatly -void phy::radio_overflow() { - sf_recv.radio_overflow(); +void phy::radio_overflow() +{ + sfsync.radio_overflow(); } void phy::reset() { Info("Resetting PHY\n"); n_ta = 0; - sf_recv.set_time_adv_sec(0); - pdcch_dl_search_reset(); - for(uint32_t i=0;ireset(); } - workers_common.reset(); + common.reset(); } uint32_t phy::get_current_tti() { - return sf_recv.get_current_tti(); + return sfsync.get_current_tti(); } - void phy::sr_send() { - workers_common.sr_enabled = true; - workers_common.sr_last_tx_tti = -1; + common.sr_enabled = true; + common.sr_last_tx_tti = -1; } int phy::sr_last_tx_tti() { - return workers_common.sr_last_tx_tti; + return common.sr_last_tx_tti; } void phy::set_earfcn(vector< uint32_t > earfcns) { - sf_recv.set_earfcn(earfcns); + sfsync.set_earfcn(earfcns); } void phy::force_freq(float dl_freq, float ul_freq) { - sf_recv.force_freq(dl_freq, ul_freq); + sfsync.force_freq(dl_freq, ul_freq); } -void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) +void phy::set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti) { - workers_common.set_rar_grant(tti, grant_payload); + common.set_rar_grant(grant_payload, rnti, tdd_config); } -void phy::set_crnti(uint16_t rnti) { +void phy::set_crnti(uint16_t rnti) +{ for(uint32_t i=0;iset_crnti(rnti); } } -// Start GUI +// Start GUI void phy::start_plot() { - workers[0].start_plot(); + workers[0]->start_plot(); } void phy::enable_pregen_signals(bool enable) -{ - for(uint32_t i=0;ienable_pregen_signals(enable); } } -uint32_t phy::tti_to_SFN(uint32_t tti) { - return tti/10; +void phy::set_config(phy_interface_rrc::phy_cfg_t* phy_cfg) +{ + if (is_initiated()) { + for (uint32_t i = 0; i < nof_workers; i++) { + workers[i]->set_pcell_config(phy_cfg); + } + } + // Save PRACH configuration + prach_cfg.config_idx = phy_cfg->common.prach_cnfg.prach_cfg_info.prach_cfg_idx; + prach_cfg.root_seq_idx = phy_cfg->common.prach_cnfg.root_seq_idx; + prach_cfg.zero_corr_zone = phy_cfg->common.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg; + prach_cfg.freq_offset = phy_cfg->common.prach_cnfg.prach_cfg_info.prach_freq_offset; + prach_cfg.hs_flag = phy_cfg->common.prach_cnfg.prach_cfg_info.high_speed_flag; } -uint32_t phy::tti_to_subf(uint32_t tti) { - return tti%10; -} +void phy::set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config) +{ + // Enable CSI request extra bit + common.multiple_csi_request_enabled = true; + uint32_t cc_idx = scell_config->s_cell_idx_r10; -void phy::get_config(phy_interface_rrc::phy_cfg_t* phy_cfg) -{ - *phy_cfg = config; -} + // Component carrier index zero should be reserved for PCell + if (cc_idx != 0 && cc_idx < args->nof_carriers) { + carrier_map_t* m = &args->carrier_map[cc_idx]; + srslte_cell_t cell = {}; + uint32_t earfcn = 0; -void phy::set_config(phy_interface_rrc::phy_cfg_t* phy_cfg) -{ - config = *phy_cfg; -} + // Initialise default parameters from primary cell + sfsync.get_current_cell(&cell, &earfcn); -void phy::set_config_64qam_en(bool enable) -{ - config.enable_64qam = enable; -} + // Parse identification + if (scell_config->cell_identif_r10_present) { + cell.id = scell_config->cell_identif_r10.pci_r10; + earfcn = scell_config->cell_identif_r10.dl_carrier_freq_r10; + } -void phy::set_config_common(phy_interface_rrc::phy_cfg_common_t* common) -{ - config.common = *common; -} + // Parse radio resource + if (scell_config->rr_cfg_common_scell_r10_present) { + rr_cfg_common_scell_r10_s* rr_cfg = &scell_config->rr_cfg_common_scell_r10; + cell.frame_type = (rr_cfg->tdd_cfg_v1130_present) ? SRSLTE_TDD : SRSLTE_FDD; + cell.nof_prb = rr_cfg->non_ul_cfg_r10.dl_bw_r10.to_number(); + cell.nof_ports = rr_cfg->non_ul_cfg_r10.ant_info_common_r10.ant_ports_count.to_number(); + cell.phich_length = (srslte_phich_length_t)rr_cfg->non_ul_cfg_r10.phich_cfg_r10.phich_dur.value; + cell.phich_resources = (srslte_phich_r_t)rr_cfg->non_ul_cfg_r10.phich_cfg_r10.phich_res.value; + } -void phy::set_config_dedicated(phys_cfg_ded_s* dedicated) -{ - config.dedicated = *dedicated; + // Send configuration to workers + for (uint32_t i = 0; i < nof_workers; i++) { + workers[i]->set_cell(cc_idx, cell); + workers[i]->set_scell_config(cc_idx, scell_config); + } + + // If SCell does not share synchronism with PCell ... + if (m->radio_idx > 0) { + scell_sync[m->radio_idx - 1].set_scell_cell(cc_idx, &cell, earfcn); + } else { + // Change frequency only if the earfcn was modified + if (scell_earfcn[cc_idx - 1] != earfcn) { + float dl_freq = srslte_band_fd(earfcn) * 1e6f; + float ul_freq = srslte_band_fu(srslte_band_ul_earfcn(earfcn)) * 1e6f; + radio_handler->set_rx_freq(m->channel_idx, dl_freq); + radio_handler->set_tx_freq(m->channel_idx, ul_freq); + } + } + + // Store SCell earfcn + scell_earfcn[cc_idx - 1] = earfcn; + + // Set SCell as configured + common.scell_configured[cc_idx] = true; + } else { + log_h->console("Received SCell configuration for index %d but there are not enough CC workers available\n", + scell_config->s_cell_idx_r10); + } } void phy::set_config_tdd(tdd_cfg_s* tdd) { - config.common.tdd_cnfg = *tdd; + tdd_config.sf_config = tdd->sf_assign.to_number(); + tdd_config.ss_config = tdd->special_sf_patterns.to_number(); + tdd_config.configured = true; + + if (!tdd_config.configured) { + log_h->console("Setting TDD-config: %d, SS config: %d\n", tdd_config.sf_config, tdd_config.ss_config); + } + + for (uint32_t i = 0; i < nof_workers; i++) { + workers[i]->set_tdd_config(tdd_config); + } } void phy::set_config_mbsfn_sib2(sib_type2_s* sib2) @@ -456,36 +505,36 @@ void phy::set_config_mbsfn_sib2(sib_type2_s* sib2) Warning("SIB2 has %d MBSFN subframe configs - only 1 supported\n", sib2->mbsfn_sf_cfg_list.size()); } if (sib2->mbsfn_sf_cfg_list_present and sib2->mbsfn_sf_cfg_list.size() > 0) { - config.mbsfn.mbsfn_subfr_cnfg = sib2->mbsfn_sf_cfg_list[0]; - workers_common.build_mch_table(); + common.mbsfn_config.mbsfn_subfr_cnfg = sib2->mbsfn_sf_cfg_list[0]; + common.build_mch_table(); } } void phy::set_config_mbsfn_sib13(sib_type13_r9_s* sib13) { - config.mbsfn.mbsfn_notification_cnfg = sib13->notif_cfg_r9; + common.mbsfn_config.mbsfn_notification_cnfg = sib13->notif_cfg_r9; if (sib13->mbsfn_area_info_list_r9.size() > 1) { Warning("SIB13 has %d MBSFN area info elements - only 1 supported\n", sib13->mbsfn_area_info_list_r9.size()); } if (sib13->mbsfn_area_info_list_r9.size() > 0) { - config.mbsfn.mbsfn_area_info = sib13->mbsfn_area_info_list_r9[0]; - workers_common.build_mcch_table(); + common.mbsfn_config.mbsfn_area_info = sib13->mbsfn_area_info_list_r9[0]; + common.build_mcch_table(); } } void phy::set_config_mbsfn_mcch(mcch_msg_s* mcch) { - config.mbsfn.mcch = *mcch; + common.mbsfn_config.mcch = *mcch; mac->set_mbsfn_config( - config.mbsfn.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].mbms_session_info_list_r9.size()); - workers_common.set_mch_period_stop( - config.mbsfn.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9); - workers_common.set_mcch(); + common.mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].mbms_session_info_list_r9.size()); + common.set_mch_period_stop( + common.mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9); + common.set_mcch(); } void phy::set_mch_period_stop(uint32_t stop) { - workers_common.set_mch_period_stop(stop); + common.set_mch_period_stop(stop); } } diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc new file mode 100644 index 000000000..3fa34ef4e --- /dev/null +++ b/srsue/src/phy/phy_common.cc @@ -0,0 +1,874 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/radio/radio_multi.h" +#include "srslte/srslte.h" +#include "srsue/hdr/phy/phy_common.h" + +#define Error(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->debug(fmt, ##__VA_ARGS__) + +using namespace asn1::rrc; + +namespace srsue { + +static cf_t zeros[50000]; +static cf_t* zeros_multi[SRSLTE_MAX_PORTS]; + +phy_common::phy_common(uint32_t max_workers) : tx_sem(max_workers) +{ + args = NULL; + log_h = NULL; + radio_h = NULL; + mac = NULL; + this->max_workers = max_workers; + rx_gain_offset = 0; + // have_mtch_stop = false; + + pthread_mutex_init(&pending_ul_ack_mutex, NULL); + pthread_mutex_init(&pending_dl_ack_mutex, NULL); + pthread_mutex_init(&pending_ul_grant_mutex, NULL); + pthread_mutex_init(&received_ul_ack_mutex, NULL); + pthread_mutex_init(&mtch_mutex, NULL); + pthread_cond_init(&mtch_cvar, NULL); + + bzero(&dl_metrics, sizeof(dl_metrics_t) * SRSLTE_MAX_CARRIERS); + dl_metrics_read = true; + dl_metrics_count = 0; + bzero(&ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS); + ul_metrics_read = true; + ul_metrics_count = 0; + bzero(&sync_metrics, sizeof(sync_metrics_t)); + sync_metrics_read = true; + sync_metrics_count = 0; + + rar_grant_tti = -1; + + bzero(zeros, 50000 * sizeof(cf_t)); + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + zeros_multi[p] = zeros; + } + + for (int i = 0; i < TTIMOD_SZ; i++) { + for (int j = 0; j < SRSLTE_MAX_CARRIERS; j++) { + bzero(&received_ul_ack[i][j], sizeof(received_ul_ack_t)); + } + } + + for (uint32_t i = 0; i < max_workers; i++) { + sem_init(&tx_sem[i], 0, 0); // All semaphores start blocked + } + + reset(); + + sib13_configured = false; + mcch_configured = false; +} + +phy_common::~phy_common() +{ + pthread_mutex_destroy(&pending_ul_ack_mutex); + pthread_mutex_destroy(&pending_dl_ack_mutex); + pthread_mutex_destroy(&pending_ul_grant_mutex); + pthread_mutex_destroy(&received_ul_ack_mutex); + for (uint32_t i = 0; i < max_workers; i++) { + sem_post(&tx_sem[i]); + } + for (uint32_t i = 0; i < max_workers; i++) { + sem_destroy(&tx_sem[i]); + } +} + +void phy_common::set_nof_workers(uint32_t nof_workers) +{ + this->nof_workers = nof_workers; +} + +void phy_common::init( + phy_args_t* _args, srslte::log* _log, srslte::radio* _radio, rrc_interface_phy* _rrc, mac_interface_phy* _mac) +{ + log_h = _log; + radio_h = _radio; + rrc = _rrc; + mac = _mac; + args = _args; + is_first_tx = true; + sr_last_tx_tti = -1; +} + +void phy_common::set_ue_dl_cfg(srslte_ue_dl_cfg_t* ue_dl_cfg) +{ + + ue_dl_cfg->snr_to_cqi_offset = args->snr_to_cqi_offset; + + srslte_chest_dl_cfg_t* chest_cfg = &ue_dl_cfg->chest_cfg; + + // Setup estimator filter + bzero(chest_cfg, sizeof(srslte_chest_dl_cfg_t)); + + if (args->estimator_fil_auto) { + chest_cfg->filter_coef[0] = 0; + } else { + chest_cfg->filter_coef[0] = args->estimator_fil_order; + chest_cfg->filter_coef[1] = args->estimator_fil_stddev; + } + chest_cfg->filter_type = SRSLTE_CHEST_FILTER_GAUSS; + + if (!args->snr_estim_alg.compare("refs")) { + chest_cfg->noise_alg = SRSLTE_NOISE_ALG_REFS; + } else if (!args->snr_estim_alg.compare("empty")) { + chest_cfg->noise_alg = SRSLTE_NOISE_ALG_EMPTY; + } else { + chest_cfg->noise_alg = SRSLTE_NOISE_ALG_PSS; + } + + chest_cfg->rsrp_neighbour = false; + chest_cfg->interpolate_subframe = args->interpolate_subframe_enabled; + chest_cfg->cfo_estimate_enable = args->cfo_ref_mask != 0; + chest_cfg->cfo_estimate_sf_mask = args->cfo_ref_mask; +} + +void phy_common::set_pdsch_cfg(srslte_pdsch_cfg_t* pdsch_cfg) +{ + bzero(pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); + pdsch_cfg->csi_enable = args->pdsch_csi_enabled; + pdsch_cfg->max_nof_iterations = args->pdsch_max_its; + pdsch_cfg->decoder_type = !args->equalizer_mode.compare("zf") ? SRSLTE_MIMO_DECODER_ZF : SRSLTE_MIMO_DECODER_MMSE; +} + +void phy_common::set_ue_ul_cfg(srslte_ue_ul_cfg_t* ue_ul_cfg) +{ + // Setup uplink configuration + bzero(ue_ul_cfg, sizeof(srslte_ue_ul_cfg_t)); + ue_ul_cfg->cfo_en = true; + ue_ul_cfg->normalize_en = true; + ue_ul_cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL; +} + +srslte::radio* phy_common::get_radio() +{ + return radio_h; +} + +// Unpack RAR dci as defined in Section 6.2 of 36.213 +void phy_common::set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], + uint16_t rnti, + srslte_tdd_config_t tdd_config) +{ + + if (MSG3_DELAY_MS < 0) { + ERROR("Error MSG3_DELAY_MS can't be negative\n"); + } + + if (rar_grant_tti < 0) { + Error("Must call set_rar_grant_tti before set_rar_grant\n"); + } + + srslte_dci_ul_t dci_ul; + srslte_dci_rar_grant_t rar_grant; + srslte_dci_rar_unpack(grant_payload, &rar_grant); + + if (srslte_dci_rar_to_ul_dci(&cell, &rar_grant, &dci_ul)) { + Error("Converting RAR message to UL dci\n"); + return; + } + dci_ul.rnti = rnti; + + uint32_t msg3_tx_tti; + if (rar_grant.ul_delay) { + msg3_tx_tti = (TTI_TX(rar_grant_tti) + MSG3_DELAY_MS + 1) % 10240; + } else { + msg3_tx_tti = (TTI_TX(rar_grant_tti) + MSG3_DELAY_MS) % 10240; + } + + if (cell.frame_type == SRSLTE_TDD) { + while (srslte_sfidx_tdd_type(tdd_config, msg3_tx_tti % 10) != SRSLTE_TDD_SF_U) { + msg3_tx_tti++; + } + } + + // Save Msg3 UL dci + pthread_mutex_lock(&pending_ul_grant_mutex); + if (!pending_ul_grant[TTIMOD(msg3_tx_tti)][0].enable) { + Debug("RAR grant rar_grant=%d, msg3_tti=%d, stored in index=%d\n", rar_grant_tti, msg3_tx_tti, TTIMOD(msg3_tx_tti)); + pending_ul_grant[TTIMOD(msg3_tx_tti)][0].pid = ul_pidof(msg3_tx_tti, &tdd_config); + pending_ul_grant[TTIMOD(msg3_tx_tti)][0].dci = dci_ul; + pending_ul_grant[TTIMOD(msg3_tx_tti)][0].enable = true; + } else { + Warning("set_rar_grant: sf->tti=%d, cc=%d already in use\n", msg3_tx_tti, 0); + } + pthread_mutex_unlock(&pending_ul_grant_mutex); + + rar_grant_tti = -1; +} + +// Table 8-2 +const static uint32_t k_pusch[7][10] = { + {4, 6, 0, 0, 0, 4, 6, 0, 0, 0}, + {0, 6, 0, 0, 4, 0, 6, 0, 0, 4}, + {0, 0, 0, 4, 0, 0, 0, 0, 4, 0}, + {4, 0, 0, 0, 0, 0, 0, 0, 4, 4}, + {0, 0, 0, 0, 0, 0, 0, 0, 4, 4}, + {0, 0, 0, 0, 0, 0, 0, 0, 4, 0}, + {7, 7, 0, 0, 0, 7, 7, 0, 0, 5}, +}; + +const static uint32_t k_phich[7][10] = {{0, 0, 4, 7, 6, 0, 0, 4, 7, 6}, + {0, 0, 4, 6, 0, 0, 0, 4, 6, 0}, + {0, 0, 6, 0, 0, 0, 0, 6, 0, 0}, + {0, 0, 6, 6, 6, 0, 0, 0, 0, 0}, + {0, 0, 6, 6, 0, 0, 0, 0, 0, 0}, + {0, 0, 6, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 4, 6, 6, 0, 0, 4, 7, 0}}; + +uint32_t phy_common::ul_pidof(uint32_t tti, srslte_tdd_config_t* tdd_config) +{ + + if (tdd_config->configured) { + /* In TDD modes 1-5, each PID is associated with a unique subframe and the number of harq processes equals the + * number of UL subframes Modes 0 and 6 have more processes than UL subframes and PID depends on sfn + */ + uint32_t sf_idx = tti % 10; + uint32_t sfn = tti / 10; + uint32_t cycle_idx; + switch (tdd_config->sf_config) { + case 0: + cycle_idx = 7 - sfn % 7; + if (sf_idx < 5) { + return (cycle_idx + sf_idx - 2) % 7; + } else { + return (cycle_idx + sf_idx - 4) % 7; + } + case 1: + if (sf_idx < 5) { + return sf_idx - 2; + } else { + return sf_idx - 5; + } + case 2: + if (sf_idx < 5) { + return 0; + } else { + return 1; + } + case 3: + case 4: + case 5: + return sf_idx - 2; + case 6: + cycle_idx = 6 - sfn % 6; + if (sf_idx < 5) { + return (cycle_idx + sf_idx - 2) % 6; + } else { + return (cycle_idx + sf_idx - 4) % 6; + } + default: + Error("Invalid SF configuration %d\n", tdd_config->sf_config); + } + } else { + return tti % SRSLTE_FDD_NOF_HARQ; + } + return 0; +} + +// Computes SF->TTI at which PHICH will be received according to 9.1.2 of 36.213 +#define tti_phich(sf) \ + (sf->tti + (cell.frame_type == SRSLTE_FDD ? FDD_HARQ_DELAY_MS : k_phich[sf->tdd_config.sf_config][sf->tti % 10])) + +// Here SF->TTI is when PUSCH is transmitted +void phy_common::set_ul_pending_ack(srslte_ul_sf_cfg_t* sf, + uint32_t cc_idx, + srslte_phich_grant_t phich_grant, + srslte_dci_ul_t* dci_ul) +{ + // Use a lock here because subframe 4 and 9 of TDD config 0 accept multiple PHICH from multiple frames + pthread_mutex_lock(&pending_ul_ack_mutex); + + if (!pending_ul_ack[TTIMOD(tti_phich(sf))][cc_idx][phich_grant.I_phich].enable) { + pending_ul_ack[TTIMOD(tti_phich(sf))][cc_idx][phich_grant.I_phich].dci_ul = *dci_ul; + pending_ul_ack[TTIMOD(tti_phich(sf))][cc_idx][phich_grant.I_phich].phich_grant = phich_grant; + pending_ul_ack[TTIMOD(tti_phich(sf))][cc_idx][phich_grant.I_phich].enable = true; + Debug("Set pending ACK for sf->tti=%d n_dmrs=%d, I_phich=%d, cc_idx=%d\n", + sf->tti, + phich_grant.n_dmrs, + phich_grant.I_phich, + cc_idx); + } else { + Warning("set_ul_pending_ack: sf->tti=%d, cc=%d already in use\n", sf->tti, cc_idx); + } + pthread_mutex_unlock(&pending_ul_ack_mutex); +} + +// Here SF->TTI is when PHICH is being transmitted so that's DL subframe +bool phy_common::get_ul_pending_ack(srslte_dl_sf_cfg_t* sf, + uint32_t cc_idx, + srslte_phich_grant_t* phich_grant, + srslte_dci_ul_t* dci_ul) +{ + pthread_mutex_lock(&pending_ul_ack_mutex); + bool ret = false; + if (pending_ul_ack[TTIMOD(sf->tti)][cc_idx][phich_grant->I_phich].enable) { + *phich_grant = pending_ul_ack[TTIMOD(sf->tti)][cc_idx][phich_grant->I_phich].phich_grant; + *dci_ul = pending_ul_ack[TTIMOD(sf->tti)][cc_idx][phich_grant->I_phich].dci_ul; + ret = true; + pending_ul_ack[TTIMOD(sf->tti)][cc_idx][phich_grant->I_phich].enable = false; + Debug("Get pending ACK for sf->tti=%d n_dmrs=%d, I_phich=%d\n", sf->tti, phich_grant->n_dmrs, phich_grant->I_phich); + } + pthread_mutex_unlock(&pending_ul_ack_mutex); + return ret; +} + +bool phy_common::is_any_ul_pending_ack() +{ + pthread_mutex_lock(&pending_ul_ack_mutex); + bool ret = false; + for (int i = 0; i < TTIMOD_SZ; i++) { + for (int n = 0; n < SRSLTE_MAX_CARRIERS; n++) { + for (int j = 0; j < 2; j++) { + if (pending_ul_ack[i][n][j].enable) { + ret = true; + goto unlock_exit; + } + } + } + } +unlock_exit: + pthread_mutex_unlock(&pending_ul_ack_mutex); + return ret; +} + +// Computes SF->TTI at which PUSCH will be transmitted according to Section 8 of 36.213 +#define tti_pusch_hi(sf) \ + (sf->tti + \ + (cell.frame_type == SRSLTE_FDD ? FDD_HARQ_DELAY_MS \ + : I_phich ? 7 : k_pusch[sf->tdd_config.sf_config][sf->tti % 10]) + \ + (TX_DELAY - FDD_HARQ_DELAY_MS)) +#define tti_pusch_gr(sf) \ + (sf->tti + \ + (cell.frame_type == SRSLTE_FDD ? FDD_HARQ_DELAY_MS \ + : dci->ul_idx == 1 ? 7 : k_pusch[sf->tdd_config.sf_config][sf->tti % 10]) + \ + (TX_DELAY - FDD_HARQ_DELAY_MS)) + +// SF->TTI is at which Format0 dci is received +void phy_common::set_ul_pending_grant(srslte_dl_sf_cfg_t* sf, uint32_t cc_idx, srslte_dci_ul_t* dci) +{ + + pthread_mutex_lock(&pending_ul_grant_mutex); + + // Calculate PID for this SF->TTI + uint32_t pid = ul_pidof(tti_pusch_gr(sf), &sf->tdd_config); + + if (!pending_ul_grant[TTIMOD(tti_pusch_gr(sf))][cc_idx].enable) { + pending_ul_grant[TTIMOD(tti_pusch_gr(sf))][cc_idx].pid = pid; + pending_ul_grant[TTIMOD(tti_pusch_gr(sf))][cc_idx].dci = *dci; + pending_ul_grant[TTIMOD(tti_pusch_gr(sf))][cc_idx].enable = true; + Debug("Set ul pending grant for sf->tti=%d current_tti=%d, pid=%d\n", tti_pusch_gr(sf), sf->tti, pid); + } else { + Warning("set_ul_pending_grant: sf->tti=%d, cc=%d already in use\n", sf->tti, cc_idx); + } + pthread_mutex_unlock(&pending_ul_grant_mutex); +} + +// SF->TTI at which PUSCH should be transmitted +bool phy_common::get_ul_pending_grant(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, uint32_t* pid, srslte_dci_ul_t* dci) +{ + pthread_mutex_lock(&pending_ul_grant_mutex); + bool ret = false; + if (pending_ul_grant[TTIMOD(sf->tti)][cc_idx].enable) { + Debug("Reading grant sf->tti=%d idx=%d\n", sf->tti, TTIMOD(sf->tti)); + if (pid) { + *pid = pending_ul_grant[TTIMOD(sf->tti)][cc_idx].pid; + } + if (dci) { + *dci = pending_ul_grant[TTIMOD(sf->tti)][cc_idx].dci; + } + pending_ul_grant[TTIMOD(sf->tti)][cc_idx].enable = false; + ret = true; + } + pthread_mutex_unlock(&pending_ul_grant_mutex); + return ret; +} + +// SF->TTI at which PHICH is received +void phy_common::set_ul_received_ack( + srslte_dl_sf_cfg_t* sf, uint32_t cc_idx, bool ack_value, uint32_t I_phich, srslte_dci_ul_t* dci_ul) +{ + pthread_mutex_lock(&received_ul_ack_mutex); + received_ul_ack[TTIMOD(tti_pusch_hi(sf))][cc_idx].hi_present = true; + received_ul_ack[TTIMOD(tti_pusch_hi(sf))][cc_idx].hi_value = ack_value; + received_ul_ack[TTIMOD(tti_pusch_hi(sf))][cc_idx].dci_ul = *dci_ul; + Debug("Set ul received ack for sf->tti=%d, current_tti=%d\n", tti_pusch_hi(sf), sf->tti); + pthread_mutex_unlock(&received_ul_ack_mutex); +} + +// SF->TTI at which PUSCH will be transmitted +bool phy_common::get_ul_received_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, bool* ack_value, srslte_dci_ul_t* dci_ul) +{ + pthread_mutex_lock(&received_ul_ack_mutex); + bool ret = false; + if (received_ul_ack[TTIMOD(sf->tti)][cc_idx].hi_present) { + if (ack_value) { + *ack_value = received_ul_ack[TTIMOD(sf->tti)][cc_idx].hi_value; + } + if (dci_ul) { + *dci_ul = received_ul_ack[TTIMOD(sf->tti)][cc_idx].dci_ul; + } + Debug("Get ul received ack for current_tti=%d\n", sf->tti); + received_ul_ack[TTIMOD(sf->tti)][cc_idx].hi_present = false; + ret = true; + } + pthread_mutex_unlock(&received_ul_ack_mutex); + return ret; +} + +// SF->TTI at which PDSCH is decoded and ACK generated +void phy_common::set_dl_pending_ack(srslte_dl_sf_cfg_t* sf, + uint32_t cc_idx, + uint8_t value[SRSLTE_MAX_CODEWORDS], + srslte_pdsch_ack_resource_t resource) +{ + pthread_mutex_lock(&pending_dl_ack_mutex); + if (!pending_dl_ack[TTIMOD(sf->tti)][cc_idx].enable) { + pending_dl_ack[TTIMOD(sf->tti)][cc_idx].enable = true; + pending_dl_ack[TTIMOD(sf->tti)][cc_idx].resource = resource; + memcpy(pending_dl_ack[TTIMOD(sf->tti)][cc_idx].value, value, SRSLTE_MAX_CODEWORDS * sizeof(uint8_t)); + Debug("Set dl pending ack for sf->tti=%d, value=%d, ncce=%d\n", sf->tti, value[0], resource.n_cce); + } else { + Warning("pending_dl_ack: sf->tti=%d, cc=%d already in use\n", sf->tti, cc_idx); + } + pthread_mutex_unlock(&pending_dl_ack_mutex); +} + +void phy_common::set_rar_grant_tti(uint32_t tti) +{ + rar_grant_tti = tti; +} + +typedef struct { + uint32_t M; + uint32_t K[9]; +} das_index_t; + +// Downlink association set index, Table 10.1-1 36.213 +das_index_t das_table[7][10] = { + {{0, {}}, {0, {}}, {1, {6}}, {0, {}}, {1, {4}}, {0, {}}, {0, {}}, {1, {6}}, {0, {}}, {1, {4}}}, + {{0, {}}, {0, {}}, {2, {7, 6}}, {1, {4}}, {0, {}}, {0, {}}, {0, {}}, {2, {7, 6}}, {1, {4}}, {0, {}}}, + {{0, {}}, {0, {}}, {4, {8, 7, 4, 6}}, {0, {}}, {0, {}}, {0, {}}, {0, {}}, {4, {8, 7, 4, 6}}, {0, {}}, {0, {}}}, + {{0, {}}, {0, {}}, {3, {7, 6, 11}}, {2, {6, 5}}, {2, {5, 4}}, {0, {}}, {0, {}}, {0, {}}, {0, {}}, {0, {}}}, + {{0, {}}, {0, {}}, {4, {12, 8, 7, 11}}, {4, {6, 5, 4, 7}}, {0, {}}, {0, {}}, {0, {}}, {0, {}}, {0, {}}, {0, {}}}, + {{0, {}}, + {0, {}}, + {9, {13, 12, 9, 8, 7, 5, 4, 11, 6}}, + {0, {}}, + {0, {}}, + {0, {}}, + {0, {}}, + {0, {}}, + {0, {}}, + {0, {}}}, + {{0, {}}, {0, {}}, {1, {7}}, {1, {7}}, {1, {5}}, {0, {}}, {0, {}}, {1, {7}}, {1, {7}}, {0, {}}}}; + +// SF->TTI at which ACK/NACK would be transmitted +bool phy_common::get_dl_pending_ack(srslte_ul_sf_cfg_t* sf, uint32_t cc_idx, srslte_pdsch_ack_cc_t* ack) +{ + pthread_mutex_lock(&pending_dl_ack_mutex); + bool ret = false; + uint32_t M; + if (cell.frame_type == SRSLTE_FDD) { + M = 1; + } else { + M = das_table[sf->tdd_config.sf_config][sf->tti % 10].M; + } + for (uint32_t i = 0; i < M; i++) { + + uint32_t k = + (cell.frame_type == SRSLTE_FDD) ? FDD_HARQ_DELAY_MS : das_table[sf->tdd_config.sf_config][sf->tti % 10].K[i]; + uint32_t pdsch_tti = TTI_SUB(sf->tti, k + (TX_DELAY - FDD_HARQ_DELAY_MS)); + if (pending_dl_ack[TTIMOD(pdsch_tti)][cc_idx].enable) { + ack->m[i].present = true; + ack->m[i].k = k; + ack->m[i].resource = pending_dl_ack[TTIMOD(pdsch_tti)][cc_idx].resource; + memcpy(ack->m[i].value, pending_dl_ack[TTIMOD(pdsch_tti)][cc_idx].value, SRSLTE_MAX_CODEWORDS * sizeof(uint8_t)); + Debug("Get dl pending ack for sf->tti=%d, i=%d, k=%d, pdsch_tti=%d, value=%d, ncce=%d, v_dai=%d\n", + sf->tti, + i, + k, + pdsch_tti, + ack->m[i].value[0], + ack->m[i].resource.n_cce, + ack->m[i].resource.v_dai_dl); + ret = true; + } + bzero(&pending_dl_ack[TTIMOD(pdsch_tti)][cc_idx], sizeof(received_ack_t)); + } + ack->M = ret ? M : 0; + pthread_mutex_unlock(&pending_dl_ack_mutex); + return ret; +} + +/* The transmission of UL subframes must be in sequence. The correct sequence is guaranteed by a chain of N semaphores, + * one per SF->TTI%max_workers. Each threads waits for the semaphore for the current thread and after transmission + * allows next SF->TTI to be transmitted + * + * 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 sent to the radio + */ +void phy_common::worker_end(uint32_t tti, + bool tx_enable, + cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS], + uint32_t nof_samples[SRSLTE_MAX_RADIOS], + srslte_timestamp_t tx_time[SRSLTE_MAX_RADIOS]) +{ + + // This variable is not protected but it is very unlikely that 2 threads arrive here simultaneously since at the + // beginning there is no workload and threads are separated by 1 ms + if (is_first_tx) { + is_first_tx = false; + // Allow my own transmission if I'm the first to transmit + sem_post(&tx_sem[tti % nof_workers]); + } + + // Wait for the green light to transmit in the current TTI + sem_wait(&tx_sem[tti % nof_workers]); + + // For each radio, transmit + for (uint32_t i = 0; i < args->nof_radios; i++) { + radio_h[i].set_tti(tti); + if (tx_enable && !srslte_timestamp_iszero(&tx_time[i])) { + radio_h[i].tx(buffer[i], nof_samples[i], tx_time[i]); + is_first_of_burst[i] = false; + } else { + if (radio_h[i].is_continuous_tx()) { + if (!is_first_of_burst[i]) { + radio_h[i].tx(zeros_multi, nof_samples[i], tx_time[i]); + } + } else { + if (!is_first_of_burst[i]) { + radio_h[i].tx_end(); + is_first_of_burst[i] = true; + } + } + } + } + + // Allow next TTI to transmit + sem_post(&tx_sem[(tti + 1) % nof_workers]); +} + +void phy_common::set_cell(const srslte_cell_t& c) +{ + cell = c; +} + +uint32_t phy_common::get_nof_prb() +{ + return cell.nof_prb; +} + +void phy_common::set_dl_metrics(const dl_metrics_t m, uint32_t cc_idx) +{ + if (dl_metrics_read) { + bzero(dl_metrics, sizeof(dl_metrics_t) * SRSLTE_MAX_CARRIERS); + dl_metrics_count = 0; + dl_metrics_read = false; + } + dl_metrics_count++; + dl_metrics[cc_idx].mcs = dl_metrics[cc_idx].mcs + (m.mcs - dl_metrics[cc_idx].mcs) / dl_metrics_count; + dl_metrics[cc_idx].n = dl_metrics[cc_idx].n + (m.n - dl_metrics[cc_idx].n) / dl_metrics_count; + dl_metrics[cc_idx].rsrq = dl_metrics[cc_idx].rsrq + (m.rsrq - dl_metrics[cc_idx].rsrq) / dl_metrics_count; + dl_metrics[cc_idx].rssi = dl_metrics[cc_idx].rssi + (m.rssi - dl_metrics[cc_idx].rssi) / dl_metrics_count; + dl_metrics[cc_idx].rsrp = dl_metrics[cc_idx].rsrp + (m.rsrp - dl_metrics[cc_idx].rsrp) / dl_metrics_count; + dl_metrics[cc_idx].sinr = dl_metrics[cc_idx].sinr + (m.sinr - dl_metrics[cc_idx].sinr) / dl_metrics_count; + dl_metrics[cc_idx].pathloss = + dl_metrics[cc_idx].pathloss + (m.pathloss - dl_metrics[cc_idx].pathloss) / dl_metrics_count; + dl_metrics[cc_idx].turbo_iters = + dl_metrics[cc_idx].turbo_iters + (m.turbo_iters - dl_metrics[cc_idx].turbo_iters) / dl_metrics_count; +} + +void phy_common::get_dl_metrics(dl_metrics_t m[SRSLTE_MAX_CARRIERS]) +{ + memcpy(m, dl_metrics, sizeof(dl_metrics_t) * SRSLTE_MAX_CARRIERS); + dl_metrics_read = true; +} + +void phy_common::set_ul_metrics(const ul_metrics_t m, uint32_t cc_idx) +{ + if (ul_metrics_read) { + bzero(ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS); + ul_metrics_count = 0; + ul_metrics_read = false; + } + ul_metrics_count++; + for (uint32_t r = 0; r < args->nof_carriers; r++) { + ul_metrics[cc_idx].mcs = ul_metrics[cc_idx].mcs + (m.mcs - ul_metrics[cc_idx].mcs) / ul_metrics_count; + ul_metrics[cc_idx].power = ul_metrics[cc_idx].power + (m.power - ul_metrics[cc_idx].power) / ul_metrics_count; + } +} + +void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_RADIOS]) +{ + memcpy(m, ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_RADIOS); + ul_metrics_read = true; +} + +void phy_common::set_sync_metrics(const sync_metrics_t& m) +{ + + if (sync_metrics_read) { + sync_metrics = m; + sync_metrics_count = 1; + sync_metrics_read = false; + } else { + sync_metrics_count++; + sync_metrics.cfo = sync_metrics.cfo + (m.cfo - sync_metrics.cfo) / sync_metrics_count; + sync_metrics.sfo = sync_metrics.sfo + (m.sfo - sync_metrics.sfo) / sync_metrics_count; + } +} + +void phy_common::get_sync_metrics(sync_metrics_t& m) +{ + m = sync_metrics; + sync_metrics_read = true; +} + +void phy_common::reset() +{ + sr_enabled = false; + is_first_tx = true; + cur_pathloss = 0; + cur_pusch_power = 0; + p0_preamble = 0; + cur_radio_power = 0; + sr_last_tx_tti = -1; + cur_pusch_power = 0; + ZERO_OBJECT(pathloss); + ZERO_OBJECT(avg_snr_db_cqi); + ZERO_OBJECT(avg_rsrp); + ZERO_OBJECT(avg_rsrp_dbm); + avg_rsrq_db = 0; + + pcell_report_period = 20; + + for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) { + is_first_of_burst[i] = true; + } + + ZERO_OBJECT(scell_configured); + ZERO_OBJECT(scell_enable); + multiple_csi_request_enabled = false; + cif_enabled = false; + srs_request_enabled = false; + ZERO_OBJECT(pending_dl_ack); + ZERO_OBJECT(pending_dl_dai); + ZERO_OBJECT(pending_ul_ack); + ZERO_OBJECT(pending_ul_grant); +} + +/* Convert 6-bit maps to 10-element subframe tables + bitmap = |0|0|0|0|0|0| + subframe index = |1|2|3|6|7|8| +*/ +void phy_common::build_mch_table() +{ + // First reset tables + bzero(&mch_table[0], sizeof(uint8_t) * 40); + + // 40 element table represents 4 frames (40 subframes) + if (mbsfn_config.mbsfn_subfr_cnfg.sf_alloc.type() == asn1::rrc::mbsfn_sf_cfg_s::sf_alloc_c_::types::one_frame) { + generate_mch_table(&mch_table[0], (uint32_t)mbsfn_config.mbsfn_subfr_cnfg.sf_alloc.one_frame().to_number(), 1u); + } else if (mbsfn_config.mbsfn_subfr_cnfg.sf_alloc.type() == + asn1::rrc::mbsfn_sf_cfg_s::sf_alloc_c_::types::four_frames) { + generate_mch_table(&mch_table[0], (uint32_t)mbsfn_config.mbsfn_subfr_cnfg.sf_alloc.four_frames().to_number(), 4u); + } else { + log_h->error("The subframe config has not been set for MBSFN\n"); + } + // Debug + + std::stringstream ss; + ss << "|"; + for (uint32_t j = 0; j < 40; j++) { + ss << (int)mch_table[j] << "|"; + } + Info("MCH table: %s\n", ss.str().c_str()); +} + +void phy_common::build_mcch_table() +{ + // First reset tables + bzero(&mcch_table[0], sizeof(uint8_t) * 10); + generate_mcch_table(&mcch_table[0], (uint32_t)mbsfn_config.mbsfn_area_info.mcch_cfg_r9.sf_alloc_info_r9.to_number()); + // Debug + std::stringstream ss; + ss << "|"; + for (uint32_t j = 0; j < 10; j++) { + ss << (int)mcch_table[j] << "|"; + } + Info("MCCH table: %s\n", ss.str().c_str()); + sib13_configured = true; +} + +void phy_common::set_mcch() +{ + mcch_configured = true; +} + +void phy_common::set_mch_period_stop(uint32_t stop) +{ + pthread_mutex_lock(&mtch_mutex); + have_mtch_stop = true; + mch_period_stop = stop; + pthread_cond_signal(&mtch_cvar); + pthread_mutex_unlock(&mtch_mutex); +} + +bool phy_common::is_mch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti) +{ + uint32_t sfn; // System Frame Number + uint8_t sf; // Subframe + uint8_t offset; + uint8_t period; + + sfn = phy_tti / 10; + sf = phy_tti % 10; + + // Set some defaults + cfg->mbsfn_area_id = 0; + cfg->non_mbsfn_region_length = 1; + cfg->mbsfn_mcs = 2; + cfg->enable = false; + cfg->is_mcch = false; + + // Check for MCCH + if (is_mcch_subframe(cfg, phy_tti)) { + cfg->is_mcch = true; + return true; + } + + // Not MCCH, check for MCH + if (sib13_configured) { + mbsfn_sf_cfg_s* subfr_cnfg = &mbsfn_config.mbsfn_subfr_cnfg; + asn1::rrc::mbsfn_area_info_r9_s* area_info = &mbsfn_config.mbsfn_area_info; + offset = subfr_cnfg->radioframe_alloc_offset; + period = subfr_cnfg->radioframe_alloc_period.to_number(); + + if (subfr_cnfg->sf_alloc.type() == mbsfn_sf_cfg_s::sf_alloc_c_::types::one_frame) { + if ((sfn % period == offset) && (mch_table[sf] > 0)) { + cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; + cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); + if (mcch_configured) { + // Iterate through PMCH configs to see which one applies in the current frame + mbsfn_area_cfg_r9_s* mcch = &mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9(); + uint32_t mbsfn_per_frame = mcch->pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9 / + mcch->pmch_info_list_r9[0].pmch_cfg_r9.mch_sched_period_r9.to_number(); + uint32_t frame_alloc_idx = sfn % mcch->common_sf_alloc_period_r9.to_number(); + uint32_t sf_alloc_idx = frame_alloc_idx * mbsfn_per_frame + ((sf < 4) ? sf - 1 : sf - 3); + pthread_mutex_lock(&mtch_mutex); + while (!have_mtch_stop) { + pthread_cond_wait(&mtch_cvar, &mtch_mutex); + } + pthread_mutex_unlock(&mtch_mutex); + + for (uint32_t i = 0; i < mcch->pmch_info_list_r9.size(); i++) { + if (sf_alloc_idx < mch_period_stop) { + // trigger conditional variable, has ot be untriggered by mtch stop location + cfg->mbsfn_mcs = mcch->pmch_info_list_r9[i].pmch_cfg_r9.data_mcs_r9; + cfg->enable = true; + } else { + // have_mtch_stop = false; + } + } + Debug("MCH subframe TTI:%d\n", phy_tti); + } + return true; + } + } else if (subfr_cnfg->sf_alloc.type() == mbsfn_sf_cfg_s::sf_alloc_c_::types::four_frames) { + uint8_t idx = sfn % period; + if ((idx >= offset) && (idx < offset + 4)) { + if (mch_table[(idx * 10) + sf] > 0) { + cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; + cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); + // TODO: check for MCCH configuration, set MCS and decode + return true; + } + } + } else { + log_h->error("The subframe allocation type is not yet configured\n"); + } + } + + return false; +} + +bool phy_common::is_mcch_subframe(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti) +{ + uint32_t sfn; // System Frame Number + uint8_t sf; // Subframe + uint8_t offset; + uint16_t period; + + sfn = phy_tti / 10; + sf = (uint8_t)(phy_tti % 10); + + if (sib13_configured) { + mbsfn_area_info_r9_s* area_info = &mbsfn_config.mbsfn_area_info; + + offset = area_info->mcch_cfg_r9.mcch_offset_r9; + period = area_info->mcch_cfg_r9.mcch_repeat_period_r9.to_number(); + + if ((sfn % period == offset) && mcch_table[sf] > 0) { + cfg->mbsfn_area_id = area_info->mbsfn_area_id_r9; + cfg->non_mbsfn_region_length = area_info->non_mbsfn_region_len.to_number(); + cfg->mbsfn_mcs = area_info->mcch_cfg_r9.sig_mcs_r9.to_number(); + cfg->enable = true; + have_mtch_stop = false; + Debug("MCCH subframe TTI:%d\n", phy_tti); + return true; + } + } + return false; +} + +bool phy_common::is_mbsfn_sf(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti) +{ + return is_mch_subframe(cfg, phy_tti); +} + +void phy_common::enable_scell(uint32_t cc_idx, bool enable) +{ + if (cc_idx < SRSLTE_MAX_RADIOS) { + scell_enable[cc_idx] = enable; + } +} + +} // namespace srsue diff --git a/srsue/src/phy/prach.cc b/srsue/src/phy/prach.cc index 74e425cb8..25be521db 100644 --- a/srsue/src/phy/prach.cc +++ b/srsue/src/phy/prach.cc @@ -39,8 +39,6 @@ #define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) -using namespace asn1::rrc; - namespace srsue { @@ -59,21 +57,21 @@ prach::~prach() { } } -void prach::init(prach_cfg_sib_s* config_, uint32_t max_prb, phy_args_t* args_, srslte::log* log_h_) +void prach::init(uint32_t max_prb, srslte::log* log_h_) { log_h = log_h_; - config = config_; - args = args_; for (int i=0;i<64;i++) { - buffer[i] = (cf_t*) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN*sizeof(cf_t)); - if(!buffer[i]) { - perror("malloc"); - return; + for (int f = 0; f < 12; f++) { + buffer[f][i] = (cf_t*)srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t)); + if (!buffer[f][i]) { + perror("malloc"); + return; + } } } if (srslte_cfo_init(&cfo_h, SRSLTE_PRACH_MAX_LEN)) { - fprintf(stderr, "PRACH: Error initiating CFO\n"); + ERROR("PRACH: Error initiating CFO\n"); return; } srslte_cfo_set_tol(&cfo_h, 0); @@ -89,38 +87,76 @@ void prach::init(prach_cfg_sib_s* config_, uint32_t max_prb, phy_args_t* args_, mem_initiated = true; } -bool prach::set_cell(srslte_cell_t cell_) +void prach::stop() +{ + if (mem_initiated) { + for (int i = 0; i < 64; i++) { + for (int f = 0; f < 12; f++) { + if (buffer[f][i]) { + free(buffer[f][i]); + } + } + } + if (signal_buffer) { + free(signal_buffer); + } + srslte_cfo_free(&cfo_h); + srslte_prach_free(&prach_obj); + mem_initiated = false; + } +} + +bool prach::set_cell(srslte_cell_t cell, srslte_prach_cfg_t prach_cfg) { if (mem_initiated) { // TODO: Check if other PRACH parameters changed - if (cell_.id != cell.id || !cell_initiated) { - cell = cell_; + if (this->cell.id != cell.id || !cell_initiated) { + this->cell = cell; preamble_idx = -1; - uint32_t configIdx = config->prach_cfg_info.prach_cfg_idx; - uint32_t rootSeq = config->root_seq_idx; - uint32_t zeroCorrConfig = config->prach_cfg_info.zero_correlation_zone_cfg; - uint32_t freq_offset = config->prach_cfg_info.prach_freq_offset; - bool highSpeed = config->prach_cfg_info.high_speed_flag; - - if (6 + freq_offset > cell.nof_prb) { - log_h->console("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); - log_h->error("Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", freq_offset, cell.nof_prb); + if (6 + prach_cfg.freq_offset > cell.nof_prb) { + log_h->console( + "Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", prach_cfg.freq_offset, cell.nof_prb); + log_h->error( + "Error no space for PRACH: frequency offset=%d, N_rb_ul=%d\n", prach_cfg.freq_offset, cell.nof_prb); return false; } Info("PRACH: configIdx=%d, rootSequence=%d, zeroCorrelationConfig=%d, freqOffset=%d\n", - configIdx, rootSeq, zeroCorrConfig, freq_offset); + prach_cfg.config_idx, + prach_cfg.root_seq_idx, + prach_cfg.zero_corr_zone, + prach_cfg.freq_offset); - if (srslte_prach_set_cell(&prach_obj, srslte_symbol_sz(cell.nof_prb), - configIdx, rootSeq, highSpeed, zeroCorrConfig)) { + if (srslte_prach_set_cfg(&prach_obj, &prach_cfg, cell.nof_prb)) { Error("Initiating PRACH library\n"); return false; } - for (int i=0;i<64;i++) { - if(srslte_prach_gen(&prach_obj, i, freq_offset, buffer[i])) { - Error("Generating PRACH preamble %d\n", i); - return false; + + uint32_t nof_f_idx = 1; + if (cell.frame_type == SRSLTE_TDD) { + nof_f_idx = srslte_prach_nof_f_idx_tdd(prach_cfg.config_idx, prach_cfg.tdd_config.sf_config); + // For format4, generate prach for even and odd position + if (prach_cfg.config_idx >= 48) { + nof_f_idx *= 2; + } + } + + for (int i = 0; i < 64; i++) { + for (uint32_t f = 0; f < nof_f_idx; f++) { + uint32_t freq_offset = prach_cfg.freq_offset; + if (cell.frame_type == SRSLTE_TDD) { + freq_offset = srslte_prach_f_ra_tdd(prach_cfg.config_idx, + prach_cfg.tdd_config.sf_config, + (f / 6) * 10, + f % 6, + prach_cfg.freq_offset, + cell.nof_prb); + } + if (srslte_prach_gen(&prach_obj, i, freq_offset, buffer[f][i])) { + Error("Generating PRACH preamble %d\n", i); + return false; + } } } @@ -130,7 +166,7 @@ bool prach::set_cell(srslte_cell_t cell_) } return true; } else { - fprintf(stderr, "PRACH: Error must call init() first\n"); + ERROR("PRACH: Error must call init() first\n"); return false; } } @@ -160,28 +196,58 @@ bool prach::is_pending() { bool prach::is_ready_to_send(uint32_t current_tti_) { if (is_pending()) { - // consider the number of subframes the transmission must be anticipated + // consider the number of subframes the transmission must be anticipated uint32_t tti_tx = TTI_TX(current_tti_); if (srslte_prach_tti_opportunity(&prach_obj, tti_tx, allowed_subframe)) { Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", tti_tx, current_tti_); transmitted_tti = tti_tx; - return true; + return true; } } - return false; + return false; } -int prach::tx_tti() { - return transmitted_tti; +phy_interface_mac::prach_info_t prach::get_info() +{ + phy_interface_mac::prach_info_t info = {}; + + info.preamble_format = prach_obj.config_idx / 16; + if (transmitted_tti >= 0) { + info.tti_ra = (uint32_t)transmitted_tti; + if (cell.frame_type == SRSLTE_TDD) { + info.f_id = + srslte_prach_f_id_tdd(prach_obj.config_idx, prach_obj.tdd_config.sf_config, prach_obj.current_prach_idx); + } + info.is_transmitted = true; + } else { + info.is_transmitted = false; + } + return info; } -cf_t *prach::generate(float cfo, uint32_t *nof_sf, float *target_power) { +cf_t* prach::generate(float cfo, uint32_t* nof_sf, float* target_power) +{ - if (cell_initiated && preamble_idx >= 0 && nof_sf && preamble_idx <= 63 && srslte_cell_isvalid(&cell) && + if (cell_initiated && preamble_idx >= 0 && nof_sf && preamble_idx <= 64 && srslte_cell_isvalid(&cell) && len < MAX_LEN_SF * 30720 && len > 0) { - // Correct CFO before transmission FIXME: UL SISO Only - srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); + uint32_t f_idx = 0; + if (cell.frame_type == SRSLTE_TDD) { + f_idx = prach_obj.current_prach_idx; + // For format4, choose odd or even position + if (prach_obj.config_idx >= 48) { + if ((transmitted_tti / 10) % 2) { + } + f_idx += 6; + } + if (f_idx >= 12) { + Error("PRACH Buffer: Invalid f_idx=%d\n", f_idx); + f_idx = 0; + } + } + + // Correct CFO before transmission + srslte_cfo_correct(&cfo_h, buffer[f_idx][preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb)); // pad guard symbols with zeros uint32_t nsf = (len-1)/SRSLTE_SF_LEN_PRB(cell.nof_prb)+1; @@ -193,8 +259,12 @@ cf_t *prach::generate(float cfo, uint32_t *nof_sf, float *target_power) { *target_power = target_power_dbm; } - Info("PRACH: Transmitted preamble=%d, tti=%d, CFO=%.2f KHz, nof_sf=%d, target_power=%.1f dBm\n", - preamble_idx, transmitted_tti, cfo*15, nsf, target_power_dbm); + Info("PRACH: Transmitted preamble=%d, tti_tx=%d, CFO=%.2f KHz, nof_sf=%d, target_power=%.1f dBm\n", + preamble_idx, + transmitted_tti, + cfo * 15, + nsf, + target_power_dbm); preamble_idx = -1; return signal_buffer; diff --git a/srsue/src/phy/sf_worker.cc b/srsue/src/phy/sf_worker.cc new file mode 100644 index 000000000..c5fb92a1d --- /dev/null +++ b/srsue/src/phy/sf_worker.cc @@ -0,0 +1,508 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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 "srsue/hdr/phy/sf_worker.h" +#include "srslte/interfaces/ue_interfaces.h" +#include +#include + +#define Error(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->error(fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->warning(fmt, ##__VA_ARGS__) +#define Info(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->info(fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) \ + if (SRSLTE_DEBUG_ENABLED) \ + log_h->debug(fmt, ##__VA_ARGS__) + +/* This is to visualize the channel response */ +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +#include + +void init_plots(srsue::sf_worker* worker); +pthread_t plot_thread; +sem_t plot_sem; +static int plot_worker_id = -1; +#else +#warning Compiling without srsGUI support +#endif +/*********************************************/ + +namespace srsue { + +sf_worker::sf_worker( + uint32_t max_prb, phy_common* phy, srslte::log* log_h, srslte::log* log_phy_lib_h, chest_feedback_itf* chest_loop) +{ + cell_initiated = false; + this->phy = phy; + this->log_h = log_h; + this->log_phy_lib_h = log_phy_lib_h; + this->chest_loop = chest_loop; + + bzero(&tdd_config, sizeof(srslte_tdd_config_t)); + + // ue_sync in phy.cc requires a buffer for 3 subframes + for (uint32_t r = 0; r < phy->args->nof_carriers; r++) { + cc_workers.push_back(new cc_worker(r, max_prb, phy, log_h)); + } + + pthread_mutex_init(&mutex, NULL); + reset_(); +} + +sf_worker::~sf_worker() +{ + for (uint32_t r = 0; r < phy->args->nof_carriers; r++) { + delete cc_workers[r]; + } + pthread_mutex_destroy(&mutex); +} + +void sf_worker::reset() +{ + pthread_mutex_lock(&mutex); + reset_(); + pthread_mutex_unlock(&mutex); +} + +void sf_worker::reset_() +{ + rssi_read_cnt = 0; + for (uint32_t i = 0; i < cc_workers.size(); i++) { + cc_workers[i]->reset(); + } +} + +bool sf_worker::set_cell(uint32_t cc_idx, srslte_cell_t cell) +{ + bool ret = false; + pthread_mutex_lock(&mutex); + + if (cc_idx < cc_workers.size()) { + if (!cc_workers[cc_idx]->set_cell(cell)) { + Error("Setting cell for cc=%d\n", cc_idx); + goto unlock; + } + } else { + Error("Setting cell for cc=%d; Not enough CC workers (%ld);\n", cc_idx, cc_workers.size()); + } + + if (cc_idx == 0) { + this->cell = cell; + cell_initiated = true; + } + ret = true; + +unlock: + pthread_mutex_unlock(&mutex); + return ret; +} + +cf_t* sf_worker::get_buffer(uint32_t carrier_idx, uint32_t antenna_idx) +{ + return cc_workers[carrier_idx]->get_rx_buffer(antenna_idx); +} + +void sf_worker::set_tti(uint32_t tti, uint32_t tx_worker_cnt) +{ + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cc_workers[cc_idx]->set_tti(tti); + } + + this->tti = tti; + + tx_sem_id = tx_worker_cnt; + log_h->step(tti); + + if (log_phy_lib_h) { + log_phy_lib_h->step(tti); + } +} + +void sf_worker::set_tx_time(uint32_t radio_idx, srslte_timestamp_t tx_time, int next_offset) +{ + this->next_offset[radio_idx] = next_offset; + this->tx_time[radio_idx] = tx_time; +} + +void sf_worker::set_prach(cf_t* prach_ptr, float prach_power) +{ + this->prach_ptr = prach_ptr; + this->prach_power = prach_power; +} + +void sf_worker::set_cfo(float cfo) +{ + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cc_workers[cc_idx]->set_cfo(cfo); + } +} + +void sf_worker::set_crnti(uint16_t rnti) +{ + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cc_workers[cc_idx]->set_crnti(rnti); + } +} + +void sf_worker::set_tdd_config(srslte_tdd_config_t config) +{ + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cc_workers[cc_idx]->set_tdd_config(config); + } + tdd_config = config; +} + +void sf_worker::enable_pregen_signals(bool enabled) +{ + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cc_workers[cc_idx]->enable_pregen_signals(enabled); + } +} + +void sf_worker::set_pcell_config(srsue::phy_interface_rrc::phy_cfg_t* phy_cfg) +{ + pthread_mutex_lock(&mutex); + Info("Setting PCell configuration for cc_worker=%d, cc=%d\n", get_id(), 0); + cc_workers[0]->set_pcell_config(phy_cfg); + pthread_mutex_unlock(&mutex); +} + +void sf_worker::set_scell_config(uint32_t cc_idx, asn1::rrc::scell_to_add_mod_r10_s* scell_config) +{ + pthread_mutex_lock(&mutex); + if (cc_idx < cc_workers.size()) { + Info("Setting SCell configuration for cc_worker=%d, cc=%d\n", get_id(), cc_idx); + cc_workers[cc_idx]->set_scell_config(scell_config); + } else { + Error("Setting scell config for cc=%d; Not enough CC workers;\n", cc_idx); + } + pthread_mutex_unlock(&mutex); +} + +void sf_worker::work_imp() +{ + if (!cell_initiated) { + return; + } + + pthread_mutex_lock(&mutex); + + /***** Downlink Processing *******/ + + bool rx_signal_ok = false; + + // Loop through all carriers. carrier_idx=0 is PCell + for (uint32_t carrier_idx = 0; carrier_idx < cc_workers.size(); carrier_idx++) { + + // Process all DL and special subframes + if (srslte_sfidx_tdd_type(tdd_config, tti % 10) != SRSLTE_TDD_SF_U || cell.frame_type == SRSLTE_FDD) { + srslte_mbsfn_cfg_t mbsfn_cfg; + ZERO_OBJECT(mbsfn_cfg); + + if (carrier_idx == 0 && phy->is_mbsfn_sf(&mbsfn_cfg, tti)) { + cc_workers[0]->work_dl_mbsfn(mbsfn_cfg); // Don't do chest_ok in mbsfn since it trigger measurements + } else { + if ((carrier_idx == 0) || phy->scell_enable[carrier_idx]) { + rx_signal_ok = cc_workers[carrier_idx]->work_dl_regular(); + } + } + } + } + + /***** Uplink Generation + Transmission *******/ + + bool tx_signal_ready = false; + cf_t* tx_signal_ptr[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {}; + + /* If TTI+4 is an uplink subframe (TODO: Support short PRACH and SRS in UpPts special subframes) */ + if ((srslte_sfidx_tdd_type(tdd_config, TTI_TX(tti) % 10) == SRSLTE_TDD_SF_U) || cell.frame_type == SRSLTE_FDD) { + // Generate Uplink signal if no PRACH pending + if (!prach_ptr) { + + // Common UCI data object for all carriers + srslte_uci_data_t uci_data; + reset_uci(&uci_data); + + // Loop through all carriers. Do in reverse order since control information from SCells is transmitted in PCell + for (int carrier_idx = phy->args->nof_carriers - 1; carrier_idx >= 0; carrier_idx--) { + tx_signal_ready = cc_workers[carrier_idx]->work_ul(&uci_data); + + // Get carrier mapping + carrier_map_t* m = &phy->args->carrier_map[carrier_idx]; + + // Set signal pointer based on offset + cf_t* b = cc_workers[carrier_idx]->get_tx_buffer(0); + if (next_offset[m->radio_idx] > 0) { + tx_signal_ptr[m->radio_idx][m->channel_idx] = b; + } else { + tx_signal_ptr[m->radio_idx][m->channel_idx] = &b[-next_offset[m->radio_idx]]; + } + } + } + } + + // Set PRACH buffer signal pointer + if (prach_ptr) { + tx_signal_ready = true; + tx_signal_ptr[0][0] = prach_ptr; + prach_ptr = NULL; + } + + uint32_t nof_samples[SRSLTE_MAX_RADIOS]; + for (uint32_t i = 0; i < phy->args->nof_radios; i++) { + nof_samples[i] = SRSLTE_SF_LEN_PRB(cell.nof_prb) + next_offset[i]; + } + + // Call worker_end to transmit the signal + phy->worker_end(tx_sem_id, tx_signal_ready, tx_signal_ptr, nof_samples, tx_time); + + if (rx_signal_ok) { + update_measurements(); + } + + pthread_mutex_unlock(&mutex); + + // Call feedback loop for chest + if (chest_loop && ((1 << (tti % 10)) & phy->args->cfo_ref_mask)) { + chest_loop->set_cfo(cc_workers[0]->get_ref_cfo()); + } + + /* Tell the plotting thread to draw the plots */ +#ifdef ENABLE_GUI + if ((int)get_id() == plot_worker_id) { + sem_post(&plot_sem); + } +#endif +} + +/********************* Uplink common control functions ****************************/ + +void sf_worker::reset_uci(srslte_uci_data_t* uci_data) +{ + bzero(uci_data, sizeof(srslte_uci_data_t)); + + /* Set all ACKs to DTX */ + memset(uci_data->value.ack.ack_value, 2, SRSLTE_UCI_MAX_ACK_BITS); +} + +/**************************** Measurements **************************/ + +void sf_worker::update_measurements() +{ + /* Only worker 0 reads the RSSI sensor every ~1-nof_cores s */ + if (get_id() == 0) { + + // Average RSSI over all symbols in antenna port 0 (make sure SF length is non-zero) + float rssi_dbm = + SRSLTE_SF_LEN_PRB(cell.nof_prb) > 0 + ? (10 * log10(srslte_vec_avg_power_cf(cc_workers[0]->get_rx_buffer(0), SRSLTE_SF_LEN_PRB(cell.nof_prb))) + + 30) + : 0; + if (std::isnormal(rssi_dbm)) { + phy->avg_rssi_dbm = SRSLTE_VEC_EMA(rssi_dbm, phy->avg_rssi_dbm, phy->args->snr_ema_coeff); + } + + if (!rssi_read_cnt) { + if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { + phy->last_radio_rssi = phy->get_radio()->get_rssi(); + phy->rx_gain_offset = phy->avg_rssi_dbm - phy->last_radio_rssi + 30; + } else { + phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset; + } + } + rssi_read_cnt++; + if (rssi_read_cnt == 1000) { + rssi_read_cnt = 0; + } + } + + // Run measurements in all carriers + for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) { + cc_workers[cc_idx]->update_measurements(); + } + + // Send PCell measurement + if ((tti % phy->pcell_report_period) == phy->pcell_report_period - 1) { + phy->rrc->new_phy_meas(phy->avg_rsrp_dbm[0], phy->avg_rsrq_db, tti); + } + + // Check in-sync / out-sync conditions + if (phy->avg_rsrp_dbm[0] > -130.0 && phy->avg_snr_db_cqi[0] > -6.0) { + log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n", + phy->avg_snr_db_cqi[0], + phy->avg_rsrp_dbm[0]); + chest_loop->in_sync(); + } else { + log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n", + phy->avg_snr_db_cqi[0], + phy->avg_rsrp_dbm[0]); + chest_loop->out_of_sync(); + } +} + +/*********************************************************** + * + * Interface for Plot visualization + * + ***********************************************************/ + +void sf_worker::start_plot() +{ +#ifdef ENABLE_GUI + if (plot_worker_id == -1) { + plot_worker_id = get_id(); + log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); + init_plots(this); + } else { + log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); + } +#else + log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in sf_worker.cc)\n"); +#endif +} + +int sf_worker::read_ce_abs(float* ce_abs, uint32_t tx_antenna, uint32_t rx_antenna) +{ + return cc_workers[0]->read_ce_abs(ce_abs, tx_antenna, rx_antenna); +} + +int sf_worker::read_pdsch_d(cf_t* pdsch_d) +{ + return cc_workers[0]->read_pdsch_d(pdsch_d); +} + +} // namespace srsue + +/*********************************************************** + * + * PLOT TO VISUALIZE THE CHANNEL RESPONSEE + * + ***********************************************************/ + +#ifdef ENABLE_GUI +plot_real_t pce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; +plot_scatter_t pconst; +#define SCATTER_PDSCH_BUFFER_LEN (20 * 6 * SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)) +#define SCATTER_PDSCH_PLOT_LEN 4000 +float tmp_plot[SCATTER_PDSCH_BUFFER_LEN]; +cf_t tmp_plot2[SRSLTE_SF_LEN_RE(SRSLTE_MAX_PRB, SRSLTE_CP_NORM)]; + +#define CFO_PLOT_LEN 0 /* Set to non zero for enabling CFO plot */ +#if CFO_PLOT_LEN > 0 +static plot_real_t pcfo; +static uint32_t icfo = 0; +static float cfo_buffer[CFO_PLOT_LEN]; +#endif /* CFO_PLOT_LEN > 0 */ + +void* plot_thread_run(void* arg) +{ + srsue::sf_worker* worker = (srsue::sf_worker*)arg; + + sdrgui_init(); + for (uint32_t tx = 0; tx < worker->get_cell_nof_ports(); tx++) { + for (uint32_t rx = 0; rx < worker->get_rx_nof_antennas(); rx++) { + char str_buf[64]; + snprintf(str_buf, 64, "|H%d%d|", rx, tx); + plot_real_init(&pce[tx][rx]); + plot_real_setTitle(&pce[tx][rx], str_buf); + plot_real_setLabels(&pce[tx][rx], (char*)"Index", (char*)"dB"); + plot_real_setYAxisScale(&pce[tx][rx], -40, 40); + + plot_real_addToWindowGrid(&pce[tx][rx], (char*)"srsue", tx, rx); + } + } + + plot_scatter_init(&pconst); + plot_scatter_setTitle(&pconst, (char*)"PDSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pconst, -4, 4); + plot_scatter_setYAxisScale(&pconst, -4, 4); + + plot_scatter_addToWindowGrid(&pconst, (char*)"srsue", 0, worker->get_rx_nof_antennas()); + +#if CFO_PLOT_LEN > 0 + plot_real_init(&pcfo); + plot_real_setTitle(&pcfo, (char*)"CFO (Hz)"); + plot_real_setLabels(&pcfo, (char*)"Time", (char*)"Hz"); + plot_real_setYAxisScale(&pcfo, -4000, 4000); + + plot_scatter_addToWindowGrid(&pcfo, (char*)"srsue", 1, worker->get_rx_nof_antennas()); +#endif /* CFO_PLOT_LEN > 0 */ + + int n; + int readed_pdsch_re = 0; + while (1) { + sem_wait(&plot_sem); + + if (readed_pdsch_re < SCATTER_PDSCH_PLOT_LEN) { + n = worker->read_pdsch_d(&tmp_plot2[readed_pdsch_re]); + readed_pdsch_re += n; + } else { + for (uint32_t tx = 0; tx < worker->get_cell_nof_ports(); tx++) { + for (uint32_t rx = 0; rx < worker->get_rx_nof_antennas(); rx++) { + n = worker->read_ce_abs(tmp_plot, tx, rx); + if (n > 0) { + plot_real_setNewData(&pce[tx][rx], tmp_plot, n); + } + } + } + if (readed_pdsch_re > 0) { + plot_scatter_setNewData(&pconst, tmp_plot2, readed_pdsch_re); + } + readed_pdsch_re = 0; + } + +#if CFO_PLOT_LEN > 0 + cfo_buffer[icfo] = worker->get_cfo() * 15000.0f; + icfo = (icfo + 1) % CFO_PLOT_LEN; + plot_real_setNewData(&pcfo, cfo_buffer, CFO_PLOT_LEN); +#endif /* CFO_PLOT_LEN > 0 */ + } + return NULL; +} + +void init_plots(srsue::sf_worker* worker) +{ + + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, &attr, plot_thread_run, worker)) { + perror("pthread_create"); + exit(-1); + } +} +#endif diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/sync.cc similarity index 73% rename from srsue/src/phy/phch_recv.cc rename to srsue/src/phy/sync.cc index e7bc1c7d6..a3654701a 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/sync.cc @@ -1,19 +1,14 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE +/* + * Copyright 2013-2019 Software Radio Systems Limited * - * This file is part of the srsUE library. + * This file is part of srsLTE. * - * srsUE is free software: you can redistribute it and/or modify + * 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. * - * srsUE is distributed in the hope that it will be useful, + * 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. @@ -24,12 +19,12 @@ * */ -#include -#include -#include "srslte/srslte.h" +#include "srsue/hdr/phy/sync.h" #include "srslte/common/log.h" -#include "srsue/hdr/phy/phch_worker.h" -#include "srsue/hdr/phy/phch_recv.h" +#include "srslte/srslte.h" +#include "srsue/hdr/phy/sf_worker.h" +#include +#include #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) @@ -39,52 +34,61 @@ namespace srsue { int radio_recv_callback(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { - return ((phch_recv*) obj)->radio_recv_fnc(data, nsamples, rx_time); + return ((sync*)obj)->radio_recv_fnc(data, nsamples, rx_time); } double callback_set_rx_gain(void *h, double gain) { - return ((phch_recv*) h)->set_rx_gain(gain); + return ((sync*)h)->set_rx_gain(gain); } - - -phch_recv::phch_recv() { - tti = 0; +sync::sync() +{ + cellsearch_earfcn_index = 0; + current_sflen = 0; + next_offset = 0; + current_earfcn = 0; + current_srate = 0; + next_time_adv_sec = 0; + time_adv_sec = 0; + tti = 0; dl_freq = -1; ul_freq = -1; bzero(&cell, sizeof(srslte_cell_t)); bzero(&metrics, sizeof(sync_metrics_t)); - cellsearch_earfcn_index = 0; running = false; worker_com = NULL; - current_sflen = 0; - next_offset = 0; - nof_rx_antennas = 1; - current_srate = 0.0f; - time_adv_sec = 0; - next_time_adv_sec = 0; } -void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc, - prach *_prach_buffer, srslte::thread_pool *_workers_pool, - phch_common *_worker_com, srslte::log *_log_h, srslte::log *_log_phy_lib_h, uint32_t nof_rx_antennas_, uint32_t prio, - int sync_cpu_affinity) +void sync::init(srslte::radio* _radio_handler, + mac_interface_phy* _mac, + rrc_interface_phy* _rrc, + prach* _prach_buffer, + srslte::thread_pool* _workers_pool, + phy_common* _worker_com, + srslte::log* _log_h, + srslte::log* _log_phy_lib_h, + async_scell_recv* scell_sync_, + uint32_t prio, + int sync_cpu_affinity) { radio_h = _radio_handler; log_h = _log_h; log_phy_lib_h = _log_phy_lib_h; mac = _mac; rrc = _rrc; + scell_sync = scell_sync_; workers_pool = _workers_pool; worker_com = _worker_com; prach_buffer = _prach_buffer; - nof_rx_antennas = nof_rx_antennas_; - for (uint32_t i = 0; i < nof_rx_antennas; i++) { - sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); + uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; + for (uint32_t r = 0; r < worker_com->args->nof_radios; r++) { + for (uint32_t p = 0; p < nof_rf_channels; p++) { + sf_buffer[r][p] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); + } } - if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rx_antennas, this)) { + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_callback, nof_rf_channels, this)) { Error("SYNC: Initiating ue_sync\n"); return; } @@ -93,10 +97,10 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma worker_com->set_nof_workers(nof_workers); // Initialize cell searcher - search_p.init(sf_buffer, log_h, nof_rx_antennas, this); + search_p.init(sf_buffer[0], log_h, nof_rf_channels, this); - // Initialize SFN synchronizer - sfn_p.init(&ue_sync, sf_buffer, log_h); + // Initialize SFN synchronizer, it uses only pcell buffer + sfn_p.init(&ue_sync, sf_buffer[0], log_h); // Start intra-frequency measurement intra_freq_meas.init(worker_com, rrc, log_h); @@ -113,24 +117,28 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma } } -phch_recv::~phch_recv() { - for (uint32_t i = 0; i < nof_rx_antennas; i++) { - if (sf_buffer[i]) { - free(sf_buffer[i]); +sync::~sync() +{ + uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; + for (uint32_t r = 0; r < worker_com->args->nof_radios; r++) { + for (uint32_t p = 0; p < nof_rf_channels; p++) { + if (sf_buffer[r][p]) { + free(sf_buffer[r][p]); + } } } pthread_mutex_destroy(&rrc_mutex); srslte_ue_sync_free(&ue_sync); } -void phch_recv::stop() +void sync::stop() { intra_freq_meas.stop(); running = false; wait_thread_finish(); } -void phch_recv::reset() +void sync::reset() { radio_is_overflow = false; radio_overflow_return = false; @@ -185,7 +193,7 @@ void phch_recv::reset() * If no cells are found in any frequency it returns 0. If error returns -1. */ -phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::phy_cell_t *found_cell) +phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_cell_t* found_cell) { phy_interface_rrc::cell_search_ret_t ret; @@ -259,7 +267,8 @@ phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::p /* Cell select synchronizes to a new cell (e.g. during HO or during cell reselection on IDLE) or * re-synchronizes with the current cell if cell argument is NULL */ -bool phch_recv::cell_select(phy_interface_rrc::phy_cell_t *new_cell) { +bool sync::cell_select(phy_interface_rrc::phy_cell_t* new_cell) +{ pthread_mutex_lock(&rrc_mutex); bool ret = false; @@ -277,7 +286,7 @@ bool phch_recv::cell_select(phy_interface_rrc::phy_cell_t *new_cell) { } // Wait for any pending PHICH - while(worker_com->is_any_pending_ack() && cnt < 10) { + while (worker_com->is_any_ul_pending_ack() && cnt < 10) { usleep(1000); cnt++; Info("Cell Select: waiting pending PHICH (cnt=%d)\n", cnt); @@ -286,11 +295,6 @@ bool phch_recv::cell_select(phy_interface_rrc::phy_cell_t *new_cell) { Info("Cell Select: Going to IDLE\n"); phy_state.go_idle(); - /* Reset everything */ - for(uint32_t i=0;iget_nof_workers();i++) { - ((phch_worker*) workers_pool->get_worker(i))->reset(); - } - worker_com->reset(); sfn_p.reset(); search_p.reset(); @@ -338,7 +342,8 @@ unlock: return ret; } -bool phch_recv::cell_is_camping() { +bool sync::cell_is_camping() +{ return phy_state.is_camping(); } @@ -361,18 +366,19 @@ bool phch_recv::cell_is_camping() { * */ -void phch_recv::run_thread() +void sync::run_thread() { - phch_worker *worker = NULL; - phch_worker *last_worker = NULL; - cf_t *buffer[SRSLTE_MAX_PORTS] = {NULL}; - uint32_t sf_idx = 0; + sf_worker* worker = NULL; + sf_worker* last_worker = NULL; + cf_t* buffer[SRSLTE_MAX_RADIOS][SRSLTE_MAX_PORTS] = {NULL}; bool is_end_of_burst = false; + bool force_camping_sfn_sync = false; cf_t *dummy_buffer[SRSLTE_MAX_PORTS]; - for (int i=0;iargs->nof_rf_channels * worker_com->args->nof_rx_ant; + for (uint32_t i = 0; i < nof_rf_channels; i++) { + dummy_buffer[i] = (cf_t*)malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); } uint32_t prach_nof_sf = 0; @@ -382,14 +388,17 @@ void phch_recv::run_thread() while (running) { - Debug("SYNC: state=%s\n", phy_state.to_string()); + Debug("SYNC: state=%s, tti=%d\n", phy_state.to_string(), tti); + + // If not camping, clear SFN sync + if (!phy_state.is_camping()) { + force_camping_sfn_sync = false; + } if (log_phy_lib_h) { log_phy_lib_h->step(tti); } - sf_idx = tti%10; - switch (phy_state.run_state()) { case sync_state::CELL_SEARCH: /* Search for a cell in the current frequency and go to IDLE. @@ -416,27 +425,63 @@ void phch_recv::run_thread() break; case sync_state::CAMPING: - worker = (phch_worker *) workers_pool->wait_worker(tti); + worker = (sf_worker*)workers_pool->wait_worker(tti); if (worker) { - for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) { - buffer[i] = worker->get_buffer(i); + // For each carrier... + for (uint32_t c = 0; c < worker_com->args->nof_carriers; c++) { + // get carrier mapping + carrier_map_t* m = &worker_com->args->carrier_map[c]; + for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) { + buffer[m->radio_idx][m->channel_idx + i] = worker->get_buffer(c, i); + } } - switch(srslte_ue_sync_zerocopy_multi(&ue_sync, buffer)) { + // Primary Cell (PCell) Synchronization + switch (srslte_ue_sync_zerocopy(&ue_sync, buffer[0])) { case 1: - if (last_worker) { - Debug("SF: cfo_tot=%7.1f Hz, ref=%f Hz, pss=%f Hz, snr_sf=%.2f dB, rsrp=%.2f dB, noise=%.2f dB\n", - srslte_ue_sync_get_cfo(&ue_sync), - 15000*last_worker->get_ref_cfo(), - 15000*ue_sync.strack.cfo_pss_mean, - last_worker->get_snr(), last_worker->get_rsrp(), last_worker->get_noise()); + // Check tti is synched with ue_sync + if (srslte_ue_sync_get_sfidx(&ue_sync) != tti % 10) { + uint32_t sfn = tti / 10; + tti = (sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync)) % 10240; + + // Force SFN decode, just in case it is in the wrong frame + force_camping_sfn_sync = true; } - last_worker = worker; + // Force decode MIB if required + if (force_camping_sfn_sync) { + uint32_t _tti = 0; + sync::sfn_sync::ret_code ret = sfn_p.decode_mib(&cell, &_tti, buffer[0]); + + if (ret == sfn_sync::SFN_FOUND) { + // Force tti + tti = _tti; + + // Disable + force_camping_sfn_sync = false; + } + } Debug("SYNC: Worker %d synchronized\n", worker->get_id()); + // Read Asynchronous SCell, for each asynch active object + for (uint32_t i = 0; i < worker_com->args->nof_radios - 1; i++) { + srslte_timestamp_t tx_time; + srslte_timestamp_init(&tx_time, 0, 0); + + // Request TTI aligment + if (scell_sync[i].tti_align(tti)) { + scell_sync[i].read_sf(buffer[i + 1], &tx_time); + srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3 - time_adv_sec); + } else { + // Failed, keep default Timestamp + // Error("SCell asynchronous failed to synchronise (%d)\n", i); + } + + worker->set_tx_time(i + 1, tx_time, next_offset); + } + metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); metrics.ta_us = time_adv_sec*1e6; @@ -448,7 +493,6 @@ void phch_recv::run_thread() if (!prach_ptr) { Error("Generating PRACH\n"); } - set_time_adv_sec(0.0f); } /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ @@ -456,15 +500,15 @@ void phch_recv::run_thread() srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); srslte_timestamp_copy(&tx_time, &rx_time); if (prach_ptr) { - srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3); + srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3); } else { - srslte_timestamp_add(&tx_time, 0, HARQ_DELAY_MS*1e-3 - time_adv_sec); + srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3 - time_adv_sec); } worker->set_prach(prach_ptr?&prach_ptr[prach_sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)]:NULL, prach_power); worker->set_cfo(get_tx_cfo()); worker->set_tti(tti, tx_worker_cnt); - worker->set_tx_time(tx_time, next_offset); + worker->set_tx_time(0, tx_time, next_offset); next_offset = 0; if (next_time_adv_sec != time_adv_sec) { time_adv_sec = next_time_adv_sec; @@ -488,17 +532,23 @@ void phch_recv::run_thread() // Save signal for Intra-frequency measurement if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) { - srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]); + srslte_pss_sic(&ue_sync.strack.pss, + &buffer[0][0][SRSLTE_SF_LEN_PRB(cell.nof_prb) / 2 - ue_sync.strack.fft_size]); } if (srslte_cell_isvalid(&cell)) { - intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + intra_freq_meas.write(tti, buffer[0][0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); } break; case 0: Warning("SYNC: Out-of-sync detected in PSS/SSS\n"); out_of_sync(); worker->release(); - worker_com->reset_ul(); + + // Force decoding MIB, for making sure that the TTI will be right + if (!force_camping_sfn_sync) { + force_camping_sfn_sync = true; + } + break; default: radio_error(); @@ -510,21 +560,26 @@ void phch_recv::run_thread() } break; case sync_state::IDLE: - if (radio_h->is_init()) { uint32_t nsamples = 1920; if (current_srate > 0) { nsamples = current_srate/1000; } Debug("Discarting %d samples\n", nsamples); - if (!radio_h->rx_now(dummy_buffer, nsamples, NULL)) { - printf("SYNC: Receiving from radio while in IDLE_RX\n"); + srslte_timestamp_t rx_time; + if (!radio_h->rx_now(dummy_buffer, nsamples, &rx_time)) { + log_h->console("SYNC: Receiving from radio while in IDLE_RX\n"); + } + // If radio is in locked state returns inmidiatetly. In that case, do a 1 ms sleep + if (rx_time.frac_secs == 0 && rx_time.full_secs == 0) { + usleep(1000); } if (is_end_of_burst) { radio_h->tx_end(); is_end_of_burst = true; } } else { + Debug("Sleeping\n"); usleep(1000); } break; @@ -565,11 +620,13 @@ void phch_recv::run_thread() // Increase TTI counter tti = (tti+1) % 10240; + + mac->run_tti(tti); } - for (int i=0;ierror("SYNC: Receiving from radio.\n"); // Need to find a method to effectively reset radio, reloading the driver does not work radio_h->reset(); } -void phch_recv::in_sync() { +void sync::in_sync() +{ in_sync_cnt++; // Send RRC in-sync signal after 100 ms consecutive subframes if (in_sync_cnt == NOF_IN_SYNC_SF) { @@ -611,8 +670,9 @@ void phch_recv::in_sync() { } } -// Out of sync called by worker or phch_recv every 1 or 5 ms -void phch_recv::out_of_sync() { +// Out of sync called by worker or sync every 1 or 5 ms +void sync::out_of_sync() +{ // Send RRC out-of-sync signal after 200 ms consecutive subframes Info("Out-of-sync %d/%d\n", out_of_sync_cnt, NOF_OUT_OF_SYNC_SF); out_of_sync_cnt++; @@ -624,11 +684,12 @@ void phch_recv::out_of_sync() { } } -void phch_recv::set_cfo(float cfo) { +void sync::set_cfo(float cfo) +{ srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); } -void phch_recv::set_agc_enable(bool enable) +void sync::set_agc_enable(bool enable) { do_agc = enable; if (do_agc) { @@ -641,22 +702,22 @@ void phch_recv::set_agc_enable(bool enable) radio_h->get_rx_gain()); search_p.set_agc_enable(true); } else { - fprintf(stderr, "Error setting AGC: PHY not initiatec\n"); + ERROR("Error setting AGC: PHY not initiatec\n"); } } else { - fprintf(stderr, "Error stopping AGC: not implemented\n"); + ERROR("Error stopping AGC: not implemented\n"); } } -void phch_recv::set_time_adv_sec(float time_adv_sec) +void sync::set_time_adv_sec(float time_adv_sec) { // If transmitting earlier, transmit less samples to align time advance. If transmit later just delay next TX - next_offset = floor((this->time_adv_sec-time_adv_sec)*srslte_sampling_freq_hz(cell.nof_prb)); + next_offset = (int)round((this->time_adv_sec - time_adv_sec) * srslte_sampling_freq_hz(cell.nof_prb)); this->next_time_adv_sec = time_adv_sec; Info("Applying time_adv_sec=%.1f us, next_offset=%d\n", time_adv_sec*1e6, next_offset); } -float phch_recv::get_tx_cfo() +float sync::get_tx_cfo() { float cfo = srslte_ue_sync_get_cfo(&ue_sync); @@ -675,7 +736,7 @@ float phch_recv::get_tx_cfo() return ret/15000; } -void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo) +void sync::set_ue_sync_opts(srslte_ue_sync_t* q, float cfo) { if (worker_com->args->cfo_integer_enabled) { srslte_ue_sync_set_cfo_i_enable(q, true); @@ -717,7 +778,8 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo) srslte_sync_set_sss_algorithm(&q->sfind, (sss_alg_t) sss_alg); } -bool phch_recv::set_cell() { +bool sync::set_cell() +{ if (!phy_state.is_idle()) { Warning("Can not change Cell while not in IDLE\n"); @@ -734,7 +796,7 @@ bool phch_recv::set_cell() { intra_freq_meas.set_primay_cell(current_earfcn, cell); for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) { - if (!((phch_worker *) workers_pool->get_worker(i))->set_cell(cell)) { + if (!((sf_worker*)workers_pool->get_worker(i))->set_cell(0, cell)) { Error("SYNC: Setting cell: initiating PHCH worker\n"); return false; } @@ -749,16 +811,18 @@ bool phch_recv::set_cell() { return true; } -void phch_recv::set_earfcn(std::vector earfcn) { +void sync::set_earfcn(std::vector earfcn) +{ this->earfcn = earfcn; } -void phch_recv::force_freq(float dl_freq, float ul_freq) { +void sync::force_freq(float dl_freq, float ul_freq) +{ this->dl_freq = dl_freq; this->ul_freq = ul_freq; } -bool phch_recv::set_frequency() +bool sync::set_frequency() { double set_dl_freq = 0; double set_ul_freq = 0; @@ -768,7 +832,11 @@ bool phch_recv::set_frequency() set_ul_freq = this->ul_freq; } else { set_dl_freq = 1e6*srslte_band_fd(current_earfcn); - set_ul_freq = 1e6*srslte_band_fu(srslte_band_ul_earfcn(current_earfcn)); + if (srslte_band_is_tdd(srslte_band_get_band(current_earfcn))) { + set_ul_freq = set_dl_freq; + } else { + set_ul_freq = 1e6 * srslte_band_fu(srslte_band_ul_earfcn(current_earfcn)); + } } if (set_dl_freq > 0 && set_ul_freq > 0) { log_h->info("SYNC: Set DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", @@ -777,9 +845,13 @@ bool phch_recv::set_frequency() log_h->console("Searching cell in DL EARFCN=%d, f_dl=%.1f MHz, f_ul=%.1f MHz\n", current_earfcn, set_dl_freq / 1e6, set_ul_freq / 1e6); - radio_h->set_rx_freq(set_dl_freq); - radio_h->set_tx_freq(set_ul_freq); - ul_dl_factor = radio_h->get_tx_freq()/radio_h->get_rx_freq(); + carrier_map_t* m = &worker_com->args->carrier_map[0]; + for (uint32_t i = 0; i < worker_com->args->nof_rx_ant; i++) { + radio_h->set_rx_freq(m->channel_idx + i, set_dl_freq); + radio_h->set_tx_freq(m->channel_idx + i, set_ul_freq); + } + + ul_dl_factor = (float)(radio_h->get_tx_freq() / radio_h->get_rx_freq()); srslte_ue_sync_reset(&ue_sync); @@ -790,11 +862,12 @@ bool phch_recv::set_frequency() } } -void phch_recv::set_sampling_rate() +void sync::set_sampling_rate() { - current_srate = (float) srslte_sampling_freq_hz(cell.nof_prb); + float new_srate = (float)srslte_sampling_freq_hz(cell.nof_prb); current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); - if (current_srate != -1) { + if (current_srate != new_srate || srate_mode != SRATE_CAMP) { + current_srate = new_srate; Info("SYNC: Setting sampling rate %.2f MHz\n", current_srate/1000000); #if 0 @@ -819,27 +892,29 @@ void phch_recv::set_sampling_rate() } } -uint32_t phch_recv::get_current_tti() { +uint32_t sync::get_current_tti() +{ return tti; } -void phch_recv::get_current_cell(srslte_cell_t *cell_, uint32_t *earfcn) { - if (cell_) { - memcpy(cell_, &cell, sizeof(srslte_cell_t)); +void sync::get_current_cell(srslte_cell_t* cell, uint32_t* earfcn) +{ + if (cell) { + *cell = this->cell; } if (earfcn) { *earfcn = current_earfcn; } } -int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) +int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time) { if (radio_h->rx_now(data, nsamples, rx_time)) { int offset = nsamples - current_sflen; if (abs(offset) < 10 && offset != 0) { - next_offset = offset; + next_offset += offset; } else if (nsamples < 10) { - next_offset = nsamples; + next_offset += nsamples; } log_h->debug("SYNC: received %d samples from radio\n", nsamples); @@ -850,7 +925,8 @@ int phch_recv::radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, s } } -double phch_recv::set_rx_gain(double gain) { +double sync::set_rx_gain(double gain) +{ return radio_h->set_rx_gain_th(gain); } @@ -863,13 +939,13 @@ double phch_recv::set_rx_gain(double gain) { /********* * Cell search class */ -phch_recv::search::~search() +sync::search::~search() { srslte_ue_mib_sync_free(&ue_mib_sync); srslte_ue_cellsearch_free(&cs); } -void phch_recv::search::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent) +void sync::search::init(cf_t* buffer[SRSLTE_MAX_PORTS], srslte::log* log_h, uint32_t nof_rx_antennas, sync* parent) { this->log_h = log_h; this->p = parent; @@ -878,33 +954,33 @@ void phch_recv::search::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, this->buffer[i] = buffer[i]; } - if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_callback, nof_rx_antennas, parent)) { + if (srslte_ue_cellsearch_init_multi(&cs, 8, radio_recv_callback, nof_rx_antennas, parent)) { Error("SYNC: Initiating UE cell search\n"); } + srslte_ue_cellsearch_set_nof_valid_frames(&cs, 4); if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_callback, nof_rx_antennas, parent)) { Error("SYNC: Initiating UE MIB synchronization\n"); } - srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); - // Set options defined in expert section p->set_ue_sync_opts(&cs.ue_sync, 0); force_N_id_2 = -1; } -void phch_recv::search::reset() +void sync::search::reset() { srslte_ue_sync_reset(&ue_mib_sync.ue_sync); } -float phch_recv::search::get_last_cfo() +float sync::search::get_last_cfo() { return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); } -void phch_recv::search::set_agc_enable(bool enable) { +void sync::search::set_agc_enable(bool enable) +{ if (enable) { srslte_rf_info_t *rf_info = p->radio_h->get_info(); srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, @@ -912,17 +988,12 @@ void phch_recv::search::set_agc_enable(bool enable) { rf_info->min_rx_gain, rf_info->max_rx_gain, p->radio_h->get_rx_gain()); - srslte_ue_sync_start_agc(&cs.ue_sync, - callback_set_rx_gain, - rf_info->min_rx_gain, - rf_info->max_rx_gain, - p->radio_h->get_rx_gain()); } else { - fprintf(stderr, "Error stop AGC not implemented\n"); + ERROR("Error stop AGC not implemented\n"); } } -phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) +sync::search::ret_code sync::search::run(srslte_cell_t* cell) { if (!cell) { @@ -948,7 +1019,7 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) int ret = SRSLTE_ERROR; Info("SYNC: Searching for cell...\n"); - printf("."); fflush(stdout); + log_h->console("."); 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]); @@ -965,15 +1036,19 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) return CELL_NOT_FOUND; } // Save result - cell->id = found_cells[max_peak_cell].cell_id; - cell->cp = found_cells[max_peak_cell].cp; + cell->id = found_cells[max_peak_cell].cell_id; + cell->cp = found_cells[max_peak_cell].cp; + cell->frame_type = found_cells[max_peak_cell].frame_type; float cfo = found_cells[max_peak_cell].cfo; - printf("\n"); - Info("SYNC: PSS/SSS detected: PCI=%d, CFO=%.1f KHz, CP=%s\n", - cell->id, cfo/1000, srslte_cp_string(cell->cp)); + log_h->console("\n"); + Info("SYNC: PSS/SSS detected: Mode=%s, PCI=%d, CFO=%.1f KHz, CP=%s\n", + cell->frame_type ? "TDD" : "FDD", + cell->id, + cfo / 1000, + srslte_cp_string(cell->cp)); - if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, cell->id, cell->cp)) { + if (srslte_ue_mib_sync_set_cell(&ue_mib_sync, *cell)) { Error("SYNC: Setting UE MIB cell\n"); return ERROR; } @@ -991,11 +1066,20 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) if (ret == 1) { srslte_pbch_mib_unpack(bch_payload, cell, NULL); - fprintf(stdout, "Found Cell: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); - - Info("SYNC: MIB Decoded: PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", - cell->id, cell->nof_prb, cell->nof_ports, cfo/1000); + fprintf(stdout, + "Found Cell: Mode=%s, PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->frame_type ? "TDD" : "FDD", + cell->id, + cell->nof_prb, + cell->nof_ports, + cfo / 1000); + + Info("SYNC: MIB Decoded: Mode=%s, PCI=%d, PRB=%d, Ports=%d, CFO=%.1f KHz\n", + cell->frame_type ? "TDD" : "FDD", + cell->id, + cell->nof_prb, + cell->nof_ports, + cfo / 1000); if (!srslte_cell_isvalid(cell)) { Error("SYNC: Detected invalid cell.\n"); @@ -1022,19 +1106,22 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell) * SFN synchronizer class */ -phch_recv::sfn_sync::~sfn_sync() +sync::sfn_sync::~sfn_sync() { srslte_ue_mib_free(&ue_mib); } -void phch_recv::sfn_sync::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_subframes) +void sync::sfn_sync::init(srslte_ue_sync_t* ue_sync, + cf_t* buffer[SRSLTE_MAX_PORTS], + srslte::log* log_h, + uint32_t nof_subframes) { this->log_h = log_h; this->ue_sync = ue_sync; this->timeout = nof_subframes; - for (int i=0;ibuffer[i] = buffer[i]; + for (int p = 0; p < SRSLTE_MAX_PORTS; p++) { + this->buffer[p] = buffer[p]; } if (srslte_ue_mib_init(&ue_mib, this->buffer, SRSLTE_MAX_PRB)) { @@ -1042,7 +1129,7 @@ void phch_recv::sfn_sync::init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MA } } -bool phch_recv::sfn_sync::set_cell(srslte_cell_t cell) +bool sync::sfn_sync::set_cell(srslte_cell_t cell) { if (srslte_ue_mib_set_cell(&ue_mib, cell)) { Error("SYNC: Setting cell: initiating ue_mib\n"); @@ -1052,60 +1139,25 @@ bool phch_recv::sfn_sync::set_cell(srslte_cell_t cell) return true; } -void phch_recv::sfn_sync::reset() +void sync::sfn_sync::reset() { cnt = 0; srslte_ue_mib_reset(&ue_mib); } -phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only) +sync::sfn_sync::ret_code sync::sfn_sync::run_subframe(srslte_cell_t* cell, uint32_t* tti_cnt, bool sfidx_only) { - uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; - - srslte_ue_sync_decode_sss_on_track(ue_sync, true); - int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); + int ret = srslte_ue_sync_zerocopy(ue_sync, buffer); if (ret < 0) { Error("SYNC: Error calling ue_sync_get_buffer.\n"); return ERROR; } if (ret == 1) { - if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { - - // Skip MIB decoding if we are only interested in subframe 0 - if (sfidx_only) { - if (tti_cnt) { - *tti_cnt = 0; - } - return SFX0_FOUND; - } - - int sfn_offset = 0; - int n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); - switch(n) { - default: - Error("SYNC: Error decoding MIB while synchronising SFN"); - return ERROR; - case SRSLTE_UE_MIB_FOUND: - uint32_t sfn; - srslte_pbch_mib_unpack(bch_payload, cell, &sfn); - - sfn = (sfn+sfn_offset)%1024; - if (tti_cnt) { - *tti_cnt = 10*sfn; - Info("SYNC: DONE, SNR=%.1f dB, TTI=%d, sfn_offset=%d\n", - 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest)), *tti_cnt, sfn_offset); - } - - srslte_ue_sync_decode_sss_on_track(ue_sync, true); - reset(); - return SFN_FOUND; - case SRSLTE_UE_MIB_NOTFOUND: - Info("SYNC: Found PSS but could not decode MIB. SNR=%.1f dB (%d/%d)\n", - 10*log10(srslte_chest_dl_get_snr(&ue_mib.chest)), cnt, timeout); - break; - } + sync::sfn_sync::ret_code ret2 = decode_mib(cell, tti_cnt, NULL, sfidx_only); + if (ret2 != SFN_NOFOUND) { + return ret2; } } else { Info("SYNC: Waiting for PSS while trying to decode MIB (%d/%d)\n", cnt, timeout); @@ -1120,15 +1172,62 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c return IDLE; } +sync::sfn_sync::ret_code +sync::sfn_sync::decode_mib(srslte_cell_t* cell, uint32_t* tti_cnt, cf_t* ext_buffer[SRSLTE_MAX_PORTS], bool sfidx_only) +{ + + uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; + + // If external buffer provided not equal to internal buffer, copy data + if ((ext_buffer != NULL) && (ext_buffer != buffer)) { + memcpy(buffer[0], ext_buffer[0], sizeof(cf_t) * ue_sync->sf_len); + } + + if (srslte_ue_sync_get_sfidx(ue_sync) == 0) { + + // Skip MIB decoding if we are only interested in subframe 0 + if (sfidx_only) { + if (tti_cnt) { + *tti_cnt = 0; + } + return SFX0_FOUND; + } + int sfn_offset = 0; + int n = srslte_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); + switch (n) { + default: + Error("SYNC: Error decoding MIB while synchronising SFN"); + return ERROR; + case SRSLTE_UE_MIB_FOUND: + uint32_t sfn; + srslte_pbch_mib_unpack(bch_payload, cell, &sfn); + sfn = (sfn + sfn_offset) % 1024; + if (tti_cnt) { + *tti_cnt = 10 * sfn; + Info("SYNC: DONE, SNR=%.1f dB, TTI=%d, sfn_offset=%d\n", ue_mib.chest_res.snr_db, *tti_cnt, sfn_offset); + } + reset(); + return SFN_FOUND; + case SRSLTE_UE_MIB_NOTFOUND: + Info("SYNC: Found PSS but could not decode MIB. SNR=%.1f dB (%d/%d)\n", ue_mib.chest_res.snr_db, cnt, timeout); + return SFN_NOFOUND; + } + } + return IDLE; +} /********* * Measurement class */ -void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes) +void sync::measure::init(cf_t* buffer[SRSLTE_MAX_PORTS], + srslte::log* log_h, + uint32_t nof_rx_antennas, + phy_common* worker_com, + uint32_t nof_subframes) { this->log_h = log_h; @@ -1141,15 +1240,17 @@ void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h Error("SYNC: Initiating ue_dl_measure\n"); return; } - srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true); + worker_com->set_ue_dl_cfg(&ue_dl_cfg); reset(); } -phch_recv::measure::~measure() { +sync::measure::~measure() +{ srslte_ue_dl_free(&ue_dl); } - -void phch_recv::measure::reset() { + +void sync::measure::reset() +{ cnt = 0; mean_rsrp = 0; mean_rsrq = 0; @@ -1157,7 +1258,7 @@ void phch_recv::measure::reset() { mean_rssi = 0; } -void phch_recv::measure::set_cell(srslte_cell_t cell) +void sync::measure::set_cell(srslte_cell_t cell) { current_prb = cell.nof_prb; if (srslte_ue_dl_set_cell(&ue_dl, cell)) { @@ -1166,48 +1267,38 @@ void phch_recv::measure::set_cell(srslte_cell_t cell) reset(); } -float phch_recv::measure::rssi() { +float sync::measure::rssi() +{ return 10*log10(mean_rssi); } -float phch_recv::measure::rsrp() { +float sync::measure::rsrp() +{ return 10*log10(mean_rsrp) + 30 - rx_gain_offset; } -float phch_recv::measure::rsrq() { +float sync::measure::rsrq() +{ return 10*log10(mean_rsrq); } -float phch_recv::measure::snr() { - return 10*log10(mean_snr); +float sync::measure::snr() +{ + return mean_snr; } -uint32_t phch_recv::measure::frame_st_idx() { +uint32_t sync::measure::frame_st_idx() +{ return final_offset; } -void phch_recv::measure::set_rx_gain_offset(float rx_gain_offset) { - this->rx_gain_offset = rx_gain_offset; -} - -phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx) +void sync::measure::set_rx_gain_offset(float rx_gain_offset) { - int sync_res = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); - if (sync_res == 1) { - log_h->info("SYNC: CFO=%.1f KHz\n", srslte_ue_sync_get_cfo(ue_sync)/1000); - return run_subframe(sf_idx); - } else { - log_h->error("SYNC: Measuring RSRP: Sync error\n"); - return ERROR; - } - - return IDLE; + this->rx_gain_offset = rx_gain_offset; } -phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer, - uint32_t offset, - uint32_t sf_idx, - uint32_t max_sf) +sync::measure::ret_code +sync::measure::run_multiple_subframes(cf_t* input_buffer, uint32_t offset, uint32_t sf_idx, uint32_t max_sf) { uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb); @@ -1278,17 +1369,20 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in return ret; } -phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) +sync::measure::ret_code sync::measure::run_subframe(uint32_t sf_idx) { - uint32_t cfi = 0; - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, sf_idx, &cfi)) { + srslte_dl_sf_cfg_t sf_cfg; + ZERO_OBJECT(sf_cfg); + sf_cfg.tti = sf_idx; + + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg, &ue_dl_cfg)) { log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); return ERROR; } - float rsrp = srslte_chest_dl_get_rsrp_neighbour(&ue_dl.chest); - float rsrq = srslte_chest_dl_get_rsrq(&ue_dl.chest); - float snr = srslte_chest_dl_get_snr(&ue_dl.chest); + float rsrp = ue_dl.chest_res.rsrp; + float rsrq = ue_dl.chest_res.rsrq; + float snr = ue_dl.chest_res.snr_db; float rssi = srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb)); if (cnt == 0) { @@ -1323,7 +1417,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx) * Secondary cell receiver */ -void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window) +void sync::scell_recv::init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com) { this->log_h = log_h; this->sic_pss_enabled = sic_pss_enabled; @@ -1335,14 +1429,14 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint3 sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size); if (!sf_buffer[0]) { - fprintf(stderr, "Error allocating %d samples for scell\n", max_sf_size); + ERROR("Error allocating %d samples for scell\n", max_sf_size); return; } - measure_p.init(sf_buffer, log_h, 1, max_sf_window); + measure_p.init(sf_buffer, log_h, 1, worker_com, max_sf_window); //do this different we don't need all this search window. if(srslte_sync_init(&sync_find, max_sf_window*max_sf_size, 5*max_sf_size, max_fft_sz)) { - fprintf(stderr, "Error initiating sync_find\n"); + ERROR("Error initiating sync_find\n"); return; } srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL); @@ -1364,25 +1458,27 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint3 reset(); } -void phch_recv::scell_recv::deinit() { +void sync::scell_recv::deinit() +{ srslte_sync_free(&sync_find); free(sf_buffer[0]); } -void phch_recv::scell_recv::reset() +void sync::scell_recv::reset() { current_fft_sz = 0; measure_p.reset(); } -int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) +int sync::scell_recv::find_cells( + cf_t* input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) { uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb); uint32_t sf_len = SRSLTE_SF_LEN(fft_sz); if (fft_sz != current_fft_sz) { if (srslte_sync_resize(&sync_find, nof_sf*sf_len, 5*sf_len, fft_sz)) { - fprintf(stderr, "Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); + ERROR("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); return SRSLTE_ERROR; } current_fft_sz = fft_sz; @@ -1394,7 +1490,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, int cell_id = 0; srslte_cell_t found_cell; - memcpy(&found_cell, &cell, sizeof(srslte_cell_t)); + found_cell = cell; measure_p.set_rx_gain_offset(rx_gain_offset); @@ -1432,7 +1528,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, switch(sync_res) { case SRSLTE_SYNC_ERROR: return SRSLTE_ERROR; - fprintf(stderr, "Error finding correlation peak\n"); + ERROR("Error finding correlation peak\n"); return SRSLTE_ERROR; case SRSLTE_SYNC_FOUND: @@ -1511,12 +1607,14 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, * */ -void phch_recv::meas_reset() { +void sync::meas_reset() +{ // Stop all measurements intra_freq_meas.clear_cells(); } -int phch_recv::meas_start(uint32_t earfcn, int pci) { +int sync::meas_start(uint32_t earfcn, int pci) +{ if ((int) earfcn == current_earfcn) { if (pci != (int) cell.id) { intra_freq_meas.add_cell(pci); @@ -1529,7 +1627,8 @@ int phch_recv::meas_start(uint32_t earfcn, int pci) { } } -int phch_recv::meas_stop(uint32_t earfcn, int pci) { +int sync::meas_stop(uint32_t earfcn, int pci) +{ if ((int) earfcn == current_earfcn) { intra_freq_meas.rem_cell(pci); return 0; @@ -1540,8 +1639,8 @@ int phch_recv::meas_stop(uint32_t earfcn, int pci) { return -1; } -phch_recv::intra_measure::intra_measure() - : scell() { +sync::intra_measure::intra_measure() : scell() +{ rrc = NULL; common = NULL; @@ -1562,20 +1661,22 @@ phch_recv::intra_measure::intra_measure() ZERO_OBJECT(primary_cell); } -phch_recv::intra_measure::~intra_measure() { +sync::intra_measure::~intra_measure() +{ srslte_ringbuffer_free(&ring_buffer); scell.deinit(); free(search_buffer); } -void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h) { +void sync::intra_measure::init(phy_common* common, rrc_interface_phy* rrc, srslte::log* log_h) +{ this->rrc = rrc; this->log_h = log_h; this->common = common; receive_enabled = false; // Start scell - scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms); + scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common); search_buffer = (cf_t*) srslte_vec_malloc(common->args->intra_freq_meas_len_ms*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); @@ -1587,20 +1688,23 @@ void phch_recv::intra_measure::init(phch_common *common, rrc_interface_phy *rrc, start(INTRA_FREQ_MEAS_PRIO); } -void phch_recv::intra_measure::stop() { +void sync::intra_measure::stop() +{ running = false; srslte_ringbuffer_stop(&ring_buffer); tti_sync.increase(); wait_thread_finish(); } -void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) { +void sync::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) +{ this->current_earfcn = earfcn; current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); - memcpy(&this->primary_cell, &cell, sizeof(srslte_cell_t)); + this->primary_cell = cell; } -void phch_recv::intra_measure::clear_cells() { +void sync::intra_measure::clear_cells() +{ active_pci.clear(); receive_enabled = false; receiving = false; @@ -1608,7 +1712,8 @@ void phch_recv::intra_measure::clear_cells() { srslte_ringbuffer_reset(&ring_buffer); } -void phch_recv::intra_measure::add_cell(int pci) { +void sync::intra_measure::add_cell(int pci) +{ if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { active_pci.push_back(pci); receive_enabled = true; @@ -1618,7 +1723,8 @@ void phch_recv::intra_measure::add_cell(int pci) { } } -int phch_recv::intra_measure::get_offset(uint32_t pci) { +int sync::intra_measure::get_offset(uint32_t pci) +{ for (int i=0;i::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); if (newEnd != active_pci.end()) { @@ -1641,7 +1748,8 @@ void phch_recv::intra_measure::rem_cell(int pci) { } } -void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples) { +void sync::intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples) +{ if (receive_enabled) { if ((tti%common->args->intra_freq_meas_period_ms) == 0) { receiving = true; @@ -1651,7 +1759,7 @@ void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples } if (receiving == true) { if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { - Warning("Error writing to ringbuffer\n"); + Warning("Error writting to ringbuffer\n"); receiving = false; } else { receive_cnt++; @@ -1664,7 +1772,7 @@ void phch_recv::intra_measure::write(uint32_t tti, cf_t *data, uint32_t nsamples } } -void phch_recv::intra_measure::run_thread() +void sync::intra_measure::run_thread() { while(running) { if (running) { diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 5858a2ffe..f1bffd5f0 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -62,8 +62,8 @@ bool ue::init(all_args_t *args_) { args = args_; int nof_phy_threads = args->expert.phy.nof_phy_threads; - if (nof_phy_threads > 3) { - nof_phy_threads = 3; + if (nof_phy_threads > srsue::phy::MAX_WORKERS) { + nof_phy_threads = srsue::phy::MAX_WORKERS; } if (!args->log.filename.compare("stdout")) { @@ -146,10 +146,6 @@ bool ue::init(all_args_t *args_) { nas_pcap.open(args->pcap.nas_filename.c_str()); nas.start_pcap(&nas_pcap); } - if(args->trace.enable) { - phy.start_trace(); - radio.start_trace(); - } // populate EARFCN list std::vector earfcn_list; @@ -165,10 +161,14 @@ bool ue::init(all_args_t *args_) { earfcn_list.push_back(earfcn); } } else { - printf("Error: dl_earfcn list is empty\n"); + rrc_log.error("Error: dl_earfcn list is empty\n"); + rrc_log.console("Error: dl_earfcn list is empty\n"); return false; } + // Consider Carrier Aggregation support if more than one + args->rrc.support_ca = (args->rf.nof_rf_channels * args->rf.nof_radios) > 1; + // Init layers // Init USIM first to allow early exit in case reader couldn't be found @@ -180,65 +180,84 @@ bool ue::init(all_args_t *args_) { // PHY inits in background, start before radio args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; - phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); + args->expert.phy.ue_category = args->rrc.ue_category; + phy.init(radios, &mac, &rrc, phy_log, &args->expert.phy); + + // Calculate number of carriers available in all radios + args->expert.phy.nof_radios = args->rf.nof_radios; + args->expert.phy.nof_rf_channels = args->rf.nof_rf_channels; + args->expert.phy.nof_carriers = args->rf.nof_radios * args->rf.nof_rf_channels; + + // Generate RF-Channel to Carrier map + for (uint32_t i = 0; i < args->expert.phy.nof_carriers; i++) { + carrier_map_t* m = &args->expert.phy.carrier_map[i]; + m->radio_idx = i / args->rf.nof_rf_channels; + m->channel_idx = (i % args->rf.nof_rf_channels) * args->rf.nof_rx_ant; + phy_log[0]->debug("Mapping carrier %d to channel %d in radio %d\n", i, m->channel_idx, m->radio_idx); + } /* Start Radio */ char *dev_name = NULL; if (args->rf.device_name.compare("auto")) { dev_name = (char*) args->rf.device_name.c_str(); } - - char *dev_args = NULL; - if (args->rf.device_args.compare("auto")) { - dev_args = (char*) args->rf.device_args.c_str(); - } - - printf("Opening RF device with %d RX antennas...\n", args->rf.nof_rx_ant); - if(!radio.init_multi(args->rf.nof_rx_ant, dev_args, dev_name)) { - printf("Failed to find device %s with args %s\n", - args->rf.device_name.c_str(), args->rf.device_args.c_str()); - return false; - } - - // Set RF options - if (args->rf.time_adv_nsamples.compare("auto")) { - int t = atoi(args->rf.time_adv_nsamples.c_str()); - radio.set_tx_adv(abs(t)); - radio.set_tx_adv_neg(t<0); - } - if (args->rf.burst_preamble.compare("auto")) { - radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str())); - } - if (args->rf.continuous_tx.compare("auto")) { - printf("set continuous %s\n", args->rf.continuous_tx.c_str()); - radio.set_continuous_tx(args->rf.continuous_tx.compare("yes")?false:true); - } - // Set PHY options - if (args->rf.tx_gain > 0) { - args->expert.phy.ul_pwr_ctrl_en = false; - } else { - args->expert.phy.ul_pwr_ctrl_en = true; + char* dev_args[SRSLTE_MAX_RADIOS] = {NULL}; + for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) { + if (args->rf.device_args[0].compare("auto")) { + dev_args[i] = (char*)args->rf.device_args[i].c_str(); + } } - if (args->rf.rx_gain < 0) { - radio.start_agc(false); - } else { - radio.set_rx_gain(args->rf.rx_gain); + phy_log[0]->console("Opening %d RF devices with %d RF channels...\n", + args->rf.nof_radios, + args->rf.nof_rf_channels * args->rf.nof_rx_ant); + for (uint32_t r = 0; r < args->rf.nof_radios; r++) { + if (!radios[r].init(phy_log[0], dev_args[r], dev_name, args->rf.nof_rf_channels * args->rf.nof_rx_ant)) { + phy_log[0]->console( + "Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args[0].c_str()); + return false; + } + + // Set RF options + if (args->rf.time_adv_nsamples.compare("auto")) { + int t = atoi(args->rf.time_adv_nsamples.c_str()); + radios[r].set_tx_adv(abs(t)); + radios[r].set_tx_adv_neg(t < 0); + } + if (args->rf.burst_preamble.compare("auto")) { + radios[r].set_burst_preamble(atof(args->rf.burst_preamble.c_str())); + } + if (args->rf.continuous_tx.compare("auto")) { + phy_log[0]->console("set continuous %s\n", args->rf.continuous_tx.c_str()); + radios[r].set_continuous_tx(args->rf.continuous_tx.compare("yes") ? false : true); + } + + // Set PHY options + + if (args->rf.rx_gain < 0) { + radios[r].start_agc(false); + } else { + radios[r].set_rx_gain(args->rf.rx_gain); + } + if (args->rf.tx_gain > 0) { + radios[r].set_tx_gain(args->rf.tx_gain); + } else { + radios[r].set_tx_gain(args->rf.rx_gain); + phy_log[0]->console("\nWarning: TX gain was not set. Using open-loop power control (not working properly)\n\n"); + } + + radios[r].register_error_handler(rf_msg); + radios[r].set_freq_offset(args->rf.freq_offset); } + if (args->rf.tx_gain > 0) { - radio.set_tx_gain(args->rf.tx_gain); + args->expert.phy.ul_pwr_ctrl_en = false; } else { - radio.set_tx_gain(args->rf.rx_gain); - std::cout << std::endl << - "Warning: TX gain was not set. " << - "Using open-loop power control (not working properly)" << std::endl << std::endl; + args->expert.phy.ul_pwr_ctrl_en = true; } - radio.register_error_handler(rf_msg); - radio.set_freq_offset(args->rf.freq_offset); - - mac.init(&phy, &rlc, &rrc, &mac_log); + mac.init(&phy, &rlc, &rrc, &mac_log, args->expert.phy.nof_carriers); rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); nas.init(usim, &rrc, &gw, &nas_log, args->nas); @@ -246,11 +265,8 @@ bool ue::init(all_args_t *args_) { gw.set_netmask(args->expert.ip_netmask); gw.set_tundevname(args->expert.ip_devname); - args->rrc.ue_category = atoi(args->ue_category_str.c_str()); - // set args and initialize RRC - rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log); - rrc.set_args(args->rrc); + rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log, &args->rrc); phy.set_earfcn(earfcn_list); @@ -258,7 +274,7 @@ bool ue::init(all_args_t *args_) { phy.force_freq(args->rf.dl_freq, args->rf.ul_freq); } - printf("Waiting PHY to initialize...\n"); + phy_log[0]->console("Waiting PHY to initialize...\n"); phy.wait_initialize(); // Enable AGC once PHY is initialized @@ -266,7 +282,7 @@ bool ue::init(all_args_t *args_) { phy.set_agc_enable(true); } - printf("...\n"); + phy_log[0]->console("...\n"); started = true; return true; @@ -296,8 +312,10 @@ void ue::stop() // PHY must be stopped before radio otherwise it will lock on rf_recv() mac.stop(); phy.stop(); - radio.stop(); - + for (uint32_t r = 0; r < args->rf.nof_radios; r++) { + radios[r].stop(); + } + usleep(1e5); if(args->pcap.enable) { mac_pcap.close(); @@ -305,10 +323,6 @@ void ue::stop() if(args->pcap.nas_enable) { nas_pcap.close(); } - if(args->trace.enable) { - phy.write_trace(args->trace.phy_filename); - radio.write_trace(args->trace.radio_filename); - } started = false; } } @@ -318,6 +332,9 @@ bool ue::switch_on() { } bool ue::switch_off() { + // stop UL data + gw.stop(); + // generate detach request nas.detach_request(); diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index 55e21f021..f1e4a5edf 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -37,7 +37,7 @@ using namespace srslte; -namespace srsue{ +namespace srsue { static ue_base* instance = NULL; pthread_mutex_t ue_instance_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 10c1563d6..1b68bafc4 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -35,6 +35,12 @@ #include #include +#include "srslte/asn1/liblte_mme.h" +#include "srslte/asn1/rrc_asn1.h" +#include "srslte/common/bcd_helpers.h" +#include "srslte/common/security.h" +#include "srsue/hdr/upper/nas.h" + using namespace srslte; using namespace asn1::rrc; diff --git a/srsue/src/upper/pcsc_usim.cc b/srsue/src/upper/pcsc_usim.cc index 736fec085..e9258872a 100644 --- a/srsue/src/upper/pcsc_usim.cc +++ b/srsue/src/upper/pcsc_usim.cc @@ -26,8 +26,9 @@ #include -#include + #include "srslte/common/bcd_helpers.h" +#include "srsue/hdr/upper/pcsc_usim.h" #include "string.h" #define CHECK_SIM_PIN 1 @@ -127,7 +128,7 @@ std::string pcsc_usim::get_imei_str() bool pcsc_usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return false; } @@ -147,7 +148,7 @@ bool pcsc_usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) bool pcsc_usim::get_imei_vec(uint8_t* imei_, uint32_t n) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return false; } @@ -168,7 +169,7 @@ bool pcsc_usim::get_imei_vec(uint8_t* imei_, uint32_t n) bool pcsc_usim::get_home_plmn_id(plmn_id_s* home_plmn_id) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return false; } @@ -208,7 +209,7 @@ auth_result_t pcsc_usim::generate_authentication_response(uint8_t *rand, { auth_result_t ret = AUTH_FAILED; if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return ret; } @@ -267,7 +268,7 @@ void pcsc_usim::generate_nas_keys(uint8_t *k_asme, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return; } @@ -293,7 +294,7 @@ void pcsc_usim::generate_as_keys(uint8_t *k_asme, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return; } @@ -332,7 +333,7 @@ void pcsc_usim::generate_as_keys_ho(uint32_t pci, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return; } diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 2bf578d88..0479df8a8 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -34,8 +34,11 @@ #include #include #include +#include #include +bool simulate_rlf = false; + using namespace srslte; using namespace asn1::rrc; @@ -63,6 +66,11 @@ rrc::rrc() : running = false; go_idle = false; go_rlf = false; + + ZERO_OBJECT(current_mac_cfg); + ZERO_OBJECT(previous_mac_cfg); + ZERO_OBJECT(current_phy_cfg); + ZERO_OBJECT(previous_phy_cfg); } rrc::~rrc() @@ -88,7 +96,7 @@ void rrc::srslte_rrc_log(const char* str) if (rrc_log) { rrc_log->warning("[ASN]: %s\n", str); } else { - printf("[ASN]: %s\n", str); + rrc_log->console("[ASN]: %s\n", str); } } @@ -107,9 +115,16 @@ void rrc::log_rrc_message(const std::string source, const direction_t dir, const } } -void rrc::init(phy_interface_rrc* phy_, mac_interface_rrc* mac_, rlc_interface_rrc* rlc_, pdcp_interface_rrc* pdcp_, - nas_interface_rrc* nas_, usim_interface_rrc* usim_, gw_interface_rrc* gw_, - mac_interface_timers* mac_timers_, srslte::log* rrc_log_) +void rrc::init(phy_interface_rrc* phy_, + mac_interface_rrc* mac_, + rlc_interface_rrc* rlc_, + pdcp_interface_rrc* pdcp_, + nas_interface_rrc* nas_, + usim_interface_rrc* usim_, + gw_interface_rrc* gw_, + mac_interface_timers* mac_timers_, + srslte::log* rrc_log_, + rrc_args_t* args_) { pool = byte_buffer_pool::get_instance(); phy = phy_; @@ -123,17 +138,22 @@ void rrc::init(phy_interface_rrc* phy_, mac_interface_rrc* mac_, rlc_interface_r // Use MAC timers mac_timers = mac_timers_; - state = RRC_STATE_IDLE; + state = RRC_STATE_IDLE; plmn_is_selected = false; security_is_activated = false; pthread_mutex_init(&mutex, NULL); - args.ue_category = SRSLTE_UE_CATEGORY; - args.supported_bands[0] = 7; - args.nof_supported_bands = 1; - args.feature_group = 0xe6041000; + if (args_) { + args = *args_; + } else { + args.ue_category_str = SRSLTE_UE_CATEGORY_DEFAULT; + args.ue_category = strtol(SRSLTE_UE_CATEGORY_DEFAULT, NULL, 10); + args.supported_bands[0] = SRSLTE_RELEASE_DEFAULT; + args.nof_supported_bands = 1; + args.feature_group = 0xe6041000; + } t300 = mac_timers->timer_get_unique_id(); t301 = mac_timers->timer_get_unique_id(); @@ -214,18 +234,23 @@ void rrc::run_thread() { } } - /* * * RRC State Machine * */ -void rrc::run_tti(uint32_t tti) { +void rrc::run_tti(uint32_t tti) +{ if (!initiated) { return; } + if (simulate_rlf) { + radio_link_failure(); + simulate_rlf = false; + } + /* We can not block in this thread because it is called from * the MAC TTI timer and needs to return immediatly to perform other * tasks. Therefore in this function we use trylock() instead of lock() and @@ -494,7 +519,7 @@ bool rrc::connection_request(asn1::rrc::establishment_cause_e cause, srslte::byt } if (!ret) { - rrc_log->warning("Could not estblish connection. Deallocating dedicatedInfoNAS PDU\n"); + rrc_log->warning("Could not establish connection. Deallocating dedicatedInfoNAS PDU\n"); pool->deallocate(this->dedicated_info_nas); this->dedicated_info_nas = NULL; } @@ -534,10 +559,10 @@ bool rrc::configure_serving_cell() { rrc_log->info("Cell has SIB%d\n", required_sibs[i]+1); switch(required_sibs[i]) { case 1: - apply_sib2_configs(serving_cell->sib2ptr()); + handle_sib2(); break; case 12: - apply_sib13_configs(serving_cell->sib13ptr()); + handle_sib13(); break; } } @@ -957,14 +982,15 @@ void rrc::set_serving_cell(uint32_t cell_idx) { rrc_log->error("Setting serving cell. Index %d is empty\n", cell_idx); return; } - neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[cell_idx]), neighbour_cells.end()); + neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[cell_idx]), + neighbour_cells.end()); // Move serving cell to neighbours list if (serving_cell->is_valid()) { // Make sure it does not exist already int serving_idx = find_neighbour_cell(serving_cell->get_earfcn(), serving_cell->get_pci()); if (serving_idx >= 0 && (uint32_t) serving_idx < neighbour_cells.size()) { - printf("Error serving cell is already in the neighbour list. Removing it\n"); + rrc_log->error("Error serving cell is already in the neighbour list. Removing it\n"); neighbour_cells.erase(std::remove(neighbour_cells.begin(), neighbour_cells.end(), neighbour_cells[serving_idx]), neighbour_cells.end()); } // If not in the list, add it to the list of neighbours (sorted inside the function) @@ -1200,10 +1226,9 @@ void rrc::radio_link_failure() { /* Reception of PUCCH/SRS release procedure (Section 5.3.13) */ void rrc::release_pucch_srs() { // Apply default configuration for PUCCH (CQI and SR) and SRS (release) - set_phy_default_pucch_srs(); - - // Configure RX signals without pregeneration because default option is release - phy->configure_ul_params(true); + if (initiated) { + set_phy_default_pucch_srs(); + } } void rrc::ra_problem() { @@ -1536,7 +1561,13 @@ bool rrc::ho_prepare() phy->reset(); mac->set_ho_rnti(mob_ctrl_info->new_ue_id.to_number(), mob_ctrl_info->target_pci); - apply_rr_config_common_dl(&mob_ctrl_info->rr_cfg_common); + + // Apply common config, but do not send to lower layers if Dedicated is present (to avoid sending twice) + apply_rr_config_common(&mob_ctrl_info->rr_cfg_common, !mob_reconf_r8->rr_cfg_ded_present); + + if (mob_reconf_r8->rr_cfg_ded_present) { + apply_rr_config_dedicated(&mob_reconf_r8->rr_cfg_ded); + } if (!phy->cell_select(&neighbour_cells[target_cell_idx]->phy_cell)) { rrc_log->error("Could not synchronize with target cell pci=%d. Trying to return to source PCI\n", @@ -1594,11 +1625,6 @@ void rrc::ho_ra_completed(bool ra_successful) { } mac_timers->timer_get(t304)->stop(); - - apply_rr_config_common_ul(&mob_reconf_r8->mob_ctrl_info.rr_cfg_common); - if (mob_reconf_r8->rr_cfg_ded_present) { - apply_rr_config_dedicated(&mob_reconf_r8->rr_cfg_ded); - } } // T304 will expiry and send ho_failure @@ -1641,6 +1667,24 @@ bool rrc::con_reconfig(asn1::rrc::rrc_conn_recfg_s* reconfig) return false; } } + if (reconfig_r8->non_crit_ext_present) { + rrc_conn_recfg_v890_ies_s* reconfig_r890 = &reconfig_r8->non_crit_ext; + if (reconfig_r890->non_crit_ext_present) { + rrc_conn_recfg_v920_ies_s* reconfig_r920 = &reconfig_r890->non_crit_ext; + if (reconfig_r920->non_crit_ext_present) { + rrc_conn_recfg_v1020_ies_s* reconfig_r1020 = &reconfig_r920->non_crit_ext; + if (reconfig_r1020->s_cell_to_add_mod_list_r10_present) { + for (uint32_t i = 0; i < reconfig_r1020->s_cell_to_add_mod_list_r10.size(); i++) { + phy->set_config_scell(&reconfig_r1020->s_cell_to_add_mod_list_r10[i]); + } + } + + if (reconfig_r1020->s_cell_to_release_list_r10_present) { + rrc_log->console("s_cell_to_release_list_r10 not handled\n"); + } + } + } + } if (reconfig_r8->meas_cfg_present) { if (!measurements.parse_meas_config(&reconfig_r8->meas_cfg)) { return false; @@ -1675,7 +1719,11 @@ void rrc::con_reconfig_failed() { // Set previous PHY/MAC configuration phy->set_config(&previous_phy_cfg); - mac->set_config(&previous_mac_cfg); + mac->set_config(previous_mac_cfg); + + // And restore current configs + current_mac_cfg = previous_mac_cfg; + current_phy_cfg = previous_phy_cfg; if (security_is_activated) { // Start the Reestablishment Procedure @@ -1687,8 +1735,8 @@ void rrc::con_reconfig_failed() void rrc::handle_rrc_con_reconfig(uint32_t lcid, asn1::rrc::rrc_conn_recfg_s* reconfig) { - phy->get_config(&previous_phy_cfg); - mac->get_config(&previous_mac_cfg); + previous_phy_cfg = current_phy_cfg; + previous_mac_cfg = current_mac_cfg; asn1::rrc::rrc_conn_recfg_r8_ies_s* reconfig_r8 = &reconfig->crit_exts.c1().rrc_conn_recfg_r8(); if (reconfig_r8->mob_ctrl_info_present) { @@ -1753,14 +1801,16 @@ void rrc::stop_timers() * * *******************************************************************************/ -void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { +void rrc::write_pdu_bcch_bch(byte_buffer_t* pdu) +{ // Do we need to do something with BCH? rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received."); pool->deallocate(pdu); } void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { - mac->clear_rntis(); + // Stop BCCH search after successful reception of 1 BCCH block + mac->bcch_stop_rx(); asn1::rrc::bcch_dl_sch_msg_s dlsch_msg; asn1::bit_ref dlsch_bref(pdu->msg, pdu->N_bytes); @@ -1833,8 +1883,42 @@ void rrc::handle_sib2() { rrc_log->info("SIB2 received\n"); - apply_sib2_configs(serving_cell->sib2ptr()); + sib_type2_s* sib2 = serving_cell->sib2ptr(); + + // Apply RACH and timeAlginmentTimer configuration + current_mac_cfg.set_rach_cfg_common(sib2->rr_cfg_common.rach_cfg_common); + current_mac_cfg.set_time_alignment(sib2->time_align_timer_common); + mac->set_config(current_mac_cfg); + // Set MBSFN configs + phy->set_config_mbsfn_sib2(sib2); + + // Apply PHY RR Config Common + current_phy_cfg.common.pdsch_cnfg = sib2->rr_cfg_common.pdsch_cfg_common; + current_phy_cfg.common.pusch_cnfg = sib2->rr_cfg_common.pusch_cfg_common; + current_phy_cfg.common.pucch_cnfg = sib2->rr_cfg_common.pucch_cfg_common; + current_phy_cfg.common.ul_pwr_ctrl = sib2->rr_cfg_common.ul_pwr_ctrl_common; + current_phy_cfg.common.prach_cnfg = sib2->rr_cfg_common.prach_cfg; + current_phy_cfg.common.srs_ul_cnfg = sib2->rr_cfg_common.srs_ul_cfg_common; + + phy->set_config(¤t_phy_cfg); + + log_rr_config_common(); + + mac_timers->timer_get(t300)->set(this, sib2->ue_timers_and_consts.t300.to_number()); + mac_timers->timer_get(t301)->set(this, sib2->ue_timers_and_consts.t301.to_number()); + mac_timers->timer_get(t310)->set(this, sib2->ue_timers_and_consts.t310.to_number()); + mac_timers->timer_get(t311)->set(this, sib2->ue_timers_and_consts.t311.to_number()); + N310 = sib2->ue_timers_and_consts.n310.to_number(); + N311 = sib2->ue_timers_and_consts.n311.to_number(); + + rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t300=%d, t301=%d, t310=%d, t311=%d\n", + N310, + N311, + mac_timers->timer_get(t300)->get_timeout(), + mac_timers->timer_get(t301)->get_timeout(), + mac_timers->timer_get(t310)->get_timeout(), + mac_timers->timer_get(t311)->get_timeout()); } void rrc::handle_sib3() @@ -1850,18 +1934,22 @@ void rrc::handle_sib3() cell_resel_cfg.threshservinglow = sib3->thresh_serving_low_q_r9; // TODO: Check first if present // intraFreqCellReselectionInfo - cell_resel_cfg.Qrxlevmin = sib3->intra_freq_cell_resel_info.q_rx_lev_min; + cell_resel_cfg.Qrxlevmin = sib3->intra_freq_cell_resel_info.q_rx_lev_min * 2; // multiply by two if (sib3->intra_freq_cell_resel_info.s_intra_search_present) { cell_resel_cfg.s_intrasearchP = sib3->intra_freq_cell_resel_info.s_intra_search; } else { - cell_resel_cfg.s_intrasearchP = INFINITY; + cell_resel_cfg.s_intrasearchP = INFINITY; } } void rrc::handle_sib13() { rrc_log->info("SIB13 received\n"); - apply_sib13_configs(serving_cell->sib13ptr()); + + sib_type13_r9_s* sib13 = serving_cell->sib13ptr(); + + phy->set_config_mbsfn_sib13(sib13); + add_mrb(0, 0); // Add MRB0 } /******************************************************************************* @@ -1918,7 +2006,7 @@ void rrc::process_pcch(byte_buffer_t *pdu) { } if (paging->sys_info_mod_present) { - rrc_log->info("Received System Information notifcation update request.\n"); + rrc_log->info("Received System Information notification update request.\n"); // invalidate and then update all SIBs of serving cell serving_cell->reset_sibs(); if (configure_serving_cell()) { @@ -2027,7 +2115,10 @@ void rrc::write_pdu(uint32_t lcid, byte_buffer_t* pdu) // FIXME: We unpack and process this message twice to check if it's ConnectionSetup asn1::bit_ref bref(pdu->msg, pdu->N_bytes); asn1::rrc::dl_ccch_msg_s dl_ccch_msg; - dl_ccch_msg.unpack(bref); + if (dl_ccch_msg.unpack(bref) != asn1::SRSASN_SUCCESS) { + rrc_log->error("Failed to unpack DL-CCCH message\n"); + return; + } if (dl_ccch_msg.msg.c1().type() == dl_ccch_msg_type_c::c1_c_::types::rrc_conn_setup) { // Must enter CONNECT before stopping T300 state = RRC_STATE_CONNECTED; @@ -2066,7 +2157,11 @@ void rrc::parse_dl_ccch(byte_buffer_t* pdu) { asn1::bit_ref bref(pdu->msg, pdu->N_bytes); asn1::rrc::dl_ccch_msg_s dl_ccch_msg; - dl_ccch_msg.unpack(bref); + if (dl_ccch_msg.unpack(bref) != asn1::SRSASN_SUCCESS) { + rrc_log->error("Failed to unpack DL-CCCH message\n"); + pool->deallocate(pdu); + return; + } log_rrc_message(get_rb_name(RB_ID_SRB0).c_str(), Rx, pdu, dl_ccch_msg); pool->deallocate(pdu); @@ -2114,7 +2209,10 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t* pdu) { asn1::bit_ref bref(pdu->msg, pdu->N_bytes); asn1::rrc::dl_dcch_msg_s dl_dcch_msg; - dl_dcch_msg.unpack(bref); + if (dl_dcch_msg.unpack(bref) != asn1::SRSASN_SUCCESS) { + rrc_log->error("Failed to unpack DL-DCCH message\n"); + return; + } log_rrc_message(get_rb_name(lcid).c_str(), Rx, pdu, dl_dcch_msg); pool->deallocate(pdu); @@ -2201,7 +2299,6 @@ void rrc::enable_capabilities() bool enable_ul_64 = args.ue_category >= 5 && serving_cell->sib2ptr()->rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.enable64_qam; rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling"); - phy->set_config_64qam_en(enable_ul_64); } void rrc::send_rrc_ue_cap_info() @@ -2219,10 +2316,41 @@ void rrc::send_rrc_ue_cap_info() info->ue_cap_rat_container_list.resize(1); info->ue_cap_rat_container_list[0].rat_type = rat_type_e::eutra; + // Check UE config arguments bounds + if (args.release < SRSLTE_RELEASE_MIN || args.release > SRSLTE_RELEASE_MAX) { + uint32_t new_release = SRSLTE_MIN(SRSLTE_RELEASE_MAX, SRSLTE_MAX(SRSLTE_RELEASE_MIN, args.release)); + rrc_log->error("Release is %d. It is out of bounds (%d ... %d), setting it to %d\n", + args.release, + SRSLTE_RELEASE_MIN, + SRSLTE_RELEASE_MAX, + new_release); + args.release = new_release; + } + + args.ue_category = (uint32_t)strtol(args.ue_category_str.c_str(), NULL, 10); + if (args.ue_category < SRSLTE_UE_CATEGORY_MIN || args.ue_category > SRSLTE_UE_CATEGORY_MAX) { + uint32_t new_category = SRSLTE_MIN(SRSLTE_UE_CATEGORY_MAX, SRSLTE_MAX(SRSLTE_UE_CATEGORY_MIN, args.ue_category)); + rrc_log->error("UE Category is %d. It is out of bounds (%d ... %d), setting it to %d\n", + args.ue_category, + SRSLTE_UE_CATEGORY_MIN, + SRSLTE_UE_CATEGORY_MAX, + new_category); + args.ue_category = new_category; + } + ue_eutra_cap_s cap; - cap.access_stratum_release = access_stratum_release_e::rel8; - cap.ue_category = (uint8_t)args.ue_category; + cap.access_stratum_release = (access_stratum_release_e::options)(args.release - SRSLTE_RELEASE_MIN); + cap.ue_category = (uint8_t)SRSLTE_MAX(1, SRSLTE_MIN(5, args.ue_category)); cap.pdcp_params.max_num_rohc_context_sessions_present = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0001_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0002_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0003_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0004_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0006_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0101_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0102_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0103_r15 = false; + cap.pdcp_params.supported_rohc_profiles.profile0x0104_r15 = false; cap.phy_layer_params.ue_specific_ref_sigs_supported = false; cap.phy_layer_params.ue_tx_ant_sel_supported = false; @@ -2239,6 +2367,77 @@ void rrc::send_rrc_ue_cap_info() cap.feature_group_inds_present = true; cap.feature_group_inds.from_number(args.feature_group); + if (args.release > 8) { + ue_eutra_cap_v920_ies_s cap_v920; + + cap_v920.phy_layer_params_v920.enhanced_dual_layer_fdd_r9_present = false; + cap_v920.phy_layer_params_v920.enhanced_dual_layer_tdd_r9_present = false; + cap_v920.inter_rat_params_geran_v920.dtm_r9_present = false; + cap_v920.inter_rat_params_geran_v920.e_redirection_geran_r9_present = false; + cap_v920.csg_proximity_ind_params_r9.inter_freq_proximity_ind_r9_present = false; + cap_v920.csg_proximity_ind_params_r9.intra_freq_proximity_ind_r9_present = false; + cap_v920.csg_proximity_ind_params_r9.utran_proximity_ind_r9_present = false; + cap_v920.neigh_cell_si_acquisition_params_r9.inter_freq_si_acquisition_for_ho_r9_present = false; + cap_v920.neigh_cell_si_acquisition_params_r9.intra_freq_si_acquisition_for_ho_r9_present = false; + cap_v920.neigh_cell_si_acquisition_params_r9.utran_si_acquisition_for_ho_r9_present = false; + cap_v920.son_params_r9.rach_report_r9_present = false; + + cap.non_crit_ext_present = true; + cap.non_crit_ext = cap_v920; + } + + if (args.release > 9) { + + phy_layer_params_v1020_s phy_layer_params_v1020; + phy_layer_params_v1020.two_ant_ports_for_pucch_r10_present = false; + phy_layer_params_v1020.tm9_with_minus8_tx_fdd_r10_present = false; + phy_layer_params_v1020.pmi_disabling_r10_present = false; + phy_layer_params_v1020.cross_carrier_sched_r10_present = args.support_ca; + phy_layer_params_v1020.simul_pucch_pusch_r10_present = false; + phy_layer_params_v1020.multi_cluster_pusch_within_cc_r10_present = false; + phy_layer_params_v1020.non_contiguous_ul_ra_within_cc_list_r10_present = false; + + band_combination_params_r10_l combination_params; + if (args.support_ca) { + for (uint32_t i = 0; i < args.nof_supported_bands; i++) { + ca_mimo_params_dl_r10_s ca_mimo_params_dl; + ca_mimo_params_dl.ca_bw_class_dl_r10 = ca_bw_class_r10_e::f; + ca_mimo_params_dl.supported_mimo_cap_dl_r10_present = false; + + ca_mimo_params_ul_r10_s ca_mimo_params_ul; + ca_mimo_params_ul.ca_bw_class_ul_r10 = ca_bw_class_r10_e::f; + ca_mimo_params_ul.supported_mimo_cap_ul_r10_present = false; + + band_params_r10_s band_params; + band_params.band_eutra_r10 = args.supported_bands[i]; + band_params.band_params_dl_r10_present = true; + band_params.band_params_dl_r10.push_back(ca_mimo_params_dl); + band_params.band_params_ul_r10_present = true; + band_params.band_params_ul_r10.push_back(ca_mimo_params_ul); + + combination_params.push_back(band_params); + } + } + + rf_params_v1020_s rf_params; + rf_params.supported_band_combination_r10.push_back(combination_params); + + ue_eutra_cap_v1020_ies_s cap_v1020; + cap_v1020.ue_category_v1020_present = true; + cap_v1020.ue_category_v1020 = (uint8_t)SRSLTE_MAX(6, SRSLTE_MIN(8, args.ue_category)); + cap_v1020.phy_layer_params_v1020_present = true; + cap_v1020.phy_layer_params_v1020 = phy_layer_params_v1020; + cap_v1020.rf_params_v1020_present = args.support_ca; + cap_v1020.rf_params_v1020 = rf_params; + + ue_eutra_cap_v940_ies_s cap_v940; + cap_v940.non_crit_ext_present = true; + cap_v940.non_crit_ext = cap_v1020; + + cap.non_crit_ext.non_crit_ext_present = true; + cap.non_crit_ext.non_crit_ext = cap_v940; + } + // Pack caps and copy to cap info uint8_t buf[64]; asn1::bit_ref bref(buf, sizeof(buf)); @@ -2252,162 +2451,152 @@ void rrc::send_rrc_ue_cap_info() } /******************************************************************************* -* -* -* -* PHY and MAC Radio Resource configuration -* -* -* -*******************************************************************************/ + * + * + * + * PHY and MAC Radio Resource configuration + * + * + * + *******************************************************************************/ -void rrc::apply_rr_config_common_dl(rr_cfg_common_s* config) +void rrc::log_rr_config_common() { - mac_interface_rrc::mac_cfg_t mac_cfg; - mac->get_config(&mac_cfg); - if (config->rach_cfg_common_present) { - mac_cfg.rach = config->rach_cfg_common; - mac_cfg.ul_harq_params.max_harq_msg3_tx = config->rach_cfg_common.max_harq_msg3_tx; - } - mac_cfg.prach_config_index = config->prach_cfg.root_seq_idx; + rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", + current_mac_cfg.get_rach_cfg().nof_preambles, + current_mac_cfg.get_rach_cfg().responseWindowSize, + current_mac_cfg.get_rach_cfg().contentionResolutionTimer); - mac->set_config(&mac_cfg); + rrc_log->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", + current_phy_cfg.common.pusch_cnfg.pusch_cfg_basic.pusch_hop_offset, + current_phy_cfg.common.pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch, + current_phy_cfg.common.pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift, + current_phy_cfg.common.pusch_cnfg.pusch_cfg_basic.n_sb); - phy_interface_rrc::phy_cfg_t phy_cfg; - phy->get_config(&phy_cfg); - phy_interface_rrc::phy_cfg_common_t* common = &phy_cfg.common; + rrc_log->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", + current_phy_cfg.common.pucch_cnfg.delta_pucch_shift.to_number(), + current_phy_cfg.common.pucch_cnfg.n_cs_an, + current_phy_cfg.common.pucch_cnfg.n1_pucch_an, + current_phy_cfg.common.pucch_cnfg.n_rb_cqi); - if (config->pdsch_cfg_common_present) { - common->pdsch_cnfg = config->pdsch_cfg_common; - } - common->prach_cnfg.root_seq_idx = config->prach_cfg.root_seq_idx; - if (config->prach_cfg.prach_cfg_info_present) { - common->prach_cnfg.prach_cfg_info = config->prach_cfg.prach_cfg_info; - } + rrc_log->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%s, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", + current_phy_cfg.common.prach_cnfg.root_seq_idx, + current_phy_cfg.common.prach_cnfg.prach_cfg_info.high_speed_flag ? "yes" : "no", + current_phy_cfg.common.prach_cnfg.prach_cfg_info.prach_freq_offset, + current_phy_cfg.common.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg, + current_phy_cfg.common.prach_cnfg.prach_cfg_info.prach_cfg_idx); - phy->set_config_common(common); + if (current_phy_cfg.common.srs_ul_cnfg.type() == setup_e::setup) { + rrc_log->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%s\n", + current_phy_cfg.common.srs_ul_cnfg.setup().srs_bw_cfg.to_number(), + current_phy_cfg.common.srs_ul_cnfg.setup().srs_sf_cfg.to_number(), + current_phy_cfg.common.srs_ul_cnfg.setup().ack_nack_srs_simul_tx ? "yes" : "no"); + } } -void rrc::apply_rr_config_common_ul(rr_cfg_common_s* config) +void rrc::apply_rr_config_common(rr_cfg_common_s* config, bool send_lower_layers) { - phy_interface_rrc::phy_cfg_t phy_cfg; - phy->get_config(&phy_cfg); - phy_interface_rrc::phy_cfg_common_t* common = &phy_cfg.common; + if (config->rach_cfg_common_present) { + current_mac_cfg.set_rach_cfg_common(config->rach_cfg_common); + } + phy_interface_rrc::phy_cfg_common_t* common = ¤t_phy_cfg.common; + + if (config->prach_cfg.prach_cfg_info_present) { + common->prach_cnfg.prach_cfg_info = config->prach_cfg.prach_cfg_info; + } + common->prach_cnfg.root_seq_idx = config->prach_cfg.root_seq_idx; + if (config->pdsch_cfg_common_present) { + common->pdsch_cnfg = config->pdsch_cfg_common; + } common->pusch_cnfg = config->pusch_cfg_common; + if (config->phich_cfg_present) { + common->phich_cnfg = config->phich_cfg; + } if (config->pucch_cfg_common_present) { common->pucch_cnfg = config->pucch_cfg_common; } + if (config->srs_ul_cfg_common_present) { + common->srs_ul_cnfg = config->srs_ul_cfg_common; + } if (config->ul_pwr_ctrl_common_present) { common->ul_pwr_ctrl = config->ul_pwr_ctrl_common; } - if (config->srs_ul_cfg_common_present) { - common->srs_ul_cnfg = config->srs_ul_cfg_common; + // TODO: p_max, antenna_info, tdd... + + log_rr_config_common(); + + if (send_lower_layers) { + mac->set_config(current_mac_cfg); + phy->set_config(¤t_phy_cfg); } - phy->set_config_common(common); - phy->configure_ul_params(); } -void rrc::apply_sib2_configs(sib_type2_s* sib2) +void rrc::log_phy_config_dedicated() { + if (!rrc_log) { + return; + } + phys_cfg_ded_s* current_cfg = ¤t_phy_cfg.dedicated; - // Apply RACH timeAlginmentTimer configuration - mac_interface_rrc::mac_cfg_t cfg; - mac->get_config(&cfg); - - cfg.main.time_align_timer_ded = sib2->time_align_timer_common; - cfg.rach = sib2->rr_cfg_common.rach_cfg_common; - cfg.prach_config_index = sib2->rr_cfg_common.prach_cfg.root_seq_idx; - cfg.ul_harq_params.max_harq_msg3_tx = cfg.rach.max_harq_msg3_tx; - // Apply MBSFN configuration - // cfg.mbsfn_subfr_cnfg_list_size = sib2->mbsfn_subfr_cnfg_list_size; - // for(uint8_t i=0;imbsfn_subfr_cnfg_list_size;i++) { - // memcpy(&cfg.mbsfn_subfr_cnfg_list[i], &sib2->mbsfn_subfr_cnfg_list[i], - // sizeof(LIBLTE_RRC_MBSFN_SUBFRAME_CONFIG_STRUCT)); - // } - - // Set MBSFN configs - phy->set_config_mbsfn_sib2(sib2); - - mac->set_config(&cfg); - - rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", - sib2->rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.to_number(), - sib2->rr_cfg_common.rach_cfg_common.ra_supervision_info.ra_resp_win_size.to_number(), - sib2->rr_cfg_common.rach_cfg_common.ra_supervision_info.mac_contention_resolution_timer.to_number()); - - // Apply PHY RR Config Common - phy_interface_rrc::phy_cfg_common_t common; - common.pdsch_cnfg = sib2->rr_cfg_common.pdsch_cfg_common; - common.pusch_cnfg = sib2->rr_cfg_common.pusch_cfg_common; - common.pucch_cnfg = sib2->rr_cfg_common.pucch_cfg_common; - common.ul_pwr_ctrl = sib2->rr_cfg_common.ul_pwr_ctrl_common; - common.prach_cnfg = sib2->rr_cfg_common.prach_cfg; - common.srs_ul_cnfg = sib2->rr_cfg_common.srs_ul_cfg_common; - phy->set_config_common(&common); - - phy->configure_ul_params(); - - rrc_log->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", - sib2->rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.pusch_hop_offset, - sib2->rr_cfg_common.pusch_cfg_common.ul_ref_sigs_pusch.group_assign_pusch, - sib2->rr_cfg_common.pusch_cfg_common.ul_ref_sigs_pusch.cyclic_shift, - sib2->rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.n_sb); - - rrc_log->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", - sib2->rr_cfg_common.pucch_cfg_common.delta_pucch_shift.to_number(), - sib2->rr_cfg_common.pucch_cfg_common.n_cs_an, sib2->rr_cfg_common.pucch_cfg_common.n1_pucch_an, - sib2->rr_cfg_common.pucch_cfg_common.n_rb_cqi); - - rrc_log->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%s, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", - sib2->rr_cfg_common.prach_cfg.root_seq_idx, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.high_speed_flag ? "yes" : "no", - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.zero_correlation_zone_cfg, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.prach_cfg_idx); - - if (sib2->rr_cfg_common.srs_ul_cfg_common.type() == setup_e::setup) { - rrc_log->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%s\n", - sib2->rr_cfg_common.srs_ul_cfg_common.setup().srs_bw_cfg.to_number(), - sib2->rr_cfg_common.srs_ul_cfg_common.setup().srs_sf_cfg.to_number(), - sib2->rr_cfg_common.srs_ul_cfg_common.setup().ack_nack_srs_simul_tx ? "yes" : "no"); + if (current_cfg->pdsch_cfg_ded_present) { + rrc_log->info("Set PDSCH-Config=%s (present)\n", current_cfg->pdsch_cfg_ded.p_a.to_string().c_str()); } - mac_timers->timer_get(t300)->set(this, sib2->ue_timers_and_consts.t300.to_number()); - mac_timers->timer_get(t301)->set(this, sib2->ue_timers_and_consts.t301.to_number()); - mac_timers->timer_get(t310)->set(this, sib2->ue_timers_and_consts.t310.to_number()); - mac_timers->timer_get(t311)->set(this, sib2->ue_timers_and_consts.t311.to_number()); - N310 = sib2->ue_timers_and_consts.n310.to_number(); - N311 = sib2->ue_timers_and_consts.n311.to_number(); + if (current_cfg->cqi_report_cfg_present) { + if (current_cfg->cqi_report_cfg.cqi_report_periodic_present and + current_cfg->cqi_report_cfg.cqi_report_periodic.type() == setup_e::setup) { + rrc_log->info( + "Set cqi-PUCCH-ResourceIndex=%d, cqi-pmi-ConfigIndex=%d, cqi-FormatIndicatorPeriodic=%s\n", + current_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, + current_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, + current_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().to_string().c_str()); + } + if (current_cfg->cqi_report_cfg.cqi_report_mode_aperiodic_present) { + rrc_log->info("Set cqi-ReportModeAperiodic=%s\n", + current_cfg->cqi_report_cfg.cqi_report_mode_aperiodic.to_string().c_str()); + } + } - rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t300=%d, t301=%d, t310=%d, t311=%d\n", N310, N311, - mac_timers->timer_get(t300)->get_timeout(), mac_timers->timer_get(t301)->get_timeout(), - mac_timers->timer_get(t310)->get_timeout(), mac_timers->timer_get(t311)->get_timeout()); -} + if (current_cfg->sched_request_cfg_present and current_cfg->sched_request_cfg.type() == setup_e::setup) { + rrc_log->info("Set PHY config ded: SR-n_pucch=%d, SR-ConfigIndex=%d, SR-TransMax=%d\n", + current_cfg->sched_request_cfg.setup().sr_pucch_res_idx, + current_cfg->sched_request_cfg.setup().sr_cfg_idx, + current_cfg->sched_request_cfg.setup().dsr_trans_max.to_number()); + } -void rrc::apply_sib13_configs(sib_type13_r9_s* sib13) -{ - phy->set_config_mbsfn_sib13(sib13); - add_mrb(0, 0); // Add MRB0 + if (current_cfg->srs_ul_cfg_ded_present and current_cfg->srs_ul_cfg_ded.type() == setup_e::setup) { + rrc_log->info("Set PHY config ded: SRS-ConfigIndex=%d, SRS-bw=%s, SRS-Nrcc=%d, SRS-hop=%s, SRS-Ncs=%s\n", + current_cfg->srs_ul_cfg_ded.setup().srs_cfg_idx, + current_cfg->srs_ul_cfg_ded.setup().srs_bw.to_string().c_str(), + current_cfg->srs_ul_cfg_ded.setup().freq_domain_position, + current_cfg->srs_ul_cfg_ded.setup().srs_hop_bw.to_string().c_str(), + current_cfg->srs_ul_cfg_ded.setup().cyclic_shift.to_string().c_str()); + } } // Go through all information elements and apply defaults (9.2.4) if not defined void rrc::apply_phy_config_dedicated(phys_cfg_ded_s* phy_cnfg, bool apply_defaults) { // Get current configuration - phys_cfg_ded_s* current_cfg; - phy_interface_rrc::phy_cfg_t c; - phy->get_config(&c); - current_cfg = &c.dedicated; + phys_cfg_ded_s* current_cfg = ¤t_phy_cfg.dedicated; - current_cfg->pucch_cfg_ded_present = true; if (phy_cnfg->pucch_cfg_ded_present) { + current_cfg->pucch_cfg_ded_present = true; current_cfg->pucch_cfg_ded = phy_cnfg->pucch_cfg_ded; } else if (apply_defaults) { current_cfg->pucch_cfg_ded.tdd_ack_nack_feedback_mode_present = true; current_cfg->pucch_cfg_ded.tdd_ack_nack_feedback_mode = pucch_cfg_ded_s::tdd_ack_nack_feedback_mode_e_::bundling; current_cfg->pucch_cfg_ded.ack_nack_repeat.set(setup_e::release); } + + if (phy_cnfg->pucch_cfg_ded_v1020_present) { + current_cfg->pucch_cfg_ded_v1020_present = true; + current_cfg->pucch_cfg_ded_v1020 = phy_cnfg->pucch_cfg_ded_v1020; + } else if (apply_defaults) { + current_cfg->pucch_cfg_ded_v1020_present = false; + } + current_cfg->pusch_cfg_ded_present = true; if (phy_cnfg->pusch_cfg_ded_present) { current_cfg->pusch_cfg_ded = phy_cnfg->pusch_cfg_ded; @@ -2465,27 +2654,14 @@ void rrc::apply_phy_config_dedicated(phys_cfg_ded_s* phy_cnfg, bool apply_defaul } else if (apply_defaults) { current_cfg->srs_ul_cfg_ded.set(setup_e::release); } - current_cfg->ant_info_present = true; - current_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); - if (phy_cnfg->ant_info_present) { - if (phy_cnfg->ant_info.type() == phys_cfg_ded_s::ant_info_c_::types::explicit_value) { - if (phy_cnfg->ant_info.explicit_value().tx_mode != ant_info_ded_s::tx_mode_e_::tm1 and - phy_cnfg->ant_info.explicit_value().tx_mode != ant_info_ded_s::tx_mode_e_::tm2 and - phy_cnfg->ant_info.explicit_value().tx_mode != ant_info_ded_s::tx_mode_e_::tm3 and - phy_cnfg->ant_info.explicit_value().tx_mode != ant_info_ded_s::tx_mode_e_::tm4) { - rrc_log->error("Transmission mode TM%s not currently supported by srsUE\n", - phy_cnfg->ant_info.explicit_value().tx_mode.to_string().c_str()); - } - current_cfg->ant_info.explicit_value() = phy_cnfg->ant_info.explicit_value(); - } else if (apply_defaults) { - current_cfg->ant_info.explicit_value().tx_mode = ant_info_ded_s::tx_mode_e_::tm2; - current_cfg->ant_info.explicit_value().codebook_subset_restrict_present = false; - current_cfg->ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); - } - } else if (apply_defaults) { + if (apply_defaults) { + current_cfg->ant_info_present = true; + current_cfg->ant_info.set(phys_cfg_ded_s::ant_info_c_::types::explicit_value); current_cfg->ant_info.explicit_value().tx_mode = ant_info_ded_s::tx_mode_e_::tm2; current_cfg->ant_info.explicit_value().codebook_subset_restrict_present = false; current_cfg->ant_info.explicit_value().ue_tx_ant_sel.set(setup_e::release); + } else { + current_cfg->ant_info = phy_cnfg->ant_info; } if (phy_cnfg->sched_request_cfg_present and phy_cnfg->sched_request_cfg.type() == setup_e::setup) { current_cfg->sched_request_cfg_present = true; @@ -2496,119 +2672,68 @@ void rrc::apply_phy_config_dedicated(phys_cfg_ded_s* phy_cnfg, bool apply_defaul current_cfg->pdsch_cfg_ded_present = true; if (phy_cnfg->pdsch_cfg_ded_present) { current_cfg->pdsch_cfg_ded = phy_cnfg->pdsch_cfg_ded; - rrc_log->info("Set PDSCH-Config=%s (present)\n", current_cfg->pdsch_cfg_ded.p_a.to_string().c_str()); } else if (apply_defaults) { current_cfg->pdsch_cfg_ded.p_a = pdsch_cfg_ded_s::p_a_e_::db0; - rrc_log->info("Set PDSCH-Config=%s (default)\n", current_cfg->pdsch_cfg_ded.p_a.to_string().c_str()); } - if (phy_cnfg->cqi_report_cfg_present) { - if (phy_cnfg->cqi_report_cfg.cqi_report_periodic_present and - phy_cnfg->cqi_report_cfg.cqi_report_periodic.type() == setup_e::setup) { - rrc_log->info( - "Set cqi-PUCCH-ResourceIndex=%d, cqi-pmi-ConfigIndex=%d, cqi-FormatIndicatorPeriodic=%s\n", - current_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx, - current_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx, - current_cfg->cqi_report_cfg.cqi_report_periodic.setup().cqi_format_ind_periodic.type().to_string().c_str()); - } - if (phy_cnfg->cqi_report_cfg.cqi_report_mode_aperiodic_present) { - rrc_log->info("Set cqi-ReportModeAperiodic=%s\n", - current_cfg->cqi_report_cfg.cqi_report_mode_aperiodic.to_string().c_str()); - } - } - - if (current_cfg->sched_request_cfg_present and current_cfg->sched_request_cfg.type() == setup_e::setup) { - rrc_log->info("Set PHY config ded: SR-n_pucch=%d, SR-ConfigIndex=%d, SR-TransMax=%d\n", - current_cfg->sched_request_cfg.setup().sr_pucch_res_idx, - current_cfg->sched_request_cfg.setup().sr_cfg_idx, - current_cfg->sched_request_cfg.setup().dsr_trans_max.to_number()); - } + log_phy_config_dedicated(); - if (current_cfg->srs_ul_cfg_ded_present and current_cfg->srs_ul_cfg_ded.type() == setup_e::setup) { - rrc_log->info("Set PHY config ded: SRS-ConfigIndex=%d, SRS-bw=%s, SRS-Nrcc=%d, SRS-hop=%s, SRS-Ncs=%s\n", - current_cfg->srs_ul_cfg_ded.setup().srs_cfg_idx, - current_cfg->srs_ul_cfg_ded.setup().srs_bw.to_string().c_str(), - current_cfg->srs_ul_cfg_ded.setup().freq_domain_position, - current_cfg->srs_ul_cfg_ded.setup().srs_hop_bw.to_string().c_str(), - current_cfg->srs_ul_cfg_ded.setup().cyclic_shift.to_string().c_str()); + if (phy != nullptr) { + phy->set_config(¤t_phy_cfg); + } else { + rrc_log->info("RRC not initialized. Skipping default PHY config.\n"); } - - phy->set_config_dedicated(current_cfg); - - // Apply changes to PHY - phy->configure_ul_params(); } -void rrc::apply_mac_config_dedicated(mac_main_cfg_s* mac_cnfg, bool apply_defaults) +void rrc::log_mac_config_dedicated() { - // Set Default MAC main configuration (9.2.2) - mac_main_cfg_s default_cfg; - default_cfg.ul_sch_cfg_present = true; - default_cfg.ul_sch_cfg.max_harq_tx = mac_main_cfg_s::ul_sch_cfg_s_::max_harq_tx_e_::n5; - default_cfg.ul_sch_cfg.periodic_bsr_timer = periodic_bsr_timer_r12_e::infinity; - default_cfg.ul_sch_cfg.retx_bsr_timer = retx_bsr_timer_r12_e::sf2560; - default_cfg.ul_sch_cfg.tti_bundling = false; - default_cfg.drx_cfg.set(setup_e::release); - default_cfg.phr_cfg.set(setup_e::release); - default_cfg.time_align_timer_ded = time_align_timer_e::infinity; - - if (!apply_defaults) { - if (mac_cnfg->ul_sch_cfg_present) { - if (mac_cnfg->ul_sch_cfg.max_harq_tx_present) { - default_cfg.ul_sch_cfg.max_harq_tx = mac_cnfg->ul_sch_cfg.max_harq_tx; - default_cfg.ul_sch_cfg.max_harq_tx_present = true; - } - if (mac_cnfg->ul_sch_cfg.periodic_bsr_timer_present) { - default_cfg.ul_sch_cfg.periodic_bsr_timer = mac_cnfg->ul_sch_cfg.periodic_bsr_timer; - default_cfg.ul_sch_cfg.periodic_bsr_timer_present = true; - } - default_cfg.ul_sch_cfg.retx_bsr_timer = mac_cnfg->ul_sch_cfg.retx_bsr_timer; - default_cfg.ul_sch_cfg.tti_bundling = mac_cnfg->ul_sch_cfg.tti_bundling; - } - if (mac_cnfg->drx_cfg_present) { - default_cfg.drx_cfg = mac_cnfg->drx_cfg; - default_cfg.drx_cfg_present = true; - } - if (mac_cnfg->phr_cfg_present) { - default_cfg.phr_cfg = mac_cnfg->phr_cfg; - default_cfg.phr_cfg_present = true; - } - default_cfg.time_align_timer_ded = mac_cnfg->time_align_timer_ded; - } - - // Setup MAC configuration - mac->set_config_main(&default_cfg); - - // Update UL HARQ config - mac_interface_rrc::mac_cfg_t cfg; - mac->get_config(&cfg); - cfg.ul_harq_params.max_harq_tx = default_cfg.ul_sch_cfg.max_harq_tx.to_number(); - mac->set_config(&cfg); - rrc_log->info("Set MAC main config: harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n", - default_cfg.ul_sch_cfg.max_harq_tx.to_number(), default_cfg.ul_sch_cfg.retx_bsr_timer.to_number(), - default_cfg.ul_sch_cfg.periodic_bsr_timer.to_number()); - if (default_cfg.phr_cfg_present and default_cfg.phr_cfg.type() == setup_e::setup) { + current_mac_cfg.get_harq_cfg().max_harq_msg3_tx, + current_mac_cfg.get_bsr_cfg().retx_timer, + current_mac_cfg.get_bsr_cfg().periodic_timer); + if (current_mac_cfg.get_phr_cfg().enabled) { rrc_log->info("Set MAC PHR config: periodicPHR-Timer=%d, prohibitPHR-Timer=%d, dl-PathlossChange=%d\n", - default_cfg.phr_cfg.setup().periodic_phr_timer.to_number(), - default_cfg.phr_cfg.setup().prohibit_phr_timer.to_number(), - default_cfg.phr_cfg.setup().dl_pathloss_change.to_number()); + current_mac_cfg.get_phr_cfg().periodic_timer, + current_mac_cfg.get_phr_cfg().prohibit_timer, + current_mac_cfg.get_phr_cfg().db_pathloss_change); } } +void rrc::apply_mac_config_dedicated_default() +{ + rrc_log->info("Set MAC default configuration\n"); + current_mac_cfg.set_defaults(); + mac->set_config(current_mac_cfg); + log_mac_config_dedicated(); +} + +void rrc::apply_mac_config_dedicated_explicit(mac_main_cfg_s mac_cnfg) +{ + current_mac_cfg.set_mac_main_cfg(mac_cnfg); + mac->set_config(current_mac_cfg); + log_mac_config_dedicated(); +} + bool rrc::apply_rr_config_dedicated(rr_cfg_ded_s* cnfg) { if (cnfg->phys_cfg_ded_present) { apply_phy_config_dedicated(&cnfg->phys_cfg_ded, false); // Apply SR configuration to MAC if (cnfg->phys_cfg_ded.sched_request_cfg_present) { - mac->set_config_sr(&cnfg->phys_cfg_ded.sched_request_cfg); + current_mac_cfg.set_sched_request_cfg(cnfg->phys_cfg_ded.sched_request_cfg); } } if (cnfg->mac_main_cfg_present) { - apply_mac_config_dedicated(&cnfg->mac_main_cfg.explicit_value(), - cnfg->mac_main_cfg.type() == rr_cfg_ded_s::mac_main_cfg_c_::types::default_value); + if (cnfg->mac_main_cfg.type() == rr_cfg_ded_s::mac_main_cfg_c_::types::default_value) { + apply_mac_config_dedicated_default(); + } else { + apply_mac_config_dedicated_explicit(cnfg->mac_main_cfg.explicit_value()); + } + } else if (cnfg->phys_cfg_ded.sched_request_cfg_present) { + // If MAC-main not set but SR config is set, use directly mac->set_config to update confi + mac->set_config(current_mac_cfg); + log_mac_config_dedicated(); } if (cnfg->sps_cfg_present) { @@ -2663,6 +2788,19 @@ void rrc::handle_con_reest(rrc_conn_reest_s* setup) pdcp->reestablish(); rlc->reestablish(); + // Update RRC Integrity keys + int ncc = setup->crit_exts.c1().rrc_conn_reest_r8().next_hop_chaining_count; + usim->generate_as_keys_ho(serving_cell->get_pci(), + phy->get_current_earfcn(), + ncc, + k_rrc_enc, + k_rrc_int, + k_up_enc, + k_up_int, + cipher_algo, + integ_algo); + pdcp->config_security_all(k_rrc_enc, k_rrc_int, k_up_enc, cipher_algo, integ_algo); + // Apply the Radio Resource configuration apply_rr_config_dedicated(&setup->crit_exts.c1().rrc_conn_reest_r8().rr_cfg_ded); @@ -2804,31 +2942,21 @@ void rrc::add_mrb(uint32_t lcid, uint32_t port) // PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4) void rrc::set_phy_default_pucch_srs() { - phy_interface_rrc::phy_cfg_t current_cfg; - phy->get_config(¤t_cfg); - // Set defaults to CQI, SRS and SR - current_cfg.dedicated.cqi_report_cfg_present = false; - current_cfg.dedicated.srs_ul_cfg_ded_present = false; - current_cfg.dedicated.sched_request_cfg_present = false; - - apply_phy_config_dedicated(¤t_cfg.dedicated, true); + current_phy_cfg.dedicated.cqi_report_cfg_present = false; + current_phy_cfg.dedicated.srs_ul_cfg_ded_present = false; + current_phy_cfg.dedicated.sched_request_cfg_present = false; - // Release SR configuration from MAC - sched_request_cfg_c cfg; - mac->set_config_sr(&cfg); + apply_phy_config_dedicated(¤t_phy_cfg.dedicated, true); + apply_mac_config_dedicated_default(); } void rrc::set_phy_default() { - phys_cfg_ded_s defaults; - apply_phy_config_dedicated(&defaults, true); + apply_phy_config_dedicated(¤t_phy_cfg.dedicated, true); } void rrc::set_mac_default() { - apply_mac_config_dedicated(NULL, true); - sched_request_cfg_c sr_cfg; - sr_cfg.set(setup_e::release); - mac->set_config_sr(&sr_cfg); + apply_mac_config_dedicated_default(); } void rrc::set_rrc_default() { @@ -3487,7 +3615,6 @@ void rrc::rrc_meas::update_phy() } } - uint8_t rrc::rrc_meas::value_to_range(quantity_t quant, float value) { uint8_t range = 0; switch(quant) { @@ -3510,7 +3637,7 @@ uint8_t rrc::rrc_meas::value_to_range(quantity_t quant, float value) { } break; case BOTH: - printf("Error quantity both not supported in value_to_range\n"); + log_h->error("Error quantity both not supported in value_to_range\n"); break; } return range; @@ -3527,7 +3654,7 @@ float rrc::rrc_meas::range_to_value(quantity_t quant, uint8_t range) val = -19.5f + (float)range / 2; break; case BOTH: - printf("Error quantity both not supported in range_to_value\n"); + log_h->error("Error quantity both not supported in range_to_value\n"); break; } return val; diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index b107498db..ededff3dd 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -124,7 +124,7 @@ std::string usim::get_imei_str() bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return false; } @@ -144,7 +144,7 @@ bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) bool usim::get_imei_vec(uint8_t* imei_, uint32_t n) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return false; } @@ -165,7 +165,7 @@ bool usim::get_imei_vec(uint8_t* imei_, uint32_t n) bool usim::get_home_plmn_id(plmn_id_s* home_plmn_id) { if (!initiated) { - fprintf(stderr, "USIM not initiated!\n"); + ERROR("USIM not initiated!\n"); return false; } diff --git a/srsue/src/upper/usim_base.cc b/srsue/src/upper/usim_base.cc index d6672cf3b..7797be405 100644 --- a/srsue/src/upper/usim_base.cc +++ b/srsue/src/upper/usim_base.cc @@ -24,10 +24,11 @@ * */ -#include -#include +#include "srsue/hdr/upper/usim_base.h" +#include "srsue/hdr/upper/usim.h" + #ifdef HAVE_PCSC -#include +#include "srsue/hdr/upper/pcsc_usim.h" #endif namespace srsue{ diff --git a/srsue/test/CMakeLists.txt b/srsue/test/CMakeLists.txt index 217c369ee..ca80ecb45 100644 --- a/srsue/test/CMakeLists.txt +++ b/srsue/test/CMakeLists.txt @@ -18,10 +18,12 @@ # and at http://www.gnu.org/licenses/. # -add_subdirectory(phy) -add_subdirectory(mac) add_subdirectory(upper) add_executable(metrics_test metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc) target_link_libraries(metrics_test srslte_phy srslte_common) add_test(metrics_test metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/ue_metrics.csv) + +add_executable(mac_test mac_test.cc) +target_link_libraries(mac_test srsue_mac srsue_phy srslte_common srslte_phy srslte_radio srslte_asn1 rrc_asn1 ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +add_test(mac_test mac_test) \ No newline at end of file diff --git a/srsue/test/mac/CMakeLists.txt b/srsue/test/mac/CMakeLists.txt deleted file mode 100644 index 2aca8ab4b..000000000 --- a/srsue/test/mac/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright 2013-2017 Software Radio Systems Limited -# -# This file is part of srsLTE -# -# 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/. -# -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch") -add_executable(mac_test mac_test.cc) -target_link_libraries(mac_test srsue_mac srsue_phy srslte_common srslte_phy srslte_radio srslte_asn1 rrc_asn1 ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) - diff --git a/srsue/test/mac/mac_test.cc b/srsue/test/mac/mac_test.cc deleted file mode 100644 index 3de2584ba..000000000 --- a/srsue/test/mac/mac_test.cc +++ /dev/null @@ -1,522 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - - -#include -#include - -#include "srslte/asn1/rrc_asn1.h" -#include "srslte/common/log_filter.h" -#include "srslte/common/mac_pcap.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srslte/radio/radio_multi.h" -#include "srsue/hdr/mac/mac.h" -#include "srsue/hdr/phy/phy.h" - -using namespace asn1::rrc; - -/********************************************************************** - * Program arguments processing - ***********************************************************************/ -typedef struct { - float rf_rx_freq; - float rf_tx_freq; - float rf_rx_gain; - float rf_tx_gain; - int verbose; - bool do_trace; - bool do_pcap; -}prog_args_t; - -void args_default(prog_args_t *args) { - args->rf_rx_freq = -1.0; - args->rf_tx_freq = -1.0; - args->rf_rx_gain = -1; // set to autogain - args->rf_tx_gain = -1; - args->verbose = 0; - args->do_trace = false; - args->do_pcap = false; -} - -void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [gGtpv] -f rx_frequency (in Hz) -F tx_frequency (in Hz)\n", prog); - printf("\t-g RF RX gain [Default AGC]\n"); - printf("\t-G RF TX gain [Default same as RX gain (AGC)]\n"); - printf("\t-t Enable trace [Default disabled]\n"); - printf("\t-p Enable PCAP capture [Default disabled]\n"); - printf("\t-v [increase verbosity, default none]\n"); -} - -void parse_args(prog_args_t *args, int argc, char **argv) { - int opt; - args_default(args); - while ((opt = getopt(argc, argv, "gGftpFv")) != -1) { - switch (opt) { - case 'g': - args->rf_rx_gain = atof(argv[optind]); - break; - case 'G': - args->rf_tx_gain = atof(argv[optind]); - break; - case 'f': - args->rf_rx_freq = atof(argv[optind]); - break; - case 'F': - args->rf_tx_freq = atof(argv[optind]); - break; - case 't': - args->do_trace = true; - break; - case 'p': - args->do_pcap = true; - break; - case 'v': - args->verbose++; - break; - default: - usage(args, argv[0]); - exit(-1); - } - } - if (args->rf_rx_freq < 0 || args->rf_tx_freq < 0) { - usage(args, argv[0]); - exit(-1); - } -} - -// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message -uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity -} - -void setup_mac_phy_sib2(sib_type2_s* sib2, srsue::mac* mac, srsue::phy* phy) -{ - - // Apply RACH configuration - srsue::mac_interface_rrc::mac_cfg_t mac_cfg; - mac->get_config(&mac_cfg); - mac_cfg.rach = sib2->rr_cfg_common.rach_cfg_common; - mac->set_config(&mac_cfg); - - printf("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms, MaxTrials=%d\n", - sib2->rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.to_number(), - sib2->rr_cfg_common.rach_cfg_common.ra_supervision_info.ra_resp_win_size.to_number(), - sib2->rr_cfg_common.rach_cfg_common.ra_supervision_info.mac_contention_resolution_timer.to_number(), - sib2->rr_cfg_common.rach_cfg_common.ra_supervision_info.preamb_trans_max.to_number()); - - // Apply PHY RR Config Common - srsue::phy_interface_rrc::phy_cfg_common_t common; - common.pdsch_cnfg = sib2->rr_cfg_common.pdsch_cfg_common; - common.pusch_cnfg = sib2->rr_cfg_common.pusch_cfg_common; - common.pucch_cnfg = sib2->rr_cfg_common.pucch_cfg_common; - common.ul_pwr_ctrl = sib2->rr_cfg_common.ul_pwr_ctrl_common; - common.prach_cnfg = sib2->rr_cfg_common.prach_cfg; - common.srs_ul_cnfg = sib2->rr_cfg_common.srs_ul_cfg_common; - - phy->set_config_common(&common); - phy->configure_ul_params(); - - printf("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", - sib2->rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.pusch_hop_offset, - sib2->rr_cfg_common.pusch_cfg_common.ul_ref_sigs_pusch.group_assign_pusch, - sib2->rr_cfg_common.pusch_cfg_common.ul_ref_sigs_pusch.cyclic_shift, - sib2->rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.n_sb); - - printf("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", - sib2->rr_cfg_common.pucch_cfg_common.delta_pucch_shift.to_number(), - sib2->rr_cfg_common.pucch_cfg_common.n_cs_an, sib2->rr_cfg_common.pucch_cfg_common.n1_pucch_an, - sib2->rr_cfg_common.pucch_cfg_common.n_rb_cqi); - - printf("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", - sib2->rr_cfg_common.prach_cfg.root_seq_idx, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.high_speed_flag ? 1 : 0, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.zero_correlation_zone_cfg, - sib2->rr_cfg_common.prach_cfg.prach_cfg_info.prach_cfg_idx); - - if (sib2->rr_cfg_common.srs_ul_cfg_common.type() == srs_ul_cfg_common_c::types::setup) { - srs_ul_cfg_common_c::setup_s_* setup = &sib2->rr_cfg_common.srs_ul_cfg_common.setup(); - printf("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n", - setup->srs_bw_cfg.to_number(), setup->srs_sf_cfg.to_number(), setup->ack_nack_srs_simul_tx ? 1 : 0); - } -} - -void process_connsetup(rrc_conn_setup_s* msg, srsue::mac* mac, srsue::phy* phy) -{ - - // FIXME: There's an error parsing the connectionSetup message. This value is hard-coded: - - rr_cfg_ded_s* rr_ded = &msg->crit_exts.c1().rrc_conn_setup_r8().rr_cfg_ded; - if (rr_ded->phys_cfg_ded_present) { - phy->set_config_dedicated(&rr_ded->phys_cfg_ded); - printf("Set PHY configuration: SR-n_pucch=%d, SR-ConfigIndex=%d, SRS-ConfigIndex=%d, SRS-bw=%d, SRS-Nrcc=%d, " - "SRS-hop=%d, SRS-Ncs=%d\n", - rr_ded->phys_cfg_ded.sched_request_cfg.setup().sr_pucch_res_idx, - rr_ded->phys_cfg_ded.sched_request_cfg.setup().sr_cfg_idx, - rr_ded->phys_cfg_ded.srs_ul_cfg_ded.setup().srs_cfg_idx, - rr_ded->phys_cfg_ded.srs_ul_cfg_ded.setup().srs_bw.to_number(), - rr_ded->phys_cfg_ded.srs_ul_cfg_ded.setup().freq_domain_position, - rr_ded->phys_cfg_ded.srs_ul_cfg_ded.setup().srs_hop_bw.to_number(), - rr_ded->phys_cfg_ded.srs_ul_cfg_ded.setup().cyclic_shift.to_number()); - } - - srsue::mac_interface_rrc::mac_cfg_t mac_set; - mac->get_config(&mac_set); - mac_set.main = rr_ded->mac_main_cfg.explicit_value(); - // SR is a PHY config but is needed by SR procedure in 36.321 5.4.4 - mac_set.sr = rr_ded->phys_cfg_ded.sched_request_cfg; - mac->set_config(&mac_set); - - printf("Set MAC configuration: dsr-TransMAX: %d, harq-MaxReTX=%d, bsr-TimerReTX=%d, bsr-TimerPeriodic=%d\n", - rr_ded->phys_cfg_ded.sched_request_cfg.setup().dsr_trans_max.to_number(), - rr_ded->mac_main_cfg.explicit_value().ul_sch_cfg.max_harq_tx.to_number(), - rr_ded->mac_main_cfg.explicit_value().ul_sch_cfg.retx_bsr_timer.to_number(), - rr_ded->mac_main_cfg.explicit_value().ul_sch_cfg.periodic_bsr_timer.to_number()); - - phy->configure_ul_params(); - - // Setup radio bearers - for (uint32_t i = 0; i < rr_ded->srb_to_add_mod_list.size(); i++) { - if (rr_ded->srb_to_add_mod_list[i].lc_ch_cfg_present) { - printf("Setting up Default Configuration for SRB%d \n", rr_ded->srb_to_add_mod_list[i].srb_id); - switch (rr_ded->srb_to_add_mod_list[i].srb_id) { - case 1: - mac->setup_lcid(1, 0, 1, -1, -1); - break; - case 2: - mac->setup_lcid(2, 0, 3, -1, -1); - break; - } - } - } -// for (int i=0;irr_cnfg.drb_to_add_mod_list_size;i++) { -// printf("Setting up DRB%d\n", msg->rr_cnfg.drb_to_add_mod_list[i].drb_id); -// // todo -// } -} - - -// Hex bytes for the connection setup complete packet -// Got hex bytes from http://www.sharetechnote.com/html/RACH_LTE.html -uint8_t setupComplete_segm[2][41] ={ { - 0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04, - 0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0, - 0xe5, 0x60, 0x13, 0x81, 0x83}, - - {0xb0, 0x01, 0x01, 0x01, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80, - 0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62, - 0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00} -}; -uint8_t setupComplete[80] = { - 0x88, 0x00, 0x00, 0x20, 0x21, 0x90, 0xa0, 0x12, 0x00, 0x00, 0x80, 0xf0, 0x5e, 0x3b, 0xf1, 0x04, - 0x64, 0x04, 0x1d, 0x20, 0x44, 0x2f, 0xd8, 0x4b, 0xd1, 0x02, 0x00, 0x00, 0x83, 0x03, 0x41, 0xb0, - 0xe5, 0x60, 0x13, 0x81, 0x83, 0x48, 0x4b, 0xd1, 0x00, 0x7d, 0x21, 0x70, 0x28, 0x01, 0x5c, 0x08, 0x80, - 0x00, 0xc4, 0x0f, 0x97, 0x80, 0xd0, 0x4c, 0x4b, 0xd1, 0x00, 0xc0, 0x58, 0x44, 0x0d, 0x5d, 0x62, - 0x99, 0x74, 0x04, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00}; - -uint32_t lengths[2] = {37, 41}; -uint8_t reply[2] = {0x00, 0x04}; - - -srslte::radio_multi radio; -srsue::phy phy; -srsue::mac mac; -srslte::mac_pcap mac_pcap; - -prog_args_t prog_args; - -void sig_int_handler(int signo) -{ - if (prog_args.do_trace) { - //radio.write_trace("radio"); - phy.write_trace("phy"); - } - if (prog_args.do_pcap) { - mac_pcap.close(); - } - mac.stop(); - exit(0); -} - -class rlctest : public srsue::rlc_interface_mac { -public: - bool mib_decoded; - bool sib1_decoded; - bool sib2_decoded; - bool connsetup_decoded; - int nsegm_dcch; - int send_ack; - uint8_t si_window_len, sib2_period; - - rlctest() { - mib_decoded = false; - sib1_decoded = false; - sib2_decoded = false; - connsetup_decoded = false; - nsegm_dcch = 0; - si_window_len = 0; - sib2_period = 0; - send_ack = 0; - bzero(&bit_msg, sizeof(bit_msg)); - bzero(&byte_msg, sizeof(byte_msg)); - } - bool has_data(uint32_t lcid) { - return get_buffer_state(lcid); - } - uint32_t get_buffer_state(uint32_t lcid) { - if (lcid == 0) { - if (sib2_decoded && !connsetup_decoded) { - return 6; - } - } else if (lcid == 1) { - if (connsetup_decoded && nsegm_dcch < 2) { - return lengths[nsegm_dcch]; - } else if (send_ack == 1) { - return 2; - } - } - return 0; - } - - int read_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) - { - if (lcid == 0) { - ul_ccch_msg_s ul_ccch_msg; - // Prepare ConnectionRequest packet - ul_ccch_msg.msg.set(ul_ccch_msg_type_c::types::c1); - ul_ccch_msg.msg.c1().set(ul_ccch_msg_type_c::c1_c_::types::rrc_conn_request); - ul_ccch_msg.msg.c1().rrc_conn_request().crit_exts.set( - rrc_conn_request_s::crit_exts_c_::types::rrc_conn_request_r8); - ul_ccch_msg.msg.c1().rrc_conn_request().crit_exts.rrc_conn_request_r8().ue_id.set( - init_ue_id_c::types::random_value); - ul_ccch_msg.msg.c1().rrc_conn_request().crit_exts.rrc_conn_request_r8().ue_id.random_value().from_number(1000); - ul_ccch_msg.msg.c1().rrc_conn_request().crit_exts.rrc_conn_request_r8().establishment_cause = - establishment_cause_e::mo_sig; - - asn1::bit_ref bref(payload, nof_bytes); - - ul_ccch_msg.pack(bref); - uint32_t nbytes = (uint32_t)bref.distance_bytes(payload); - // assert(nbytes<1024); - - uint64_t uecri = 0; - uint8_t* ue_cri_ptr = (uint8_t*)&uecri; - uint8_t* ptr = bit_msg.msg; - for (uint32_t i=0;i= 80) { - printf("Sending Connection Setup Complete length 80\n"); - memcpy(payload, setupComplete, 80); - return 80; - } else { - uint32_t r = 0; - if (nof_bytes >= lengths[nsegm_dcch]) { - printf("Sending Connection Setup Complete %d/2 length %d\n", nsegm_dcch, lengths[nsegm_dcch]); - memcpy(payload, setupComplete_segm[nsegm_dcch], lengths[nsegm_dcch]); - r = lengths[nsegm_dcch]; - nsegm_dcch++; - } else { - r = 0; - } - return r; - } - } else if (send_ack == 1) { - printf("Send RLC ACK\n"); - memcpy(payload, reply, 2*sizeof(uint8_t)); - send_ack = 2; - return 2; - } - } - return 0; - } - - void write_pdu(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) { - if (lcid == 0) { - dl_ccch_msg_s dl_ccch_msg; - printf("ConnSetup received %d bytes\n", nof_bytes); - srslte_vec_fprint_byte(stdout, payload, nof_bytes); - - asn1::bit_ref bref(payload, nof_bytes); - dl_ccch_msg.unpack(bref); - - printf("Response: %s\n", dl_ccch_msg.msg.c1().type().to_string().c_str()); - switch (dl_ccch_msg.msg.c1().type().value) { - case dl_ccch_msg_type_c::c1_c_::types::rrc_conn_setup: - // Process ConnectionSetup - process_connsetup(&dl_ccch_msg.msg.c1().rrc_conn_setup(), &mac, &phy); - connsetup_decoded = true; - break; - case dl_ccch_msg_type_c::c1_c_::types::rrc_conn_reject: - case dl_ccch_msg_type_c::c1_c_::types::rrc_conn_reest: - case dl_ccch_msg_type_c::c1_c_::types::rrc_conn_reest_reject: - break; - } - } else if (lcid == 1) { - printf("Received on DCCH0 %d bytes\n", nof_bytes); - if (send_ack == 0) { - send_ack = 1; - } - } - } - - void write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes) - { - mib_s mib; - srslte_vec_fprint_byte(stdout, payload, nof_bytes); - - asn1::bit_ref bref(payload, nof_bytes); - mib.unpack(bref); - - printf("MIB received %d bytes, BW=%s MHz\n", nof_bytes, mib.dl_bw.to_string().c_str()); - mib_decoded = true; - } - - void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes) - { - bcch_dl_sch_msg_s dlsch_msg; - - asn1::bit_ref bref(payload, nof_bytes); - dlsch_msg.unpack(bref); - - if (dlsch_msg.msg.c1().type().value == bcch_dl_sch_msg_type_c::c1_c_::types::sib_type1) { - si_window_len = dlsch_msg.msg.c1().sib_type1().si_win_len.to_number(); - sib2_period = dlsch_msg.msg.c1().sib_type1().sched_info_list[0].si_periodicity.to_number(); - printf("SIB1 received %d bytes, CellID=%d, si_window=%d, sib2_period=%d\n", nof_bytes, - (uint32_t)dlsch_msg.msg.c1().sib_type1().cell_access_related_info.cell_id.to_number() & 0xfff, - si_window_len, sib2_period); - mac.clear_rntis(); - } else { - sys_info_r8_ies_s::sib_type_and_info_l_& sib_list = - dlsch_msg.msg.c1().sys_info().crit_exts.sys_info_r8().sib_type_and_info; - - if (sib_list.size() > 0 and sib_list[0].type() == sib_info_item_c::types::sib2) { - printf("SIB2 received %d bytes\n", nof_bytes); - setup_mac_phy_sib2(&sib_list[0].sib2(), &mac, &phy); - sib2_decoded = true; - mac.clear_rntis(); - } - } - } - - void write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) {} - void write_pdu_mch(uint32_t lcid, uint8_t *payload, uint32_t nof_bytes) {} - -private: - LIBLTE_BIT_MSG_STRUCT bit_msg; - LIBLTE_BYTE_MSG_STRUCT byte_msg; -}; - - -int main(int argc, char *argv[]) -{ - srslte::log_filter mac_log("MAC"); - rlctest my_rlc; - parse_args(&prog_args, argc, argv); - - // Capture SIGINT to write traces - if (prog_args.do_trace) { - signal(SIGINT, sig_int_handler); - //radio.start_trace(); - phy.start_trace(); - } - - if (prog_args.do_pcap) { - if (!prog_args.do_trace) { - signal(SIGINT, sig_int_handler); - } - mac_pcap.open("/tmp/ue_mac.pcap"); - mac.start_pcap(&mac_pcap); - } - - // Init Radio and PHY - if (!radio.init()) { - exit(1); - } - - std::vector phy_log; - - srslte::log_filter *mylog = new srslte::log_filter("PHY"); - char tmp[16]; - sprintf(tmp, "PHY%d",0); - phy_log.push_back(mylog); - - switch (prog_args.verbose) { - case 1: - mac_log.set_level(srslte::LOG_LEVEL_INFO); - mylog->set_level(srslte::LOG_LEVEL_INFO); - break; - case 2: - mac_log.set_level(srslte::LOG_LEVEL_DEBUG); - mylog->set_level(srslte::LOG_LEVEL_DEBUG); - break; - } - - phy.init(&radio, &mac, NULL, phy_log); - if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) { - radio.set_rx_gain(prog_args.rf_rx_gain); - radio.set_tx_gain(prog_args.rf_tx_gain); - } else { - radio.start_agc(false); - radio.set_tx_rx_gain_offset(10); - phy.set_agc_enable(true); - } - // Init MAC - mac.init(&phy, &my_rlc, NULL, &mac_log); - - // Set RX freq - radio.set_rx_freq(prog_args.rf_rx_freq); - radio.set_tx_freq(prog_args.rf_tx_freq); - - - while(1) { - uint32_t tti; - if (my_rlc.mib_decoded && mac.get_current_tti()) { - if (!my_rlc.sib1_decoded) { - usleep(10000); - tti = mac.get_current_tti(); - mac.bcch_start_rx(sib_start_tti(tti, 2, 5), 1); - } else if (!my_rlc.sib2_decoded) { - usleep(10000); - tti = mac.get_current_tti(); - mac.bcch_start_rx(sib_start_tti(tti, my_rlc.sib2_period, 0), my_rlc.si_window_len); - } - } - usleep(50000); - } -} - - - diff --git a/srsue/test/mac_test.cc b/srsue/test/mac_test.cc new file mode 100644 index 000000000..8707f8d19 --- /dev/null +++ b/srsue/test/mac_test.cc @@ -0,0 +1,186 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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/common/log_filter.h" +#include "srslte/interfaces/ue_interfaces.h" +#include "srsue/hdr/mac/mac.h" +#include +#include + +using namespace srsue; +using namespace srslte; + +#define TESTASSERT(cond) \ + { \ + if (!(cond)) { \ + std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \ + return SRSLTE_ERROR; \ + } \ + } + +namespace srslte { + +// fake classes +class rlc_dummy : public srsue::rlc_interface_mac +{ +public: + rlc_dummy(srslte::log_filter* log_) : received_bytes(0), log(log_) {} + bool has_data(const uint32_t lcid) { return false; } + uint32_t get_buffer_state(const uint32_t lcid) { return 10; } + int read_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) { return 0; }; + void write_pdu(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes) + { + log->debug_hex(payload, nof_bytes, "Received %d B on LCID %d\n", nof_bytes, lcid); + received_bytes += nof_bytes; + }; + void write_pdu_bcch_bch(uint8_t* payload, uint32_t nof_bytes){}; + void write_pdu_bcch_dlsch(uint8_t* payload, uint32_t nof_bytes){}; + void write_pdu_pcch(uint8_t* payload, uint32_t nof_bytes){}; + void write_pdu_mch(uint32_t lcid, uint8_t* payload, uint32_t nof_bytes){}; + uint32_t get_received_bytes() { return received_bytes; } + +private: + uint32_t received_bytes; + srslte::log_filter* log; +}; + +class phy_dummy : public phy_interface_mac +{ +public: + phy_dummy() : scell_cmd(0){}; + // phy_interface_mac + void configure_prach_params(){}; + virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm){}; + prach_info_t prach_get_info() + { + prach_info_t info = {}; + return info; + }; + void sr_send(){}; + int sr_last_tx_tti() { return 0; }; + void set_mch_period_stop(uint32_t stop){}; + + // phy_interface_mac_common + void set_crnti(uint16_t rnti){}; + void set_timeadv_rar(uint32_t ta_cmd){}; + void set_timeadv(uint32_t ta_cmd){}; + void set_activation_deactivation_scell(uint32_t cmd) { scell_cmd = cmd; }; + void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti){}; + uint32_t get_current_tti() { return 0; } + float get_phr() { return 0; }; + float get_pathloss_db() { return 0; }; + + // getter for test execution + uint32_t get_scell_cmd() { return scell_cmd; } + +private: + uint32_t scell_cmd; +}; + +class rrc_dummy : public rrc_interface_mac +{ +public: + void ho_ra_completed(bool ra_successful) { printf("%s\n", __FUNCTION__); } + void release_pucch_srs() { printf("%s\n", __FUNCTION__); } + void run_tti(uint32_t tti) { printf("%s\n", __FUNCTION__); } + void ra_problem() { printf("%s\n", __FUNCTION__); } +}; + +} // namespace srslte + +int mac_unpack_test() +{ + // This MAC PDU contains three subheaders + const uint32_t mac_header_len = 4; + // Subheader 1 is SCell Activation/Deactivation CE + // - 1 byte SDU payload 0x02 + const uint32_t mac_pdu1_len = 1; + // Subheader 2 is for LCID 1 + // - 2 bytes SDU payload 0x00 0x08 + const uint32_t mac_pdu2_len = 2; + // Subheader 3 is for LCID 3 (RLC AM PDU with 2 B header and 54 B data) + // - 56 bytes SDU payload 0x98 .. 0x89, 0x00, 0x00 + const uint32_t mac_pdu3_len = 56; + + uint8_t dl_sch_pdu[] = {0x3b, 0x21, 0x02, 0x03, 0x02, 0x00, 0x08, 0x98, 0x1b, 0x45, 0x00, 0x05, 0xda, + 0xc7, 0x23, 0x40, 0x00, 0x40, 0x11, 0xe6, 0x9b, 0xc0, 0xa8, 0x03, 0x01, 0xc0, + 0xa8, 0x03, 0x02, 0xd8, 0x29, 0x13, 0x89, 0x05, 0xc6, 0x2b, 0x73, 0x00, 0x0d, + 0xc3, 0xb3, 0x5c, 0xa3, 0x23, 0xad, 0x00, 0x03, 0x20, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x89, 0x00, 0x00}; + + srslte::log_filter rlc_log("RLC"); + srslte::log_filter mac_log("MAC"); + + mac_log.set_level(srslte::LOG_LEVEL_DEBUG); + mac_log.set_hex_limit(100000); + rlc_log.set_level(srslte::LOG_LEVEL_DEBUG); + rlc_log.set_hex_limit(100000); + + // dummy layers + phy_dummy phy; + rlc_dummy rlc(&rlc_log); + rrc_dummy rrc; + + // the actual MAC + mac mac; + mac.init(&phy, &rlc, &rrc, &mac_log); + + // create dummy DL action and grant and push MAC PDU + mac_interface_phy::tb_action_dl_t dl_action; + mac_interface_phy::mac_grant_dl_t mac_grant; + bzero(&dl_action, sizeof(dl_action)); + bzero(&mac_grant, sizeof(mac_grant)); + mac_grant.rnti = 0xbeaf; + mac_grant.tb[0].tbs = sizeof(dl_sch_pdu); + int cc_idx = 0; + + // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC + mac.new_grant_dl(cc_idx, mac_grant, &dl_action); + + // Copy PDU into provided buffer + bool dl_ack[SRSLTE_MAX_CODEWORDS] = {true, false}; + memcpy(dl_action.tb[0].payload, dl_sch_pdu, sizeof(dl_sch_pdu)); + dl_action.tb[0].enabled = true; + mac.tb_decoded(cc_idx, mac_grant, dl_ack); + + // make sure MAC PDU thread picks up before stopping + sleep(1); + mac.run_tti(0); + mac.stop(); + + // check length of both received RLC PDUs + TESTASSERT(rlc.get_received_bytes() == mac_pdu2_len + mac_pdu3_len); + + // check received SCell activation command + TESTASSERT(phy.get_scell_cmd() == 2); + + return SRSLTE_SUCCESS; +} + +int main(int argc, char** argv) +{ + if (mac_unpack_test()) { + printf("MAC PDU unpack test failed.\n"); + return -1; + } + + return 0; +} diff --git a/srsue/test/metrics_test.cc b/srsue/test/metrics_test.cc index 4a23a55cf..949fc4688 100644 --- a/srsue/test/metrics_test.cc +++ b/srsue/test/metrics_test.cc @@ -24,15 +24,16 @@ * */ +#include "srslte/common/metrics_hub.h" +#include "srslte/srslte.h" +#include "srsue/hdr/metrics_csv.h" +#include "srsue/hdr/metrics_stdout.h" +#include "srsue/hdr/ue_metrics_interface.h" #include #include #include #include #include -#include "srsue/hdr/ue_metrics_interface.h" -#include "srslte/common/metrics_hub.h" -#include "srsue/hdr/metrics_stdout.h" -#include "srsue/hdr/metrics_csv.h" using namespace srsue; @@ -49,8 +50,15 @@ public: // fill dummy values bzero(&m, sizeof(ue_metrics_t)); m.rf.rf_o = 10; - m.phy.dl.rsrp = -10.0; - m.phy.dl.pathloss = 74; + m.phy.nof_active_cc = 2; + m.phy.dl[0].rsrp = -10.0f; + m.phy.dl[0].pathloss = 74; + m.mac[0].rx_pkts = 100; + m.mac[0].rx_errors = 0; + + m.mac[1].rx_pkts = 100; + m.mac[1].rx_errors = 100; + return true; } diff --git a/srsue/test/phy/CMakeLists.txt b/srsue/test/phy/CMakeLists.txt deleted file mode 100644 index a0570f0e7..000000000 --- a/srsue/test/phy/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright 2013-2017 Software Radio Systems Limited -# -# This file is part of srsLTE -# -# 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/. -# - -#add_executable(ue_itf_test_sib1 ue_itf_test_sib1.cc) -#target_link_libraries(ue_itf_test_sib1 srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) - -#add_executable(ue_itf_test_prach ue_itf_test_prach.cc) -#target_link_libraries(ue_itf_test_prach srsue_phy srslte_common srslte_phy srslte_radio ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/srsue/test/phy/ue_itf_test_prach.cc b/srsue/test/phy/ue_itf_test_prach.cc deleted file mode 100644 index 9ae63d049..000000000 --- a/srsue/test/phy/ue_itf_test_prach.cc +++ /dev/null @@ -1,403 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include - -#include "srslte/phy/utils/debug.h" -#include "srsue/hdr/phy/phy.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srslte/common/log_filter.h" -#include "srslte/radio/radio_multi.h" - -/********************************************************************** - * Program arguments processing - ***********************************************************************/ -typedef struct { - float rf_rx_freq; - float rf_tx_freq; - float rf_rx_gain; - float rf_tx_gain; - bool continous; -}prog_args_t; - -prog_args_t prog_args; -uint32_t srsapps_verbose = 0; - -void args_default(prog_args_t *args) { - args->rf_rx_freq = -1.0; - args->rf_tx_freq = -1.0; - args->rf_rx_gain = -1; // set to autogain - args->rf_tx_gain = -1; - args->continous = false; -} - -void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [gGcv] -f rx_frequency -F tx_frequency (in Hz)\n", prog); - printf("\t-g RF RX gain [Default AGC]\n"); - printf("\t-G RF TX gain [Default same as RX gain (AGC)]\n"); - printf("\t-c Run continuously [Default only once]\n"); - printf("\t-v [increase verbosity, default none]\n"); -} - -void parse_args(prog_args_t *args, int argc, char **argv) { - int opt; - args_default(args); - while ((opt = getopt(argc, argv, "gGfFcv")) != -1) { - switch (opt) { - case 'g': - args->rf_rx_gain = atof(argv[optind]); - break; - case 'G': - args->rf_tx_gain = atof(argv[optind]); - break; - case 'f': - args->rf_rx_freq = atof(argv[optind]); - break; - case 'F': - args->rf_tx_freq = atof(argv[optind]); - break; - case 'c': - args->continous = true; - break; - case 'v': - srsapps_verbose++; - break; - default: - usage(args, argv[0]); - exit(-1); - } - } - if (args->rf_rx_freq < 0 || args->rf_tx_freq < 0) { - usage(args, argv[0]); - exit(-1); - } -} - - - -typedef enum{ - rar_header_type_bi = 0, - rar_header_type_rapid, - rar_header_type_n_items, -}rar_header_t; -static const char rar_header_text[rar_header_type_n_items][8] = {"BI", "RAPID"}; - -typedef struct { - rar_header_t hdr_type; - bool hopping_flag; - uint32_t tpc_command; - bool ul_delay; - bool csi_req; - uint16_t rba; - uint16_t timing_adv_cmd; - uint16_t temp_c_rnti; - uint8_t mcs; - uint8_t RAPID; - uint8_t BI; -}rar_msg_t; - - -int rar_unpack(uint8_t *buffer, rar_msg_t *msg) -{ - int ret = SRSLTE_ERROR; - uint8_t *ptr = buffer; - - if(buffer != NULL && - msg != NULL) - { - ptr++; - msg->hdr_type = (rar_header_t) *ptr++; - if(msg->hdr_type == rar_header_type_bi) { - ptr += 2; - msg->BI = srslte_bit_pack(&ptr, 4); - ret = SRSLTE_SUCCESS; - } else if (msg->hdr_type == rar_header_type_rapid) { - msg->RAPID = srslte_bit_pack(&ptr, 6); - ptr++; - - msg->timing_adv_cmd = srslte_bit_pack(&ptr, 11); - msg->hopping_flag = *ptr++; - msg->rba = srslte_bit_pack(&ptr, 10); - msg->mcs = srslte_bit_pack(&ptr, 4); - msg->tpc_command = srslte_bit_pack(&ptr, 3); - msg->ul_delay = *ptr++; - msg->csi_req = *ptr++; - msg->temp_c_rnti = srslte_bit_pack(&ptr, 16); - ret = SRSLTE_SUCCESS; - } - } - - return(ret); -} - - - -srsue::phy my_phy; -bool bch_decoded = false; - -uint8_t payload[SRSLTE_MAX_TB][10240]; -uint8_t payload_bits[SRSLTE_MAX_TB][10240]; -const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6, 0x00, 0x00, 0x00}; - -enum mac_state {RA, RAR, CONNREQUEST, CONNSETUP} state = RA; - -uint32_t preamble_idx = 0; -rar_msg_t rar_msg; - -uint32_t nof_rtx_connsetup = 0; -uint32_t rv_value[4] = {0, 2, 3, 1}; - -void config_phy() { - srsue::phy_interface_rrc::phy_cfg_t config; - - config.common.prach_cnfg.prach_cnfg_info.prach_config_index = 0; - config.common.prach_cnfg.prach_cnfg_info.prach_freq_offset = 0; - config.common.prach_cnfg.prach_cnfg_info.high_speed_flag = false; - config.common.prach_cnfg.root_sequence_index = 0; - config.common.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config = 11; - - config.common.pusch_cnfg.ul_rs.group_hopping_enabled = false; - config.common.pusch_cnfg.ul_rs.sequence_hopping_enabled = false; - config.common.pusch_cnfg.n_sb = 2; - config.common.pusch_cnfg.ul_rs.cyclic_shift = 0; - config.common.pusch_cnfg.ul_rs.group_assignment_pusch = 0; - config.common.pusch_cnfg.pusch_hopping_offset = 0; - - config.common.pucch_cnfg.delta_pucch_shift = LIBLTE_RRC_DELTA_PUCCH_SHIFT_DS2; - config.common.pucch_cnfg.n_cs_an = 0; - config.common.pucch_cnfg.n1_pucch_an = 1; - - my_phy.configure_ul_params(); - my_phy.configure_prach_params(); -} - -srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_TB]; -srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_TB]; - -uint16_t temp_c_rnti; - - -class rrc_dummy : public srsue::rrc_interface_phy -{ -public: - void in_sync() {}; - void out_of_sync() {}; -}; - -/******** MAC Interface implementation */ -class testmac : public srsue::mac_interface_phy -{ -public: - - testmac() { - rar_rnti_set = false; - } - - bool rar_rnti_set; - - void pch_decoded_ok(uint32_t len) {} - - - void tti_clock(uint32_t tti) { - if (!rar_rnti_set) { - int prach_tti = my_phy.prach_tx_tti(); - if (prach_tti > 0) { - my_phy.pdcch_dl_search(SRSLTE_RNTI_RAR, 1+prach_tti%10, prach_tti+3, prach_tti+13); - rar_rnti_set = true; - } - } - } - - void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) { - printf("New grant UL\n"); - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) { - memcpy(payload[tb], conn_request_msg, grant.n_bytes[tb]*sizeof(uint8_t)); - action->rv[tb] = rv_value[nof_rtx_connsetup%4]; - action->payload_ptr[tb] = payload[tb]; - if (action->rv[tb] == 0) { - srslte_softbuffer_tx_reset(&softbuffers_tx[tb]); - } - } - action->current_tx_nb = nof_rtx_connsetup; - action->softbuffers = softbuffers_tx; - action->rnti = temp_c_rnti; - action->expect_ack = (nof_rtx_connsetup < 5)?true:false; - memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - memcpy(&last_grant, &grant, sizeof(mac_grant_t)); - action->tx_enabled = true; - my_phy.pdcch_dl_search(SRSLTE_RNTI_USER, temp_c_rnti); - } - - void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) { - printf("New grant UL ACK\n"); - } - - void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) { - printf("harq recv hi=%d\n", ack?1:0); - if (!ack) { - nof_rtx_connsetup++; - action->current_tx_nb = nof_rtx_connsetup; - action->softbuffers = softbuffers_tx; - action->rnti = temp_c_rnti; - action->expect_ack = true; - memcpy(&action->phy_grant, &last_grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->tx_enabled = true; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) { - action->rv[tb] = rv_value[nof_rtx_connsetup%4]; - if (action->rv[tb] == 0) { - srslte_softbuffer_tx_reset(&softbuffers_tx[tb]); - } - printf("Retransmission %d (TB %d), rv=%d\n", nof_rtx_connsetup, tb, action->rv[tb]); - - } - } - } - - void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { - action->decode_enabled[0] = true; - action->default_ack[0] = false; - if (grant.rnti == 2) { - action->generate_ack = false; - } else { - action->generate_ack = true; - } - action->rnti = grant.rnti; - memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - memcpy(&last_grant, &grant, sizeof(mac_grant_t)); - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb ++) { - action->softbuffers[tb] = &softbuffers_rx[tb]; - action->rv[tb] = grant.rv[tb]; - action->payload_ptr[tb] = payload[tb]; - if (action->rv[tb] == 0) { - srslte_softbuffer_rx_reset(&softbuffers_rx[tb]); - } - } - } - - void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { - if (ack) { - if (rnti_type == SRSLTE_RNTI_RAR) { - my_phy.pdcch_dl_search_reset(); - srslte_bit_unpack_vector(payload[tb_idx], payload_bits[tb_idx], last_grant.n_bytes[tb_idx]*8); - rar_unpack(payload_bits[tb_idx], &rar_msg); - if (rar_msg.RAPID == preamble_idx) { - - printf("Received RAR at TTI: %d\n", last_grant.tti); - my_phy.set_timeadv_rar(rar_msg.timing_adv_cmd); - - temp_c_rnti = rar_msg.temp_c_rnti; - - if (last_grant.n_bytes[0]*8 > 20 + SRSLTE_RAR_GRANT_LEN) { - uint8_t rar_grant[SRSLTE_RAR_GRANT_LEN]; - memcpy(rar_grant, &payload_bits[20], sizeof(uint8_t)*SRSLTE_RAR_GRANT_LEN); - my_phy.set_rar_grant(last_grant.tti, rar_grant); - } - } else { - printf("Received RAR RAPID=%d\n", rar_msg.RAPID); - } - } else { - printf("Received Connection Setup\n"); - my_phy.pdcch_dl_search_reset(); - } - } - } - - void bch_decoded_ok(uint8_t *payload, uint32_t len) { - printf("BCH decoded\n"); - bch_decoded = true; - srslte_cell_t cell; - my_phy.get_current_cell(&cell); - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - srslte_softbuffer_rx_init(&softbuffers_rx[tb], cell.nof_prb); - srslte_softbuffer_tx_init(&softbuffers_tx[tb], cell.nof_prb); - } - } - -private: - mac_grant_t last_grant; -}; - - -testmac my_mac; -srslte::radio_multi radio; -rrc_dummy rrc_dummy; - -int main(int argc, char *argv[]) -{ - srslte::log_filter log("PHY"); - - parse_args(&prog_args, argc, argv); - - // Init Radio and PHY - radio.init(); - my_phy.init(&radio, &my_mac, &rrc_dummy, &log); - if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) { - radio.set_rx_gain(prog_args.rf_rx_gain); - radio.set_tx_gain(prog_args.rf_tx_gain); - } else { - radio.start_agc(false); - radio.set_tx_rx_gain_offset(10); - my_phy.set_agc_enable(true); - } - - if (srsapps_verbose == 1) { - log.set_level(srslte::LOG_LEVEL_INFO); - printf("Log level info\n"); - } - if (srsapps_verbose == 2) { - log.set_level(srslte::LOG_LEVEL_DEBUG); - printf("Log level debug\n"); - } - - // Give it time to create thread - sleep(1); - - // Set RX freq - radio.set_rx_freq(prog_args.rf_rx_freq); - radio.set_tx_freq(prog_args.rf_tx_freq); - - // Instruct the PHY to configure PRACH parameters and sync to current cell - while(!my_phy.cell_is_camping()) { - usleep(20000); - } - - // Setup PHY parameters - config_phy(); - - /* Instruct PHY to send PRACH and prepare it for receiving RAR */ - my_phy.prach_send(preamble_idx); - - /* go to idle and process each tti */ - bool running = true; - while(running) { - sleep(1); - } - my_phy.stop(); - radio.stop_rx(); -} - - - diff --git a/srsue/test/phy/ue_itf_test_sib1.cc b/srsue/test/phy/ue_itf_test_sib1.cc deleted file mode 100644 index bf1f9bbe7..000000000 --- a/srsue/test/phy/ue_itf_test_sib1.cc +++ /dev/null @@ -1,224 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include - -#include "srslte/phy/utils/debug.h" -#include "srsue/hdr/phy/phy.h" -#include "srslte/common/log_filter.h" -#include "srslte/interfaces/ue_interfaces.h" -#include "srslte/radio/radio_multi.h" - - -/********************************************************************** - * Program arguments processing - ***********************************************************************/ - -typedef struct { - float rf_freq; - float rf_gain; -}prog_args_t; - -uint32_t srsapps_verbose = 0; - -prog_args_t prog_args; - -void args_default(prog_args_t *args) { - args->rf_freq = -1.0; - args->rf_gain = -1.0; -} - -void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [gv] -f rx_frequency (in Hz)\n", prog); - printf("\t-g RF RX gain [Default AGC]\n"); - printf("\t-v [increase verbosity, default none]\n"); -} - -void parse_args(prog_args_t *args, int argc, char **argv) { - int opt; - args_default(args); - while ((opt = getopt(argc, argv, "gfv")) != -1) { - switch (opt) { - case 'g': - args->rf_gain = atof(argv[optind]); - break; - case 'f': - args->rf_freq = atof(argv[optind]); - break; - case 'v': - srsapps_verbose++; - break; - default: - usage(args, argv[0]); - exit(-1); - } - } - if (args->rf_freq < 0) { - usage(args, argv[0]); - exit(-1); - } -} - -srsue::phy my_phy; -bool bch_decoded = false; -uint32_t total_pkts=0; -uint32_t total_dci=0; -uint32_t total_oks=0; -uint8_t payload[SRSLTE_MAX_TB][1024]; -srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_TB]; - -class rrc_dummy : public srsue::rrc_interface_phy -{ -public: - void in_sync() {}; - void out_of_sync() {}; -}; - -/******** MAC Interface implementation */ -class testmac : public srsue::mac_interface_phy -{ -public: - void new_grant_ul(mac_grant_t grant, tb_action_ul_t *action) { - printf("New grant UL\n"); - } - void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action) { - printf("New grant UL ACK\n"); - } - - void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action) { - printf("harq recv\n"); - } - - void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { - total_dci++; - - - action->decode_enabled[0] = true; - action->default_ack[0] = false; - action->generate_ack = false; - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - action->payload_ptr[tb] = payload[tb]; - action->rv[tb] = ((uint32_t) ceilf((float) 3 * ((my_phy.tti_to_SFN(grant.tti) / 2) % 4) / 2)) % 4; - if (action->rv == 0) { - srslte_softbuffer_rx_reset(&softbuffers[tb]); - } - action->softbuffers[0] = &softbuffers[tb]; - } - memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - - action->rnti = grant.rnti; - } - - - - void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) { - if (ack) { - total_oks++; - } - } - - void pch_decoded_ok(uint32_t len) {} - - void bch_decoded_ok(uint8_t *payload, uint32_t len) { - printf("BCH decoded\n"); - bch_decoded = true; - srslte_cell_t cell; - my_phy.get_current_cell(&cell); - for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - srslte_softbuffer_rx_init(&softbuffers[tb], cell.nof_prb); - } - } - void tti_clock(uint32_t tti) { - - } -}; - - -testmac my_mac; -srslte::radio_multi radio; -rrc_dummy rrc_dummy; - - - -int main(int argc, char *argv[]) -{ - srslte::log_filter log("PHY"); - - parse_args(&prog_args, argc, argv); - - // Init Radio and PHY - radio.init(); - my_phy.init(&radio, &my_mac, &rrc_dummy, &log); - if (prog_args.rf_gain > 0) { - radio.set_rx_gain(prog_args.rf_gain); - } else { - radio.start_agc(false); - my_phy.set_agc_enable(true); - } - - if (srsapps_verbose == 1) { - log.set_level(srslte::LOG_LEVEL_INFO); - printf("Log level info\n"); - } - if (srsapps_verbose == 2) { - log.set_level(srslte::LOG_LEVEL_DEBUG); - printf("Log level debug\n"); - } - - // Give it time to create thread - sleep(1); - - // Set RX freq and gain - radio.set_rx_freq(prog_args.rf_freq); - - bool running = true; - while(running) { - if (bch_decoded && my_phy.cell_is_camping()) { - uint32_t tti = my_phy.get_current_tti(); - - // SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1 - tti = (((tti/20)*20) + 25)%10240; - my_phy.pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, tti, tti+1); - - total_pkts++; - } - usleep(30000); - if (bch_decoded && my_phy.cell_is_camping() && total_pkts > 0) { - if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) { - float gain = prog_args.rf_gain; - if (gain < 0) { - gain = radio.get_rx_gain(); - } - printf("PDCCH BLER %.1f \%% PDSCH BLER %.1f \%% (total pkts: %5u) Gain: %.1f dB\r", - 100-(float) 100*total_dci/total_pkts, - (float) 100*(1 - total_oks/total_pkts), - total_pkts, gain); - } - } - } - my_phy.stop(); - radio.stop_rx(); -} diff --git a/srsue/test/upper/ip_test.cc b/srsue/test/upper/ip_test.cc deleted file mode 100644 index 553840926..000000000 --- a/srsue/test/upper/ip_test.cc +++ /dev/null @@ -1,648 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "srslte/phy/utils/debug.h" -#include "srsue/hdr/mac/mac.h" -#include "srsue/hdr/phy/phy.h" -#include "srslte/common/threads.h" -#include "srslte/common/common.h" -#include "srslte/common/buffer_pool.h" -#include "srslte/common/logger_file.h" -#include "srslte/common/log_filter.h" -#include "srslte/upper/rlc.h" -#include "srsue/hdr/upper/rrc.h" -#include "srslte/radio/radio_multi.h" - -#define START_TUNTAP -#define USE_RADIO -#define PRINT_GW 0 - -using namespace asn1::rrc; - -/********************************************************************** - * Program arguments processing - ***********************************************************************/ - -#define LCID 3 - -typedef struct { - float rx_freq; - float tx_freq; - float rx_gain; - float tx_gain; - int time_adv; - std::string ip_address; -}prog_args_t; - -uint32_t srsapps_verbose = 1; - -prog_args_t prog_args; - -void args_default(prog_args_t *args) { - args->tx_freq = 2.505e9; - args->rx_freq = 2.625e9; - args->rx_gain = 50.0; - args->tx_gain = 70.0; - args->time_adv = -1; // calibrated for b210 - args->ip_address = "192.168.3.2"; -} - -void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [gGIrfFtv]\n", prog); - printf("\t-f RX frequency [Default %.1f MHz]\n", args->rx_freq/1e6); - printf("\t-F TX frequency [Default %.1f MHz]\n", args->tx_freq/1e6); - printf("\t-g RX gain [Default %.1f]\n", args->rx_gain); - printf("\t-G TX gain [Default %.1f]\n", args->tx_gain); - printf("\t-I IP address [Default %s]\n", args->ip_address.c_str()); - printf("\t-t time advance (in samples) [Default %d]\n", args->time_adv); - printf("\t-v [increase verbosity, default none]\n"); -} - -void parse_args(prog_args_t *args, int argc, char **argv) { - int opt; - args_default(args); - while ((opt = getopt(argc, argv, "gGfFItv")) != -1) { - switch (opt) { - case 'g': - args->rx_gain = atof(argv[optind]); - break; - case 'G': - args->tx_gain = atof(argv[optind]); - break; - case 'f': - args->rx_freq = atof(argv[optind]); - break; - case 'F': - args->tx_freq = atof(argv[optind]); - break; - case 'I': - args->ip_address = argv[optind]; - break; - case 't': - args->time_adv = atoi(argv[optind]); - break; - case 'v': - srsapps_verbose++; - break; - default: - usage(args, argv[0]); - exit(-1); - } - } - if (args->rx_freq < 0 || args->tx_freq < 0) { - usage(args, argv[0]); - exit(-1); - } -} - -int setup_if_addr(char *ip_addr); - -// Define dummy RLC always transmitts -class tester : public srsue::pdcp_interface_rlc, - public srsue::rrc_interface_rlc, - public srsue::rrc_interface_phy, - public srsue::rrc_interface_mac, - public srsue::ue_interface, - public thread -{ -public: - - tester() { - state = srsue::RRC_STATE_SIB1_SEARCH; - read_enable = true; - } - - void init(srsue::phy *phy_, srsue::mac *mac_, srslte::rlc *rlc_, srslte::log *log_h_, std::string ip_address) { - log_h = log_h_; - rlc = rlc_; - mac = mac_; - phy = phy_; - -#ifdef START_TUNTAP - if (init_tuntap((char*) ip_address.c_str())) { - log_h->error("Initiating IP address\n"); - } -#endif - - pool = srslte::byte_buffer_pool::get_instance(); - - // Start reader thread - running=true; - start(); - - } - - - void sib_search() - { - bool searching = true; - uint32_t tti ; - uint32_t si_win_start, si_win_len; - uint16_t period; - uint32_t nof_sib1_trials = 0; - const int SIB1_SEARCH_TIMEOUT = 30; - - while(searching) - { - switch(state) - { - case srsue::RRC_STATE_SIB1_SEARCH: - // Instruct MAC to look for SIB1 - while(!phy->status_is_sync()){ - usleep(50000); - } - usleep(10000); - tti = mac->get_current_tti(); - si_win_start = sib_start_tti(tti, 2, 5); - mac->bcch_start_rx(si_win_start, 1); - log_h->info("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", - si_win_start, 1); - nof_sib1_trials++; - if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { - log_h->info("Timeout while searching for SIB1. Resynchronizing SFN...\n"); - log_h->console("Timeout while searching for SIB1. Resynchronizing SFN...\n"); - phy->resync_sfn(); - nof_sib1_trials = 0; - } - break; - case srsue::RRC_STATE_SIB2_SEARCH: - // Instruct MAC to look for SIB2 - usleep(10000); - tti = mac->get_current_tti(); - period = sib1.sched_info[0].si_periodicity.to_number(); - si_win_start = sib_start_tti(tti, period, 0); - si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length]; - - mac->bcch_start_rx(si_win_start, si_win_len); - log_h->info("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", - si_win_start, si_win_len); - - break; - default: - searching = false; - break; - } - usleep(100000); - } - } - - bool is_sib_received() { - return state == srsue::RRC_STATE_WAIT_FOR_CON_SETUP; - } - - - void release_pucch_srs() {} - void ra_problem() {} - void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) {} - void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu) - { - log_h->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); - log_h->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); - LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8); - bit_buf.N_bits = pdu->N_bytes*8; - pool->deallocate(pdu); - liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg); - - if (dlsch_msg.N_sibs > 0) { - if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB1_SEARCH == state) { - // Handle SIB1 - memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); - log_h->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", - sib1.cell_id&0xfff, - liblte_rrc_si_window_length_num[sib1.si_window_length], - liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]); - std::stringstream ss; - for(uint32_t i=0;iconsole("SIB1 received, CellID=%d, %s\n", - sib1.cell_id&0xfff, - ss.str().c_str()); - - state = srsue::RRC_STATE_SIB2_SEARCH; - mac->bcch_stop_rx(); - //TODO: Use all SIB1 info - - } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB2_SEARCH == state) { - // Handle SIB2 - memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - log_h->console("SIB2 received\n"); - log_h->info("SIB2 received\n"); - state = srsue::RRC_STATE_WAIT_FOR_CON_SETUP; - mac->bcch_stop_rx(); - apply_sib2_configs(); - - srslte::byte_buffer_t *sdu = pool_allocate; - assert(sdu); - - // Send Msg3 - sdu->N_bytes = 10; - for (uint32_t i=0;iN_bytes;i++) { - sdu->msg[i] = i+1; - } - uint64_t uecri = 0; - uint8_t *ue_cri_ptr = (uint8_t*) &uecri; - uint32_t nbytes = 6; - for (uint32_t i=0;imsg[i]; - } - log_h->info("Setting UE contention resolution ID: %d\n", uecri); - mac->set_contention_id(uecri); - - rlc->write_sdu(0, sdu); - - } - } - } - void write_pdu_pcch(srslte::byte_buffer_t *sdu) {} - void max_retx_attempted(){} - std::string get_rb_name(uint32_t lcid) { return std::string("rb"); } - void in_sync() {}; - void out_of_sync() {}; - - void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu) - { - uint32_t n=0; - switch(lcid) { - case LCID: - n = write(tun_fd, sdu->msg, sdu->N_bytes); - if (n != sdu->N_bytes) { - log_h->error("TUN/TAP write failure n=%d, nof_bytes=%d\n", n, sdu->N_bytes); - return; - } - log_h->debug_hex(sdu->msg, sdu->N_bytes, - "Wrote %d bytes to TUN/TAP\n", - sdu->N_bytes); - pool->deallocate(sdu); - break; - case 0: - log_h->info("Received ConnectionSetupComplete\n"); - - // Setup a single UM bearer - LIBLTE_RRC_RLC_CONFIG_STRUCT cfg; - bzero(&cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT)); - cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI; - cfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS100; - cfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; - cfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10; - rlc->add_bearer(LCID, &cfg); - - mac->setup_lcid(LCID, 0, 1, -1, 100000); - - LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; - bzero(&dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); - dedicated.pusch_cnfg_ded.beta_offset_ack_idx = 5; - dedicated.pusch_cnfg_ded.beta_offset_ri_idx = 12; - dedicated.pusch_cnfg_ded.beta_offset_cqi_idx = 15; - dedicated.pusch_cnfg_ded_present = true; - dedicated.sched_request_cnfg.dsr_trans_max = LIBLTE_RRC_DSR_TRANS_MAX_N4; - dedicated.sched_request_cnfg.sr_pucch_resource_idx = 0; - dedicated.sched_request_cnfg.sr_cnfg_idx = 35; - dedicated.sched_request_cnfg.setup_present = true; - dedicated.sched_request_cnfg_present = true; - phy->set_config_dedicated(&dedicated); - phy->configure_ul_params(); - - srsue::mac_interface_rrc::mac_cfg_t mac_cfg; - mac->get_config(&mac_cfg); - memcpy(&mac_cfg.sr, &dedicated.sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT)); - mac_cfg.main.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_SF40; - mac->set_config(&mac_cfg); - - break; - default: - log_h->error("Received message for lcid=%d\n", lcid); - break; - } - } - -private: - int tun_fd; - bool running; - srslte::log *log_h; - srslte::byte_buffer_pool *pool; - srslte::rlc *rlc; - srsue::mac *mac; - srsue::phy *phy; - srslte::bit_buffer_t bit_buf; - srsue::rrc_state_t state; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; - LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; - bool read_enable; - - - // Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message - uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity - } - - int init_tuntap(char *ip_address) { - read_enable = true; - tun_fd = setup_if_addr(ip_address); - if (tun_fd<0) { - fprintf(stderr, "Error setting up IP %s\n", ip_address); - return -1; - } - - printf("Created tun/tap interface at IP %s\n", ip_address); - return 0; - } - - void run_thread() { - struct iphdr *ip_pkt; - uint32_t idx = 0; - int32_t N_bytes; - srslte::byte_buffer_t *pdu = pool_allocate; - - log_h->info("TUN/TAP reader thread running\n"); - - while(running) { - N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); - if(N_bytes > 0 && read_enable) - { - pdu->N_bytes = idx + N_bytes; - ip_pkt = (struct iphdr*)pdu->msg; - - log_h->debug_hex(pdu->msg, pdu->N_bytes, - "Read %d bytes from TUN/TAP\n", - N_bytes); - - // Check if entire packet was received - if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) - { - log_h->info_hex(pdu->msg, pdu->N_bytes, "UL PDU"); - - // Send PDU directly to PDCP - pdu->set_timestamp(); - rlc->write_sdu(LCID, pdu); - - pdu = pool_allocate; - idx = 0; - } else{ - idx += N_bytes; - } - }else{ - log_h->error("Failed to read from TUN interface - gw receive thread exiting.\n"); - break; - } - } - } - - - void apply_sib2_configs() - { - - // Apply RACH timeAlginmentTimer configuration - srsue::mac_interface_rrc::mac_cfg_t cfg; - mac->get_config(&cfg); - cfg.main.time_alignment_timer = sib2.time_alignment_timer; - memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT)); - cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index; - mac->set_config(&cfg); - - log_h->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n", - liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles], - liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size], - liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]); - - // Apply PHY RR Config Common - srsue::phy_interface_rrc::phy_cfg_common_t common; - memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT)); - memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT)); - memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT)); - memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT)); - memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT)); - if (sib2.rr_config_common_sib.srs_ul_cnfg.present) { - memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT)); - } else { - // default is release - common.srs_ul_cnfg.present = false; - } - phy->set_config_common(&common); - - phy->configure_ul_params(); - - log_h->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n", - sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset, - sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch, - sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift, - sib2.rr_config_common_sib.pusch_cnfg.n_sb); - - log_h->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n", - liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift], - sib2.rr_config_common_sib.pucch_cnfg.n_cs_an, - sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an, - sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi); - - log_h->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n", - sib2.rr_config_common_sib.prach_cnfg.root_sequence_index, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config, - sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index); - - log_h->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n", - sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg, - sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg, - sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx); - - } -}; - - - -// Create classes -srslte::logger_file logger; -srslte::log_filter log_phy; -srslte::log_filter log_mac; -srslte::log_filter log_rlc; -srslte::log_filter log_tester; -srslte::mac_pcap mac_pcap; -srsue::phy my_phy; -srsue::mac my_mac; -srslte::rlc rlc; -srslte::radio_multi my_radio; - -// Local classes for testing -tester my_tester; - - -bool running = true; - -void sig_int_handler(int signo) -{ - running = false; -} - -int main(int argc, char *argv[]) -{ - - parse_args(&prog_args, argc, argv); - - // set to null to disable pcap - const char *pcap_filename = "/tmp/ip_test.pcap"; - - logger.init("/tmp/ip_test_ue.log"); - log_phy.init("PHY ", &logger, true); - log_mac.init("MAC ", &logger, true); - log_rlc.init("RLC ", &logger); - log_tester.init("TEST", &logger); - logger.log("\n\n"); - - if (srsapps_verbose == 1) { - log_phy.set_level(srslte::LOG_LEVEL_INFO); - log_phy.set_hex_limit(100); - log_mac.set_level(srslte::LOG_LEVEL_DEBUG); - log_mac.set_hex_limit(100); - log_rlc.set_level(srslte::LOG_LEVEL_DEBUG); - log_rlc.set_hex_limit(1000); - log_tester.set_level(srslte::LOG_LEVEL_DEBUG); - log_tester.set_hex_limit(100); - printf("Log level info\n"); - } - if (srsapps_verbose == 2) { - log_phy.set_level(srslte::LOG_LEVEL_DEBUG); - log_phy.set_hex_limit(100); - log_mac.set_level(srslte::LOG_LEVEL_DEBUG); - log_mac.set_hex_limit(100); - log_rlc.set_level(srslte::LOG_LEVEL_DEBUG); - log_rlc.set_hex_limit(100); - log_tester.set_level(srslte::LOG_LEVEL_DEBUG); - log_tester.set_hex_limit(100); - srslte_verbose = SRSLTE_VERBOSE_DEBUG; - printf("Log level debug\n"); - } - - // Init Radio and PHY -#ifdef USE_RADIO - my_radio.init(); -#else - my_radio.init(NULL, "dummy"); -#endif - - my_radio.set_tx_freq(prog_args.tx_freq); - my_radio.set_tx_gain(prog_args.tx_gain); - my_radio.set_rx_freq(prog_args.rx_freq); - my_radio.set_rx_gain(prog_args.rx_gain); - if (prog_args.time_adv >= 0) { - printf("Setting TA=%d samples\n",prog_args.time_adv); - my_radio.set_tx_adv(prog_args.time_adv); - } - - my_phy.init(&my_radio, &my_mac, &my_tester, &log_phy, NULL); - my_mac.init(&my_phy, &rlc, &my_tester, &log_mac); - rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac, 0 /* SRB0 */); - my_tester.init(&my_phy, &my_mac, &rlc, &log_tester, prog_args.ip_address); - - - if (pcap_filename) { - mac_pcap.open(pcap_filename); - my_mac.start_pcap(&mac_pcap); - signal(SIGINT, sig_int_handler); - } - - // Set MAC defaults - mac_main_cfg_s default_cfg; - bzero(&default_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT)); - default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5; - default_cfg.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY; - default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560; - default_cfg.ulsch_cnfg.tti_bundling = false; - default_cfg.drx_cnfg.setup_present = false; - default_cfg.phr_cnfg.setup_present = false; - default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY; - my_mac.set_config_main(&default_cfg); - - while(running) { - if (my_tester.is_sib_received()) { - printf("Main running\n"); - sleep(1); - } else { - my_tester.sib_search(); - } - } - - if (pcap_filename) { - mac_pcap.close(); - } - - my_phy.stop(); - my_mac.stop(); -} - - - - -/******************* This is copied from srsue gw **********************/ -int setup_if_addr(char *ip_addr) -{ - - char *dev = (char*) "tun_srsue"; - - // Construct the TUN device - int tun_fd = open("/dev/net/tun", O_RDWR); - if(0 > tun_fd) - { - perror("open"); - return(-1); - } - - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); - if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) - { - perror("ioctl"); - return -1; - } - - // Bring up the interface - int sock = socket(AF_INET, SOCK_DGRAM, 0); - if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) - { - perror("socket"); - return -1; - } - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) - { - perror("ioctl"); - return -1; - } - - // Setup the IP address - sock = socket(AF_INET, SOCK_DGRAM, 0); - ifr.ifr_addr.sa_family = AF_INET; - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = inet_addr(ip_addr); - if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) - { - perror("ioctl"); - return -1; - } - ifr.ifr_netmask.sa_family = AF_INET; - ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); - if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) - { - perror("ioctl"); - return -1; - } - - return(tun_fd); -} diff --git a/srsue/test/upper/pcsc_usim_test.cc b/srsue/test/upper/pcsc_usim_test.cc index b28b5e749..825e6a497 100644 --- a/srsue/test/upper/pcsc_usim_test.cc +++ b/srsue/test/upper/pcsc_usim_test.cc @@ -24,11 +24,11 @@ * */ +#include #include + #include "srsue/hdr/upper/pcsc_usim.h" #include "srslte/common/log_filter.h" -#include -#include using namespace srsue; using namespace std; diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index f4bfe10f2..f04e4205d 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -3,7 +3,7 @@ ##################################################################### # RF configuration # -# dl_earfcn: Downlink EARFCN code list 3400,2100,... +# dl_earfcn: Downlink EARFCN code. # freq_offset: Uplink and Downlink optional frequency offset (in Hz) # tx_gain: Transmit gain (dB). # rx_gain: Optional receive gain (dB). If disabled, AGC if enabled @@ -11,11 +11,15 @@ # Optional parameters: # dl_freq: Override DL frequency corresponding to dl_earfcn # ul_freq: Override UL frequency corresponding to dl_earfcn -# nof_rx_ant: Number of RX antennas (Default 1, supported 1 or 2) +# nof_radios: Number of available RF devices +# nof_rf_channels: Number of RF channels per radio +# nof_rx_ant: Number of RX antennas per channel # device_name: Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" # device_args: Arguments for the device driver. Options are "auto" or any string. # Default for UHD: "recv_frame_size=9232,send_frame_size=9232" # Default for bladeRF: "" +# device_args_2: Arguments for the RF device driver 2. +# device_args_3: Arguments for the RF device driver 3. # time_adv_nsamples: Transmission time advance (in number of samples) to compensate for RF delay # from antenna to timestamp insertion. # Default "auto". B210 USRP: 100 samples, bladeRF: 27. @@ -30,9 +34,12 @@ freq_offset = 0 tx_gain = 80 #rx_gain = 40 +#nof_radios = 1 #nof_rx_ant = 1 #device_name = auto #device_args = auto +#device_args_2 = auto +#device_args_3 = auto #time_adv_nsamples = auto #burst_preamble_us = auto #continuous_tx = auto @@ -109,11 +116,13 @@ imei = 353490069873319 # RRC configuration # # ue_category: Sets UE category (range 1-5). Default: 4 +# release: UE Release (8 to 10) # feature_group: Hex value of the featureGroupIndicators field in the # UECapabilityInformation message. Default 0xe6041000 ##################################################################### [rrc] #ue_category = 4 +#release = 8 #feature_group = 0xe6041000 ##################################################################### @@ -159,8 +168,6 @@ enable = false # refs: use difference between noise references and noiseless (after filtering) # empty: use empty subcarriers in the boarder of pss/sss signal # pdsch_max_its: Maximum number of turbo decoder iterations (Default 4) -# attach_enable_64qam: Enables PUSCH 64QAM modulation before attachment (Necessary for old -# Amarisoft LTE 100 eNodeB, disabled by default) # nof_phy_threads: Selects the number of PHY threads (maximum 4, minimum 1, default 2) # equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any # non-negative real number to indicate a regularized zf coefficient. @@ -178,10 +185,11 @@ enable = false # estimator_fil_order: Sets the channel estimator smooth gaussian filter order (even values perform better). # The taps are [w, 1-2w, w] # +# snr_to_cqi_offset: Sets an offset in the SNR to CQI table. This is used to adjust the reported CQI. +# # pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. # -# average_subframe_enabled: Averages in the time domain the channel estimates within 1 subframe. -# Needs accurate CFO correction. +# interpolate_subframe_enabled: Interpolates in the time domain the channel estimates within 1 subframe. Default is to average. # # sic_pss_enabled: Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. # Must be disabled if cells have identical channel and timing, for instance if generated from @@ -228,8 +236,7 @@ enable = false #snr_ema_coeff = 0.1 #snr_estim_alg = refs #pdsch_max_its = 8 # These are half iterations -#attach_enable_64qam = false -#nof_phy_threads = 2 +#nof_phy_threads = 3 #equalizer_mode = mmse #time_correct_period = 5 #sfo_correct_disable = false @@ -239,7 +246,8 @@ enable = false #estimator_fil_auto = false #estimator_fil_stddev = 1.0 #estimator_fil_order = 4 -#average_subframe_enabled = true +#snr_to_cqi_offset = 0.0 +#interpolate_subframe_enabled = false #sic_pss_enabled = true #pregenerate_signals = false #metrics_csv_enable = false