diff --git a/lib/include/srslte/phy/ch_estimation/chest_sl.h b/lib/include/srslte/phy/ch_estimation/chest_sl.h index 0c5ac90db..90bd52aeb 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_sl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_sl.h @@ -18,34 +18,37 @@ * and at http://www.gnu.org/licenses/. * */ + #ifndef SRSLTE_CHEST_SL_H #define SRSLTE_CHEST_SL_H #include #include "srslte/config.h" - #include "srslte/phy/ch_estimation/chest_common.h" #include "srslte/phy/ch_estimation/refsignal_ul.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/resampling/interp.h" +#define SRSLTE_SL_MAX_DMRS_SYMB (4) +#define SRSLTE_SL_NOF_PRIME_NUMBERS (196) + typedef struct { uint32_t nof_prb; uint32_t sf_n_re; uint32_t M_sc_rs; - int8_t nr_DMRS_symbols; + int8_t nof_dmrs_symbols; // Orthogonal Sequence (W) Transmission Mode 1, 2 and PSBCH - int8_t* w; + int8_t w[SRSLTE_SL_MAX_DMRS_SYMB]; // Cyclic Shift Values - int8_t* n_CS; + int8_t n_CS[SRSLTE_SL_MAX_DMRS_SYMB]; - // Refrence Signal Cyclic Shift - float* alpha; + // Reference Signal Cyclic Shift + float alpha[SRSLTE_SL_MAX_DMRS_SYMB]; // Group Hopping Flag uint32_t f_gh; @@ -53,47 +56,53 @@ typedef struct { uint32_t f_ss; // Sequence Group Number - uint32_t* u; + uint32_t u[SRSLTE_SL_MAX_DMRS_SYMB]; // Base Sequence Number - always 0 for sidelink uint32_t v; int32_t N_zc; - int32_t* q; + int32_t q[SRSLTE_SL_MAX_DMRS_SYMB]; - float** r; + float* r[SRSLTE_SL_MAX_DMRS_SYMB]; - cf_t** r_uv; + cf_t* r_uv[SRSLTE_SL_MAX_DMRS_SYMB]; - cf_t** r_sequence; + cf_t* r_sequence[SRSLTE_SL_MAX_DMRS_SYMB]; - cf_t** dmrs_received; - cf_t* pilot_estimates_1; - cf_t* pilot_estimates_2; - cf_t* ce; + cf_t* dmrs_received[SRSLTE_SL_MAX_DMRS_SYMB]; + cf_t* pilot_estimates_1; + cf_t* pilot_estimates_2; + cf_t* ce; srslte_interp_linsrslte_vec_t lin_vec_sl; } srslte_chest_sl_t; -int srslte_chest_sl_gen_psbch_dmrs( - srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t nof_prb, uint32_t sf_idx, uint32_t N_sl_id); - int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q); -int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, cf_t* sf_buffer, srslte_sl_tm_t tx_mode, uint32_t nof_prb); -void srslte_chest_sl_put_pscch_dmrs( - srslte_chest_sl_t* q, uint32_t prb_idx, uint32_t nof_prb, cf_t* sf_buffer, srslte_sl_tm_t txMode); -void srslte_chest_sl_put_pssch_dmrs(srslte_chest_sl_t* q, - uint32_t prb_start, - uint32_t prb_end, - uint32_t prb_num, - uint32_t nof_prb, - cf_t* sf_buffer, - srslte_sl_tm_t txMode); - -void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q, cf_t* sf_buffer, cf_t* output, uint32_t nof_prb); +int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t N_sl_id); + +int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer, + srslte_sl_tm_t tx_mode, + uint32_t nof_prb, + srslte_cp_t cp); + +void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q, + cf_t* sf_buffer, + cf_t* sf_buffer_rx, + uint32_t nof_prb, + srslte_sl_tm_t txMode, + srslte_cp_t cp); + +int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer_rx, + cf_t** dmrs_received, + srslte_sl_tm_t tx_mode, + uint32_t nof_prb, + srslte_cp_t cp); void srslte_chest_sl_free(srslte_chest_sl_t* q); diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 704f30871..a545cc1b9 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -331,19 +331,46 @@ typedef struct SRSLTE_API { ///< Sidelink typedef enum SRSLTE_API { - SRSLTE_SIDELINK_TM1, + SRSLTE_SIDELINK_TM1 = 0, SRSLTE_SIDELINK_TM2, SRSLTE_SIDELINK_TM3, SRSLTE_SIDELINK_TM4 } srslte_sl_tm_t; typedef enum SRSLTE_API { - SRSLTE_SIDELINK_PSBCH, + SRSLTE_SIDELINK_PSBCH = 0, SRSLTE_SIDELINK_PSCCH, SRSLTE_SIDELINK_PSSCH, SRSLTE_SIDELINK_PSDCH } srslte_sl_channels_t; +typedef enum SRSLTE_API { + SRSLTE_SIDELINK_DATA_SYMBOL = 0, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_GUARD_SYMBOL +} srslte_sl_symbol_t; + +#define SRSLTE_PSBCH_NOF_PRB (6) +#define SRSLTE_PSCCH_TM34_NOF_PRB (2) + +#define SRSLTE_MIB_SL_LEN (40) // TM1/2: 40 bits +#define SRSLTE_MIB_SL_V2X_LEN (48) // TM3/4: 48 bits +#define SRSLTE_MIB_SL_MAX_LEN (SRSLTE_MIB_SL_V2X_LEN) + +#define SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS (2) +#define SRSLTE_SL_TM34_DEFAULT_NUM_DMRS_SYMBOLS (4) ///< In TM3/4, all channels have 4 DMRS by default + +#define SRSLTE_PSBCH_TM12_NUM_DATA_SYMBOLS (7) ///< SL-BCH is in 7 OFDM symbols +#define SRSLTE_PSBCH_TM12_NUM_DMRS_SYMBOLS (2) ///< PSBCH has 2 DMRS symbols +#define SRSLTE_PSBCH_TM12_NUM_SYNC_SYMBOLS (4) ///< Two symbols PSSS and two SSSS + +#define SRSLTE_PSBCH_TM34_NUM_DATA_SYMBOLS (6) ///< SL-BCH is in 7 OFDM symbols +#define SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS (3) ///< PSBCH has 3 DMRS symbols in TM3 and TM4 +#define SRSLTE_PSBCH_TM34_NUM_SYNC_SYMBOLS (4) ///< Two symbols PSSS and two SSSS + +///< PHY common function declarations + SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t* cell); SRSLTE_API void srslte_cell_fprint(FILE* stream, srslte_cell_t* cell, uint32_t sfn); @@ -437,4 +464,6 @@ SRSLTE_API float srslte_band_fu_nbiot(uint32_t ul_earfcn, const float m_ul); SRSLTE_API char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode); +bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i); + #endif // SRSLTE_PHY_COMMON_H diff --git a/lib/include/srslte/phy/phch/mib_sl.h b/lib/include/srslte/phy/phch/mib_sl.h new file mode 100644 index 000000000..532996053 --- /dev/null +++ b/lib/include/srslte/phy/phch/mib_sl.h @@ -0,0 +1,80 @@ +/* + * 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_MIB_SL_H +#define SRSLTE_MIB_SL_H + +#include +#include + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" + +/** + * Master information block - Sidelink (MIB-SL and MIB-SL-V2X). + * + * \brief MIB-SL packing/unpacking functions to convert between bit streams + * + * Reference: 3GPP TS 36.331 version 15.6.0 Release 15 Sec. 6.5 + */ +typedef struct SRSLTE_API { + + uint32_t mib_sl_len; + + // sl-Bandwidth-r12 enum {6, 15, 25, 50, 75, 100} (3 bits) + uint32_t sl_bandwidth_r12; + + // tdd-ConfigSL-r12 (3 bits) + uint32_t tdd_config_sl_r12; + + // directFrameNumber-r12 (10 bits) + uint32_t direct_frame_number_r12; + + // directSubframeNumber-r12 (4 bits) + uint32_t direct_subframe_number_r12; + + // inCoverage-r12 (1 bit) + bool in_coverage_r12; + + // reserved-r12 + // TM2: (19 bits) + // TM4: (27 bits) + +} srslte_mib_sl_t; + +SRSLTE_API int srslte_mib_sl_init(srslte_mib_sl_t* q, srslte_sl_tm_t tm); + +SRSLTE_API int srslte_mib_sl_set(srslte_mib_sl_t* q, + uint32_t nof_prb, + uint32_t tdd_config, + uint32_t direct_frame_number, + uint32_t direct_subframe_number, + bool in_coverage); + +SRSLTE_API void srslte_mib_sl_pack(srslte_mib_sl_t* q, uint8_t* msg); + +SRSLTE_API void srslte_mib_sl_unpack(srslte_mib_sl_t* q, uint8_t* msg); + +SRSLTE_API void srslte_mib_sl_free(srslte_mib_sl_t* q); + +SRSLTE_API void srslte_mib_sl_printf(FILE* f, srslte_mib_sl_t* q); + +#endif // SRSLTE_MIB_SL_H diff --git a/lib/include/srslte/phy/phch/psbch.h b/lib/include/srslte/phy/phch/psbch.h index 74185f878..94b5f5745 100644 --- a/lib/include/srslte/phy/phch/psbch.h +++ b/lib/include/srslte/phy/phch/psbch.h @@ -31,50 +31,59 @@ #include #define SRSLTE_SL_BCH_CRC_LEN 16 -#define SRSLTE_SL_BCH_PAYLOAD_LEN 40 -#define SRSLTE_SL_BCH_PAYLOADCRC_LEN (SRSLTE_SL_BCH_PAYLOAD_LEN + SRSLTE_SL_BCH_CRC_LEN) -#define SRSLTE_SL_BCH_ENCODED_LEN 3 * (SRSLTE_SL_BCH_PAYLOADCRC_LEN) -typedef struct { - bool is_ue; +/** + * \brief Physical Sidelink broadcast channel. + * + * Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6 + */ +typedef struct SRSLTE_API { + uint32_t N_sl_id; + srslte_sl_tm_t tm; + srslte_cp_t cp; + + uint32_t nof_data_re; uint32_t E; uint32_t Qm; uint32_t len_after_mod; uint32_t nof_prb; - uint32_t nof_symbols; - uint32_t N_sl_id; + uint32_t nof_data_symbols; + uint32_t sl_bch_tb_len; + uint32_t sl_bch_tb_crc_len; + uint32_t sl_bch_encoded_len; float precoding_scaling; - uint32_t nof_prb_psbch; // data - uint8_t* a; + uint8_t* c; // crc - uint32_t crc_poly; - srslte_crc_t crc_mib; + srslte_crc_t crc_mib_sl; uint8_t* crc_temp; // channel coding srslte_viterbi_t dec; srslte_convcoder_t encoder; uint8_t* d; + float* d_float; // rate matching uint8_t* e; - int16_t* e_16; + float* e_float; + + uint8_t* codeword; + float* llr; // interleaving + uint8_t* temp_g_bits; + uint32_t* interleaver; uint32_t* interleaver_lut; - uint8_t* codeword; // scrambling srslte_sequence_t seq; // modulation srslte_modem_table_t mod; - cf_t* symbols; - float* llr; - // layer mapping + cf_t* mod_symbols; // dft precoding srslte_dft_precoding_t dft_precoder; @@ -83,14 +92,19 @@ typedef struct { } srslte_psbch_t; -int srslte_psbch_init(srslte_psbch_t* q, uint32_t N_sl_id, uint32_t nof_prb); +SRSLTE_API int +srslte_psbch_init(srslte_psbch_t* q, uint32_t nof_prb, uint32_t N_sl_id, srslte_sl_tm_t tm, srslte_cp_t cp); + +SRSLTE_API void srslte_psbch_free(srslte_psbch_t* q); + +SRSLTE_API int srslte_psbch_encode(srslte_psbch_t* q, uint8_t* input, uint32_t input_len, cf_t* sf_buffer); + +SRSLTE_API int srslte_psbch_decode(srslte_psbch_t* q, cf_t* scfdma_symbols, uint8_t* output, uint32_t max_output_len); -void srslte_psbch_encode(srslte_psbch_t* q, uint8_t* mib_sl); -int srslte_psbch_decode(srslte_psbch_t* q, uint8_t* mib_sl); +SRSLTE_API int srslte_psbch_reset(srslte_psbch_t* q, uint32_t N_sl_id); -void srslte_psbch_put(srslte_psbch_t* q, cf_t* sf_buffer); -void srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer); +SRSLTE_API int srslte_psbch_put(srslte_psbch_t* q, cf_t* symbols, cf_t* sf_buffer); -void srslte_psbch_free(srslte_psbch_t* q); +SRSLTE_API int srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer, cf_t* symbols); #endif // SRSLTE_PSBCH_H diff --git a/lib/src/phy/ch_estimation/chest_sl.c b/lib/src/phy/ch_estimation/chest_sl.c index d7827f00a..ea8f3ceb6 100644 --- a/lib/src/phy/ch_estimation/chest_sl.c +++ b/lib/src/phy/ch_estimation/chest_sl.c @@ -18,304 +18,249 @@ * and at http://www.gnu.org/licenses/. * */ + #include #include -#include -#include -#include #include #include #include #include - -#include "srslte/config.h" #include "srslte/phy/ch_estimation/chest_sl.h" -#include "srslte/phy/dft/dft_precoding.h" -#include "srslte/phy/utils/convolution.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" #include "ul_rs_tables.h" -#define NOF_PRIME_NUMBERS_SL 196 -#define SRSLTE_SL_MAX_DMRS 4 -#define SRSLTE_SL_MAX_M_SC_RS 100 * 12 - -static uint32_t get_q(uint32_t u, uint32_t v, uint32_t N_sz) -{ - float q; - float q_hat; - float n_sz = (float)N_sz; - - q_hat = n_sz * (u + 1) / 31; - if ((((uint32_t)(2 * q_hat)) % 2) == 0) { - q = q_hat + 0.5 + v; - } else { - q = q_hat + 0.5 - v; - } - return (uint32_t)q; -} - -static void interpolate_pilots_sl_psbch(srslte_interp_linsrslte_vec_t* q, cf_t* ce, uint32_t n_prb) -{ - uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, SRSLTE_CP_NORM); - uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, SRSLTE_CP_NORM); - uint32_t NL = 2 * SRSLTE_CP_NSYMB(SRSLTE_CP_NORM); - - uint32_t nre = n_prb * SRSLTE_NRE; - - srslte_interp_linear_vector_resize(q, nre); - - uint32_t ce_l1 = SRSLTE_RE_IDX(n_prb, L1, 0 * SRSLTE_NRE); - uint32_t ce_l2 = SRSLTE_RE_IDX(n_prb, L2, 0 * SRSLTE_NRE); - - srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L2 - L1), L1, false, nre); - srslte_interp_linear_vector3(q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L2 - L1), (L2 - L1) - 1, true, nre); - srslte_interp_linear_vector3( - q, &ce[ce_l1], &ce[ce_l2], &ce[ce_l2], &ce[ce_l2 + nre], (L2 - L1), (NL - L2) - 1, true, nre); -} - -// TS36.211 S9.8 Table 9.8-2: Reference signal parameters for PSCCH int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q, uint32_t N_sa_id) { srslte_interp_linear_vector_init(&q->lin_vec_sl, SRSLTE_MAX_PRB * SRSLTE_NRE); - q->n_CS = srslte_vec_malloc(sizeof(int8_t) * SRSLTE_SL_MAX_DMRS); - if (!q->n_CS) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - q->alpha = srslte_vec_malloc(sizeof(float) * SRSLTE_SL_MAX_DMRS); - if (!q->alpha) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - q->w = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_MAX_DMRS); - if (!q->w) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - q->q = srslte_vec_malloc(sizeof(uint32_t) * SRSLTE_SL_MAX_DMRS); - if (!q->q) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - q->r = (float**)srslte_vec_malloc(sizeof(float*) * SRSLTE_SL_MAX_DMRS); - if (!q->r) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - for (int i = 0; i < SRSLTE_SL_MAX_DMRS; i++) { + for (int i = 0; i < SRSLTE_SL_MAX_DMRS_SYMB; i++) { q->r[i] = srslte_vec_malloc(sizeof(float) * SRSLTE_MAX_PRB * SRSLTE_NRE); if (!q->r[i]) { - ERROR("Error allocating memmory"); + ERROR("Error allocating memory"); return SRSLTE_ERROR; } - } - q->r_uv = (cf_t**)srslte_vec_malloc(sizeof(cf_t*) * SRSLTE_SL_MAX_DMRS); - if (!q->r_uv) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - for (int i = 0; i < SRSLTE_SL_MAX_DMRS; i++) { + q->r_uv[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE); if (!q->r_uv[i]) { - ERROR("Error allocating memmory"); + ERROR("Error allocating memory"); return SRSLTE_ERROR; } - } - q->r_sequence = (cf_t**)srslte_vec_malloc(sizeof(cf_t*) * SRSLTE_SL_MAX_DMRS); - if (!q->r_sequence) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - for (int i = 0; i < SRSLTE_SL_MAX_DMRS; i++) { + q->r_sequence[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE); if (!q->r_sequence[i]) { - ERROR("Error allocating memmory"); + ERROR("Error allocating memory"); + return SRSLTE_ERROR; + } + + q->dmrs_received[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_MAX_PRB * SRSLTE_NRE); + if (!q->dmrs_received[i]) { + ERROR("Error allocating memory"); return SRSLTE_ERROR; } } - q->u = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS); - if (!q->u) { - ERROR("Error allocating memmory"); - return SRSLTE_ERROR; - } - q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS); // MAX PERIOD LENGTH 320 + + q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS_SYMB); // MAX PERIOD LENGTH 320 if (!q->f_gh_pattern) { - ERROR("Error allocating memmory"); + ERROR("Error allocating memory"); return SRSLTE_ERROR; } srslte_group_hopping_f_gh(q->f_gh_pattern, N_sa_id); - q->ce = srslte_vec_malloc(sizeof(cf_t) * 100 * 12 * 14); + q->ce = srslte_vec_malloc(sizeof(cf_t) * 2 * SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * SRSLTE_MAX_PRB); if (!q->ce) { - ERROR("Error allocating memmory"); + ERROR("Error allocating memory"); return SRSLTE_ERROR; } return SRSLTE_SUCCESS; } -int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q) +static uint32_t get_q(uint32_t u, uint32_t v, uint32_t N_sz) { - return srslte_chest_sl_init_dmrs(q, 0); + float q; + float n_sz = (float)N_sz; + + float q_hat = n_sz * (u + 1) / 31; + if ((((uint32_t)(2 * q_hat)) % 2) == 0) { + q = q_hat + 0.5 + v; + } else { + q = q_hat + 0.5 - v; + } + return (uint32_t)q; } int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, - srslte_sl_tm_t txMode, - uint32_t nof_prb, + srslte_sl_tm_t tm, srslte_sl_channels_t ch, uint32_t sf_idx, uint32_t N_sl_id, - uint32_t available_pool_rbs, + uint32_t L_crb, uint32_t N_sa_id) { // M_sc_rs - Reference Signal Length switch (ch) { case SRSLTE_SIDELINK_PSBCH: - q->M_sc_rs = 72; + q->M_sc_rs = SRSLTE_PSBCH_NOF_PRB * SRSLTE_NRE; break; case SRSLTE_SIDELINK_PSCCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { - q->M_sc_rs = 12; - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - q->M_sc_rs = 24; + q->M_sc_rs = SRSLTE_NRE; + if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + q->M_sc_rs = SRSLTE_PSCCH_TM34_NOF_PRB * SRSLTE_NRE; } break; case SRSLTE_SIDELINK_PSSCH: - q->M_sc_rs = available_pool_rbs; + q->M_sc_rs = L_crb * SRSLTE_NRE; break; case SRSLTE_SIDELINK_PSDCH: printf("channel not supported yet\n\n"); break; default: - printf("channel not supported yet\n\n"); + printf("channel not supported\n\n"); return SRSLTE_ERROR; } - // nr_DMRS_symbols - switch (txMode) { - case SRSLTE_SIDELINK_TM1: - case SRSLTE_SIDELINK_TM2: - q->nr_DMRS_symbols = 2; - break; - case SRSLTE_SIDELINK_TM3: - case SRSLTE_SIDELINK_TM4: - printf("transmission mode not supported yet\n"); - return SRSLTE_ERROR; - default: - printf("transmission mode not supported \n"); - return SRSLTE_ERROR; + // Number of DMRS symbols + if (tm <= SRSLTE_SIDELINK_TM2) { + q->nof_dmrs_symbols = SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS; + } else { + if (ch == SRSLTE_SIDELINK_PSBCH) { + // only PSBCH has fewer symbols + q->nof_dmrs_symbols = SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS; + } else { + // all other channels have 4 DMRS + q->nof_dmrs_symbols = SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS; + } } - // n_CS - Cyclic Shift + // Cyclic Shift + // 36.211, Section 9.8 switch (ch) { case SRSLTE_SIDELINK_PSBCH: - for (int i = 0; i < q->nr_DMRS_symbols; i++) { + for (int i = 0; i < q->nof_dmrs_symbols; i++) { q->n_CS[i] = (int)(N_sl_id / 2) % 8; } break; case SRSLTE_SIDELINK_PSCCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { - for (int i = 0; i < q->nr_DMRS_symbols; i++) { + if (tm <= SRSLTE_SIDELINK_TM2) { + for (int i = 0; i < q->nof_dmrs_symbols; i++) { q->n_CS[i] = 0; } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - for (int i = 0; i < q->nr_DMRS_symbols; i++) { - q->n_CS[i] = i * 3; + } else { + for (int i = 0; i < q->nof_dmrs_symbols; i++) { + // TODO: TS 36.213 Section 14.2.1: "The UE shall randomly select the cyclic shift n_CS among {0, 3, 6, 9} in + // each PSCCH transmission." + q->n_CS[i] = 0; + // q->n_CS[i] = i * 3; } } break; case SRSLTE_SIDELINK_PSSCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { - for (int i = 0; i < q->nr_DMRS_symbols; i++) { + if (tm <= SRSLTE_SIDELINK_TM2) { + for (int i = 0; i < q->nof_dmrs_symbols; i++) { + q->n_CS[i] = (int)(N_sa_id / 2) % 8; + } + } else { + // TODO: both equation are the same here but spec says N_id_X for Mode3+4 + for (int i = 0; i < q->nof_dmrs_symbols; i++) { q->n_CS[i] = (int)(N_sa_id / 2) % 8; } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { } break; case SRSLTE_SIDELINK_PSDCH: - for (int i = 0; i < q->nr_DMRS_symbols; i++) { + for (int i = 0; i < q->nof_dmrs_symbols; i++) { q->n_CS[i] = 0; } break; } // alpha - Reference Signal Cyclic Shift - for (int i = 0; i < q->nr_DMRS_symbols; ++i) { + for (int i = 0; i < q->nof_dmrs_symbols; ++i) { q->alpha[i] = (2 * M_PI * q->n_CS[i]) / 12; } // Group Hopping + // 36.211, Section 10.1.4.1.3 // Base Sequence Number - always 0 for sidelink q->v = 0; switch (ch) { case SRSLTE_SIDELINK_PSBCH: q->f_gh = 0; q->f_ss = (N_sl_id / 16) % 30; - for (int i = 0; i < q->nr_DMRS_symbols; ++i) { + for (int i = 0; i < q->nof_dmrs_symbols; ++i) { q->u[i] = (q->f_gh + q->f_ss) % 30; } break; case SRSLTE_SIDELINK_PSCCH: q->f_gh = 0; - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { + if (tm <= SRSLTE_SIDELINK_TM2) { q->f_ss = 0; - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { + } else { q->f_ss = 8; } - for (int i = 0; i < q->nr_DMRS_symbols; ++i) { + for (int i = 0; i < q->nof_dmrs_symbols; ++i) { q->u[i] = (q->f_gh + q->f_ss) % 30; } break; case SRSLTE_SIDELINK_PSSCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { - q->f_gh = 1; - q->f_ss = N_sa_id % 30; + if (tm <= SRSLTE_SIDELINK_TM2) { + q->f_gh = 1; + q->f_ss = N_sa_id % 30; + uint32_t delta_ss = 0; uint8_t i = 0; for (uint32_t ns = 2 * sf_idx; ns < 2 * (sf_idx + 1); ns++) { uint32_t f_gh = q->f_gh_pattern[ns]; + q->u[i++] = (f_gh + q->f_ss + delta_ss) % 30; + } + } else { + // TM3/4 + q->f_gh = 1; + q->f_ss = (N_sa_id / 16) % 30; + uint32_t delta_ss = 0; - uint32_t delta_ss = 0; - q->u[i++] = (f_gh + (N_sa_id % 30) + delta_ss) % 30; + for (uint32_t ns = 0; ns <= q->nof_dmrs_symbols; ns++) { + uint32_t f_gh = q->f_gh_pattern[ns]; + q->u[ns] = (f_gh + q->f_ss + delta_ss) % 30; } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - q->f_gh = 1; } break; case SRSLTE_SIDELINK_PSDCH: q->f_gh = 0; q->f_ss = 0; - for (int i = 0; i < q->nr_DMRS_symbols; ++i) { + for (int i = 0; i < q->nof_dmrs_symbols; ++i) { q->u[i] = (q->f_gh + q->f_ss) % 30; } break; } // N_zc - Zadoff Chu Sequence Length + + // TODO: the refsignal_ul.c should be reused for this, code looks almost the same switch (q->M_sc_rs / SRSLTE_NRE) { case 1: - for (int j = 0; j < q->nr_DMRS_symbols; ++j) { + for (int j = 0; j < q->nof_dmrs_symbols; ++j) { for (int i = 0; i < SRSLTE_NRE; i++) { q->r[j][i] = phi_M_sc_12[q->u[j]][i] * M_PI / 4; } } break; case 2: - for (int j = 0; j < q->nr_DMRS_symbols; ++j) { + for (int j = 0; j < q->nof_dmrs_symbols; ++j) { for (int i = 0; i < q->M_sc_rs; i++) { q->r[j][i] = phi_M_sc_24[q->u[j]][i] * M_PI / 4; } } break; default: - for (uint32_t i = NOF_PRIME_NUMBERS_SL - 1; i > 0; i--) { + for (uint32_t i = SRSLTE_SL_NOF_PRIME_NUMBERS - 1; i > 0; i--) { if (prime_numbers[i] < q->M_sc_rs) { q->N_zc = prime_numbers[i]; break; } } - for (int j = 0; j < q->nr_DMRS_symbols; ++j) { + for (int j = 0; j < q->nof_dmrs_symbols; ++j) { q->q[j] = get_q(q->u[j], q->v, q->N_zc); float n_sz = (float)q->N_zc; for (uint32_t i = 0; i < q->M_sc_rs; i++) { @@ -323,43 +268,56 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, q->r[j][i] = -M_PI * q->q[j] * m * (m + 1) / n_sz; } } - break; } + // Do complex exponential and adjust amplitude - for (int j = 0; j < q->nr_DMRS_symbols; ++j) { + // 36.211, Section 5.5.1 + for (int j = 0; j < q->nof_dmrs_symbols; ++j) { for (int i = 0; i < q->M_sc_rs; i++) { q->r_uv[j][i] = cexpf(I * (q->r[j][i] + q->alpha[0] * i)); } } // w - Orthogonal Sequence + // 36.211, Section 9.8 switch (ch) { case SRSLTE_SIDELINK_PSBCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { + case SRSLTE_SIDELINK_PSDCH: + if (tm <= SRSLTE_SIDELINK_TM2) { + if (N_sl_id % 2) { + q->w[0] = 1; + q->w[1] = -1; + } else { + q->w[0] = 1; + q->w[1] = 1; + } + } else { + // TM3/4 if (N_sl_id % 2) { q->w[0] = 1; q->w[1] = -1; + q->w[2] = 1; } else { q->w[0] = 1; q->w[1] = 1; + q->w[2] = 1; } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - printf("transmission mode not supported \n"); - return SRSLTE_ERROR; } break; case SRSLTE_SIDELINK_PSCCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { + if (tm <= SRSLTE_SIDELINK_TM2) { q->w[0] = 1; q->w[1] = 1; - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - printf("transmission mode not supported \n"); - return SRSLTE_ERROR; + } else { + q->w[0] = 1; + q->w[1] = 1; + q->w[2] = 1; + q->w[3] = 1; } break; case SRSLTE_SIDELINK_PSSCH: - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { + if (tm <= SRSLTE_SIDELINK_TM2) { if (N_sa_id % 2 == 0) { q->w[0] = 1; q->w[1] = 1; @@ -367,145 +325,247 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q, q->w[0] = 1; q->w[1] = -1; } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - printf("transmission mode not supported \n"); - return SRSLTE_ERROR; + } else { + // TM3/4 + if (N_sa_id % 2 == 0) { + q->w[0] = 1; + q->w[1] = 1; + q->w[2] = 1; + q->w[3] = 1; + } else { + q->w[0] = 1; + q->w[1] = -1; + q->w[2] = 1; + q->w[3] = -1; + } } break; default: return SRSLTE_ERROR; } - for (int j = 0; j < q->nr_DMRS_symbols; j++) { + + for (int j = 0; j < q->nof_dmrs_symbols; j++) { for (int i = 0; i < q->M_sc_rs; i++) { q->r_sequence[j][i] = q->w[j] * q->r_uv[j][i]; } } + return SRSLTE_SUCCESS; } -int srslte_chest_sl_gen_psbch_dmrs( - srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t nof_prb, uint32_t sf_idx, uint32_t N_sl_id) +int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q) { - return srslte_chest_sl_gen_dmrs(q, txMode, nof_prb, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0); + return srslte_chest_sl_init_dmrs(q, 0); } -int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, cf_t* sf_buffer, srslte_sl_tm_t tx_mode, uint32_t nof_prb) +int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t tm, uint32_t N_sl_id) { - int sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * nof_prb * 2; - if (tx_mode == SRSLTE_SIDELINK_TM1 || tx_mode == SRSLTE_SIDELINK_TM2) { - int k = (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) - 4) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 36; - memcpy(&sf_buffer[k], &q->r_sequence[0][0], q->M_sc_rs * sizeof(cf_t)); - memcpy(&sf_buffer[k + sf_n_re / 2], &q->r_sequence[1][0], q->M_sc_rs * sizeof(cf_t)); - } else if (tx_mode == SRSLTE_SIDELINK_TM3 || tx_mode == SRSLTE_SIDELINK_TM4) { - printf("transmission mode not supported yet\n"); - return SRSLTE_ERROR; - } - return SRSLTE_SUCCESS; + return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0); } -void srslte_chest_sl_put_pscch_dmrs( - srslte_chest_sl_t* q, uint32_t prb_idx, uint32_t nof_prb, cf_t* sf_buffer, srslte_sl_tm_t txMode) +int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer, + srslte_sl_tm_t tm, + uint32_t nof_prb, + srslte_cp_t cp) { - uint32_t l = 3; - uint32_t k = prb_idx * SRSLTE_NRE; - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { - for (int i = 0; i < q->nr_DMRS_symbols; i++) { - memcpy(&sf_buffer[k + l * SRSLTE_NRE * nof_prb], q->r_sequence[i], q->M_sc_rs * sizeof(cf_t)); - l += 7; - } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - l = 2; - for (int i = 0; i < q->nr_DMRS_symbols; i++) { - memcpy(&sf_buffer[k + l * SRSLTE_NRE * nof_prb], q->r_sequence[i], q->M_sc_rs * sizeof(cf_t)); - l += 3; + uint32_t sample_pos = 0; + uint32_t k = nof_prb * SRSLTE_NRE / 2 - 36; + uint32_t sf_nsymbols = 0; + + if (tm <= SRSLTE_SIDELINK_TM2) { + sf_nsymbols = (cp == SRSLTE_CP_NORM) ? SRSLTE_CP_NORM_SF_NSYMB : SRSLTE_CP_EXT_SF_NSYMB; + } else { + // TM3/4 + sf_nsymbols = SRSLTE_CP_NORM_SF_NSYMB; + } + + // Mapping to physical resources + for (uint32_t i = 0; i < sf_nsymbols; i++) { + if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i)) { + memcpy(&sf_buffer[k + i * nof_prb * SRSLTE_NRE], &q->r_sequence[sample_pos][0], q->M_sc_rs * sizeof(cf_t)); + sample_pos++; } } + + return SRSLTE_SUCCESS; } -void srslte_chest_sl_put_pssch_dmrs(srslte_chest_sl_t* q, - uint32_t prb_start, - uint32_t prb_end, - uint32_t prb_num, - uint32_t nof_prb, - cf_t* sf_buffer, - srslte_sl_tm_t txMode) +static void interpolate_pilots_sl_psbch(srslte_interp_linsrslte_vec_t* q, + cf_t* ce, + uint32_t n_prb, + srslte_sl_tm_t tm, + srslte_cp_t cp) { - uint32_t k = prb_start * SRSLTE_NRE; - if (txMode == SRSLTE_SIDELINK_TM1 || txMode == SRSLTE_SIDELINK_TM2) { - uint32_t l = 3; - for (int i = 0; i < q->nr_DMRS_symbols; i++) { - memcpy(&sf_buffer[k + l * nof_prb * SRSLTE_NRE], q->r_sequence[i], q->M_sc_rs / 2 * sizeof(cf_t)); - k = ((prb_end + 1) * SRSLTE_NRE) - (prb_num * SRSLTE_NRE); - memcpy( - &sf_buffer[k + l * nof_prb * SRSLTE_NRE], &q->r_sequence[i][q->M_sc_rs / 2], q->M_sc_rs / 2 * sizeof(cf_t)); - l += 7; + uint32_t L1; + uint32_t L2; + uint32_t L3; + uint32_t ce_l1; + uint32_t ce_l2; + uint32_t ce_l3; + + if (tm <= SRSLTE_SIDELINK_TM2) { + if (cp == SRSLTE_CP_NORM) { + L1 = 3; + L2 = 10; + } else { + L1 = 2; + L2 = 8; + } + } else { + // TM3/4 + if (cp == SRSLTE_CP_NORM) { + L1 = 4; + L2 = 6; + L3 = 9; + } else { + ERROR("Invalid CP"); + return; } - } else if (txMode == SRSLTE_SIDELINK_TM3 || txMode == SRSLTE_SIDELINK_TM4) { - printf("Transmission Mode not supported\n"); } -} -void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q, cf_t* sf_buffer, cf_t* output, uint32_t nof_prb) -{ + uint32_t NL = 2 * SRSLTE_CP_NSYMB(cp); + + uint32_t nre = n_prb * SRSLTE_NRE; - int sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * nof_prb * 2; + srslte_interp_linear_vector_resize(q, nre); - // Get Demodulation Reference Signals from resource grid - int k = (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) - 4) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 36; + ce_l1 = SRSLTE_RE_IDX(n_prb, L1, 0 * SRSLTE_NRE); + ce_l2 = SRSLTE_RE_IDX(n_prb, L2, 0 * SRSLTE_NRE); - bzero(q->ce, sizeof(cf_t) * sf_n_re); + if (tm <= SRSLTE_SIDELINK_TM2) { + srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L2 - L1), L1, false, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L2 - L1), (L2 - L1) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l1], &ce[ce_l2], &ce[ce_l2], &ce[ce_l2 + nre], (L2 - L1), (NL - L2) - 1, true, nre); + } else { + // TM3/4 + ce_l3 = SRSLTE_RE_IDX(n_prb, L3, 0 * SRSLTE_NRE); + srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L2 - L1), L1, false, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L2 - L1), (L2 - L1) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l2], &ce[ce_l3], NULL, &ce[ce_l2 + nre], (L3 - L2), (L3 - L2) - 1, true, nre); + srslte_interp_linear_vector3( + q, &ce[ce_l2], &ce[ce_l3], &ce[ce_l3], &ce[ce_l3 + nre], (L3 - L2), (NL - L3) - 1, true, nre); + } +} + +void srslte_chest_sl_psbch_ls_estimate_equalize(srslte_chest_sl_t* q, + cf_t* sf_buffer, + cf_t* sf_buffer_rx, + uint32_t nof_prb, + srslte_sl_tm_t tm, + srslte_cp_t cp) +{ + int sf_n_re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * nof_prb * 2; + + uint32_t k = nof_prb * SRSLTE_NRE / 2 - 36; // Get Pilot Estimates // Use the known DMRS signal to compute least-squares estimates - srslte_vec_prod_conj_ccc(&sf_buffer[k], &q->r_sequence[0][0], &q->ce[k], q->M_sc_rs); - srslte_vec_prod_conj_ccc(&sf_buffer[k + sf_n_re / 2], &q->r_sequence[1][0], &q->ce[k + sf_n_re / 2], q->M_sc_rs); + bzero(q->ce, sizeof(cf_t) * sf_n_re); - interpolate_pilots_sl_psbch(&q->lin_vec_sl, q->ce, nof_prb); + if (tm <= SRSLTE_SIDELINK_TM2) { + if (cp == SRSLTE_CP_NORM) { + srslte_vec_prod_conj_ccc(&sf_buffer[3 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[0][0], + &q->ce[3 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[10 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[1][0], + &q->ce[10 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + } else { + srslte_vec_prod_conj_ccc(&sf_buffer[2 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[0][0], + &q->ce[2 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[8 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[1][0], + &q->ce[8 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + } + } else { + // TM3/4 + if (cp == SRSLTE_CP_NORM) { + srslte_vec_prod_conj_ccc(&sf_buffer[4 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[0][0], + &q->ce[4 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[6 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[1][0], + &q->ce[6 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + srslte_vec_prod_conj_ccc(&sf_buffer[9 * nof_prb * SRSLTE_NRE + k], + &q->r_sequence[2][0], + &q->ce[9 * nof_prb * SRSLTE_NRE + k], + q->M_sc_rs); + } else { + ERROR("Invalid CP"); + return; + } + } + + interpolate_pilots_sl_psbch(&q->lin_vec_sl, q->ce, nof_prb, tm, cp); // Perform channel equalization - srslte_predecoding_single(sf_buffer, q->ce, output, NULL, sf_n_re, 1, 0.0); + srslte_predecoding_single(sf_buffer, q->ce, sf_buffer_rx, NULL, sf_n_re, 1, 0.0); } -void srslte_chest_sl_free(srslte_chest_sl_t* q) +int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q, + cf_t* sf_buffer_rx, + cf_t** dmrs_received, + srslte_sl_tm_t tm, + uint32_t nof_prb, + srslte_cp_t cp) { - srslte_interp_linear_vector_free(&q->lin_vec_sl); - if (q->w) { - free(q->w); - } - if (q->n_CS) { - free(q->n_CS); - } - if (q->q) { - free(q->q); + uint32_t sample_pos = 0; + uint32_t k = nof_prb * SRSLTE_NRE / 2 - 36; + uint32_t sf_nsymbols = SRSLTE_CP_NORM_SF_NSYMB; + + // Get DMRSs + for (uint32_t i = 0; i < sf_nsymbols; i++) { + if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i)) { + memcpy(&q->dmrs_received[sample_pos][0], &sf_buffer_rx[k + i * nof_prb * SRSLTE_NRE], q->M_sc_rs * sizeof(cf_t)); + sample_pos++; + } } - if (q->alpha) { - free(q->alpha); + + for (uint32_t i = 0; i < q->nof_dmrs_symbols; i++) { + memcpy(&dmrs_received[i][0], &q->dmrs_received[i][0], q->M_sc_rs * sizeof(cf_t)); } - if (q->r) { - for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) { + + return sample_pos; +} + +void srslte_chest_sl_free(srslte_chest_sl_t* q) +{ + srslte_interp_linear_vector_free(&q->lin_vec_sl); + + for (int i = 0; i < SRSLTE_SL_MAX_DMRS_SYMB; i++) { + if (q->r[i]) { free(q->r[i]); } - free(q->r); - } - if (q->r_uv) { - for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) { + + if (q->r_uv[i]) { free(q->r_uv[i]); } - free(q->r_uv); - } - if (q->r_sequence) { - for (int i = 0; i < SRSLTE_SL_MAX_DMRS; ++i) { + + if (q->r_sequence[i]) { free(q->r_sequence[i]); } - free(q->r_sequence); - } - if (q->u) { - free(q->u); + + if (q->dmrs_received[i]) { + free(q->dmrs_received[i]); + } } + if (q->f_gh_pattern) { free(q->f_gh_pattern); } if (q->ce) { free(q->ce); } -} \ No newline at end of file +} diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 085fff6e4..94d08b55c 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -811,4 +811,46 @@ char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode) default: return "N/A"; } -} \ No newline at end of file +} + +///< Sidelink helpers + +///< Look-up tables for Sidelink channel symbols +srslte_sl_symbol_t srslte_psbch_symbol_map_tm12[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_GUARD_SYMBOL}; + +srslte_sl_symbol_t srslte_psbch_symbol_map_tm34[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_DMRS_SYMBOL, + SRSLTE_SIDELINK_DATA_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_SYNC_SYMBOL, + SRSLTE_SIDELINK_GUARD_SYMBOL}; + +bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i) +{ + if (tm <= SRSLTE_SIDELINK_TM2) { + return srslte_psbch_symbol_map_tm12[i] == type; + } else { + return srslte_psbch_symbol_map_tm34[i] == type; + } +} diff --git a/lib/src/phy/phch/mib_sl.c b/lib/src/phy/phch/mib_sl.c new file mode 100644 index 000000000..c9aedb053 --- /dev/null +++ b/lib/src/phy/phch/mib_sl.c @@ -0,0 +1,123 @@ +/* + * 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/phy/phch/mib_sl.h" +#include "srslte/phy/utils/bit.h" +//#include "srslte/phy/common/phy_sl_common.h" + +int srslte_mib_sl_init(srslte_mib_sl_t* q, srslte_sl_tm_t tm) +{ + if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) { + q->mib_sl_len = SRSLTE_MIB_SL_LEN; + } else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) { + q->mib_sl_len = SRSLTE_MIB_SL_V2X_LEN; + } else { + return SRSLTE_ERROR; + } + + q->sl_bandwidth_r12 = 0; + q->direct_frame_number_r12 = 0; + q->direct_subframe_number_r12 = 0; + q->in_coverage_r12 = false; + q->tdd_config_sl_r12 = 0; + + return SRSLTE_SUCCESS; +} + +int srslte_mib_sl_set(srslte_mib_sl_t* q, + uint32_t nof_prb, + uint32_t tdd_config, + uint32_t direct_frame_number, + uint32_t direct_subframe_number, + bool in_coverage) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL) { + switch (nof_prb) { + case 6: + q->sl_bandwidth_r12 = 0; + break; + case 15: + q->sl_bandwidth_r12 = 1; + break; + case 25: + q->sl_bandwidth_r12 = 2; + break; + case 50: + q->sl_bandwidth_r12 = 3; + break; + case 75: + q->sl_bandwidth_r12 = 4; + break; + case 100: + q->sl_bandwidth_r12 = 5; + break; + default: + printf("Invalid bandwidth\n"); + return SRSLTE_ERROR; + } + q->tdd_config_sl_r12 = tdd_config; + q->direct_frame_number_r12 = direct_frame_number; + q->direct_subframe_number_r12 = direct_subframe_number; + q->in_coverage_r12 = in_coverage; + + ret = SRSLTE_SUCCESS; + } + + return ret; +} + +void srslte_mib_sl_pack(srslte_mib_sl_t* q, uint8_t* msg) +{ + bzero(msg, sizeof(uint8_t) * SRSLTE_MIB_SL_MAX_LEN); + srslte_bit_unpack(q->sl_bandwidth_r12, &msg, 3); + srslte_bit_unpack(q->tdd_config_sl_r12, &msg, 3); + srslte_bit_unpack(q->direct_frame_number_r12, &msg, 10); + srslte_bit_unpack(q->direct_subframe_number_r12, &msg, 4); + srslte_bit_unpack((uint32_t)q->in_coverage_r12, &msg, 1); +} + +void srslte_mib_sl_unpack(srslte_mib_sl_t* q, uint8_t* msg) +{ + q->sl_bandwidth_r12 = srslte_bit_pack(&msg, 3); + q->tdd_config_sl_r12 = srslte_bit_pack(&msg, 3); + q->direct_frame_number_r12 = srslte_bit_pack(&msg, 10); + q->direct_subframe_number_r12 = srslte_bit_pack(&msg, 4); + q->in_coverage_r12 = (bool)srslte_bit_pack(&msg, 1); +} + +void srslte_mib_sl_printf(FILE* f, srslte_mib_sl_t* q) +{ + fprintf(f, " - Bandwidth: %i\n", q->sl_bandwidth_r12); + fprintf(f, " - Direct Frame Number: %i\n", q->direct_frame_number_r12); + fprintf(f, " - Direct Subframe Number: %i\n", q->direct_subframe_number_r12); + fprintf(f, " - TDD config: %i\n", q->tdd_config_sl_r12); + fprintf(f, " - In coverage: %s\n", q->in_coverage_r12 ? "yes" : "no"); +} + +void srslte_mib_sl_free(srslte_mib_sl_t* q) +{ + if (q != NULL) { + bzero(q, sizeof(srslte_mib_sl_t)); + } +} diff --git a/lib/src/phy/phch/psbch.c b/lib/src/phy/phch/psbch.c index 796485b63..e214987f5 100644 --- a/lib/src/phy/phch/psbch.c +++ b/lib/src/phy/phch/psbch.c @@ -19,16 +19,18 @@ * */ -#include - -#include -#include -#include -#include -#include +#include "srslte/phy/phch/psbch.h" +#include "srslte/phy/fec/rm_conv.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" #include #include +#define HAVE_INTERLEAVING 1 + +#if HAVE_INTERLEAVING void slbch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm, uint32_t* interleaver_lut) { uint32_t NL = 1; @@ -50,293 +52,348 @@ void slbch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32 } } } +#endif // HAVE_INTERLEAVING -int srslte_psbch_init(srslte_psbch_t* q, uint32_t N_sl_id, uint32_t nof_prb) +int srslte_psbch_init(srslte_psbch_t* q, uint32_t nof_prb, uint32_t N_sl_id, srslte_sl_tm_t tm, srslte_cp_t cp) { - int ret = SRSLTE_ERROR_INVALID_INPUTS; + bzero(q, sizeof(srslte_psbch_t)); - if (q != NULL) { + q->N_sl_id = N_sl_id; + q->tm = tm; - ret = SRSLTE_ERROR; + q->nof_prb = nof_prb; - q->nof_prb = nof_prb; - q->N_sl_id = N_sl_id; + if (SRSLTE_CP_ISEXT(cp)) { + ERROR("Extended CP is not supported yet."); + return SRSLTE_ERROR; + } + q->cp = cp; + + // Calculate rate matching params + if (q->tm <= SRSLTE_SIDELINK_TM2) { + q->nof_data_symbols = SRSLTE_PSBCH_TM12_NUM_DATA_SYMBOLS; + q->sl_bch_tb_len = SRSLTE_MIB_SL_LEN; + } else { + q->nof_data_symbols = SRSLTE_PSBCH_TM34_NUM_DATA_SYMBOLS; + q->sl_bch_tb_len = SRSLTE_MIB_SL_V2X_LEN; + } + q->nof_data_re = q->nof_data_symbols * (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB); + q->sl_bch_tb_crc_len = q->sl_bch_tb_len + SRSLTE_SL_BCH_CRC_LEN; + q->sl_bch_encoded_len = 3 * q->sl_bch_tb_crc_len; - q->nof_prb_psbch = 6; + q->c = srslte_vec_malloc(sizeof(uint8_t) * q->sl_bch_tb_crc_len); + if (!q->c) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - q->a = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOADCRC_LEN); - if (!q->a) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - q->d = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_ENCODED_LEN); - if (!q->d) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - bzero(q->d, sizeof(uint8_t) * SRSLTE_SL_BCH_ENCODED_LEN); + q->d = srslte_vec_malloc(sizeof(uint8_t) * q->sl_bch_encoded_len); + if (!q->d) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - // crc - q->crc_poly = 0x11021; - if (srslte_crc_init(&q->crc_mib, q->crc_poly, SRSLTE_SL_BCH_CRC_LEN)) { - ERROR("Error crc init"); - return SRSLTE_ERROR; - } - q->crc_temp = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN); - if (!q->crc_temp) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } + q->d_float = srslte_vec_malloc(sizeof(float) * q->sl_bch_encoded_len); + if (!q->d_float) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - // channel coding - q->encoder.K = 7; - q->encoder.R = 3; - q->encoder.tail_biting = true; - int poly[3] = {0x6D, 0x4F, 0x57}; - memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + // CRC + if (srslte_crc_init(&q->crc_mib_sl, SRSLTE_LTE_CRC16, SRSLTE_SL_BCH_CRC_LEN)) { + ERROR("Error crc init"); + return SRSLTE_ERROR; + } - // channel decoding - if (srslte_viterbi_init(&q->dec, SRSLTE_VITERBI_37, poly, 56, true)) { - return SRSLTE_ERROR; - } + q->crc_temp = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN); + if (!q->crc_temp) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - // rate matching - q->nof_symbols = 8; - q->E = q->nof_symbols * SRSLTE_NRE * q->nof_prb_psbch * 2; - q->e = srslte_vec_malloc(sizeof(uint8_t) * q->E); - if (!q->e) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - q->e_16 = srslte_vec_malloc(sizeof(int16_t) * q->E); - if (!q->e_16) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - bzero(q->e, sizeof(uint8_t) * q->E); - - // interleaving - q->Qm = 2; // Always QPSK - q->interleaver_lut = srslte_vec_malloc(sizeof(uint32_t) * q->E); - if (!q->interleaver_lut) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - slbch_interleave_gen(q->E / 2, q->nof_symbols, q->Qm, q->interleaver_lut); - q->codeword = srslte_vec_malloc(sizeof(uint8_t) * q->E); - if (!q->codeword) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } + // Channel coding + q->encoder.K = 7; + q->encoder.R = 3; + q->encoder.tail_biting = true; + int poly[3] = {0x6D, 0x4F, 0x57}; + memcpy(q->encoder.poly, poly, 3 * sizeof(int)); - // scrambling - bzero(&q->seq, sizeof(srslte_sequence_t)); - srslte_sequence_LTE_pr(&q->seq, q->E, q->N_sl_id); + if (srslte_viterbi_init(&q->dec, SRSLTE_VITERBI_37, poly, q->sl_bch_tb_crc_len, true)) { + return SRSLTE_ERROR; + } - // modulation - if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) { - return SRSLTE_ERROR; - } + // QPSK modulation + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6 - Table 9.6.2-1: PSBCH modulation schemes + q->Qm = srslte_mod_bits_x_symbol(SRSLTE_MOD_QPSK); + q->E = q->nof_data_re * q->Qm; - q->len_after_mod = q->E / q->mod.nbits_x_symbol; - q->symbols = srslte_vec_malloc(sizeof(cf_t) * q->len_after_mod); - if (!q->symbols) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - bzero(q->symbols, sizeof(cf_t) * q->len_after_mod); + q->e = srslte_vec_malloc(sizeof(uint8_t) * q->E); + if (!q->e) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - q->llr = srslte_vec_malloc(sizeof(float) * q->E); - if (!q->llr) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - bzero(q->llr, sizeof(float) * q->E); + q->e_float = srslte_vec_malloc(sizeof(float) * q->E); + if (!q->e_float) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - // dft precoding - q->precoding_scaling = 1.0; - if (srslte_dft_precoding_init(&q->dft_precoder, q->nof_prb_psbch, true)) { - return SRSLTE_ERROR; - } +#if HAVE_INTERLEAVING + // Interleaving + q->interleaver_lut = srslte_vec_malloc(sizeof(uint32_t) * q->E); + if (!q->interleaver_lut) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + slbch_interleave_gen(q->nof_data_re, q->nof_data_symbols, q->Qm, q->interleaver_lut); +#endif - q->scfdma_symbols = srslte_vec_malloc(sizeof(cf_t) * q->len_after_mod); - if (!q->scfdma_symbols) { - ERROR("Error allocating memmory\n"); - return SRSLTE_ERROR; - } - bzero(q->scfdma_symbols, sizeof(cf_t) * q->len_after_mod); + // Scrambling + bzero(&q->seq, sizeof(srslte_sequence_t)); + if (srslte_sequence_LTE_pr(&q->seq, q->E, N_sl_id) != SRSLTE_SUCCESS) { + ERROR("Error srslte_sequence_LTE_pr\n"); + return SRSLTE_ERROR; + } - // idft predecoding - if (srslte_dft_precoding_init(&q->idft_precoder, q->nof_prb_psbch, false)) { - return SRSLTE_ERROR; - } + q->codeword = srslte_vec_malloc(sizeof(uint8_t) * q->E); + if (!q->codeword) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } - ret = SRSLTE_SUCCESS; + // Modulation QPSK + if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK) != SRSLTE_SUCCESS) { + ERROR("Error srslte_modem_table_lte\n"); + return SRSLTE_ERROR; } - return ret; + q->mod_symbols = srslte_vec_malloc(sizeof(cf_t) * q->nof_data_re); + if (!q->mod_symbols) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + q->llr = srslte_vec_malloc(sizeof(float) * q->E); + if (!q->llr) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + // Transform precoding + q->precoding_scaling = 1.0; + if (srslte_dft_precoding_init_tx(&q->dft_precoder, SRSLTE_PSBCH_NOF_PRB) != SRSLTE_SUCCESS) { + ERROR("Error srslte_dft_precoding_init\n"); + return SRSLTE_ERROR; + } + + q->scfdma_symbols = srslte_vec_malloc(sizeof(cf_t) * q->nof_data_re); + if (!q->scfdma_symbols) { + ERROR("Error allocating memory\n"); + return SRSLTE_ERROR; + } + + if (srslte_dft_precoding_init_rx(&q->idft_precoder, SRSLTE_PSBCH_NOF_PRB) != SRSLTE_SUCCESS) { + ERROR("Error srslte_idft_precoding_init\n"); + return SRSLTE_ERROR; + } + + return SRSLTE_SUCCESS; } -void srslte_psbch_encode(srslte_psbch_t* q, uint8_t* mib_sl) +int srslte_psbch_encode(srslte_psbch_t* q, uint8_t* input, uint32_t input_len, cf_t* sf_buffer) { - // ******************************************************************************************************** - // SL-BCH Processing - // ******************************************************************************************************** + if (input == NULL || input_len > q->sl_bch_tb_len) { + ERROR("Can't encode PSBCH, input too long (%d > %d)\n", input_len, q->sl_bch_tb_len); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Copy into codeword buffer + memcpy(q->c, input, sizeof(uint8_t) * input_len); // CRC Attachment - memcpy(q->a, mib_sl, sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOAD_LEN); - srslte_crc_attach(&q->crc_mib, q->a, SRSLTE_SL_BCH_PAYLOAD_LEN); + srslte_crc_attach(&q->crc_mib_sl, q->c, input_len); // Channel Coding - srslte_convcoder_encode(&q->encoder, q->a, q->d, SRSLTE_SL_BCH_PAYLOADCRC_LEN); + srslte_convcoder_encode(&q->encoder, q->c, q->d, q->sl_bch_tb_crc_len); // Rate matching - q->nof_symbols = 8; - q->E = q->nof_symbols * (SRSLTE_NRE * q->nof_prb_psbch) * 2; - srslte_rm_conv_tx(q->d, SRSLTE_SL_BCH_ENCODED_LEN, q->e, q->E); + srslte_rm_conv_tx(q->d, q->sl_bch_encoded_len, q->codeword, q->E); - // Interleaving +#if HAVE_INTERLEAVING + // PUSCH de-interleaving for (int i = 0; i < q->E; i++) { - q->codeword[i] = (uint8_t)q->e[q->interleaver_lut[i]]; + q->e[i] = q->codeword[q->interleaver_lut[i]]; } - - // ******************************************************************************************************** - // PSBCH Processing - // ******************************************************************************************************** +#endif // Scrambling - srslte_scrambling_b(&q->seq, q->codeword); + srslte_scrambling_b(&q->seq, q->e); // Modulation - srslte_mod_modulate(&q->mod, q->codeword, q->symbols, q->E); + srslte_mod_modulate(&q->mod, q->e, q->mod_symbols, q->E); - // Layer Mapping - TS 36.211 SEC 9.6.3 - Single layer + // Layer Mapping + // Void: Single layer + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.3 - // DFT Precoding - srslte_dft_precoding(&q->dft_precoder, q->symbols, q->scfdma_symbols, q->nof_prb_psbch, q->nof_symbols); + // Transform precoding + srslte_dft_precoding(&q->dft_precoder, q->mod_symbols, q->scfdma_symbols, SRSLTE_PSBCH_NOF_PRB, q->nof_data_symbols); - // Precoding - TS 36.211 SEC 9.6.5 - Single antenna port -} + // Precoding + // Void: Single antenna port + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.5 -void srslte_psbch_put(srslte_psbch_t* q, cf_t* sf_buffer) -{ - uint32_t samplePos = 0; - uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36; + // RE mapping + srslte_psbch_put(q, q->scfdma_symbols, sf_buffer); - // Mapping to physical resources - for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) { - if (i == 1 || i == 2 || i == 3 || i == 10 || i == 11 || i == 12) { - continue; - } - memcpy(&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE], - &q->scfdma_symbols[samplePos], - (SRSLTE_NRE * q->nof_prb_psbch) * sizeof(cf_t)); - samplePos += (SRSLTE_NRE * q->nof_prb_psbch); - } + return SRSLTE_SUCCESS; } -void srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer) +int srslte_psbch_decode(srslte_psbch_t* q, cf_t* equalized_sf_syms, uint8_t* output, uint32_t max_output_len) { - uint32_t samplePos = 0; - uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36; - - // Get PSBCH RE's - for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) { - if (i == 1 || i == 2 || i == 3 || i == 10 || i == 11 || i == 12) { - continue; - } - memcpy(&q->scfdma_symbols[samplePos], - &sf_buffer[k + i * q->nof_prb * SRSLTE_NRE], - (SRSLTE_NRE * q->nof_prb_psbch) * sizeof(cf_t)); - samplePos += (SRSLTE_NRE * q->nof_prb_psbch); + if (max_output_len < q->sl_bch_tb_len) { + ERROR("Can't decode PSBCH, provided buffer too small (%d < %d)\n", max_output_len, q->sl_bch_tb_len); + return SRSLTE_ERROR; } -} -int srslte_psbch_decode(srslte_psbch_t* q, uint8_t* mib_sl) -{ - // ******************************************************************************************************** - // PSBCH Processing - // ******************************************************************************************************** + // RE extraction + if (q->nof_data_re != srslte_psbch_get(q, equalized_sf_syms, q->scfdma_symbols)) { + ERROR("There was an error getting the PSBCH symbols\n"); + return SRSLTE_ERROR; + } - // Precoding - TS 36.211 SEC 9.6.5 - Single antenna port Skipped + // Precoding + // Void: Single antenna port + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.5 - // IDFT Precoding - q->len_after_mod = q->E / q->Qm; - srslte_dft_precoding(&q->idft_precoder, q->scfdma_symbols, q->symbols, q->nof_prb_psbch, q->nof_symbols); + // Transform precoding + srslte_dft_precoding(&q->idft_precoder, q->scfdma_symbols, q->mod_symbols, SRSLTE_PSBCH_NOF_PRB, q->nof_data_symbols); - // Layer Mapping - TS 36.211 SEC 9.6.3 - Single layer Skipped + // Layer Mapping + // Void: Single layer + // 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.6.3 // Demodulation - srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->symbols, q->llr, q->len_after_mod); + srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->mod_symbols, q->e_float, q->nof_data_re); - // Descramble + // De-scramble + srslte_scrambling_f(&q->seq, q->e_float); + +#if HAVE_INTERLEAVING + // Deinterleaving for (int i = 0; i < q->E; i++) { - q->codeword[i] = q->llr[i] > 0 ? (uint8_t)1 : (uint8_t)0; + q->e_float[q->interleaver_lut[i]] = q->e_float[i]; } - srslte_scrambling_b(&q->seq, q->codeword); +#endif - // TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall not be - // used for sidelink transmission. - bzero(&q->codeword[1008], sizeof(uint8_t) * 144); + // Rate match + srslte_rm_conv_rx(q->e_float, q->E, q->d_float, q->sl_bch_encoded_len); - // ******************************************************************************************************** - // SL-BCH Processing - // ******************************************************************************************************** + // Channel decoding + srslte_viterbi_decode_f(&q->dec, q->d_float, q->c, q->sl_bch_tb_crc_len); - // Deinterleaving - for (int i = 0; i < q->E; i++) { - q->e_16[q->interleaver_lut[i]] = q->codeword[i]; - } + printf("after viterbi\n"); + srslte_vec_fprint_b(stdout, q->c, q->sl_bch_tb_crc_len); - // Unrate Matching - float input_rm_rate_matching[q->E]; - float output_rm_rate_matching[SRSLTE_SL_BCH_ENCODED_LEN]; - for (int i = 0; i < q->E; i++) { - input_rm_rate_matching[i] = (float)q->e_16[i]; - } - srslte_rm_conv_rx(input_rm_rate_matching, q->E, output_rm_rate_matching, SRSLTE_SL_BCH_ENCODED_LEN); - - // Channel Decoding - uint16_t decoder_input[SRSLTE_SL_BCH_ENCODED_LEN]; - srslte_vec_quant_fus(output_rm_rate_matching, decoder_input, 8192, 32767.5, 65535, SRSLTE_SL_BCH_ENCODED_LEN); - srslte_viterbi_decode_us(&q->dec, decoder_input, q->a, SRSLTE_SL_BCH_PAYLOADCRC_LEN); - - // RM CRC - memcpy(q->crc_temp, &q->a[SRSLTE_SL_BCH_PAYLOAD_LEN], sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN); - srslte_crc_attach(&q->crc_mib, q->a, SRSLTE_SL_BCH_PAYLOAD_LEN); - if (srslte_bit_diff(q->crc_temp, &q->a[SRSLTE_SL_BCH_PAYLOAD_LEN], SRSLTE_SL_BCH_CRC_LEN) != 0) { - printf("Error in mib_sl crc check\n"); + // Copy received crc to temp + memcpy(q->crc_temp, &q->c[q->sl_bch_tb_len], sizeof(uint8_t) * SRSLTE_SL_BCH_CRC_LEN); + + // Re-attach crc + srslte_crc_attach(&q->crc_mib_sl, q->c, q->sl_bch_tb_len); + + // CRC check + if (srslte_bit_diff(q->crc_temp, &q->c[q->sl_bch_tb_len], SRSLTE_SL_BCH_CRC_LEN) != 0) { return SRSLTE_ERROR; } - memcpy(mib_sl, q->a, sizeof(uint8_t) * SRSLTE_SL_BCH_PAYLOAD_LEN); + // Remove CRC and copy to output buffer + memcpy(output, q->c, sizeof(uint8_t) * q->sl_bch_tb_len); + return SRSLTE_SUCCESS; } +int srslte_psbch_reset(srslte_psbch_t* q, uint32_t N_sl_id) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if (q != NULL) { + if (q->N_sl_id != N_sl_id) { + q->N_sl_id = N_sl_id; + + // Regen scrambling sequence + if (srslte_sequence_LTE_pr(&q->seq, q->E, N_sl_id) != SRSLTE_SUCCESS) { + ERROR("Error srslte_sequence_LTE_pr\n"); + return SRSLTE_ERROR; + } + } + ret = SRSLTE_SUCCESS; + } + return ret; +} + +int srslte_psbch_put(srslte_psbch_t* q, cf_t* symbols, cf_t* sf_buffer) +{ + uint32_t sample_pos = 0; + uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36; + + // Mapping to physical resources + for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) { + if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i)) { + memcpy(&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE], + &symbols[sample_pos], + sizeof(cf_t) * (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB)); + sample_pos += (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB); + } + } + + return sample_pos; +} + +int srslte_psbch_get(srslte_psbch_t* q, cf_t* sf_buffer, cf_t* symbols) +{ + uint32_t sample_pos = 0; + uint32_t k = q->nof_prb * SRSLTE_NRE / 2 - 36; + + // Get PSBCH REs + for (uint32_t i = 0; i < SRSLTE_CP_NORM_SF_NSYMB; i++) { + if (srslte_psbch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i)) { + memcpy(&symbols[sample_pos], + &sf_buffer[k + i * q->nof_prb * SRSLTE_NRE], + sizeof(cf_t) * (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB)); + sample_pos += (SRSLTE_NRE * SRSLTE_PSBCH_NOF_PRB); + } + } + + return sample_pos; +} + void srslte_psbch_free(srslte_psbch_t* q) { if (q) { - srslte_dft_precoding_free(&q->dft_precoder); srslte_dft_precoding_free(&q->idft_precoder); srslte_viterbi_free(&q->dec); srslte_sequence_free(&q->seq); srslte_modem_table_free(&q->mod); - if (q->a) { - free(q->a); + if (q->crc_temp) { + free(q->crc_temp); + } + + if (q->c) { + free(q->c); } if (q->d) { free(q->d); } - if (q->crc_temp) { - free(q->crc_temp); + if (q->d_float) { + free(q->d_float); } if (q->e) { free(q->e); } - if (q->e_16) { - free(q->e_16); + if (q->e_float) { + free(q->e_float); } if (q->interleaver_lut) { free(q->interleaver_lut); @@ -344,16 +401,16 @@ void srslte_psbch_free(srslte_psbch_t* q) if (q->codeword) { free(q->codeword); } - if (q->symbols) { - free(q->symbols); - } if (q->llr) { free(q->llr); } + if (q->mod_symbols) { + free(q->mod_symbols); + } if (q->scfdma_symbols) { free(q->scfdma_symbols); } bzero(q, sizeof(srslte_psbch_t)); } -} \ 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 e8cf5964c..e881ab2a5 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -40,16 +40,24 @@ add_executable(psbch_test psbch_test.c) target_link_libraries(psbch_test srslte_phy) # TM2 self tests -add_test(psbch_test_self_test_tm2_p6_c168_self psbch_test -p 6 -c 168 -d) -add_test(psbch_test_self_test_tm2_p25_c168_self psbch_test -p 25 -c 168 -d) -add_test(psbch_test_self_test_tm2_p100_c168_self psbch_test -p 100 -c 168 -d) +add_test(psbch_test_self_test_tm2_p6_c168_self psbch_test -p 6 -c 168 -t 2) +add_test(psbch_test_self_test_tm2_p50_c168_self psbch_test -p 50 -c 252 -t 2) +add_test(psbch_test_self_test_tm2_p100_c168_self psbch_test -p 100 -c 335 -t 2) + +# TM4 self tests +add_test(psbch_test_self_test_tm4_p6_c168_self psbch_test -p 6 -c 168 -t 4) +add_test(psbch_test_self_test_tm4_p50_c168_self psbch_test -p 50 -c 252 -t 4) +add_test(psbch_test_self_test_tm4_p100_c168_self psbch_test -p 100 -c 335 -t 4) + +add_executable(psbch_file_test psbch_file_test.c) +target_link_libraries(psbch_file_test srslte_phy) # TM2 file tests -add_test(psbch_file_test_ideal_tm2_p6_c0 psbch_test -p 6 -c 0 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat) -add_test(psbch_file_test_ideal_tm2_p15_c84 psbch_test -p 15 -c 84 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat) -add_test(psbch_file_test_ideal_tm2_p25_c168 psbch_test -p 25 -c 168 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat) -add_test(psbch_file_test_ideal_tm2_p50_c252 psbch_test -p 50 -c 252 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat) -add_test(psbch_file_test_ideal_tm2_p100_c335 psbch_test -p 100 -c 335 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat) +#add_test(psbch_file_test_ideal_tm2_p6_c0 psbch_test -p 6 -t 2 -c 0 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e+6.dat) +#add_test(psbch_file_test_ideal_tm2_p15_c84 psbch_test -p 15 -t 2 -c 84 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e+6.dat) +#add_test(psbch_file_test_ideal_tm2_p25_c168 psbch_test -p 25 -t 2 -c 168 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e+6.dat) +#add_test(psbch_file_test_ideal_tm2_p50_c252 psbch_test -p 50 -t 2 -c 252 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e+6.dat) +#add_test(psbch_file_test_ideal_tm2_p100_c335 psbch_test -p 100 -t 2 -c 335 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e+6.dat) ######################################################################## # NPBCH TEST diff --git a/lib/src/phy/phch/test/psbch_file_test.c b/lib/src/phy/phch/test/psbch_file_test.c new file mode 100644 index 000000000..2c55331be --- /dev/null +++ b/lib/src/phy/phch/test/psbch_file_test.c @@ -0,0 +1,219 @@ +/* + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +char* input_file_name; +int32_t N_sl_id = 168; +uint32_t offset = 0; +float frequency_offset = 0.0; +float snr = 100.0; +srslte_cp_t cp = SRSLTE_CP_NORM; +uint32_t nof_prb = 6; +bool use_standard_lte_rates = false; +bool do_equalization = true; +srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2; + +srslte_filesource_t fsrc; + +void usage(char* prog) +{ + printf("Usage: %s [cdeipt]\n", prog); + printf("\t-i input_file_name\n"); + printf("\t-p nof_prb [Default %d]\n", nof_prb); + printf("\t-e extended CP [Default normal]\n"); + printf("\t-d use_standard_lte_rates [Default %i]\n", use_standard_lte_rates); + printf("\t-s skip equalization [Default no]\n"); + printf("\t-c N_sl_id [Default %d]\n", N_sl_id); + printf("\t-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (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, "cdeisptv")) != -1) { + switch (opt) { + case 'c': + N_sl_id = atoi(argv[optind]); + break; + case 'd': + use_standard_lte_rates = true; + break; + case 's': + do_equalization = false; + break; + case 'e': + cp = SRSLTE_CP_EXT; + break; + case 'i': + input_file_name = argv[optind]; + break; + case 'p': + nof_prb = atoi(argv[optind]); + break; + case 't': + switch (atoi(argv[optind])) { + case 1: + tm = SRSLTE_SIDELINK_TM1; + break; + case 2: + tm = SRSLTE_SIDELINK_TM2; + break; + case 3: + tm = SRSLTE_SIDELINK_TM3; + break; + case 4: + tm = SRSLTE_SIDELINK_TM4; + break; + default: + usage(argv[0]); + exit(-1); + break; + } + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char** argv) +{ + int ret = SRSLTE_ERROR; + + parse_args(argc, argv); + srslte_use_standard_symbol_size(use_standard_lte_rates); + + int32_t symbol_sz = srslte_symbol_sz(nof_prb); + printf("Symbol SZ: %i\n", symbol_sz); + + uint32_t sf_n_samples = srslte_symbol_sz(nof_prb) * 15; + printf("sf_n_samples: %i\n", sf_n_samples); + + uint32_t sf_n_re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * 2 * nof_prb; + cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); + cf_t* equalized_sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); + + cf_t* input_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); + cf_t* output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); + + // TX + srslte_ofdm_t ifft; + if (srslte_ofdm_tx_init(&ifft, cp, sf_buffer, output_buffer, nof_prb)) { + ERROR("Error creating IFFT object\n"); + return SRSLTE_ERROR; + } + srslte_ofdm_set_normalize(&ifft, true); + srslte_ofdm_set_freq_shift(&ifft, 0.5); + + // RX + srslte_ofdm_t fft; + if (srslte_ofdm_rx_init(&fft, cp, input_buffer, sf_buffer, nof_prb)) { + fprintf(stderr, "Error creating FFT object\n"); + return SRSLTE_ERROR; + } + srslte_ofdm_set_normalize(&fft, true); + srslte_ofdm_set_freq_shift(&fft, -0.5); + + // PSBCH + srslte_psbch_t psbch; + srslte_psbch_init(&psbch, nof_prb, N_sl_id, tm, SRSLTE_CP_NORM); + + // PSCBH DMRS + srslte_chest_sl_t psbch_chest; + srslte_chest_sl_init_psbch_dmrs(&psbch_chest); + + // Read subframe from third party implementations + if (!input_file_name || srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { + printf("Error opening file %s\n", input_file_name); + return SRSLTE_ERROR; + } + + srslte_filesource_read(&fsrc, input_buffer, sf_n_samples); + // srslte_vec_sc_prod_cfc(input_buffer, sqrtf(symbol_sz), input_buffer, sf_n_samples); + + // Run FFT + srslte_ofdm_rx_sf(&fft); + + // Equalize + if (do_equalization) { + srslte_chest_sl_gen_psbch_dmrs(&psbch_chest, tm, N_sl_id); + srslte_chest_sl_psbch_ls_estimate_equalize(&psbch_chest, sf_buffer, equalized_sf_buffer, nof_prb, tm, cp); + } else { + // just copy symbols + memcpy(equalized_sf_buffer, sf_buffer, sizeof(cf_t) * sf_n_re); + } + + // prepare Rx buffer + uint8_t mib_sl_rx[SRSLTE_MIB_SL_MAX_LEN] = {}; + + // Decode PSBCH + if (srslte_psbch_decode(&psbch, equalized_sf_buffer, mib_sl_rx, sizeof(mib_sl_rx)) == SRSLTE_SUCCESS) { + printf("Rx payload: "); + srslte_vec_fprint_hex(stdout, mib_sl_rx, sizeof(mib_sl_rx)); + + // Unpack and print MIB-SL + srslte_mib_sl_t mib_sl; + srslte_mib_sl_init(&mib_sl, tm); + srslte_mib_sl_unpack(&mib_sl, mib_sl_rx); + srslte_mib_sl_printf(stdout, &mib_sl); + + ret = SRSLTE_SUCCESS; + } + + if (SRSLTE_VERBOSE_ISDEBUG()) { + char* filename = (do_equalization) ? "psbch_rx_syms_eq_on.bin" : "psbch_rx_syms_eq_off.bin"; + printf("Saving PSBCH symbols (%d) to %s\n", psbch.E / psbch.Qm, filename); + srslte_vec_save_file(filename, psbch.mod_symbols, psbch.E / psbch.Qm * sizeof(cf_t)); + } + + srslte_ofdm_tx_free(&ifft); + srslte_ofdm_rx_free(&fft); + + srslte_filesource_free(&fsrc); + + srslte_chest_sl_free(&psbch_chest); + srslte_psbch_free(&psbch); + + free(sf_buffer); + free(equalized_sf_buffer); + free(input_buffer); + free(output_buffer); + + return ret; +} diff --git a/lib/src/phy/phch/test/psbch_test.c b/lib/src/phy/phch/test/psbch_test.c index b1103f974..0cc00fc07 100644 --- a/lib/src/phy/phch/test/psbch_test.c +++ b/lib/src/phy/phch/test/psbch_test.c @@ -18,53 +18,70 @@ * and at http://www.gnu.org/licenses/. * */ -#include + #include #include +#include #include -#include "srslte/phy/dft/ofdm.h" - -#include "srslte/phy/io/filesource.h" - -#include "srslte/phy/ch_estimation/chest_sl.h" -#include "srslte/phy/phch/psbch.h" -#include "srslte/phy/ue/ue_mib_sl.h" - -#define SRSLTE_NSUBFRAMES_X_FRAME 10 +#include "srslte/common/test_common.h" +#include +#include +#include +#include -char* input_file_name = NULL; -srslte_cp_t cp = SRSLTE_CP_NORM; -int sf_n_re, sf_n_samples, fft_size; -uint32_t N_sl_id = 168, nof_prb = 25; -bool use_standard_lte_rates = false; +int32_t N_sl_id = 168; +srslte_cp_t cp = SRSLTE_CP_NORM; +uint32_t nof_prb = 6; +srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2; void usage(char* prog) { - printf("Usage: %s [cdip]\n", prog); - printf("\t-c n_sl_id [Default %d]\n", N_sl_id); - printf("\t-d use_standard_lte_rates [Deafult %i]\n", use_standard_lte_rates); - printf("\t-i input file (radio frame)\n"); + printf("Usage: %s [cdeipt]\n", prog); printf("\t-p nof_prb [Default %d]\n", nof_prb); + printf("\t-e extended CP [Default normal]\n"); + printf("\t-c N_sl_id [Default %d]\n", N_sl_id); + printf("\t-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (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, "cdip")) != -1) { + while ((opt = getopt(argc, argv, "ceiptv")) != -1) { switch (opt) { case 'c': N_sl_id = atoi(argv[optind]); break; - case 'd': - use_standard_lte_rates = true; - break; - case 'i': - input_file_name = argv[optind]; + case 'e': + cp = SRSLTE_CP_EXT; break; case 'p': nof_prb = atoi(argv[optind]); break; + case 't': + switch (atoi(argv[optind])) { + case 1: + tm = SRSLTE_SIDELINK_TM1; + break; + case 2: + tm = SRSLTE_SIDELINK_TM2; + break; + case 3: + tm = SRSLTE_SIDELINK_TM3; + break; + case 4: + tm = SRSLTE_SIDELINK_TM4; + break; + default: + usage(argv[0]); + exit(-1); + break; + } + break; + case 'v': + srslte_verbose++; + break; default: usage(argv[0]); exit(-1); @@ -74,137 +91,64 @@ void parse_args(int argc, char** argv) int main(int argc, char** argv) { - parse_args(argc, argv); - srslte_use_standard_symbol_size(use_standard_lte_rates); - uint32_t symbol_sz = srslte_symbol_sz(nof_prb); - printf("Symbol SZ: %i\n", symbol_sz); - - sf_n_samples = symbol_sz * 15; - fft_size = sf_n_samples * 2; - sf_n_re = SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * 12 * 2 * nof_prb; - int ret = SRSLTE_ERROR; - uint8_t* mib_sl_rx = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_MIB_SL_MAX_LEN); - bzero(mib_sl_rx, sizeof(uint8_t) * SRSLTE_MIB_SL_MAX_LEN); - - cf_t* sf_buffer_samples = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); - bzero(sf_buffer_samples, sizeof(cf_t) * sf_n_samples); - - cf_t* rx_re = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); - bzero(rx_re, sizeof(cf_t) * sf_n_re); - - cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); - bzero(sf_buffer, sizeof(cf_t) * sf_n_re); - - cf_t* equalized_sf = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); - bzero(equalized_sf, sizeof(cf_t) * sf_n_re); + parse_args(argc, argv); - srslte_ofdm_t fft; - if (srslte_ofdm_rx_init(&fft, SRSLTE_CP_NORM, sf_buffer_samples, rx_re, nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - return SRSLTE_ERROR; - } - srslte_ofdm_set_normalize(&fft, true); - srslte_ofdm_set_freq_shift(&fft, (float)-0.5); + uint32_t sf_n_re = SRSLTE_SF_LEN_RE(nof_prb, cp); + cf_t* sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); - srslte_ofdm_t ifft; - if (srslte_ofdm_tx_init(&ifft, SRSLTE_CP_NORM, sf_buffer, sf_buffer_samples, nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - return SRSLTE_ERROR; - } - srslte_ofdm_set_normalize(&ifft, true); - srslte_ofdm_set_freq_shift(&ifft, 0.5); + // MIB-SL + srslte_mib_sl_t mib_sl; + srslte_mib_sl_init(&mib_sl, tm); + srslte_mib_sl_set(&mib_sl, nof_prb, 0, 128, 4, false); + // PSBCH srslte_psbch_t psbch; - if (srslte_psbch_init(&psbch, N_sl_id, nof_prb)) { - printf("Error creating PSBCH object\n"); - return SRSLTE_ERROR; - } - - srslte_ue_mib_sl_t mib_sl; - srslte_ue_mib_sl_set(&mib_sl, nof_prb, 0, 0, 0, false); - - srslte_chest_sl_t psbch_est; - srslte_chest_sl_init_psbch_dmrs(&psbch_est); - srslte_chest_sl_gen_psbch_dmrs(&psbch_est, SRSLTE_SIDELINK_TM2, nof_prb, 0, N_sl_id); - - if (!input_file_name) { - // ************************************************************************************************************* - // PSBCH ENCODING - // ************************************************************************************************************* - srslte_ue_mib_sl_pack(&mib_sl, psbch.a); - srslte_psbch_encode(&psbch, psbch.a); + srslte_psbch_init(&psbch, nof_prb, N_sl_id, tm, SRSLTE_CP_NORM); - // Map PSBCH to subframe - srslte_psbch_put(&psbch, sf_buffer); + // MIB message bits + uint8_t mib_sl_tx[SRSLTE_MIB_SL_MAX_LEN] = {}; + srslte_mib_sl_pack(&mib_sl, mib_sl_tx); - // Map PSBCH DMRS to subframe - srslte_chest_sl_put_psbch_dmrs(&psbch_est, sf_buffer, SRSLTE_SIDELINK_TM2, nof_prb); - - // TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall not be - // used for sidelink transmission. - bzero(&sf_buffer[SRSLTE_NRE * nof_prb * (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * 2 - 1)], - sizeof(cf_t) * SRSLTE_NRE * nof_prb); - srslte_ofdm_tx_sf(&ifft); - - } else { - // ************************************************************************************************************* - // RADIO FRAME FROM MATLAB - // ************************************************************************************************************* - srslte_filesource_t fsrc; - if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { - printf("Error opening file %s\n", input_file_name); - return SRSLTE_ERROR; - } + printf("Tx payload: "); + srslte_vec_fprint_hex(stdout, mib_sl_tx, mib_sl.mib_sl_len); - srslte_filesource_read(&fsrc, sf_buffer_samples, sf_n_samples); - srslte_vec_sc_prod_cfc(sf_buffer_samples, sqrtf(symbol_sz), sf_buffer_samples, (uint32_t)sf_n_samples); + // Put MIB-SL into PSBCH + srslte_psbch_encode(&psbch, mib_sl_tx, mib_sl.mib_sl_len, sf_buffer); - srslte_filesource_free(&fsrc); - } + // prepare Rx buffer + uint8_t mib_sl_rx[SRSLTE_MIB_SL_MAX_LEN] = {}; - srslte_ofdm_rx_sf(&fft); - // TS 36.211 Section 9.3.2: The last SC-FDMA symbol in a sidelink subframe serves as a guard period and shall not be - // used for sidelink transmission. - bzero(&rx_re[SRSLTE_NRE * nof_prb * (SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * 2 - 1)], sizeof(cf_t) * SRSLTE_NRE * nof_prb); + // Decode PSBCH + if (srslte_psbch_decode(&psbch, sf_buffer, mib_sl_rx, sizeof(mib_sl_rx)) == SRSLTE_SUCCESS) { + printf("Rx payload: "); + srslte_vec_fprint_hex(stdout, mib_sl_rx, mib_sl.mib_sl_len); - srslte_chest_sl_psbch_ls_estimate_equalize(&psbch_est, rx_re, equalized_sf, nof_prb); + srslte_mib_sl_unpack(&mib_sl, mib_sl_rx); + srslte_mib_sl_printf(stdout, &mib_sl); - srslte_psbch_get(&psbch, equalized_sf); - if (srslte_psbch_decode(&psbch, mib_sl_rx) == SRSLTE_SUCCESS) { - printf("RX MIB-SL: "); - for (int i = 0; i < SRSLTE_MIB_SL_MAX_LEN; ++i) { - printf("%i", mib_sl_rx[i]); - } - printf("\n"); ret = SRSLTE_SUCCESS; + } - srslte_ue_mib_sl_t rx_mib_sl; - srlste_ue_mib_sl_unpack(&rx_mib_sl, mib_sl_rx); - - printf("Bandwidth: %i\n", rx_mib_sl.sl_bandwidth_r12); - printf("TDD Config: %i\n", rx_mib_sl.tdd_config_sl_r12); - printf("Direct Frame Number: %i\n", rx_mib_sl.direct_frame_number_r12); - printf("Direct Subframe Number: %i\n", rx_mib_sl.direct_subframe_number_r12); - printf("In Coverage: %i\n", rx_mib_sl.in_coverage_r12); + // Sanity check + if (tm <= SRSLTE_SIDELINK_TM2) { + // TM1 and TM2 have always 504 PSBCH resource elements + TESTASSERT(psbch.E / psbch.Qm == 504); + } else { + // TM3 and TM4 have always 432 PSBCH resource elements + TESTASSERT(psbch.E / psbch.Qm == 432); } - srslte_chest_sl_free(&psbch_est); + if (SRSLTE_VERBOSE_ISDEBUG()) { + printf("PSBCH eq. symbols (%d), saving to psbch_rx_syms.bin\n", psbch.E / psbch.Qm); + srslte_vec_fprint_c(stdout, psbch.mod_symbols, 8); + srslte_vec_save_file("psbch_rx_syms.bin", psbch.mod_symbols, psbch.E / psbch.Qm * sizeof(cf_t)); + } + srslte_mib_sl_free(&mib_sl); srslte_psbch_free(&psbch); - srslte_ue_mib_sl_free(&mib_sl); - - srslte_ofdm_rx_free(&fft); - srslte_ofdm_tx_free(&ifft); - - free(rx_re); - free(mib_sl_rx); free(sf_buffer); - free(equalized_sf); - free(sf_buffer_samples); - - printf(ret == SRSLTE_ERROR ? "FAILED\n" : "SUCCESS\n"); return ret; } diff --git a/lib/src/phy/sync/test/psss_file_test.c b/lib/src/phy/sync/test/psss_file_test.c index 5746bf0e6..797f030ab 100644 --- a/lib/src/phy/sync/test/psss_file_test.c +++ b/lib/src/phy/sync/test/psss_file_test.c @@ -34,8 +34,6 @@ #include "srslte/srslte.h" char* input_file_name; -// int32_t N_sl_id = 168; -// uint32_t offset = 0; float frequency_offset = 0.0; float snr = 100.0; srslte_cp_t cp = SRSLTE_CP_NORM;