diff --git a/lib/examples/pssch_ue.c b/lib/examples/pssch_ue.c index 0f1b36730..1547d4a45 100644 --- a/lib/examples/pssch_ue.c +++ b/lib/examples/pssch_ue.c @@ -32,6 +32,8 @@ #include "srslte/phy/common/phy_common_sl.h" #include "srslte/phy/dft/ofdm.h" #include "srslte/phy/phch/pscch.h" +#include "srslte/phy/phch/pssch.h" +#include "srslte/phy/phch/ra_sl.h" #include "srslte/phy/phch/sci.h" #include "srslte/phy/rf/rf.h" #include "srslte/phy/ue/ue_sync.h" @@ -50,7 +52,8 @@ srslte_cell_sl_t cell_sl = {.nof_prb = 50, .tm = SRSLTE_SIDELINK_TM4, .c bool use_standard_lte_rates = false; bool disable_plots = false; -srslte_pscch_t pscch; // Defined global for plotting thread +static srslte_pscch_t pscch = {}; // Defined global for plotting thread +static srslte_pssch_t pssch = {}; #ifdef ENABLE_GUI #include "srsgui/srsgui.h" @@ -219,8 +222,8 @@ int main(int argc, char** argv) // SCI srslte_sci_t sci; srslte_sci_init(&sci, cell_sl, sl_comm_resource_pool); - uint8_t sci_rx[SRSLTE_SCI_MAX_LEN] = {}; - char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = {}; + uint8_t sci_rx[SRSLTE_SCI_MAX_LEN] = {}; + char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = {}; // init PSCCH object if (srslte_pscch_init(&pscch, SRSLTE_MAX_PRB) != SRSLTE_SUCCESS) { @@ -241,6 +244,22 @@ int main(int argc, char** argv) return SRSLTE_ERROR; } + if (srslte_pssch_init(&pssch, cell_sl, sl_comm_resource_pool) != SRSLTE_SUCCESS) { + ERROR("Error initializing PSSCH\n"); + return SRSLTE_ERROR; + } + + srslte_chest_sl_cfg_t pssch_chest_sl_cfg; + srslte_chest_sl_t pssch_chest; + if (srslte_chest_sl_init(&pssch_chest, SRSLTE_SIDELINK_PSSCH, cell_sl, sl_comm_resource_pool) != SRSLTE_SUCCESS) { + ERROR("Error in chest PSSCH init\n"); + return SRSLTE_ERROR; + } + + uint32_t num_decoded_tb = 0; + uint8_t tb[SRSLTE_SL_SCH_MAX_TB_LEN] = {}; + uint32_t pssch_sf_idx = 0; + srslte_ue_sync_t sync; if (srslte_ue_sync_init_multi_decim_mode( &sync, SRSLTE_MAX_PRB, false, srslte_rf_recv_wrapper, nof_rx_antennas, (void*)&rf, 1.0, SYNC_MODE_GNSS)) { @@ -289,6 +308,8 @@ int main(int argc, char** argv) ts_rx.frac_secs, srslte_ue_sync_get_sfn(&sync), srslte_ue_sync_get_sfidx(&sync)); + + pssch_sf_idx = (srslte_ue_sync_get_sfn(&sync) * 10) + srslte_ue_sync_get_sfidx(&sync); } // do FFT @@ -318,6 +339,47 @@ int main(int argc, char** argv) sem_post(&plot_sem); } #endif + + // Decode PSSCH + + uint32_t sub_channel_start_idx = 0; + uint32_t L_subCH = 0; + srslte_ra_sl_type0_from_riv( + sci.riv, sl_comm_resource_pool.num_sub_channel, &L_subCH, &sub_channel_start_idx); + + // 3GPP TS 36.213 Section 14.1.1.4C + uint32_t pssch_prb_start_idx = (sub_channel_idx * sl_comm_resource_pool.size_sub_channel) + + pscch.pscch_nof_prb + sl_comm_resource_pool.start_prb_sub_channel; + uint32_t nof_prb_pssch = ((L_subCH + sub_channel_idx) * sl_comm_resource_pool.size_sub_channel) - + pssch_prb_start_idx + sl_comm_resource_pool.start_prb_sub_channel; + + uint32_t N_x_id = 0; + for (int j = 0; j < SRSLTE_SCI_CRC_LEN; j++) { + N_x_id += pscch.sci_crc[j] * exp2(SRSLTE_SCI_CRC_LEN - 1 - j); + } + + uint32_t rv_idx = 0; + if (sci.retransmission == true) { + rv_idx = 1; + } + + // PSSCH Channel estimation + pssch_chest_sl_cfg.N_x_id = N_x_id; + pssch_chest_sl_cfg.sf_idx = pssch_sf_idx; + pssch_chest_sl_cfg.prb_start_idx = pssch_prb_start_idx; + pssch_chest_sl_cfg.nof_prb = nof_prb_pssch; + srslte_chest_sl_set_cfg(&pssch_chest, pssch_chest_sl_cfg); + srslte_chest_sl_ls_estimate_equalize(&pssch_chest, sf_buffer[0], equalized_sf_buffer); + + srslte_pssch_cfg_t pssch_cfg = { + pssch_prb_start_idx, nof_prb_pssch, N_x_id, sci.mcs_idx, rv_idx, pssch_sf_idx}; + if (srslte_pssch_set_cfg(&pssch, pssch_cfg) == SRSLTE_SUCCESS) { + if (srslte_pssch_decode(&pssch, equalized_sf_buffer, tb, SRSLTE_SL_SCH_MAX_TB_LEN) == SRSLTE_SUCCESS) { + srslte_vec_fprint_byte(stdout, tb, pssch.sl_sch_tb_len); + num_decoded_tb++; + printf("PSSCH num_decoded_tb: %d\n", num_decoded_tb); + } + } } } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -333,7 +395,7 @@ int main(int argc, char** argv) } } } - + pssch_sf_idx++; subframe_count++; } diff --git a/lib/include/srslte/phy/common/phy_common_sl.h b/lib/include/srslte/phy/common/phy_common_sl.h index 62cbc7bbf..f6370a6fc 100644 --- a/lib/include/srslte/phy/common/phy_common_sl.h +++ b/lib/include/srslte/phy/common/phy_common_sl.h @@ -57,6 +57,7 @@ typedef struct SRSLTE_API { srslte_cp_t cp; } srslte_cell_sl_t; +#define SRSLTE_SL_MAX_PERIOD_LENGTH 320 // SL-PeriodComm-r12 3GPP TS 36.331 Section 6.3.8 // SL-CommResourcePool: 3GPP TS 36.331 version 15.6.0 Release 15 Section 6.3.8 typedef struct SRSLTE_API { uint32_t period_length; @@ -65,10 +66,16 @@ typedef struct SRSLTE_API { uint32_t prb_start; uint32_t prb_end; + uint8_t pscch_sf_bitmap[SRSLTE_SL_MAX_PERIOD_LENGTH]; + uint8_t pssch_sf_bitmap[SRSLTE_SL_MAX_PERIOD_LENGTH]; + uint32_t size_sub_channel; // sizeSubchannel-r14 uint32_t num_sub_channel; // numSubchannel-r14 uint32_t start_prb_sub_channel; // startRB-Subchannel-r14 offset bool adjacency_pscch_pssch; // adjacencyPSCCH-PSSCH-r14 + + uint32_t sf_bitmap_tm34_len; + uint8_t sf_bitmap_tm34[SRSLTE_SL_MAX_PERIOD_LENGTH]; // sl_Subframe_r14: 3GPP 36.331 Section 6.3.8 } srslte_sl_comm_resource_pool_t; typedef enum SRSLTE_API { @@ -81,6 +88,10 @@ typedef enum SRSLTE_API { #define SRSLTE_SL_DUPLEX_MODE_FDD (1) #define SRSLTE_SL_DUPLEX_MODE_TDD (2) +#define SRSLTE_SLSS_SIDE_PEAK_OFFSET (0.005f) +#define SRSLTE_SLSS_SIDE_PEAK_THRESHOLD_HIGH (0.49f) // square(0.7), max 70% of main peak +#define SRSLTE_SLSS_SIDE_PEAK_THRESHOLD_LOW (0.09f) // square(0.3), min 30% of main peak + #define SRSLTE_PSBCH_NOF_PRB (6) #define SRSLTE_PSCCH_TM34_NOF_PRB (2) @@ -124,9 +135,11 @@ typedef enum SRSLTE_API { (SRSLTE_NRE * SRSLTE_PSCCH_TM34_NUM_DATA_SYMBOLS * SRSLTE_PSCCH_TM34_NOF_PRB * SRSLTE_PSCCH_QM) #define SRSLTE_PSCCH_MAX_CODED_BITS SRSLTE_MAX(SRSLTE_PSCCH_TM12_NOF_CODED_BITS, SRSLTE_PSCCH_TM34_NOF_CODED_BITS) +#define SRSLTE_PSSCH_MAX_QM 6 #define SRSLTE_PSSCH_CRC_LEN 24 #define SRSLTE_MAX_CODEWORD_LEN 168000 // 12 subcarriers * 100 PRB * 14 symbols * 10 bits, assuming 1024QAM #define SRSLTE_SL_SCH_MAX_TB_LEN 1000000 // Must be checked in 3GPP +#define SRSLTE_PSSCH_MAX_CODED_BITS (3 * SRSLTE_TCOD_MAX_LEN_CB + SRSLTE_TCOD_TOTALTAIL) #define SRSLTE_PSSCH_TM12_NUM_DATA_SYMBOLS (12) // PSSCH is in 12 OFDM symbols (but only 11 are tx'ed) #define SRSLTE_PSSCH_TM12_NUM_DMRS_SYMBOLS (2) // PSSCH has 2 DMRS symbols in TM1 and TM2 @@ -142,6 +155,14 @@ typedef enum SRSLTE_API { SRSLTE_API int srslte_sl_group_hopping_f_gh(uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME * 2], uint32_t N_x_id); #define SRSLTE_PSCCH_MAX_NUM_DATA_SYMBOLS (SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS) +SRSLTE_API bool srslte_slss_side_peak_pos_is_valid(uint32_t side_peak_pos, + uint32_t main_peak_pos, + uint32_t side_peak_delta_a, + uint32_t side_peak_delta_b); +SRSLTE_API bool srslte_slss_side_peak_value_is_valid(float side_peak_value, float threshold_low, float threshold_high); + +SRSLTE_API int srslte_sl_tm_to_cell_sl_tm_t(srslte_cell_sl_t* q, uint32_t tm); + SRSLTE_API int srslte_sl_get_num_symbols(srslte_sl_tm_t tm, srslte_cp_t cp); SRSLTE_API bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i, srslte_cp_t cp); SRSLTE_API bool srslte_pscch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i, srslte_cp_t cp); diff --git a/lib/include/srslte/phy/phch/pssch.h b/lib/include/srslte/phy/phch/pssch.h new file mode 100644 index 000000000..ee6cabf2c --- /dev/null +++ b/lib/include/srslte/phy/phch/pssch.h @@ -0,0 +1,128 @@ +/* + * Copyright 2013-2020 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_PSSCH_H +#define SRSLTE_PSSCH_H + +#include "srslte/phy/common/phy_common_sl.h" +#include "srslte/phy/dft/dft_precoding.h" +#include "srslte/phy/fec/crc.h" +#include "srslte/phy/fec/turbocoder.h" +#include "srslte/phy/fec/turbodecoder.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/scrambling/scrambling.h" + +/** + * \brief Physical Sidelink shared channel. + * + * Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3 + */ + +// Redundancy version +static const uint8_t srslte_pssch_rv[4] = {0, 2, 3, 1}; + +typedef struct SRSLTE_API { + uint32_t prb_start_idx; // PRB start idx to map RE from RIV + uint32_t nof_prb; // PSSCH nof_prbs, Length of continuous PRB to map RE (in the pool) from RIV + uint32_t N_x_id; + uint32_t mcs_idx; + uint32_t rv_idx; + uint32_t sf_idx; // PSSCH sf_idx +} srslte_pssch_cfg_t; + +typedef struct SRSLTE_API { + + srslte_cell_sl_t cell; + srslte_sl_comm_resource_pool_t sl_comm_resource_pool; + srslte_pssch_cfg_t pssch_cfg; + + srslte_cbsegm_t cb_segm; + + uint32_t G; + uint32_t E; + uint32_t Qm; + uint32_t nof_data_symbols; + uint32_t nof_tx_symbols; + + uint32_t nof_data_re; // Number of RE considered during the channel mapping + uint32_t nof_tx_re; // Number of RE actually transmitted over the air (without last OFDM symbol) + uint32_t sl_sch_tb_len; + uint32_t scfdma_symbols_len; + + // data + uint8_t* b; + + // crc + uint8_t* c_r; + uint8_t* c_r_bytes; + uint8_t* tb_crc_temp; + srslte_crc_t tb_crc; + uint8_t* cb_crc_temp; + srslte_crc_t cb_crc; + + // channel coding + uint8_t* d_r; + int16_t* d_r_16; + srslte_tcod_t tcod; + srslte_tdec_t tdec; + + // rate matching + uint8_t* e_r; + int16_t* e_r_16; + uint8_t* buff_b; + + uint8_t* codeword; + uint8_t* codeword_bytes; + int16_t* llr; + + // interleaving + uint8_t* f; + uint8_t* f_bytes; + int16_t* f_16; + uint32_t* interleaver_lut; + + // scrambling + srslte_sequence_t scrambling_seq; + + // modulation + srslte_mod_t mod_idx; + srslte_modem_table_t mod[SRSLTE_MOD_NITEMS]; + cf_t* symbols; + uint8_t* bits_after_demod; + uint8_t* bytes_after_demod; + + // dft precoding + srslte_dft_precoding_t dft_precoder; + cf_t* scfdma_symbols; + srslte_dft_precoding_t idft_precoder; + +} srslte_pssch_t; + +SRSLTE_API int + srslte_pssch_init(srslte_pssch_t* q, srslte_cell_sl_t cell, srslte_sl_comm_resource_pool_t sl_comm_resource_pool); +SRSLTE_API int srslte_pssch_set_cfg(srslte_pssch_t* q, srslte_pssch_cfg_t pssch_cfg); +SRSLTE_API int srslte_pssch_encode(srslte_pssch_t* q, uint8_t* input, uint32_t input_len, cf_t* sf_buffer); +SRSLTE_API int srslte_pssch_decode(srslte_pssch_t* q, cf_t* equalized_sf_syms, uint8_t* output, uint32_t output_len); +SRSLTE_API int srslte_pssch_put(srslte_pssch_t* q, cf_t* sf_buffer, cf_t* symbols); +SRSLTE_API int srslte_pssch_get(srslte_pssch_t* q, cf_t* sf_buffer, cf_t* symbols); +SRSLTE_API void srslte_pssch_free(srslte_pssch_t* q); + +#endif // SRSLTE_PSSCH_H \ No newline at end of file diff --git a/lib/include/srslte/phy/phch/ra_sl.h b/lib/include/srslte/phy/phch/ra_sl.h new file mode 100644 index 000000000..48dcb1194 --- /dev/null +++ b/lib/include/srslte/phy/phch/ra_sl.h @@ -0,0 +1,145 @@ +/* + * Copyright 2013-2020 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_RA_SL_H +#define SRSLTE_RA_SL_H + +SRSLTE_API int srslte_sl_get_available_pool_prb(uint32_t prb_num, uint32_t prb_start, uint32_t prb_end); + +SRSLTE_API int srslte_pscch_resources(uint32_t prb_num, + uint32_t prb_start, + uint32_t prb_end, + uint8_t* pscch_sf_bitmap, + uint32_t period_length, + uint32_t n_pscch, + uint32_t* m_a, + uint32_t* l_b); + +SRSLTE_API uint32_t srslte_ra_sl_type0_to_riv(uint32_t nof_prb, uint32_t prb_start, uint32_t L_crb); +SRSLTE_API void srslte_ra_sl_type0_from_riv(uint32_t riv, uint32_t nof_prb, uint32_t* L_crb, uint32_t* prb_start); +SRSLTE_API int + srslte_ra_sl_pssch_allowed_sf(uint32_t pssch_sf_idx, uint32_t trp_idx, uint32_t duplex_mode, uint32_t tdd_config); +SRSLTE_API int srslte_sci_generate_trp_idx(uint32_t duplex_mode, uint32_t tdd_config, uint32_t k_TRP); + +// TS 36.213 table 14.1.1.1.1-3: Time Resource pattern Index mapping for N_TRP = 6 +static const uint8_t srslte_sl_N_TRP_6_k_1[] = {1, 2, 4, 8, 16, 32}; +static const uint8_t srslte_sl_N_TRP_6_k_2[] = {3, 5, 6, 9, 10, 12, 17, 18, 20, 24, 33, 34, 36, 40, 48}; +static const uint8_t srslte_sl_N_TRP_6_k_3[] = {7, 11, 13, 14, 19, 21, 22, 25, 26, 28, + 35, 37, 38, 41, 42, 44, 49, 50, 52, 56}; +static const uint8_t srslte_sl_N_TRP_6_k_4[] = {15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60}; +static const uint8_t srslte_sl_N_TRP_6_k_5[] = {31, 47, 55, 59, 61, 62}; +static const uint8_t srslte_sl_N_TRP_6_k_6[] = {63}; +static const uint8_t srslte_sl_N_TRP_6[][6] = { + {0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0}, + {1, 0, 1, 0, 0, 0}, {0, 1, 1, 0, 0, 0}, {1, 1, 1, 0, 0, 0}, {0, 0, 0, 1, 0, 0}, {1, 0, 0, 1, 0, 0}, + {0, 1, 0, 1, 0, 0}, {1, 1, 0, 1, 0, 0}, {0, 0, 1, 1, 0, 0}, {1, 0, 1, 1, 0, 0}, {0, 1, 1, 1, 0, 0}, + {1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 1, 0}, {1, 0, 0, 0, 1, 0}, {0, 1, 0, 0, 1, 0}, {1, 1, 0, 0, 1, 0}, + {0, 0, 1, 0, 1, 0}, {1, 0, 1, 0, 1, 0}, {0, 1, 1, 0, 1, 0}, {1, 1, 1, 0, 1, 0}, {0, 0, 0, 1, 1, 0}, + {1, 0, 0, 1, 1, 0}, {0, 1, 0, 1, 1, 0}, {1, 1, 0, 1, 1, 0}, {0, 0, 1, 1, 1, 0}, {1, 0, 1, 1, 1, 0}, + {0, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 1}, {0, 1, 0, 0, 0, 1}, + {1, 1, 0, 0, 0, 1}, {0, 0, 1, 0, 0, 1}, {1, 0, 1, 0, 0, 1}, {0, 1, 1, 0, 0, 1}, {1, 1, 1, 0, 0, 1}, + {0, 0, 0, 1, 0, 1}, {1, 0, 0, 1, 0, 1}, {0, 1, 0, 1, 0, 1}, {1, 1, 0, 1, 0, 1}, {0, 0, 1, 1, 0, 1}, + {1, 0, 1, 1, 0, 1}, {0, 1, 1, 1, 0, 1}, {1, 1, 1, 1, 0, 1}, {0, 0, 0, 0, 1, 1}, {1, 0, 0, 0, 1, 1}, + {0, 1, 0, 0, 1, 1}, {1, 1, 0, 0, 1, 1}, {0, 0, 1, 0, 1, 1}, {1, 0, 1, 0, 1, 1}, {0, 1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1, 1}, {0, 0, 0, 1, 1, 1}, {1, 0, 0, 1, 1, 1}, {0, 1, 0, 1, 1, 1}, {1, 1, 0, 1, 1, 1}, + {0, 0, 1, 1, 1, 1}, {1, 0, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}}; + +// TS 36.213 table 14.1.1.1.1-2: Time Resource pattern Index mapping for N_TRP = 7 +static const uint8_t srslte_sl_N_TRP_7_k_1[] = {1, 2, 4, 8, 16, 32, 64}; +static const uint8_t srslte_sl_N_TRP_7_k_2[] = {3, 5, 6, 9, 10, 12, 17, 18, 20, 24, 33, + 34, 36, 40, 48, 65, 66, 68, 72, 80, 96}; +static const uint8_t srslte_sl_N_TRP_7_k_3[] = {7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, + 38, 41, 42, 44, 49, 50, 52, 56, 67, 69, 70, 73, + 74, 76, 81, 82, 84, 88, 97, 98, 100, 104, 112}; +static const uint8_t srslte_sl_N_TRP_7_k_4[] = {15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, + 57, 58, 60, 71, 75, 77, 78, 83, 85, 86, 89, 90, + 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120}; +static const uint8_t srslte_sl_N_TRP_7_k_5[] = {31, 47, 55, 59, 61, 62, 79, 87, 91, 93, 94, + 103, 107, 109, 110, 115, 117, 118, 121, 122, 124}; +static const uint8_t srslte_sl_N_TRP_7_k_6[] = {63, 95, 111, 119, 123, 125, 126}; +static const uint8_t srslte_sl_N_TRP_7_k_7[] = {127}; +static const uint8_t srslte_sl_N_TRP_7[][7] = { + {0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0}, + {1, 0, 1, 0, 0, 0, 0}, {0, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0}, {1, 0, 0, 1, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0}, {1, 1, 0, 1, 0, 0, 0}, {0, 0, 1, 1, 0, 0, 0}, {1, 0, 1, 1, 0, 0, 0}, {0, 1, 1, 1, 0, 0, 0}, + {1, 1, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0}, {1, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 0, 1, 0, 0}, {1, 1, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 1, 0, 0}, {1, 0, 1, 0, 1, 0, 0}, {0, 1, 1, 0, 1, 0, 0}, {1, 1, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 1, 0, 0}, + {1, 0, 0, 1, 1, 0, 0}, {0, 1, 0, 1, 1, 0, 0}, {1, 1, 0, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 0, 0}, {1, 0, 1, 1, 1, 0, 0}, + {0, 1, 1, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 0, 1, 0}, {1, 0, 0, 0, 0, 1, 0}, {0, 1, 0, 0, 0, 1, 0}, + {1, 1, 0, 0, 0, 1, 0}, {0, 0, 1, 0, 0, 1, 0}, {1, 0, 1, 0, 0, 1, 0}, {0, 1, 1, 0, 0, 1, 0}, {1, 1, 1, 0, 0, 1, 0}, + {0, 0, 0, 1, 0, 1, 0}, {1, 0, 0, 1, 0, 1, 0}, {0, 1, 0, 1, 0, 1, 0}, {1, 1, 0, 1, 0, 1, 0}, {0, 0, 1, 1, 0, 1, 0}, + {1, 0, 1, 1, 0, 1, 0}, {0, 1, 1, 1, 0, 1, 0}, {1, 1, 1, 1, 0, 1, 0}, {0, 0, 0, 0, 1, 1, 0}, {1, 0, 0, 0, 1, 1, 0}, + {0, 1, 0, 0, 1, 1, 0}, {1, 1, 0, 0, 1, 1, 0}, {0, 0, 1, 0, 1, 1, 0}, {1, 0, 1, 0, 1, 1, 0}, {0, 1, 1, 0, 1, 1, 0}, + {1, 1, 1, 0, 1, 1, 0}, {0, 0, 0, 1, 1, 1, 0}, {1, 0, 0, 1, 1, 1, 0}, {0, 1, 0, 1, 1, 1, 0}, {1, 1, 0, 1, 1, 1, 0}, + {0, 0, 1, 1, 1, 1, 0}, {1, 0, 1, 1, 1, 1, 0}, {0, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0, 1}, + {1, 0, 0, 0, 0, 0, 1}, {0, 1, 0, 0, 0, 0, 1}, {1, 1, 0, 0, 0, 0, 1}, {0, 0, 1, 0, 0, 0, 1}, {1, 0, 1, 0, 0, 0, 1}, + {0, 1, 1, 0, 0, 0, 1}, {1, 1, 1, 0, 0, 0, 1}, {0, 0, 0, 1, 0, 0, 1}, {1, 0, 0, 1, 0, 0, 1}, {0, 1, 0, 1, 0, 0, 1}, + {1, 1, 0, 1, 0, 0, 1}, {0, 0, 1, 1, 0, 0, 1}, {1, 0, 1, 1, 0, 0, 1}, {0, 1, 1, 1, 0, 0, 1}, {1, 1, 1, 1, 0, 0, 1}, + {0, 0, 0, 0, 1, 0, 1}, {1, 0, 0, 0, 1, 0, 1}, {0, 1, 0, 0, 1, 0, 1}, {1, 1, 0, 0, 1, 0, 1}, {0, 0, 1, 0, 1, 0, 1}, + {1, 0, 1, 0, 1, 0, 1}, {0, 1, 1, 0, 1, 0, 1}, {1, 1, 1, 0, 1, 0, 1}, {0, 0, 0, 1, 1, 0, 1}, {1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 1, 1, 0, 1}, {1, 1, 0, 1, 1, 0, 1}, {0, 0, 1, 1, 1, 0, 1}, {1, 0, 1, 1, 1, 0, 1}, {0, 1, 1, 1, 1, 0, 1}, + {1, 1, 1, 1, 1, 0, 1}, {0, 0, 0, 0, 0, 1, 1}, {1, 0, 0, 0, 0, 1, 1}, {0, 1, 0, 0, 0, 1, 1}, {1, 1, 0, 0, 0, 1, 1}, + {0, 0, 1, 0, 0, 1, 1}, {1, 0, 1, 0, 0, 1, 1}, {0, 1, 1, 0, 0, 1, 1}, {1, 1, 1, 0, 0, 1, 1}, {0, 0, 0, 1, 0, 1, 1}, + {1, 0, 0, 1, 0, 1, 1}, {0, 1, 0, 1, 0, 1, 1}, {1, 1, 0, 1, 0, 1, 1}, {0, 0, 1, 1, 0, 1, 1}, {1, 0, 1, 1, 0, 1, 1}, + {0, 1, 1, 1, 0, 1, 1}, {1, 1, 1, 1, 0, 1, 1}, {0, 0, 0, 0, 1, 1, 1}, {1, 0, 0, 0, 1, 1, 1}, {0, 1, 0, 0, 1, 1, 1}, + {1, 1, 0, 0, 1, 1, 1}, {0, 0, 1, 0, 1, 1, 1}, {1, 0, 1, 0, 1, 1, 1}, {0, 1, 1, 0, 1, 1, 1}, {1, 1, 1, 0, 1, 1, 1}, + {0, 0, 0, 1, 1, 1, 1}, {1, 0, 0, 1, 1, 1, 1}, {0, 1, 0, 1, 1, 1, 1}, {1, 1, 0, 1, 1, 1, 1}, {0, 0, 1, 1, 1, 1, 1}, + {1, 0, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1}}; + +// TS 36.213 table 14.1.1.1.1-1: Time Resource pattern Index mapping for N_TRP = 8 +static const uint8_t srslte_sl_N_TRP_8_k_1[] = {0, 1, 2, 3, 4, 5, 6, 7}; +static const uint8_t srslte_sl_N_TRP_8_k_2[] = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; +static const uint8_t srslte_sl_N_TRP_8_k_4[] = { + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105}; +static const uint8_t srslte_sl_N_TRP_8_k_8[] = {106}; +static const uint8_t srslte_sl_N_TRP_8[][8] = { + {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 1}, + {1, 1, 0, 0, 0, 0, 0, 0}, {1, 0, 1, 0, 0, 0, 0, 0}, {0, 1, 1, 0, 0, 0, 0, 0}, {1, 0, 0, 1, 0, 0, 0, 0}, + {0, 1, 0, 1, 0, 0, 0, 0}, {0, 0, 1, 1, 0, 0, 0, 0}, {1, 0, 0, 0, 1, 0, 0, 0}, {0, 1, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 1, 0, 0, 0}, {0, 0, 0, 1, 1, 0, 0, 0}, {1, 0, 0, 0, 0, 1, 0, 0}, {0, 1, 0, 0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0, 1, 0, 0}, {0, 0, 0, 1, 0, 1, 0, 0}, {0, 0, 0, 0, 1, 1, 0, 0}, {1, 0, 0, 0, 0, 0, 1, 0}, + {0, 1, 0, 0, 0, 0, 1, 0}, {0, 0, 1, 0, 0, 0, 1, 0}, {0, 0, 0, 1, 0, 0, 1, 0}, {0, 0, 0, 0, 1, 0, 1, 0}, + {0, 0, 0, 0, 0, 1, 1, 0}, {1, 0, 0, 0, 0, 0, 0, 1}, {0, 1, 0, 0, 0, 0, 0, 1}, {0, 0, 1, 0, 0, 0, 0, 1}, + {0, 0, 0, 1, 0, 0, 0, 1}, {0, 0, 0, 0, 1, 0, 0, 1}, {0, 0, 0, 0, 0, 1, 0, 1}, {0, 0, 0, 0, 0, 0, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 0}, {1, 1, 1, 0, 1, 0, 0, 0}, {1, 1, 0, 1, 1, 0, 0, 0}, {1, 0, 1, 1, 1, 0, 0, 0}, + {0, 1, 1, 1, 1, 0, 0, 0}, {1, 1, 1, 0, 0, 1, 0, 0}, {1, 1, 0, 1, 0, 1, 0, 0}, {1, 0, 1, 1, 0, 1, 0, 0}, + {0, 1, 1, 1, 0, 1, 0, 0}, {1, 1, 0, 0, 1, 1, 0, 0}, {1, 0, 1, 0, 1, 1, 0, 0}, {0, 1, 1, 0, 1, 1, 0, 0}, + {1, 0, 0, 1, 1, 1, 0, 0}, {0, 1, 0, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 0, 0}, {1, 1, 1, 0, 0, 0, 1, 0}, + {1, 1, 0, 1, 0, 0, 1, 0}, {1, 0, 1, 1, 0, 0, 1, 0}, {0, 1, 1, 1, 0, 0, 1, 0}, {1, 1, 0, 0, 1, 0, 1, 0}, + {1, 0, 1, 0, 1, 0, 1, 0}, {0, 1, 1, 0, 1, 0, 1, 0}, {1, 0, 0, 1, 1, 0, 1, 0}, {0, 1, 0, 1, 1, 0, 1, 0}, + {0, 0, 1, 1, 1, 0, 1, 0}, {1, 1, 0, 0, 0, 1, 1, 0}, {1, 0, 1, 0, 0, 1, 1, 0}, {0, 1, 1, 0, 0, 1, 1, 0}, + {1, 0, 0, 1, 0, 1, 1, 0}, {0, 1, 0, 1, 0, 1, 1, 0}, {0, 0, 1, 1, 0, 1, 1, 0}, {1, 0, 0, 0, 1, 1, 1, 0}, + {0, 1, 0, 0, 1, 1, 1, 0}, {0, 0, 1, 0, 1, 1, 1, 0}, {0, 0, 0, 1, 1, 1, 1, 0}, {1, 1, 1, 0, 0, 0, 0, 1}, + {1, 1, 0, 1, 0, 0, 0, 1}, {1, 0, 1, 1, 0, 0, 0, 1}, {0, 1, 1, 1, 0, 0, 0, 1}, {1, 1, 0, 0, 1, 0, 0, 1}, + {1, 0, 1, 0, 1, 0, 0, 1}, {0, 1, 1, 0, 1, 0, 0, 1}, {1, 0, 0, 1, 1, 0, 0, 1}, {0, 1, 0, 1, 1, 0, 0, 1}, + {0, 0, 1, 1, 1, 0, 0, 1}, {1, 1, 0, 0, 0, 1, 0, 1}, {1, 0, 1, 0, 0, 1, 0, 1}, {0, 1, 1, 0, 0, 1, 0, 1}, + {1, 0, 0, 1, 0, 1, 0, 1}, {0, 1, 0, 1, 0, 1, 0, 1}, {0, 0, 1, 1, 0, 1, 0, 1}, {1, 0, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 1, 1, 0, 1}, {0, 0, 1, 0, 1, 1, 0, 1}, {0, 0, 0, 1, 1, 1, 0, 1}, {1, 1, 0, 0, 0, 0, 1, 1}, + {1, 0, 1, 0, 0, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1, 1}, {1, 0, 0, 1, 0, 0, 1, 1}, {0, 1, 0, 1, 0, 0, 1, 1}, + {0, 0, 1, 1, 0, 0, 1, 1}, {1, 0, 0, 0, 1, 0, 1, 1}, {0, 1, 0, 0, 1, 0, 1, 1}, {0, 0, 1, 0, 1, 0, 1, 1}, + {0, 0, 0, 1, 1, 0, 1, 1}, {1, 0, 0, 0, 0, 1, 1, 1}, {0, 1, 0, 0, 0, 1, 1, 1}, {0, 0, 1, 0, 0, 1, 1, 1}, + {0, 0, 0, 1, 0, 1, 1, 1}, {0, 0, 0, 0, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1}}; + +#endif // SRSLTE_RA_SL_H diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index b55fef4ce..67e4e4f49 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -95,6 +95,8 @@ SRSLTE_API void* srslte_vec_realloc(void* ptr, uint32_t old_size, uint32_t new_s SRSLTE_API void srslte_vec_cf_zero(cf_t* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_f_zero(float* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_u8_zero(uint8_t* ptr, uint32_t nsamples); +SRSLTE_API void srslte_vec_i16_zero(int16_t* ptr, uint32_t nsamples); +SRSLTE_API void srslte_vec_u32_zero(uint32_t* ptr, uint32_t nsamples); /* Copy memory */ SRSLTE_API void srs_vec_cf_copy(cf_t* dst, const cf_t* src, uint32_t len); diff --git a/lib/src/phy/common/phy_common_sl.c b/lib/src/phy/common/phy_common_sl.c index f818eb418..929966835 100644 --- a/lib/src/phy/common/phy_common_sl.c +++ b/lib/src/phy/common/phy_common_sl.c @@ -24,6 +24,7 @@ #include "srslte/phy/common/phy_common_sl.h" #include "srslte/phy/common/sequence.h" #include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" int srslte_sl_group_hopping_f_gh(uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME * 2], uint32_t N_x_id) { @@ -45,6 +46,50 @@ int srslte_sl_group_hopping_f_gh(uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME * 2], uint3 return SRSLTE_SUCCESS; } +bool srslte_slss_side_peak_pos_is_valid(uint32_t side_peak_pos, + uint32_t main_peak_pos, + uint32_t side_peak_delta_a, + uint32_t side_peak_delta_b) +{ + if ((side_peak_pos >= (main_peak_pos - side_peak_delta_b)) && + (side_peak_pos <= (main_peak_pos - side_peak_delta_a))) { + return true; + } else if ((side_peak_pos >= (main_peak_pos + side_peak_delta_a)) && + (side_peak_pos <= (main_peak_pos + side_peak_delta_b))) { + return true; + } + return false; +} + +bool srslte_slss_side_peak_value_is_valid(float side_peak_value, float threshold_low, float threshold_high) +{ + if ((side_peak_value >= threshold_low) && (side_peak_value <= threshold_high)) { + return true; + } + return false; +} + +int srslte_sl_tm_to_cell_sl_tm_t(srslte_cell_sl_t* q, uint32_t tm) +{ + switch (tm) { + case 1: + q->tm = SRSLTE_SIDELINK_TM1; + break; + case 2: + q->tm = SRSLTE_SIDELINK_TM2; + break; + case 3: + q->tm = SRSLTE_SIDELINK_TM3; + break; + case 4: + q->tm = SRSLTE_SIDELINK_TM4; + break; + default: + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; +} + int srslte_sl_get_num_symbols(srslte_sl_tm_t tm, srslte_cp_t cp) { if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { @@ -279,11 +324,23 @@ int srslte_sl_comm_resource_pool_get_default_config(srslte_sl_comm_resource_pool q->prb_start = 0; q->prb_end = cell.nof_prb - 1; + // 0110000000000000000000000000000000000000 + bzero(q->pscch_sf_bitmap, SRSLTE_SL_MAX_PERIOD_LENGTH); + memset(&q->pscch_sf_bitmap[1], 1, 2); + + // 0001111111111111111111111111111111111111 + bzero(q->pssch_sf_bitmap, SRSLTE_SL_MAX_PERIOD_LENGTH); + memset(&q->pssch_sf_bitmap[3], 1, 37); + q->size_sub_channel = 10; q->num_sub_channel = 5; q->start_prb_sub_channel = 0; q->adjacency_pscch_pssch = true; + q->sf_bitmap_tm34_len = 10; + bzero(q->sf_bitmap_tm34, SRSLTE_SL_MAX_PERIOD_LENGTH); + memset(q->sf_bitmap_tm34, 1, q->sf_bitmap_tm34_len); + if (cell.tm == SRSLTE_SIDELINK_TM4) { switch (cell.nof_prb) { case 6: diff --git a/lib/src/phy/phch/pssch.c b/lib/src/phy/phch/pssch.c new file mode 100644 index 000000000..73886d6ee --- /dev/null +++ b/lib/src/phy/phch/pssch.c @@ -0,0 +1,666 @@ +/* + * Copyright 2013-2020 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/phy/fec/rm_turbo.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/phch/pssch.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" + +int srslte_pssch_init(srslte_pssch_t* q, srslte_cell_sl_t cell, srslte_sl_comm_resource_pool_t sl_comm_resource_pool) +{ + if (q == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + q->cell = cell; + q->sl_comm_resource_pool = sl_comm_resource_pool; + + if (cell.tm == SRSLTE_SIDELINK_TM1 || cell.tm == SRSLTE_SIDELINK_TM2) { + if (cell.cp == SRSLTE_CP_NORM) { + q->nof_data_symbols = SRSLTE_PSSCH_TM12_NUM_DATA_SYMBOLS; + } else { + q->nof_data_symbols = SRSLTE_PSSCH_TM12_NUM_DATA_SYMBOLS_CP_EXT; + } + } else if (cell.tm == SRSLTE_SIDELINK_TM3 || cell.tm == SRSLTE_SIDELINK_TM4) { + if (cell.cp == SRSLTE_CP_NORM) { + q->nof_data_symbols = SRSLTE_PSSCH_TM34_NUM_DATA_SYMBOLS; + } else { + ERROR("Invalid CP for PSSCH, SL TM 3/4\n"); + return SRSLTE_ERROR_INVALID_INPUTS; + } + } else { + ERROR("Invalid SL TM\n"); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Transport Block + q->b = srslte_vec_u8_malloc(SRSLTE_SL_SCH_MAX_TB_LEN + SRSLTE_PSSCH_CRC_LEN); + if (!q->b) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Transport Block CRC + if (srslte_crc_init(&q->tb_crc, SRSLTE_LTE_CRC24A, SRSLTE_PSSCH_CRC_LEN)) { + ERROR("Error Transport Block CRC init\n"); + return SRSLTE_ERROR; + } + q->tb_crc_temp = srslte_vec_u8_malloc(SRSLTE_PSSCH_CRC_LEN); + if (!q->tb_crc_temp) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Code Block Segmentation + q->c_r = srslte_vec_u8_malloc(SRSLTE_TCOD_MAX_LEN_CB); + if (!q->c_r) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->f_16 = srslte_vec_i16_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->f_16) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->c_r_bytes = srslte_vec_u8_malloc(SRSLTE_TCOD_MAX_LEN_CB / 8); + if (!q->c_r_bytes) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Code Block CRC + if (srslte_crc_init(&q->cb_crc, SRSLTE_LTE_CRC24B, SRSLTE_PSSCH_CRC_LEN)) { + ERROR("Error Code Block CRC init\n"); + return SRSLTE_ERROR; + } + q->cb_crc_temp = srslte_vec_u8_malloc(SRSLTE_PSSCH_CRC_LEN); + if (!q->cb_crc_temp) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Channel Coding + srslte_tcod_init(&q->tcod, SRSLTE_TCOD_MAX_LEN_CB); + q->d_r = srslte_vec_u8_malloc(SRSLTE_PSSCH_MAX_CODED_BITS); + if (!q->d_r) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + srslte_tdec_init(&q->tdec, SRSLTE_TCOD_MAX_LEN_CB); + srslte_tdec_force_not_sb(&q->tdec); + q->d_r_16 = srslte_vec_i16_malloc(SRSLTE_PSSCH_MAX_CODED_BITS); + if (!q->d_r_16) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Rate Matching + q->e_r = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->e_r) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->buff_b = srslte_vec_u8_malloc(SRSLTE_PSSCH_MAX_CODED_BITS); + if (!q->buff_b) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + srslte_vec_u8_zero(q->buff_b, SRSLTE_PSSCH_MAX_CODED_BITS); + q->e_r_16 = srslte_vec_i16_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->e_r_16) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + srslte_rm_turbo_gentables(); + + // Code Block Concatenation + q->f = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->f) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Interleaving + q->f_bytes = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN / 8); + if (!q->f_bytes) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->interleaver_lut = srslte_vec_u32_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->interleaver_lut) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + srslte_vec_u32_zero(q->interleaver_lut, SRSLTE_MAX_CODEWORD_LEN); + + // Scrambling + q->codeword = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->codeword) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->codeword_bytes = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN / 8); + if (!q->codeword_bytes) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Modulation + q->symbols = srslte_vec_cf_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->symbols) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + srslte_vec_cf_zero(q->symbols, SRSLTE_MAX_CODEWORD_LEN); + + q->bits_after_demod = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->bits_after_demod) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + q->bytes_after_demod = srslte_vec_u8_malloc(SRSLTE_MAX_CODEWORD_LEN / 8); + if (!q->bytes_after_demod) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + for (int i = 0; i < SRSLTE_MOD_NITEMS; i++) { + if (srslte_modem_table_lte(&q->mod[i], (srslte_mod_t)i)) { + ERROR("Error initiating modem tables\n"); + return SRSLTE_ERROR; + } + } + + // Demodulation + q->llr = srslte_vec_i16_malloc(SRSLTE_MAX_CODEWORD_LEN); + if (!q->llr) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Transform Precoding + q->scfdma_symbols = srslte_vec_cf_malloc(q->nof_data_symbols * SRSLTE_NRE * SRSLTE_MAX_PRB); + if (!q->scfdma_symbols) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + if (srslte_dft_precoding_init(&q->dft_precoder, SRSLTE_MAX_PRB, true)) { + ERROR("Error DFT precoder init\n"); + return SRSLTE_ERROR; + } + if (srslte_dft_precoding_init(&q->idft_precoder, SRSLTE_MAX_PRB, false)) { + ERROR("Error in DFT precoder init\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_pssch_set_cfg(srslte_pssch_t* q, srslte_pssch_cfg_t pssch_cfg) +{ + if (q == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + q->pssch_cfg = pssch_cfg; + + q->mod_idx = srslte_ra_ul_mod_from_mcs(pssch_cfg.mcs_idx); + q->Qm = srslte_mod_bits_x_symbol(q->mod_idx); + q->sl_sch_tb_len = + srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(pssch_cfg.mcs_idx, false, true), pssch_cfg.nof_prb); + + if (q->cell.tm == SRSLTE_SIDELINK_TM1 || q->cell.tm == SRSLTE_SIDELINK_TM2) { + q->nof_data_symbols = SRSLTE_PSSCH_TM12_NUM_DATA_SYMBOLS; + + if (q->cell.cp == SRSLTE_CP_EXT) { + q->nof_data_symbols = SRSLTE_PSSCH_TM12_NUM_DATA_SYMBOLS_CP_EXT; + } + } else if (q->cell.tm == SRSLTE_SIDELINK_TM3 || q->cell.tm == SRSLTE_SIDELINK_TM4) { + q->nof_data_symbols = SRSLTE_PSSCH_TM34_NUM_DATA_SYMBOLS; + } else { + return SRSLTE_ERROR; + } + + q->nof_tx_symbols = q->nof_data_symbols - 1; // Last OFDM symbol is used in channel processing but not transmitted + q->nof_tx_re = q->nof_tx_symbols * SRSLTE_NRE * pssch_cfg.nof_prb; + q->nof_data_re = q->nof_data_symbols * SRSLTE_NRE * pssch_cfg.nof_prb; + + q->E = q->nof_data_re * q->Qm; + q->G = srslte_mod_bits_x_symbol(srslte_ra_ul_mod_from_mcs(pssch_cfg.mcs_idx)) * q->nof_data_re; + q->scfdma_symbols_len = q->G / q->Qm; + + return SRSLTE_SUCCESS; +} + +int srslte_pssch_encode(srslte_pssch_t* q, uint8_t* input, uint32_t input_len, cf_t* sf_buffer) +{ + if (!input || input_len > q->sl_sch_tb_len) { + ERROR("Can't encode PSSCH, input too long (%d > %d)\n", input_len, q->sl_sch_tb_len); + return SRSLTE_ERROR; + } + + srslte_cbsegm(&q->cb_segm, q->sl_sch_tb_len); + uint32_t L = SRSLTE_PSSCH_CRC_LEN; + if (q->cb_segm.C == 1) { + L = 0; + } + + uint32_t K_r = 0; + uint32_t E_r = 0; + uint32_t s = 0; + q->G = 0; + uint32_t Gp = q->E / q->Qm; + uint32_t gamma = Gp % q->cb_segm.C; + + // Copy into codeword buffer + memcpy(q->b, input, sizeof(uint8_t) * input_len); + + // Transport block CRC attachment + srslte_crc_attach(&q->tb_crc, q->b, q->sl_sch_tb_len); + + for (int r = 0; r < q->cb_segm.C; r++) { + + // Code block segmentation + if (r < q->cb_segm.C2) { + K_r = q->cb_segm.K2; + } else { + K_r = q->cb_segm.K1; + } + + if (r <= (q->cb_segm.C - gamma - 1)) { + E_r = q->Qm * (Gp / q->cb_segm.C); + } else { + E_r = q->Qm * ((uint32_t)ceilf((float)Gp / q->cb_segm.C)); + } + + if (r == 0) { + memset(q->c_r, SRSLTE_TX_NULL, sizeof(uint8_t) * q->cb_segm.F); + memcpy(&q->c_r[q->cb_segm.F], q->b, sizeof(uint8_t) * (K_r - L)); + s += (K_r - L - q->cb_segm.F); + } else { + memcpy(q->c_r, &q->b[s], sizeof(uint8_t) * (K_r - L)); + s += (K_r - L); + } + + // Code block CRC attachment + if (q->cb_segm.C > 1) { + if (r == 0) { + srslte_vec_u8_zero(q->c_r, q->cb_segm.F); + } + srslte_crc_attach(&q->cb_crc, q->c_r, (int)(K_r - L)); + if (r == 0) { + memset(q->c_r, SRSLTE_TX_NULL, sizeof(uint8_t) * q->cb_segm.F); + } + } + + // Channel coding + srslte_tcod_encode(&q->tcod, q->c_r, q->d_r, K_r); + + // Rate matching + srslte_vec_u8_zero(q->buff_b, SRSLTE_PSSCH_MAX_CODED_BITS); + srslte_rm_turbo_tx(q->buff_b, SRSLTE_PSSCH_MAX_CODED_BITS, q->d_r, 3 * K_r + SRSLTE_TCOD_TOTALTAIL, q->e_r, E_r, 0); + + if (q->pssch_cfg.rv_idx > 0) { + srslte_rm_turbo_tx(q->buff_b, + SRSLTE_PSSCH_MAX_CODED_BITS, + q->d_r, + 3 * K_r + SRSLTE_TCOD_TOTALTAIL, + q->e_r, + E_r, + srslte_pssch_rv[q->pssch_cfg.rv_idx]); + } + + // Code block concatenation + memcpy(&q->f[q->G], q->e_r, sizeof(uint8_t) * E_r); + q->G += E_r; + } + + // Interleaving + srslte_bit_pack_vector(q->f, q->f_bytes, q->G); + srslte_sl_ulsch_interleave(q->f_bytes, q->Qm, q->G / q->Qm, q->nof_data_symbols, q->codeword_bytes); + srslte_bit_unpack_vector(q->codeword_bytes, q->codeword, q->G); + + // Scrambling follows 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3.1 + srslte_sequence_LTE_pr( + &q->scrambling_seq, q->G, q->pssch_cfg.N_x_id * 16384 + (q->pssch_cfg.sf_idx % 10) * 512 + 510); + srslte_scrambling_b(&q->scrambling_seq, q->codeword); + + // Modulation + srslte_mod_modulate(&q->mod[q->mod_idx], q->codeword, q->symbols, q->G); + + // Layer Mapping + // Voided: Single layer + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3.3 + + // Transform Precoding + srslte_dft_precoding(&q->dft_precoder, q->symbols, q->scfdma_symbols, q->pssch_cfg.nof_prb, q->nof_data_symbols); + + // Precoding + // Voided: Single antenna port + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3.5 + + // RE mapping + if (q->nof_tx_re != srslte_pssch_put(q, sf_buffer, q->scfdma_symbols)) { + ERROR("There was an error mapping the PSSCH symbols\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; +} + +int srslte_pssch_decode(srslte_pssch_t* q, cf_t* equalized_sf_syms, uint8_t* output, uint32_t output_len) +{ + if (output_len < q->sl_sch_tb_len) { + ERROR("Can't decode PSSCH, provided buffer too small (%d < %d)\n", output_len, q->sl_sch_tb_len); + return SRSLTE_ERROR; + } + + // RE extraction + if (q->nof_tx_re != srslte_pssch_get(q, equalized_sf_syms, q->scfdma_symbols)) { + ERROR("There was an error getting the PSSCH symbols\n"); + return SRSLTE_ERROR; + } + + // Precoding + // Voided: Single antenna port + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3.5 + + // Transform Predecoding + if (srslte_dft_precoding( + &q->idft_precoder, q->scfdma_symbols, q->symbols, q->pssch_cfg.nof_prb, q->nof_data_symbols) != + SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + + // Layer Mapping + // Voided: Single layer + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3.3 + + // Demodulation + srslte_demod_soft_demodulate_s(q->Qm / 2, q->symbols, q->llr, q->G / q->Qm); + + // Descramble follows 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.3.1 + srslte_sequence_LTE_pr( + &q->scrambling_seq, q->G, q->pssch_cfg.N_x_id * 16384 + (q->pssch_cfg.sf_idx % 10) * 512 + 510); + srslte_scrambling_s(&q->scrambling_seq, q->llr); + + srslte_cbsegm(&q->cb_segm, q->sl_sch_tb_len); + uint32_t L = SRSLTE_PSSCH_CRC_LEN; + if (q->cb_segm.C == 1) { + L = 0; + } + + uint32_t B = 0; + uint32_t K_r = 0; + uint32_t E_r = 0; + uint32_t s = 0; + uint32_t Gp = q->E / q->Qm; + uint32_t gamma = Gp % q->cb_segm.C; + + // Deinterleaving + srslte_sl_ulsch_deinterleave(q->llr, q->Qm, q->G / q->Qm, q->nof_data_symbols, q->f_16, q->interleaver_lut); + + for (int r = 0; r < q->cb_segm.C; r++) { + // Code block segmentation + if (r < q->cb_segm.C2) { + K_r = q->cb_segm.K2; + } else { + K_r = q->cb_segm.K1; + } + + if (r <= (q->cb_segm.C - gamma - 1)) { + E_r = q->Qm * (Gp / q->cb_segm.C); + } else { + E_r = q->Qm * ((uint32_t)ceilf((float)Gp / q->cb_segm.C)); + } + + memcpy(q->e_r_16, &q->f_16[s], sizeof(int16_t) * E_r); + s += E_r; + + // Rate matching + uint32_t cb_len_idx = r < q->cb_segm.C1 ? q->cb_segm.K1_idx : q->cb_segm.K2_idx; + srslte_vec_i16_zero(q->d_r_16, SRSLTE_PSSCH_MAX_CODED_BITS); + srslte_rm_turbo_rx_lut_(q->e_r_16, q->d_r_16, E_r, cb_len_idx, srslte_pssch_rv[q->pssch_cfg.rv_idx], false); + + // Channel decoding + srslte_tdec_new_cb(&q->tdec, K_r); + srslte_tdec_run_all(&q->tdec, q->d_r_16, q->c_r_bytes, 3, K_r); + srslte_bit_unpack_vector(q->c_r_bytes, q->c_r, K_r); + + if (q->cb_segm.C > 1) { + + // Copy received crc to temp + memcpy(q->cb_crc_temp, &q->c_r[(K_r - L)], sizeof(uint8_t) * L); + + // Re-attach crc + srslte_crc_attach(&q->cb_crc, q->c_r, (int)(K_r - L)); + + // CRC check + if (srslte_bit_diff(q->cb_crc_temp, &q->c_r[(K_r - L)], L) != 0) { + return SRSLTE_ERROR; + } + } + + // Code Block Concatenation, dettach CRC and remove filler bits + if (r == 0) { + memcpy(q->b, &q->c_r[q->cb_segm.F], sizeof(uint8_t) * (K_r - L - q->cb_segm.F)); + B += (K_r - L - q->cb_segm.F); + } else { + memcpy(&q->b[B], q->c_r, sizeof(uint8_t) * (K_r - L)); + B += (K_r - L); + } + } + + // Copy received crc to temp + memcpy(q->tb_crc_temp, &q->b[B - SRSLTE_PSSCH_CRC_LEN], sizeof(uint8_t) * SRSLTE_PSSCH_CRC_LEN); + + // Re-attach crc + srslte_crc_attach(&q->tb_crc, q->b, (int)(B - SRSLTE_PSSCH_CRC_LEN)); + + // CRC check + if (srslte_bit_diff(q->tb_crc_temp, &q->b[(B - SRSLTE_PSSCH_CRC_LEN)], SRSLTE_PSSCH_CRC_LEN) != 0) { + return SRSLTE_ERROR; + } + + // Remove CRC and copy to output buffer + memcpy(output, q->b, sizeof(uint8_t) * q->sl_sch_tb_len); + + return SRSLTE_SUCCESS; +} + +int srslte_pssch_put(srslte_pssch_t* q, cf_t* sf_buffer, cf_t* symbols) +{ + uint32_t sample_pos = 0; + uint32_t k = q->pssch_cfg.prb_start_idx * SRSLTE_NRE; + for (int i = 0; i < srslte_sl_get_num_symbols(q->cell.tm, q->cell.cp); i++) { + if (srslte_pssch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->cell.tm, i, q->cell.cp)) { + + if (q->cell.tm == SRSLTE_SIDELINK_TM1 || q->cell.tm == SRSLTE_SIDELINK_TM2) { + if (q->pssch_cfg.nof_prb <= q->sl_comm_resource_pool.prb_num) { + k = q->pssch_cfg.prb_start_idx * SRSLTE_NRE; + memcpy(&sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + &symbols[sample_pos], + sizeof(cf_t) * (SRSLTE_NRE * q->pssch_cfg.nof_prb)); + sample_pos += (SRSLTE_NRE * q->pssch_cfg.nof_prb); + } else { + // First band + k = q->pssch_cfg.prb_start_idx * SRSLTE_NRE; + memcpy(&sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + &symbols[sample_pos], + sizeof(cf_t) * (SRSLTE_NRE * q->sl_comm_resource_pool.prb_num)); + sample_pos += (SRSLTE_NRE * q->sl_comm_resource_pool.prb_num); + + // Second band + if ((q->sl_comm_resource_pool.prb_num * 2) > + (q->sl_comm_resource_pool.prb_end - q->sl_comm_resource_pool.prb_start + 1)) { + k = (q->sl_comm_resource_pool.prb_end + 1 - q->sl_comm_resource_pool.prb_num + 1) * SRSLTE_NRE; + } else { + k = (q->sl_comm_resource_pool.prb_end + 1 - q->sl_comm_resource_pool.prb_num) * SRSLTE_NRE; + } + memcpy(&sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + &symbols[sample_pos], + sizeof(cf_t) * (SRSLTE_NRE * (q->pssch_cfg.nof_prb - q->sl_comm_resource_pool.prb_num))); + sample_pos += (SRSLTE_NRE * (q->pssch_cfg.nof_prb - q->sl_comm_resource_pool.prb_num)); + } + } else if (q->cell.tm == SRSLTE_SIDELINK_TM3 || q->cell.tm == SRSLTE_SIDELINK_TM4) { + memcpy(&sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + &symbols[sample_pos], + sizeof(cf_t) * (SRSLTE_NRE * q->pssch_cfg.nof_prb)); + sample_pos += (SRSLTE_NRE * q->pssch_cfg.nof_prb); + } + } + } + + return sample_pos; +} + +int srslte_pssch_get(srslte_pssch_t* q, cf_t* sf_buffer, cf_t* symbols) +{ + uint32_t sample_pos = 0; + uint32_t k = q->pssch_cfg.prb_start_idx * SRSLTE_NRE; + for (int i = 0; i < srslte_sl_get_num_symbols(q->cell.tm, q->cell.cp); i++) { + if (srslte_pssch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->cell.tm, i, q->cell.cp)) { + if (q->cell.tm == SRSLTE_SIDELINK_TM1 || q->cell.tm == SRSLTE_SIDELINK_TM2) { + if (q->pssch_cfg.nof_prb <= q->sl_comm_resource_pool.prb_num) { + k = q->pssch_cfg.prb_start_idx * SRSLTE_NRE; + memcpy(&symbols[sample_pos], + &sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + sizeof(cf_t) * (SRSLTE_NRE * q->pssch_cfg.nof_prb)); + sample_pos += (SRSLTE_NRE * q->pssch_cfg.nof_prb); + } else { + // First band + k = q->pssch_cfg.prb_start_idx * SRSLTE_NRE; + memcpy(&symbols[sample_pos], + &sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + sizeof(cf_t) * (SRSLTE_NRE * q->sl_comm_resource_pool.prb_num)); + sample_pos += (SRSLTE_NRE * q->sl_comm_resource_pool.prb_num); + + // Second band + if ((q->sl_comm_resource_pool.prb_num * 2) > + (q->sl_comm_resource_pool.prb_end - q->sl_comm_resource_pool.prb_start + 1)) { + k = (q->sl_comm_resource_pool.prb_end + 1 - q->sl_comm_resource_pool.prb_num + 1) * SRSLTE_NRE; + } else { + k = (q->sl_comm_resource_pool.prb_end + 1 - q->sl_comm_resource_pool.prb_num) * SRSLTE_NRE; + } + memcpy(&symbols[sample_pos], + &sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + sizeof(cf_t) * (SRSLTE_NRE * (q->pssch_cfg.nof_prb - q->sl_comm_resource_pool.prb_num))); + sample_pos += (SRSLTE_NRE * (q->pssch_cfg.nof_prb - q->sl_comm_resource_pool.prb_num)); + } + } else if (q->cell.tm == SRSLTE_SIDELINK_TM3 || q->cell.tm == SRSLTE_SIDELINK_TM4) { + memcpy(&symbols[sample_pos], + &sf_buffer[k + i * q->cell.nof_prb * SRSLTE_NRE], + sizeof(cf_t) * (SRSLTE_NRE * q->pssch_cfg.nof_prb)); + sample_pos += (SRSLTE_NRE * q->pssch_cfg.nof_prb); + } + } + } + + return sample_pos; +} + +void srslte_pssch_free(srslte_pssch_t* q) +{ + if (q) { + srslte_dft_precoding_free(&q->dft_precoder); + srslte_dft_precoding_free(&q->idft_precoder); + srslte_tcod_free(&q->tcod); + srslte_tdec_free(&q->tdec); + srslte_sequence_free(&q->scrambling_seq); + srslte_rm_turbo_free_tables(); + + for (int i = 0; i < SRSLTE_MOD_NITEMS; i++) { + srslte_modem_table_free(&q->mod[i]); + } + + if (q->b) { + free(q->b); + } + if (q->tb_crc_temp) { + free(q->tb_crc_temp); + } + if (q->cb_crc_temp) { + free(q->cb_crc_temp); + } + if (q->c_r) { + free(q->c_r); + } + if (q->c_r_bytes) { + free(q->c_r_bytes); + } + if (q->d_r) { + free(q->d_r); + } + if (q->d_r_16) { + free(q->d_r_16); + } + if (q->e_r) { + free(q->e_r); + } + if (q->e_r_16) { + free(q->e_r_16); + } + if (q->buff_b) { + free(q->buff_b); + } + if (q->f) { + free(q->f); + } + if (q->f_16) { + free(q->f_16); + } + if (q->f_bytes) { + free(q->f_bytes); + } + if (q->codeword) { + free(q->codeword); + } + if (q->codeword_bytes) { + free(q->codeword_bytes); + } + if (q->llr) { + free(q->llr); + } + if (q->interleaver_lut) { + free(q->interleaver_lut); + } + if (q->symbols) { + free(q->symbols); + } + if (q->scfdma_symbols) { + free(q->scfdma_symbols); + } + if (q->bits_after_demod) { + free(q->bits_after_demod); + } + if (q->bytes_after_demod) { + free(q->bytes_after_demod); + } + + bzero(q, sizeof(srslte_pssch_t)); + } +} \ No newline at end of file diff --git a/lib/src/phy/phch/ra_sl.c b/lib/src/phy/phch/ra_sl.c new file mode 100644 index 000000000..3a315c28e --- /dev/null +++ b/lib/src/phy/phch/ra_sl.c @@ -0,0 +1,193 @@ +/* + * Copyright 2013-2020 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/phy/common/phy_common_sl.h" +#include "srslte/phy/phch/ra.h" +#include "srslte/phy/phch/ra_sl.h" +#include "srslte/phy/utils/random.h" + +int srslte_sl_get_available_pool_prb(uint32_t prb_num, uint32_t prb_start, uint32_t prb_end) +{ + if ((prb_num * 2) <= (prb_end - prb_start + 1)) { + return prb_num * 2; + } else { + return prb_num * 2 - 1; + } +} + +int srslte_pscch_resources(uint32_t prb_num, + uint32_t prb_start, + uint32_t prb_end, + uint8_t* pscch_sf_bitmap, + uint32_t period_length, + uint32_t n_pscch, + uint32_t* m_a, + uint32_t* l_b) +{ + uint8_t M = srslte_sl_get_available_pool_prb(prb_num, prb_start, prb_end); + uint32_t L = 0; + for (uint32_t i = 0; i < period_length; i++) { + if (pscch_sf_bitmap[i] == 1) { + L++; + } + } + + if (L == 0) { + // ERROR("Invalid PSCCH subframe bitmap"); + return SRSLTE_ERROR; + } + + n_pscch = n_pscch % (L * M / 2); + + uint32_t a1 = n_pscch / L; // RB index A + uint32_t b1 = n_pscch % L; // SF index A + uint32_t a2 = a1 + M / 2; // RB index B + uint32_t b2 = (n_pscch + 1 + (a1 % (L - 1))) % L; // SF index B + + m_a[0] = a1 + prb_start; // PRB 1 + m_a[1] = a2 + (prb_end + 1 - M); // PRB 2 + + uint32_t k = 0; + for (uint32_t i = 0; i < period_length; i++) { + if (pscch_sf_bitmap[i] == 1) { + k++; + if (k == (b1 + 1)) { + l_b[0] = i; + break; + } + } + } + + k = 0; + for (uint32_t i = 0; i < period_length; i++) { + if (pscch_sf_bitmap[i] == 1) { + k++; + if (k == (b2 + 1)) { + l_b[1] = i; + break; + } + } + } + + return SRSLTE_SUCCESS; +} + +// 3GPP TS 36.213 Section 8.1.1. Uplink resource allocation type 0 +uint32_t srslte_ra_sl_type0_to_riv(uint32_t nof_prb, uint32_t prb_start, uint32_t L_crb) +{ + return srslte_ra_type2_to_riv(L_crb, prb_start, nof_prb); +} + +// 3GPP TS 36.213 Section 8.1.1. Uplink resource allocation type 0 +void srslte_ra_sl_type0_from_riv(uint32_t riv, uint32_t nof_prb, uint32_t* L_crb, uint32_t* prb_start) +{ + srslte_ra_type2_from_riv(riv, L_crb, prb_start, nof_prb, nof_prb); +} + +int srslte_ra_sl_pssch_allowed_sf(uint32_t pssch_sf_idx, uint32_t trp_idx, uint32_t duplex_mode, uint32_t tdd_config) +{ + if (duplex_mode == SRSLTE_SL_DUPLEX_MODE_FDD) { + return srslte_sl_N_TRP_8[trp_idx][pssch_sf_idx % 8]; + } + switch (tdd_config) { + // N_TRP = 6 + case 3: + case 6: + return srslte_sl_N_TRP_6[trp_idx][pssch_sf_idx % 6]; + // N_TRP = 7 + case 0: + return srslte_sl_N_TRP_7[trp_idx][pssch_sf_idx % 7]; + // N_TRP = 8 + case 1: + case 2: + case 4: + case 5: + return srslte_sl_N_TRP_8[trp_idx][pssch_sf_idx % 8]; + default: + return 0; + } +} + +int srslte_sci_generate_trp_idx(uint32_t duplex_mode, uint32_t tdd_config, uint32_t k_TRP) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + srslte_random_t random = srslte_random_init(tv.tv_usec); + + // N_TRP = 8 + if (duplex_mode == SRSLTE_SL_DUPLEX_MODE_FDD || tdd_config == 1 || tdd_config == 2 || tdd_config == 4 || + tdd_config == 5) { + switch (k_TRP) { + case 1: + return srslte_sl_N_TRP_8_k_1[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_8_k_1) - 1)]; + case 2: + return srslte_sl_N_TRP_8_k_2[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_8_k_2) - 1)]; + case 4: + return srslte_sl_N_TRP_8_k_4[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_8_k_4) - 1)]; + case 8: + return srslte_sl_N_TRP_8_k_8[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_8_k_8) - 1)]; + default: + return SRSLTE_ERROR; + } + // N_TRP = 7 + } else if (tdd_config == 0) { + switch (k_TRP) { + case 1: + return srslte_sl_N_TRP_7_k_1[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_1) - 1)]; + case 2: + return srslte_sl_N_TRP_7_k_2[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_2) - 1)]; + case 3: + return srslte_sl_N_TRP_7_k_3[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_3) - 1)]; + case 4: + return srslte_sl_N_TRP_7_k_4[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_4) - 1)]; + case 5: + return srslte_sl_N_TRP_7_k_5[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_5) - 1)]; + case 6: + return srslte_sl_N_TRP_7_k_6[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_6) - 1)]; + case 7: + return srslte_sl_N_TRP_7_k_7[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_7_k_7) - 1)]; + default: + return SRSLTE_ERROR; + } + // N_TRP = 6 + } else if (tdd_config == 3 || tdd_config == 6) { + switch (k_TRP) { + case 1: + return srslte_sl_N_TRP_6_k_1[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_6_k_1) - 1)]; + case 2: + return srslte_sl_N_TRP_6_k_2[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_6_k_2) - 1)]; + case 3: + return srslte_sl_N_TRP_6_k_3[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_6_k_3) - 1)]; + case 4: + return srslte_sl_N_TRP_6_k_4[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_6_k_4) - 1)]; + case 5: + return srslte_sl_N_TRP_6_k_5[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_6_k_5) - 1)]; + case 6: + return srslte_sl_N_TRP_6_k_6[srslte_random_uniform_int_dist(random, 0, sizeof(srslte_sl_N_TRP_6_k_6) - 1)]; + default: + return SRSLTE_ERROR; + } + } + + return SRSLTE_SUCCESS; +} \ No newline at end of file diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 9e95b6334..1de12d749 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -88,43 +88,72 @@ add_test(pscch_test_tm4_p50 pscch_test -p 50 -t 4) add_test(pscch_test_tm4_p75 pscch_test -p 75 -t 4) add_test(pscch_test_tm4_p100 pscch_test -p 100 -t 4) -add_executable(pscch_file_test pscch_file_test.c) -target_link_libraries(pscch_file_test srslte_phy) +######################################################################## +# PSSCH TEST +######################################################################## + +add_executable(pssch_test pssch_test.c) +target_link_libraries(pssch_test srslte_phy) + +# TM2 self tests +add_test(pssch_test_tm2_p6 pssch_test -p 6 -m 2) +add_test(pssch_test_tm2_p15 pssch_test -p 15 -m 6) +add_test(pssch_test_tm2_p25 pssch_test -p 25 -m 7) +add_test(pssch_test_tm2_p50 pssch_test -p 50 -m 9) +add_test(pssch_test_tm2_p50_ext pssch_test -p 50 -m 9 -e) +add_test(pssch_test_tm2_p75 pssch_test -p 75 -m 17) +add_test(pssch_test_tm2_p100 pssch_test -p 100 -m 21) +add_test(pssch_test_tm2_p100_ext pssch_test -p 100 -m 21 -e) + +# TM4 self tests +add_test(pssch_test_tm4_p6 pssch_test -p 6 -t 4 -m 2) +add_test(pssch_test_tm4_p15 pssch_test -p 15 -t 4 -m 6) +add_test(pssch_test_tm4_p25 pssch_test -p 25 -t 4 -m 7) +add_test(pssch_test_tm4_p50 pssch_test -p 50 -t 4 -m 9) +add_test(pssch_test_tm4_p75 pssch_test -p 75 -t 4 -m 17) +add_test(pssch_test_tm4_p100 pssch_test -p 100 -t 4 -m 21) + +######################################################################## +# PSCCH AND PSSCH FILE TEST +######################################################################## + +add_executable(pssch_pscch_file_test pssch_pscch_file_test.c) +target_link_libraries(pssch_pscch_file_test srslte_phy) # TM2 file tests -add_test(pscch_file_test_ideal_tm2_p100 pscch_file_test -p 100 -t 2 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat) -set_property(TEST pscch_file_test_ideal_tm2_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2") +add_test(pssch_pscch_file_test_ideal_tm2_p100 pssch_pscch_file_test -p 100 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat) +set_property(TEST pssch_pscch_file_test_ideal_tm2_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2 num_decoded_tb=1") # TM4 file tests -add_test(pscch_file_test_ideal_tm4_p100 pscch_file_test -p 100 -t 4 -s 10 -n 10 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat) -set_property(TEST pscch_file_test_ideal_tm4_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") +add_test(pssch_pscch_file_test_ideal_tm4_p100 pssch_pscch_file_test -p 100 -t 4 -s 10 -n 10 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat) +set_property(TEST pssch_pscch_file_test_ideal_tm4_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1 num_decoded_tb=1") -add_test(pscch_test_tm4_p50_qc pscch_file_test -p 50 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat) -set_property(TEST pscch_test_tm4_p50_qc PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") +add_test(pssch_pscch_test_tm4_p50_qc pssch_pscch_file_test -p 50 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat) +set_property(TEST pssch_pscch_test_tm4_p50_qc PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1 num_decoded_tb=1") -# Capture has a SFO offset of ~64 samples, but offsetting by 20 is sufficiant to decode it -add_test(pscch_test_tm4_p50_cmw pscch_file_test -p 50 -t 4 -o 20 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat) -set_property(TEST pscch_test_tm4_p50_cmw PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1") +# Capture has a SFO offset of ~64 samples, but offsetting by 20 is enough to decode it +add_test(pssch_pscch_test_tm4_p50_cmw pssch_pscch_file_test -p 50 -t 4 -o 20 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat) +set_property(TEST pssch_pscch_test_tm4_p50_cmw PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1 num_decoded_tb=1") # With PHY retransmission (3 TTI offset) -add_test(pscch_test_tm4_p50_huawei pscch_file_test -p 50 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat) -set_property(TEST pscch_test_tm4_p50_huawei PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2") +add_test(pssch_pscch_test_tm4_p50_huawei pssch_pscch_file_test -p 50 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat) +set_property(TEST pssch_pscch_test_tm4_p50_huawei PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2 num_decoded_tb=2") # With PHY ReTx (0 TTI offset?) -add_test(pscch_test_tm4_p50_uxm1 pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat) -set_property(TEST pscch_test_tm4_p50_uxm1 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=2") +add_test(pssch_pscch_test_tm4_p50_uxm1 pssch_pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat) +set_property(TEST pssch_pscch_test_tm4_p50_uxm1 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=2 num_decoded_tb=2") # 100 PRB startOffset 1 MCS12 MAC padding -add_test(pscch_test_tm4_p100_uxm2 pscch_file_test -p 100 -t 4 -s 10 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat) -set_property(TEST pscch_test_tm4_p100_uxm2 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=4") +add_test(pssch_pscch_test_tm4_p100_uxm2 pssch_pscch_file_test -p 100 -t 4 -s 10 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat) +set_property(TEST pssch_pscch_test_tm4_p100_uxm2 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=4 num_decoded_tb=4") # 100 PRB LTE sampling rate, startOffset1 MCS12 ITS data -add_test(pscch_test_tm4_p100_uxm3 pscch_file_test -p 100 -d -t 4 -s 10 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat) -set_property(TEST pscch_test_tm4_p100_uxm3 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=1") +add_test(pssch_pscch_test_tm4_p100_uxm3 pssch_pscch_file_test -p 100 -d -t 4 -s 10 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat) +set_property(TEST pssch_pscch_test_tm4_p100_uxm3 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=1 num_decoded_tb=1") # 50 PRB LTE sampling rate, startOffset0 MCS28 MAC padding -add_test(pscch_test_tm4_p50_uxm4 pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat) -set_property(TEST pscch_test_tm4_p50_uxm4 PROPERTY PASS_REGULAR_EXPRESSION "mcs=28.*num_decoded_sci=5") +add_test(pssch_pscch_test_tm4_p50_uxm4 pssch_pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat) +set_property(TEST pssch_pscch_test_tm4_p50_uxm4 PROPERTY PASS_REGULAR_EXPRESSION "mcs=28.*num_decoded_sci=5 num_decoded_tb=5") ######################################################################## # NPBCH TEST diff --git a/lib/src/phy/phch/test/pscch_file_test.c b/lib/src/phy/phch/test/pssch_pscch_file_test.c similarity index 58% rename from lib/src/phy/phch/test/pscch_file_test.c rename to lib/src/phy/phch/test/pssch_pscch_file_test.c index 4668aabb3..81d89f7d2 100644 --- a/lib/src/phy/phch/test/pscch_file_test.c +++ b/lib/src/phy/phch/test/pssch_pscch_file_test.c @@ -30,6 +30,8 @@ #include "srslte/phy/dft/ofdm.h" #include "srslte/phy/io/filesource.h" #include "srslte/phy/phch/pscch.h" +#include "srslte/phy/phch/pssch.h" +#include "srslte/phy/phch/ra_sl.h" #include "srslte/phy/phch/sci.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" @@ -47,12 +49,15 @@ static cf_t* input_buffer = NULL; static srslte_sci_t sci = {}; static srslte_pscch_t pscch = {}; static srslte_chest_sl_t pscch_chest = {}; +static srslte_pssch_t pssch = {}; +static srslte_chest_sl_t pssch_chest = {}; static srslte_ofdm_t fft = {}; static srslte_sl_comm_resource_pool_t sl_comm_resource_pool = {}; static uint32_t size_sub_channel = 10; static uint32_t num_sub_channel = 5; static srslte_chest_sl_cfg_t pscch_chest_sl_cfg = {}; +static srslte_chest_sl_cfg_t pssch_chest_sl_cfg = {}; static srslte_filesource_t fsrc = {}; @@ -97,23 +102,9 @@ void parse_args(int argc, char** argv) cell.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); break; case 't': - switch ((int32_t)strtol(argv[optind], NULL, 10)) { - case 1: - cell.tm = SRSLTE_SIDELINK_TM1; - break; - case 2: - cell.tm = SRSLTE_SIDELINK_TM2; - break; - case 3: - cell.tm = SRSLTE_SIDELINK_TM3; - break; - case 4: - cell.tm = SRSLTE_SIDELINK_TM4; - break; - default: - usage(argv[0]); - exit(-1); - break; + if (srslte_sl_tm_to_cell_sl_tm_t(&cell, strtol(argv[optind], NULL, 10)) != SRSLTE_SUCCESS) { + usage(argv[0]); + exit(-1); } break; case 'v': @@ -124,7 +115,7 @@ void parse_args(int argc, char** argv) exit(-1); } } - if (cell.cp == SRSLTE_CP_EXT && cell.tm >= SRSLTE_SIDELINK_TM3) { + if (SRSLTE_CP_ISEXT(cell.cp) && cell.tm >= SRSLTE_SIDELINK_TM3) { ERROR("Selected TM does not support extended CP"); usage(argv[0]); exit(-1); @@ -178,6 +169,16 @@ int base_init() return SRSLTE_ERROR; } + if (srslte_pssch_init(&pssch, cell, sl_comm_resource_pool) != SRSLTE_SUCCESS) { + ERROR("Error initializing PSSCH\n"); + return SRSLTE_ERROR; + } + + if (srslte_chest_sl_init(&pssch_chest, SRSLTE_SIDELINK_PSSCH, cell, sl_comm_resource_pool) != SRSLTE_SUCCESS) { + ERROR("Error in chest PSSCH init\n"); + return SRSLTE_ERROR; + } + if (input_file_name) { if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { printf("Error opening file %s\n", input_file_name); @@ -207,6 +208,9 @@ void base_free() srslte_pscch_free(&pscch); srslte_chest_sl_free(&pscch_chest); + srslte_pssch_free(&pssch); + srslte_chest_sl_free(&pssch_chest); + if (sf_buffer) { free(sf_buffer); } @@ -232,13 +236,21 @@ int main(int argc, char** argv) return SRSLTE_ERROR; } + bool sci_decoded = false; uint32_t num_decoded_sci = 0; char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = {}; + uint32_t num_decoded_tb = 0; + uint8_t tb[SRSLTE_SL_SCH_MAX_TB_LEN] = {}; + int max_num_subframes = 128; int num_subframes = 0; int nread = 0; + uint32_t period_sf_idx = 0; + uint32_t pssch_sf_idx = 0; + uint32_t allowed_pssch_sf_idx = 0; + if (file_offset > 0) { printf("Offsetting file by %d samples.\n", file_offset); srslte_filesource_seek(&fsrc, file_offset * sizeof(cf_t)); @@ -261,38 +273,76 @@ int main(int argc, char** argv) if (cell.tm == SRSLTE_SIDELINK_TM1 || cell.tm == SRSLTE_SIDELINK_TM2) { - for (uint32_t pscch_prb_start_idx = sl_comm_resource_pool.prb_start; - pscch_prb_start_idx <= sl_comm_resource_pool.prb_end; - pscch_prb_start_idx++) { + // 3GPP TS 36.213 Section 14.2.1.2 UE procedure for determining subframes + // and resource blocks for transmitting PSCCH for sidelink transmission mode 2 + if (sl_comm_resource_pool.pscch_sf_bitmap[period_sf_idx] == 1) { + + for (uint32_t pscch_prb_start_idx = sl_comm_resource_pool.prb_start; + pscch_prb_start_idx <= sl_comm_resource_pool.prb_end; + pscch_prb_start_idx++) { + + // PSCCH Channel estimation + pscch_chest_sl_cfg.prb_start_idx = pscch_prb_start_idx; + srslte_chest_sl_set_cfg(&pscch_chest, pscch_chest_sl_cfg); + srslte_chest_sl_ls_estimate_equalize(&pscch_chest, sf_buffer, equalized_sf_buffer); - // PSCCH Channel estimation - pscch_chest_sl_cfg.prb_start_idx = pscch_prb_start_idx; - srslte_chest_sl_set_cfg(&pscch_chest, pscch_chest_sl_cfg); - srslte_chest_sl_ls_estimate_equalize(&pscch_chest, sf_buffer, equalized_sf_buffer); + if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_start_idx) == SRSLTE_SUCCESS) { + if (srslte_sci_format0_unpack(&sci, sci_rx) == SRSLTE_SUCCESS) { - if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_start_idx) == SRSLTE_SUCCESS) { - if (srslte_sci_format0_unpack(&sci, sci_rx) == SRSLTE_SUCCESS) { + srslte_sci_info(&sci, sci_msg, sizeof(sci_msg)); + fprintf(stdout, "%s", sci_msg); - srslte_sci_info(&sci, sci_msg, sizeof(sci_msg)); - fprintf(stdout, "%s", sci_msg); + sci_decoded = true; + num_decoded_sci++; + } + } - num_decoded_sci++; + if ((sl_comm_resource_pool.prb_num * 2) <= + (sl_comm_resource_pool.prb_end - sl_comm_resource_pool.prb_start + 1)) { + if ((pscch_prb_start_idx + 1) == (sl_comm_resource_pool.prb_start + sl_comm_resource_pool.prb_num)) { + pscch_prb_start_idx = sl_comm_resource_pool.prb_end - sl_comm_resource_pool.prb_num; + } } } + } - if ((sl_comm_resource_pool.prb_num * 2) <= - (sl_comm_resource_pool.prb_end - sl_comm_resource_pool.prb_start + 1)) { - if ((pscch_prb_start_idx + 1) == (sl_comm_resource_pool.prb_start + sl_comm_resource_pool.prb_num)) { - pscch_prb_start_idx = sl_comm_resource_pool.prb_end - sl_comm_resource_pool.prb_num; + if ((sl_comm_resource_pool.pssch_sf_bitmap[period_sf_idx] == 1) && (sci_decoded == true)) { + if (srslte_ra_sl_pssch_allowed_sf(pssch_sf_idx, sci.trp_idx, SRSLTE_SL_DUPLEX_MODE_FDD, 0)) { + + // Redundancy version + uint32_t rv_idx = allowed_pssch_sf_idx % 4; + + uint32_t nof_prb_pssch = 0; + uint32_t pssch_prb_start_idx = 0; + srslte_ra_sl_type0_from_riv(sci.riv, cell.nof_prb, &nof_prb_pssch, &pssch_prb_start_idx); + printf("pssch_start_prb_idx = %i nof_prb = %i\n", pssch_prb_start_idx, nof_prb_pssch); + + // PSSCH Channel estimation + pssch_chest_sl_cfg.N_x_id = sci.N_sa_id; + pssch_chest_sl_cfg.sf_idx = pssch_sf_idx; + pssch_chest_sl_cfg.prb_start_idx = pssch_prb_start_idx; + pssch_chest_sl_cfg.nof_prb = nof_prb_pssch; + srslte_chest_sl_set_cfg(&pssch_chest, pssch_chest_sl_cfg); + srslte_chest_sl_ls_estimate_equalize(&pssch_chest, sf_buffer, equalized_sf_buffer); + + srslte_pssch_cfg_t pssch_cfg = { + pssch_prb_start_idx, nof_prb_pssch, sci.N_sa_id, sci.mcs_idx, rv_idx, pssch_sf_idx}; + if (srslte_pssch_set_cfg(&pssch, pssch_cfg) == SRSLTE_SUCCESS) { + if (srslte_pssch_decode(&pssch, equalized_sf_buffer, tb, SRSLTE_SL_SCH_MAX_TB_LEN) == SRSLTE_SUCCESS) { + srslte_vec_fprint_byte(stdout, tb, pssch.sl_sch_tb_len); + num_decoded_tb++; + printf("> Transport Block SUCCESS! TB count: %i\n", num_decoded_tb); + } } + allowed_pssch_sf_idx++; } + pssch_sf_idx++; } } else if (cell.tm == SRSLTE_SIDELINK_TM3 || cell.tm == SRSLTE_SIDELINK_TM4) { - for (int i = 0; i < sl_comm_resource_pool.num_sub_channel; i++) { - uint32_t pscch_prb_start_idx = sl_comm_resource_pool.size_sub_channel * i; + for (int sub_channel_idx = 0; sub_channel_idx < sl_comm_resource_pool.num_sub_channel; sub_channel_idx++) { + uint32_t pscch_prb_start_idx = sl_comm_resource_pool.size_sub_channel * sub_channel_idx; for (uint32_t cyclic_shift = 0; cyclic_shift <= 9; cyclic_shift += 3) { - // PSCCH Channel estimation pscch_chest_sl_cfg.cyclic_shift = cyclic_shift; pscch_chest_sl_cfg.prb_start_idx = pscch_prb_start_idx; @@ -301,11 +351,50 @@ int main(int argc, char** argv) if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_start_idx) == SRSLTE_SUCCESS) { if (srslte_sci_format1_unpack(&sci, sci_rx) == SRSLTE_SUCCESS) { - srslte_sci_info(&sci, sci_msg, sizeof(sci_msg)); fprintf(stdout, "%s", sci_msg); num_decoded_sci++; + + // Decode PSSCH + + uint32_t sub_channel_start_idx = 0; + uint32_t L_subCH = 0; + srslte_ra_sl_type0_from_riv( + sci.riv, sl_comm_resource_pool.num_sub_channel, &L_subCH, &sub_channel_start_idx); + + // 3GPP TS 36.213 Section 14.1.1.4C + uint32_t pssch_prb_start_idx = (sub_channel_idx * sl_comm_resource_pool.size_sub_channel) + + pscch.pscch_nof_prb + sl_comm_resource_pool.start_prb_sub_channel; + uint32_t nof_prb_pssch = ((L_subCH + sub_channel_idx) * sl_comm_resource_pool.size_sub_channel) - + pssch_prb_start_idx + sl_comm_resource_pool.start_prb_sub_channel; + + uint32_t N_x_id = 0; + for (int j = 0; j < SRSLTE_SCI_CRC_LEN; j++) { + N_x_id += pscch.sci_crc[j] * exp2(SRSLTE_SCI_CRC_LEN - 1 - j); + } + + uint32_t rv_idx = 0; + if (sci.retransmission == true) { + rv_idx = 1; + } + + // PSSCH Channel estimation + pssch_chest_sl_cfg.N_x_id = N_x_id; + pssch_chest_sl_cfg.sf_idx = pssch_sf_idx; + pssch_chest_sl_cfg.prb_start_idx = pssch_prb_start_idx; + pssch_chest_sl_cfg.nof_prb = nof_prb_pssch; + srslte_chest_sl_set_cfg(&pssch_chest, pssch_chest_sl_cfg); + srslte_chest_sl_ls_estimate_equalize(&pssch_chest, sf_buffer, equalized_sf_buffer); + + srslte_pssch_cfg_t pssch_cfg = { + pssch_prb_start_idx, nof_prb_pssch, N_x_id, sci.mcs_idx, rv_idx, pssch_sf_idx}; + if (srslte_pssch_set_cfg(&pssch, pssch_cfg) == SRSLTE_SUCCESS) { + if (srslte_pssch_decode(&pssch, equalized_sf_buffer, tb, SRSLTE_SL_SCH_MAX_TB_LEN) == SRSLTE_SUCCESS) { + srslte_vec_fprint_byte(stdout, tb, pssch.sl_sch_tb_len); + num_decoded_tb++; + } + } } } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -321,17 +410,19 @@ int main(int argc, char** argv) } } } + pssch_sf_idx++; } num_subframes++; + period_sf_idx++; } while (nread > 0 && num_subframes < max_num_subframes); clean_exit: base_free(); - printf("num_decoded_sci=%d\n", num_decoded_sci); + printf("num_decoded_sci=%d num_decoded_tb=%d\n", num_decoded_sci, num_decoded_tb); ret = (num_decoded_sci > 0) ? SRSLTE_SUCCESS : SRSLTE_ERROR; return ret; -} +} \ No newline at end of file diff --git a/lib/src/phy/phch/test/pssch_test.c b/lib/src/phy/phch/test/pssch_test.c new file mode 100644 index 000000000..3027a87c0 --- /dev/null +++ b/lib/src/phy/phch/test/pssch_test.c @@ -0,0 +1,157 @@ +/* + * Copyright 2013-2020 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 + +#include "srslte/phy/phch/pssch.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/random.h" +#include "srslte/phy/utils/vector.h" + +srslte_cell_sl_t cell = {.nof_prb = 6, .N_sl_id = 0, .tm = SRSLTE_SIDELINK_TM2, .cp = SRSLTE_CP_NORM}; + +uint32_t mcs_idx = 4; +uint32_t prb_start_idx = 0; + +void usage(char* prog) +{ + printf("Usage: %s [emptv]\n", prog); + printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-m mcs_idx [Default %d]\n", mcs_idx); + printf("\t-e extended CP [Default normal]\n"); + printf("\t-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (cell.tm + 1)); + 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, "emptv")) != -1) { + switch (opt) { + case 'e': + cell.cp = SRSLTE_CP_EXT; + break; + case 'm': + mcs_idx = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'p': + cell.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 't': + if (srslte_sl_tm_to_cell_sl_tm_t(&cell, strtol(argv[optind], NULL, 10)) != SRSLTE_SUCCESS) { + usage(argv[0]); + exit(-1); + } + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (SRSLTE_CP_ISEXT(cell.cp) && cell.tm >= SRSLTE_SIDELINK_TM3) { + ERROR("Selected TM does not support extended CP"); + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char** argv) +{ + uint32_t ret = SRSLTE_ERROR; + + parse_args(argc, argv); + + srslte_sl_comm_resource_pool_t sl_comm_resource_pool; + if (srslte_sl_comm_resource_pool_get_default_config(&sl_comm_resource_pool, cell) != SRSLTE_SUCCESS) { + ERROR("Error initializing sl_comm_resource_pool\n"); + return SRSLTE_ERROR; + } + + srslte_pssch_t pssch; + if (srslte_pssch_init(&pssch, cell, sl_comm_resource_pool) != SRSLTE_SUCCESS) { + ERROR("Error initializing PSSCH\n"); + return SRSLTE_ERROR; + } + + // FIXME: Due to srslte_dft_precoding, many values give error + uint32_t nof_prb_pssch = cell.nof_prb; + while (srslte_dft_precoding_valid_prb(nof_prb_pssch) == false) { + nof_prb_pssch--; + if (nof_prb_pssch == 0) { + ERROR("Invalid parameters"); + exit(-1); + } + } + + uint32_t N_x_id = 255; + uint32_t sf_n_re = SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); + cf_t* sf_buffer = srslte_vec_cf_malloc(sf_n_re); + + // Transport block buffer + uint8_t tb[SRSLTE_SL_SCH_MAX_TB_LEN] = {}; + + // Rx transport block buffer + uint8_t tb_rx[SRSLTE_SL_SCH_MAX_TB_LEN] = {}; + + srslte_pssch_cfg_t pssch_cfg = {prb_start_idx, nof_prb_pssch, N_x_id, mcs_idx, 0, 0}; + if (srslte_pssch_set_cfg(&pssch, pssch_cfg) != SRSLTE_SUCCESS) { + ERROR("Error configuring PSSCH\n"); + goto clean_exit; + } + + // Randomize data to fill the transport block + struct timeval tv; + gettimeofday(&tv, NULL); + srslte_random_t random = srslte_random_init(tv.tv_usec); + for (int i = 0; i < pssch.sl_sch_tb_len; i++) { + tb[i] = srslte_random_uniform_int_dist(random, 0, 1); + } + + // PSSCH encoding + if (srslte_pssch_encode(&pssch, tb, pssch.sl_sch_tb_len, sf_buffer) != SRSLTE_SUCCESS) { + ERROR("Error encoding PSSCH\n"); + goto clean_exit; + } + + // PSSCH decoding + if (srslte_pssch_decode(&pssch, sf_buffer, tb_rx, pssch.sl_sch_tb_len) != SRSLTE_SUCCESS) { + ERROR("Error decoding PSSCH\n"); + goto clean_exit; + } + + if (memcmp(tb_rx, tb, pssch.sl_sch_tb_len) == 0) { + ret = SRSLTE_SUCCESS; + } else { + ret = SRSLTE_ERROR; + } + +clean_exit: + free(sf_buffer); + srslte_pssch_free(&pssch); + + printf("%s", ret == SRSLTE_SUCCESS ? "SUCCESS\n" : "FAILED\n"); + return ret; +} \ No newline at end of file diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 07b031c7b..655331c00 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -190,6 +190,16 @@ void srslte_vec_u8_zero(uint8_t* ptr, uint32_t nsamples) memset(ptr, 0, sizeof(uint8_t) * nsamples); } +void srslte_vec_i16_zero(int16_t* ptr, uint32_t nsamples) +{ + memset(ptr, 0, sizeof(int16_t) * nsamples); +} + +void srslte_vec_u32_zero(uint32_t* ptr, uint32_t nsamples) +{ + memset(ptr, 0, sizeof(uint32_t) * nsamples); +} + void srslte_vec_cf_zero(cf_t* ptr, uint32_t nsamples) { memset(ptr, 0, sizeof(cf_t) * nsamples);