baseline implementation of pscch

master
Tiago Alves 5 years ago committed by Andre Puschmann
parent 8e4f2a4d59
commit cabd9ae742

@ -30,8 +30,12 @@
#include "srslte/phy/common/phy_common.h" #include "srslte/phy/common/phy_common.h"
#include "srslte/phy/resampling/interp.h" #include "srslte/phy/resampling/interp.h"
#define SRSLTE_SL_N_RU_SEQ (30)
#define SRSLTE_SL_MAX_DMRS_SYMB (4) #define SRSLTE_SL_MAX_DMRS_SYMB (4)
#define SRSLTE_SL_NOF_PRIME_NUMBERS (196)
// Base Sequence Number - always 0 for sidelink: 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 5.5.1.4
#define SRSLTE_SL_BASE_SEQUENCE_NUMBER 0
#define SRSLTE_SL_MAX_DMRS_PERIOD_LENGTH 320
typedef struct { typedef struct {
@ -80,6 +84,15 @@ typedef struct {
} srslte_chest_sl_t; } srslte_chest_sl_t;
SRSLTE_API int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
srslte_sl_tm_t tm,
srslte_sl_channels_t ch,
uint32_t sf_idx,
uint32_t N_sl_id,
uint32_t L_crb,
uint32_t N_x_id,
uint32_t cyclic_shift);
SRSLTE_API int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q); SRSLTE_API int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q);
SRSLTE_API int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t N_sl_id); SRSLTE_API int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t txMode, uint32_t N_sl_id);
@ -104,6 +117,33 @@ SRSLTE_API int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q,
uint32_t nof_prb, uint32_t nof_prb,
srslte_cp_t cp); srslte_cp_t cp);
SRSLTE_API int srslte_chest_sl_init_pscch_dmrs(srslte_chest_sl_t* q);
SRSLTE_API int srslte_chest_sl_gen_pscch_dmrs(srslte_chest_sl_t* q, uint32_t cyclic_shift, srslte_sl_tm_t tm);
SRSLTE_API int srslte_chest_sl_put_pscch_dmrs(srslte_chest_sl_t* q,
cf_t* sf_buffer,
uint32_t prb_idx,
srslte_sl_tm_t tm,
uint32_t nof_prb,
srslte_cp_t cp);
SRSLTE_API void srslte_chest_sl_pscch_ls_estimate_equalize(srslte_chest_sl_t* q,
cf_t* sf_buffer,
uint32_t prb_idx,
cf_t* sf_buffer_rx,
uint32_t nof_prb,
srslte_sl_tm_t tm,
srslte_cp_t cp);
SRSLTE_API int srslte_chest_sl_get_pscch_dmrs(srslte_chest_sl_t* q,
cf_t* sf_buffer_rx,
uint32_t prb_idx,
cf_t** dmrs_received,
srslte_sl_tm_t tm,
uint32_t nof_prb,
srslte_cp_t cp);
SRSLTE_API void srslte_chest_sl_free(srslte_chest_sl_t* q); SRSLTE_API void srslte_chest_sl_free(srslte_chest_sl_t* q);
#endif #endif

@ -362,6 +362,11 @@ typedef enum SRSLTE_API {
SRSLTE_SIDELINK_GUARD_SYMBOL SRSLTE_SIDELINK_GUARD_SYMBOL
} srslte_sl_symbol_t; } srslte_sl_symbol_t;
typedef enum {
SRSLTE_SCI_FORMAT0 = 0,
SRSLTE_SCI_FORMAT1
} srslte_sci_format_t;
#define SRSLTE_PSBCH_NOF_PRB (6) #define SRSLTE_PSBCH_NOF_PRB (6)
#define SRSLTE_PSCCH_TM34_NOF_PRB (2) #define SRSLTE_PSCCH_TM34_NOF_PRB (2)
@ -380,6 +385,22 @@ typedef enum SRSLTE_API {
#define SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS (3) ///< PSBCH has 3 DMRS symbols in TM3 and TM4 #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 #define SRSLTE_PSBCH_TM34_NUM_SYNC_SYMBOLS (4) ///< Two symbols PSSS and two SSSS
#define SRSLTE_SCI_CRC_LEN (16)
#define SRSLTE_SCI_MAX_LEN (45)
#define SRSLTE_SCI_TM34_LEN (32)
#define SRSLTE_PSCCH_QM 2
#define SRSLTE_PSCCH_TM12_NOF_PRB (1)
#define SRSLTE_PSCCH_TM34_NOF_PRB (2)
#define SRSLTE_PSCCH_SCRAMBLING_SEED (510) ///< Scrambling seed for PSCCH is 510
#define SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS (12)
#define SRSLTE_PSCCH_TM12_NUM_DMRS_SYMBOLS (2)
#define SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS_EXT (10)
#define SRSLTE_PSCCH_TM34_NUM_DATA_SYMBOLS (10)
#define SRSLTE_PSCCH_TM34_NUM_DMRS_SYMBOLS (4)
///< PHY common function declarations ///< PHY common function declarations
SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t* cell); SRSLTE_API bool srslte_cell_isvalid(srslte_cell_t* cell);
@ -475,7 +496,10 @@ 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); 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); 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_API bool srslte_pscch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i, srslte_cp_t cp);
SRSLTE_API uint32_t srslte_sci_format0_sizeof(uint32_t nof_prb);
/** /**
* Returns a constant string pointer with the ACK/NACK feedback mode * Returns a constant string pointer with the ACK/NACK feedback mode

@ -0,0 +1,100 @@
/*
* 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_PSCCH_H
#define SRSLTE_PSCCH_H
#include <stdint.h>
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/common/sequence.h"
#include "srslte/phy/dft/dft_precoding.h"
#include "srslte/phy/fec/convcoder.h"
#include "srslte/phy/fec/crc.h"
#include "srslte/phy/fec/viterbi.h"
#include "srslte/phy/modem/modem_table.h"
/**
* \brief Physical Sidelink control channel.
*
* Reference: 3GPP TS 36.211 version 15.6.0 Release 15 Section 9.4
*/
typedef struct SRSLTE_API {
srslte_sl_tm_t tm;
srslte_cp_t cp;
uint32_t sci_len;
uint32_t nof_tx_re;
uint32_t pscch_nof_prb;
// crc
uint8_t* c;
srslte_crc_t crc;
uint8_t* sci_crc;
// channel coding
srslte_viterbi_t dec;
srslte_convcoder_t encoder;
uint8_t* d;
int16_t* d_16;
// rate matching
uint32_t E;
uint8_t* e;
int16_t* e_16;
uint8_t* e_bytes; ///< To pack bits to bytes
uint32_t nof_symbols;
// interleaving
uint32_t* interleaver_lut;
uint8_t* codeword;
uint8_t* codeword_bytes;
uint32_t nof_prb;
// scrambling
srslte_sequence_t seq;
// modulation
srslte_modem_table_t mod;
cf_t* mod_symbols;
int16_t* llr;
// dft precoding
srslte_dft_precoding_t dft_precoder;
srslte_dft_precoding_t idft_precoder;
cf_t* scfdma_symbols;
} srslte_pscch_t;
SRSLTE_API int srslte_pscch_init(srslte_pscch_t* q, uint32_t nof_prb, srslte_sl_tm_t tm, srslte_cp_t cp);
SRSLTE_API int srslte_pscch_encode(srslte_pscch_t* q, uint8_t* sci, cf_t* sf_buffer, uint32_t prb_idx);
SRSLTE_API int srslte_pscch_decode(srslte_pscch_t* q, cf_t* equalized_sf_syms, uint8_t* sci, uint32_t prb_idx);
SRSLTE_API int srslte_pscch_put(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx);
SRSLTE_API int srslte_pscch_get(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx);
SRSLTE_API void srslte_pscch_free(srslte_pscch_t* q);
#endif // SRSLTE_PSCCH_H

@ -0,0 +1,103 @@
/*
* 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_SCI_H
#define SRSLTE_SCI_H
#include <stdbool.h>
#include <stdint.h>
#include "srslte/config.h"
#include "srslte/phy/common/phy_common.h"
#define SRSLTE_SCI_MSG_MAX_LEN 80
/**
* Sidelink Control Information - Sidelink (SCI0 and SCI1).
*
* \brief SCI0/1 packing/unpacking functions to convert between bit streams
*
* Reference: 3GPP TS 36.212 version 15.6.0 Release 15 Section 5.4.3
*/
typedef struct SRSLTE_API {
srslte_sl_tm_t tm;
uint32_t sci_len;
uint32_t nof_prb;
srslte_sci_format_t format;
// sizeSubChannel
uint32_t size_sub_channel;
// numSubChannel
uint32_t num_sub_channel;
///< SCI Format 0: Resource block assignment and hopping resource allocation
///< SCI Format 1: Frequency resource location (0,3,6,7,8 bits)
uint32_t riv;
// Modulation and coding scheme (bits);
uint32_t mcs_idx;
///< SCI Format 0
// Frequency hopping flag (1 bit)
bool freq_hopping_flag;
uint32_t hopping_bits;
// TRP - Time resource pattern (7bits)
uint32_t trp_idx;
// Timing advance indication (11 bits)
uint32_t timing_advance;
// Group ID (8 bits)
uint32_t N_sa_id;
///< SCI Format 1
// Priority (3bits)
uint32_t priority;
// Resource reservation (4 bits)
uint32_t resource_reserv;
// Time gap (4 bits)
uint32_t time_gap;
// Retransmission index (1 bit)
bool retransmission;
} srslte_sci_t;
SRSLTE_API int srslte_sci_init(srslte_sci_t* q,
uint32_t nof_prb,
srslte_sl_tm_t tm,
uint32_t size_sub_channel,
uint32_t num_sub_channel);
SRSLTE_API int srslte_sci_format0_pack(srslte_sci_t* q, uint8_t* output);
SRSLTE_API int srslte_sci_format1_pack(srslte_sci_t* q, uint8_t* output);
SRSLTE_API int srslte_sci_format0_unpack(srslte_sci_t* q, uint8_t* input);
SRSLTE_API int srslte_sci_format1_unpack(srslte_sci_t* q, uint8_t* input);
SRSLTE_API void srslte_sci_info(char* str, srslte_sci_t* q);
SRSLTE_API void srslte_sci_free(srslte_sci_t* q);
#endif // SRSLTE_SCI_H

@ -34,6 +34,7 @@
#include "srslte/config.h" #include "srslte/config.h"
#include "srslte/phy/utils/cexptab.h" #include "srslte/phy/utils/cexptab.h"
#include "srslte/phy/common/phy_common.h"
#define SRSLTE_CFO_CEXPTAB_SIZE 4096 #define SRSLTE_CFO_CEXPTAB_SIZE 4096
@ -61,4 +62,6 @@ srslte_cfo_correct_offset(srslte_cfo_t* h, const cf_t* input, cf_t* output, floa
SRSLTE_API float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb); SRSLTE_API float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb);
SRSLTE_API float srslte_sl_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb, srslte_cp_t cp);
#endif // SRSLTE_CFO_H #endif // SRSLTE_CFO_H

@ -24,14 +24,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h> #include "srslte/phy/ch_estimation/chest_sl.h"
#include "srslte/phy/ch_estimation/chest_sl.h"
#include "srslte/phy/mimo/precoding.h" #include "srslte/phy/mimo/precoding.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
#include "ul_rs_tables.h" #include "ul_rs_tables.h"
int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q, uint32_t N_sa_id) int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q)
{ {
srslte_interp_linear_vector_init(&q->lin_vec_sl, SRSLTE_MAX_PRB * SRSLTE_NRE); srslte_interp_linear_vector_init(&q->lin_vec_sl, SRSLTE_MAX_PRB * SRSLTE_NRE);
@ -61,12 +60,11 @@ int srslte_chest_sl_init_dmrs(srslte_chest_sl_t* q, uint32_t N_sa_id)
} }
} }
q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * 320 * SRSLTE_SL_MAX_DMRS_SYMB); // MAX PERIOD LENGTH 320 q->f_gh_pattern = srslte_vec_malloc(sizeof(uint32_t) * SRSLTE_SL_MAX_DMRS_PERIOD_LENGTH); // MAX PERIOD LENGTH 320
if (!q->f_gh_pattern) { if (!q->f_gh_pattern) {
ERROR("Error allocating memory"); ERROR("Error allocating memory");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
srslte_group_hopping_f_gh(q->f_gh_pattern, N_sa_id);
q->ce = srslte_vec_malloc(sizeof(cf_t) * 2 * SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * SRSLTE_MAX_PRB); q->ce = srslte_vec_malloc(sizeof(cf_t) * 2 * SRSLTE_CP_NSYMB(SRSLTE_CP_NORM) * SRSLTE_NRE * SRSLTE_MAX_PRB);
if (!q->ce) { if (!q->ce) {
@ -97,7 +95,8 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t N_sl_id, uint32_t N_sl_id,
uint32_t L_crb, uint32_t L_crb,
uint32_t N_sa_id) uint32_t N_x_id,
uint32_t cyclic_shift)
{ {
// M_sc_rs - Reference Signal Length // M_sc_rs - Reference Signal Length
switch (ch) { switch (ch) {
@ -130,7 +129,7 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
q->nof_dmrs_symbols = SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS; q->nof_dmrs_symbols = SRSLTE_PSBCH_TM34_NUM_DMRS_SYMBOLS;
} else { } else {
// all other channels have 4 DMRS // all other channels have 4 DMRS
q->nof_dmrs_symbols = SRSLTE_SL_TM12_DEFAULT_NUM_DMRS_SYMBOLS; q->nof_dmrs_symbols = SRSLTE_SL_TM34_DEFAULT_NUM_DMRS_SYMBOLS;
} }
} }
@ -149,22 +148,19 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
} }
} else { } else {
for (int i = 0; i < q->nof_dmrs_symbols; i++) { 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 q->n_CS[i] = cyclic_shift;
// each PSCCH transmission."
q->n_CS[i] = 0;
// q->n_CS[i] = i * 3;
} }
} }
break; break;
case SRSLTE_SIDELINK_PSSCH: case SRSLTE_SIDELINK_PSSCH:
if (tm <= SRSLTE_SIDELINK_TM2) { if (tm <= SRSLTE_SIDELINK_TM2) {
for (int i = 0; i < q->nof_dmrs_symbols; i++) { for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = (int)(N_sa_id / 2) % 8; q->n_CS[i] = (int)(N_x_id / 2) % 8;
} }
} else { } else {
// TODO: both equation are the same here but spec says N_id_X for Mode3+4 // 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++) { for (int i = 0; i < q->nof_dmrs_symbols; i++) {
q->n_CS[i] = (int)(N_sa_id / 2) % 8; q->n_CS[i] = (int)(N_x_id / 2) % 8;
} }
} }
break; break;
@ -181,90 +177,92 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
} }
// Group Hopping // Group Hopping
uint32_t f_gh; // Group Hopping Flag
uint32_t f_ss;
uint32_t u[SRSLTE_SL_MAX_DMRS_SYMB]; // Sequence Group Number
// 36.211, Section 10.1.4.1.3 // 36.211, Section 10.1.4.1.3
// Base Sequence Number - always 0 for sidelink // Base Sequence Number - always 0 for sidelink
q->v = 0;
switch (ch) { switch (ch) {
case SRSLTE_SIDELINK_PSBCH: case SRSLTE_SIDELINK_PSBCH:
q->f_gh = 0; f_gh = 0;
q->f_ss = (N_sl_id / 16) % 30; f_ss = (N_sl_id / 16) % SRSLTE_SL_N_RU_SEQ;
for (int i = 0; i < q->nof_dmrs_symbols; ++i) { for (int ns = 0; ns < q->nof_dmrs_symbols; ns++) {
q->u[i] = (q->f_gh + q->f_ss) % 30; u[ns] = (f_gh + f_ss) % SRSLTE_SL_N_RU_SEQ;
} }
break; break;
case SRSLTE_SIDELINK_PSCCH: case SRSLTE_SIDELINK_PSCCH:
q->f_gh = 0; f_gh = 0;
if (tm <= SRSLTE_SIDELINK_TM2) { if (tm <= SRSLTE_SIDELINK_TM2) {
q->f_ss = 0; f_ss = 0;
} else { } else {
q->f_ss = 8; f_ss = 8;
} }
for (int i = 0; i < q->nof_dmrs_symbols; ++i) { for (int ns = 0; ns < q->nof_dmrs_symbols; ns++) {
q->u[i] = (q->f_gh + q->f_ss) % 30; u[ns] = (f_gh + f_ss) % SRSLTE_SL_N_RU_SEQ;
} }
break; break;
case SRSLTE_SIDELINK_PSSCH: case SRSLTE_SIDELINK_PSSCH:
srslte_group_hopping_f_gh(q->f_gh_pattern, N_x_id);
if (tm <= SRSLTE_SIDELINK_TM2) { if (tm <= SRSLTE_SIDELINK_TM2) {
q->f_gh = 1; f_ss = N_x_id % SRSLTE_SL_N_RU_SEQ;
q->f_ss = N_sa_id % 30;
uint32_t delta_ss = 0; uint32_t delta_ss = 0;
uint8_t i = 0; for (uint32_t ns = 0; ns < q->nof_dmrs_symbols; ns++) {
for (uint32_t ns = 2 * sf_idx; ns < 2 * (sf_idx + 1); ns++) { f_gh = q->f_gh_pattern[ns];
uint32_t f_gh = q->f_gh_pattern[ns]; u[ns] = (f_gh + f_ss + delta_ss) % SRSLTE_SL_N_RU_SEQ;
q->u[i++] = (f_gh + q->f_ss + delta_ss) % 30;
} }
} else { } else {
// TM3/4 // TM3/4
q->f_gh = 1; f_ss = (N_x_id / 16) % SRSLTE_SL_N_RU_SEQ;
q->f_ss = (N_sa_id / 16) % 30;
uint32_t delta_ss = 0; uint32_t delta_ss = 0;
for (uint32_t ns = 0; ns <= q->nof_dmrs_symbols; ns++) { for (uint32_t ns = 0; ns < q->nof_dmrs_symbols; ns++) {
uint32_t f_gh = q->f_gh_pattern[ns]; f_gh = q->f_gh_pattern[(2 * 2 * (sf_idx % 10)) + ns];
q->u[ns] = (f_gh + q->f_ss + delta_ss) % 30; u[ns] = (f_gh + f_ss + delta_ss) % SRSLTE_SL_N_RU_SEQ;
} }
} }
break; break;
case SRSLTE_SIDELINK_PSDCH: case SRSLTE_SIDELINK_PSDCH:
q->f_gh = 0; f_gh = 0;
q->f_ss = 0; f_ss = 0;
for (int i = 0; i < q->nof_dmrs_symbols; ++i) { for (int ns = 0; ns < q->nof_dmrs_symbols; ns++) {
q->u[i] = (q->f_gh + q->f_ss) % 30; u[ns] = (f_gh + f_ss) % SRSLTE_SL_N_RU_SEQ;
} }
break; break;
} }
// N_zc - Zadoff Chu Sequence Length // N_zc - Zadoff Chu Sequence Length
int32_t N_zc = 0; // N_zc - Zadoff Chu Sequence Length
// TODO: the refsignal_ul.c should be reused for this, code looks almost the same // TODO: the refsignal_ul.c should be reused for this, code looks almost the same
switch (q->M_sc_rs / SRSLTE_NRE) { switch (q->M_sc_rs / SRSLTE_NRE) {
case 1: case 1:
for (int j = 0; j < q->nof_dmrs_symbols; ++j) { for (int j = 0; j < q->nof_dmrs_symbols; ++j) {
for (int i = 0; i < SRSLTE_NRE; i++) { for (int i = 0; i < SRSLTE_NRE; i++) {
q->r[j][i] = phi_M_sc_12[q->u[j]][i] * M_PI / 4; q->r[j][i] = phi_M_sc_12[u[j]][i] * M_PI / 4;
} }
} }
break; break;
case 2: case 2:
for (int j = 0; j < q->nof_dmrs_symbols; ++j) { for (int j = 0; j < q->nof_dmrs_symbols; ++j) {
for (int i = 0; i < q->M_sc_rs; i++) { 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; q->r[j][i] = phi_M_sc_24[u[j]][i] * M_PI / 4;
} }
} }
break; break;
default: default:
for (uint32_t i = SRSLTE_SL_NOF_PRIME_NUMBERS - 1; i > 0; i--) { for (uint32_t i = NOF_PRIME_NUMBERS - 1; i > 0; i--) {
if (prime_numbers[i] < q->M_sc_rs) { if (prime_numbers[i] < q->M_sc_rs) {
q->N_zc = prime_numbers[i]; N_zc = prime_numbers[i];
break; break;
} }
} }
for (int j = 0; j < q->nof_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); q->q[j] = get_q(u[j], SRSLTE_SL_BASE_SEQUENCE_NUMBER, N_zc);
float n_sz = (float)q->N_zc; float n_sz = (float)N_zc;
for (uint32_t i = 0; i < q->M_sc_rs; i++) { for (uint32_t i = 0; i < q->M_sc_rs; i++) {
float m = (float)(i % q->N_zc); float m = (float)(i % N_zc);
q->r[j][i] = -M_PI * q->q[j] * m * (m + 1) / n_sz; q->r[j][i] = -M_PI * q->q[j] * m * (m + 1) / n_sz;
} }
} }
@ -318,7 +316,7 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
break; break;
case SRSLTE_SIDELINK_PSSCH: case SRSLTE_SIDELINK_PSSCH:
if (tm <= SRSLTE_SIDELINK_TM2) { if (tm <= SRSLTE_SIDELINK_TM2) {
if (N_sa_id % 2 == 0) { if (N_x_id % 2 == 0) {
q->w[0] = 1; q->w[0] = 1;
q->w[1] = 1; q->w[1] = 1;
} else { } else {
@ -327,7 +325,7 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
} }
} else { } else {
// TM3/4 // TM3/4
if (N_sa_id % 2 == 0) { if (N_x_id % 2 == 0) {
q->w[0] = 1; q->w[0] = 1;
q->w[1] = 1; q->w[1] = 1;
q->w[2] = 1; q->w[2] = 1;
@ -353,14 +351,15 @@ int srslte_chest_sl_gen_dmrs(srslte_chest_sl_t* q,
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q) int srslte_chest_sl_init_psbch_dmrs(srslte_chest_sl_t* q)
{ {
return srslte_chest_sl_init_dmrs(q, 0); return srslte_chest_sl_init_dmrs(q);
} }
int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t tm, uint32_t N_sl_id) int srslte_chest_sl_gen_psbch_dmrs(srslte_chest_sl_t* q, srslte_sl_tm_t tm, uint32_t N_sl_id)
{ {
return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0); return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSBCH, 0, N_sl_id, 0, 0, 0);
} }
int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q, int srslte_chest_sl_put_psbch_dmrs(srslte_chest_sl_t* q,
@ -540,6 +539,176 @@ int srslte_chest_sl_get_psbch_dmrs(srslte_chest_sl_t* q,
return sample_pos; return sample_pos;
} }
int srslte_chest_sl_init_pscch_dmrs(srslte_chest_sl_t* q)
{
return srslte_chest_sl_init_dmrs(q);
}
int srslte_chest_sl_gen_pscch_dmrs(srslte_chest_sl_t* q, uint32_t cyclic_shift, srslte_sl_tm_t tm)
{
return srslte_chest_sl_gen_dmrs(q, tm, SRSLTE_SIDELINK_PSCCH, 0, 0, 0, 0, cyclic_shift);
}
int srslte_chest_sl_put_pscch_dmrs(srslte_chest_sl_t* q,
cf_t* sf_buffer,
uint32_t prb_idx,
srslte_sl_tm_t tm,
uint32_t nof_prb,
srslte_cp_t cp)
{
uint32_t samplePos = 0;
uint32_t k = prb_idx * SRSLTE_NRE;
// Mapping to physical resources
for (uint32_t i = 0; i < srslte_sl_get_num_symbols(tm, cp); i++) {
if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i, cp)) {
memcpy(&sf_buffer[k + i * nof_prb * SRSLTE_NRE], &q->r_sequence[samplePos][0], q->M_sc_rs * sizeof(cf_t));
samplePos++;
}
}
return SRSLTE_SUCCESS;
}
static void interpolate_pilots_sl_pscch(srslte_interp_linsrslte_vec_t* q,
cf_t* ce,
uint32_t n_prb,
uint32_t prb_idx,
srslte_sl_tm_t tm,
srslte_cp_t cp)
{
uint32_t l_idx = 0;
uint32_t L[SRSLTE_SL_MAX_DMRS_SYMB] = {};
for (int i = 0; i < srslte_sl_get_num_symbols(tm, cp); i++) {
if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i, cp)) {
L[l_idx] = i;
l_idx++;
}
}
uint32_t NL = 2 * SRSLTE_CP_NSYMB(cp);
uint32_t nre = n_prb * SRSLTE_NRE;
srslte_interp_linear_vector_resize(q, nre);
uint32_t ce_l1 = SRSLTE_RE_IDX(n_prb, L[0], 0 * SRSLTE_NRE);
uint32_t ce_l2 = SRSLTE_RE_IDX(n_prb, L[1], 0 * SRSLTE_NRE);
if ((tm == SRSLTE_SIDELINK_TM1) || (tm == SRSLTE_SIDELINK_TM2)) {
srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L[1] - L[0]), L[0], false, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L[1] - L[0]), (L[1] - L[0]) - 1, true, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l1], &ce[ce_l2], &ce[ce_l2], &ce[ce_l2 + nre], (L[1] - L[0]), (NL - L[1]) - 1, true, nre);
} else {
uint32_t ce_l3 = SRSLTE_RE_IDX(n_prb, L[2], 0 * SRSLTE_NRE);
uint32_t ce_l4 = SRSLTE_RE_IDX(n_prb, L[3], 0 * SRSLTE_NRE);
srslte_interp_linear_vector3(q, &ce[ce_l2], &ce[ce_l1], &ce[ce_l1], &ce[ce_l1 - nre], (L[1] - L[0]), L[0], false, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l1], &ce[ce_l2], NULL, &ce[ce_l1 + nre], (L[1] - L[0]), (L[1] - L[0]) - 1, true, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l2], &ce[ce_l3], NULL, &ce[ce_l2 + nre], (L[2] - L[1]), (L[2] - L[1]) - 1, true, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l3], &ce[ce_l4], NULL, &ce[ce_l3 + nre], (L[3] - L[2]), (L[3] - L[2]) - 1, true, nre);
srslte_interp_linear_vector3(
q, &ce[ce_l3], &ce[ce_l4], &ce[ce_l4], &ce[ce_l4 + nre], (L[3] - L[2]), (NL - L[3]) - 1, true, nre);
}
}
void srslte_chest_sl_pscch_ls_estimate_equalize(srslte_chest_sl_t* q,
cf_t* sf_buffer,
uint32_t prb_idx,
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;
// Get Pilot Estimates
// Use the known DMRS signal to compute least-squares estimates
bzero(q->ce, sizeof(cf_t) * sf_n_re);
if ((tm == SRSLTE_SIDELINK_TM1) || (tm == SRSLTE_SIDELINK_TM2)) {
if (cp == SRSLTE_CP_NORM) {
srslte_vec_prod_conj_ccc(&sf_buffer[3 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[0][0],
&q->ce[3 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[10 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[1][0],
&q->ce[10 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
} else {
srslte_vec_prod_conj_ccc(&sf_buffer[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[0][0],
&q->ce[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[1][0],
&q->ce[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
}
} else if ((tm == SRSLTE_SIDELINK_TM3) || (tm == SRSLTE_SIDELINK_TM4)) {
if (cp == SRSLTE_CP_NORM) {
srslte_vec_prod_conj_ccc(&sf_buffer[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[0][0],
&q->ce[2 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[5 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[1][0],
&q->ce[5 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[2][0],
&q->ce[8 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
srslte_vec_prod_conj_ccc(&sf_buffer[11 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
&q->r_sequence[3][0],
&q->ce[11 * nof_prb * SRSLTE_NRE + prb_idx * SRSLTE_NRE],
q->M_sc_rs);
} else {
ERROR("Invalid CP");
return;
}
} else {
ERROR("Invalid TM");
return;
}
interpolate_pilots_sl_pscch(&q->lin_vec_sl, q->ce, nof_prb, prb_idx, tm, cp);
// Perform channel equalization
srslte_predecoding_single(sf_buffer, q->ce, sf_buffer_rx, NULL, sf_n_re, 1, 0.0);
}
int srslte_chest_sl_get_pscch_dmrs(srslte_chest_sl_t* q,
cf_t* sf_buffer_rx,
uint32_t prb_idx,
cf_t** dmrs_received,
srslte_sl_tm_t tm,
uint32_t nof_prb,
srslte_cp_t cp)
{
uint32_t samplePos = 0;
uint32_t k = prb_idx * SRSLTE_NRE;
// Get DMRSs
for (uint32_t i = 0; i < srslte_sl_get_num_symbols(tm, cp); i++) {
if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DMRS_SYMBOL, tm, i, cp)) {
memcpy(&q->dmrs_received[samplePos][0], &sf_buffer_rx[k + i * nof_prb * SRSLTE_NRE], q->M_sc_rs * sizeof(cf_t));
samplePos++;
}
}
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));
}
return SRSLTE_SUCCESS;
}
void srslte_chest_sl_free(srslte_chest_sl_t* q) void srslte_chest_sl_free(srslte_chest_sl_t* q)
{ {
srslte_interp_linear_vector_free(&q->lin_vec_sl); srslte_interp_linear_vector_free(&q->lin_vec_sl);

@ -814,9 +814,29 @@ char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode)
} }
///< Sidelink helpers ///< Sidelink helpers
int srslte_sl_get_num_symbols(srslte_sl_tm_t tm, srslte_cp_t cp)
{
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
if (cp == SRSLTE_CP_NORM) {
return SRSLTE_CP_NORM_SF_NSYMB;
} else {
return SRSLTE_CP_EXT_SF_NSYMB;
}
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
if (cp == SRSLTE_CP_NORM) {
return SRSLTE_CP_NORM_SF_NSYMB;
} else {
ERROR("Invalid CP");
return SRSLTE_ERROR;
}
} else {
ERROR("Invalid TM");
return SRSLTE_ERROR;
}
}
///< Look-up tables for Sidelink channel symbols ///< 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, static const 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_SYNC_SYMBOL, SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL, SRSLTE_SIDELINK_DMRS_SYMBOL,
@ -831,7 +851,7 @@ srslte_sl_symbol_t srslte_psbch_symbol_map_tm12[SRSLTE_CP_NORM_SF_NSYMB] = {SRSL
SRSLTE_SIDELINK_SYNC_SYMBOL, SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL}; SRSLTE_SIDELINK_GUARD_SYMBOL};
srslte_sl_symbol_t srslte_psbch_symbol_map_tm34[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL, static const 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_SYNC_SYMBOL, SRSLTE_SIDELINK_SYNC_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL, SRSLTE_SIDELINK_DATA_SYMBOL,
@ -897,3 +917,85 @@ srslte_ack_nack_feedback_mode_t srslte_string_ack_nack_feedback_mode(const char*
// Otherwise Normal // Otherwise Normal
return SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL; return SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL;
} }
static const srslte_sl_symbol_t srslte_pscch_symbol_map_tm12[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_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_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL};
static const srslte_sl_symbol_t srslte_pscch_symbol_map_tm12_ext[SRSLTE_CP_EXT_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_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_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL};
static const srslte_sl_symbol_t srslte_pscch_symbol_map_tm34[SRSLTE_CP_NORM_SF_NSYMB] = {SRSLTE_SIDELINK_DATA_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_DATA_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_DMRS_SYMBOL,
SRSLTE_SIDELINK_DATA_SYMBOL,
SRSLTE_SIDELINK_GUARD_SYMBOL};
bool srslte_pscch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i, srslte_cp_t cp)
{
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
if (cp == SRSLTE_CP_EXT) {
return srslte_pscch_symbol_map_tm12_ext[i] == type;
}
return srslte_pscch_symbol_map_tm12[i] == type;
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
return srslte_pscch_symbol_map_tm34[i] == type;
}
return false;
}
uint32_t srslte_sci_format0_sizeof(uint32_t nof_prb)
{
// 3GPP TS 36.212 5.4.3.1
uint32_t n = 0;
// Frequency hopping flag 1 bit
n += 1;
// Resource block assignment and hopping resource allocation
n += (uint32_t)ceil(log((nof_prb * (nof_prb + 1)) / 2.0) / log(2));
// Time resource pattern 7 bits
n += 7;
// Modulation and coding scheme 5 bit
n += 5;
// Timing advance indication 11 bits
n += 11;
// Group destination ID 8 bits
n += 8;
return n;
}

@ -0,0 +1,361 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "srslte/phy/phch/pscch.h"
#include "srslte/phy/fec/rm_conv.h"
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/modem/demod_soft.h"
#include "srslte/phy/modem/mod.h"
#include "srslte/phy/phch/sch.h"
#include "srslte/phy/scrambling/scrambling.h"
int srslte_pscch_init(srslte_pscch_t* q, uint32_t nof_prb, srslte_sl_tm_t tm, srslte_cp_t cp)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
ret = SRSLTE_ERROR;
q->cp = cp;
q->tm = tm;
q->nof_prb = nof_prb;
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
q->sci_len = srslte_sci_format0_sizeof(nof_prb);
q->nof_symbols = SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS;
q->pscch_nof_prb = SRSLTE_PSCCH_TM12_NOF_PRB;
if (cp == SRSLTE_CP_EXT) {
q->nof_symbols = SRSLTE_PSCCH_TM12_NUM_DATA_SYMBOLS_EXT;
}
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
q->sci_len = SRSLTE_SCI_TM34_LEN;
q->nof_symbols = SRSLTE_PSCCH_TM34_NUM_DATA_SYMBOLS;
q->pscch_nof_prb = SRSLTE_PSCCH_TM34_NOF_PRB;
} else {
return SRSLTE_ERROR;
}
// CRC
uint32_t crc_poly = 0x11021;
if (srslte_crc_init(&q->crc, crc_poly, SRSLTE_SCI_CRC_LEN)) {
return SRSLTE_ERROR;
}
q->c = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN);
if (!q->c) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->sci_crc = srslte_vec_malloc(sizeof(uint8_t) * SRSLTE_SCI_CRC_LEN);
if (!q->sci_crc) {
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));
q->d = srslte_vec_malloc(sizeof(uint8_t) * (3 * (SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN)));
if (!q->d) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
bzero(q->d, sizeof(uint8_t) * (3 * (SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN)));
q->d_16 = srslte_vec_malloc(sizeof(int16_t) * (3 * (SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN)));
if (!q->d_16) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
srslte_viterbi_init(
&q->dec, SRSLTE_VITERBI_37, q->encoder.poly, SRSLTE_SCI_MAX_LEN + SRSLTE_SCI_CRC_LEN, q->encoder.tail_biting);
q->E = SRSLTE_NRE * q->nof_symbols * q->pscch_nof_prb * SRSLTE_PSCCH_QM;
q->e = srslte_vec_malloc(sizeof(uint8_t) * q->E);
if (!q->e) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->e_16 = srslte_vec_malloc(sizeof(int16_t) * q->E);
if (!q->e_16) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->e_bytes = srslte_vec_malloc(sizeof(uint8_t) * q->E / 8);
if (!q->e_bytes) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->interleaver_lut = srslte_vec_malloc(sizeof(uint32_t) * q->E);
if (!q->interleaver_lut) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->codeword = srslte_vec_malloc(sizeof(uint8_t) * q->E);
if (!q->codeword) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
q->codeword_bytes = srslte_vec_malloc(sizeof(uint8_t) * q->E / 8);
if (!q->codeword_bytes) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
// Scrambling
bzero(&q->seq, sizeof(srslte_sequence_t));
srslte_sequence_LTE_pr(&q->seq, q->E, SRSLTE_PSCCH_SCRAMBLING_SEED);
// Modulation
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
return SRSLTE_ERROR;
}
q->mod_symbols = srslte_vec_malloc(sizeof(cf_t) * q->E / SRSLTE_PSCCH_QM);
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;
}
// DFT Precoding
if (srslte_dft_precoding_init(&q->dft_precoder, q->nof_prb, true)) {
return SRSLTE_ERROR;
}
q->scfdma_symbols = srslte_vec_malloc(sizeof(cf_t) * q->E / SRSLTE_PSCCH_QM);
if (!q->scfdma_symbols) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
// IDFT Predecoding
if (srslte_dft_precoding_init(&q->idft_precoder, q->pscch_nof_prb, false)) {
return SRSLTE_ERROR;
}
q->nof_tx_re = (q->nof_symbols - 1) * SRSLTE_NRE * q->pscch_nof_prb; // Last OFDM symbol is used channel processing but not transmitted
ret = SRSLTE_SUCCESS;
}
return ret;
}
int srslte_pscch_encode(srslte_pscch_t* q, uint8_t* sci, cf_t* sf_buffer, uint32_t prb_idx)
{
memcpy(q->c, sci, sizeof(uint8_t) * q->sci_len);
// CRC Attachment
srslte_crc_attach(&q->crc, q->c, q->sci_len);
// Channel Coding
srslte_convcoder_encode(&q->encoder, q->c, q->d, q->sci_len + SRSLTE_SCI_CRC_LEN);
// Rate Matching
if (srslte_rm_conv_tx(q->d, (3 * (q->sci_len + SRSLTE_SCI_CRC_LEN)), q->e, q->E)) {
return SRSLTE_ERROR;
}
// Interleaving
srslte_bit_pack_vector(q->e, q->e_bytes, q->E);
srslte_sl_ulsch_interleave(q->e_bytes, // input bytes
SRSLTE_PSCCH_QM, // modulation
q->E / SRSLTE_PSCCH_QM, // prime number
q->nof_symbols, // nof pscch symbols
q->codeword_bytes // output
);
srslte_bit_unpack_vector(q->codeword_bytes, q->codeword, q->E);
// Scrambling
srslte_scrambling_b(&q->seq, q->codeword);
// Modulation
srslte_mod_modulate(&q->mod, q->codeword, q->mod_symbols, q->E);
// Layer Mapping
// Void: Single layer
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.3
// DFT Precoding
srslte_dft_precoding(&q->dft_precoder, q->mod_symbols, q->scfdma_symbols, q->pscch_nof_prb, q->nof_symbols);
// Precoding
// Void: Single antenna port
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.5
if (srslte_pscch_put(q, sf_buffer, prb_idx) != q->nof_tx_re) {
printf("Error during PSCCH RE mapping\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int srslte_pscch_decode(srslte_pscch_t* q, cf_t* equalized_sf_syms, uint8_t* sci, uint32_t prb_idx)
{
if (srslte_pscch_get(q, equalized_sf_syms, prb_idx) != q->nof_tx_re) {
printf("Error during PSCCH RE extraction\n");
return SRSLTE_ERROR;
}
// Precoding
// Void: Single antenna port
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.5
// IDFT Precoding
srslte_dft_precoding(&q->idft_precoder, q->scfdma_symbols, q->mod_symbols, q->pscch_nof_prb, q->nof_symbols);
// Layer Mapping
// Void: Single layer
// 3GPP TS 36.211 version 15.6.0 Release 15 Sec. 9.4.3
// Demodulation
srslte_demod_soft_demodulate_s(SRSLTE_MOD_QPSK, q->mod_symbols, q->llr, q->E / SRSLTE_PSCCH_QM);
// Descrambling
srslte_scrambling_s(&q->seq, q->llr);
// Deinterleaving
srslte_sl_ulsch_deinterleave(
q->llr, SRSLTE_PSCCH_QM, q->E / SRSLTE_PSCCH_QM, q->nof_symbols, q->e_16, q->interleaver_lut);
// Rate matching
srslte_rm_conv_rx_s(q->e_16, q->E, q->d_16, (3 * (q->sci_len + SRSLTE_SCI_CRC_LEN)));
// Channel decoding
srslte_viterbi_decode_s(&q->dec, q->d_16, q->c, q->sci_len + SRSLTE_SCI_CRC_LEN);
// Copy received crc
memcpy(q->sci_crc, &q->c[q->sci_len], sizeof(uint8_t) * SRSLTE_SCI_CRC_LEN);
// Re-attach crc
srslte_crc_attach(&q->crc, q->c, q->sci_len);
// CRC check
if (srslte_bit_diff(q->sci_crc, &q->c[q->sci_len], SRSLTE_SCI_CRC_LEN) != 0) {
return SRSLTE_ERROR;
}
// Remove CRC and copy content to sci buffer
memcpy(sci, q->c, sizeof(uint8_t) * q->sci_len);
return SRSLTE_SUCCESS;
}
int srslte_pscch_put(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx)
{
int sample_pos = 0;
int k = prb_idx * SRSLTE_NRE;
for (int i = 0; i < srslte_sl_get_num_symbols(q->tm, q->cp); ++i) {
if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i, q->cp)) {
memcpy(&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE],
&q->scfdma_symbols[sample_pos],
sizeof(cf_t) * (SRSLTE_NRE * q->pscch_nof_prb));
sample_pos += (SRSLTE_NRE * q->pscch_nof_prb);
}
}
return sample_pos;
}
int srslte_pscch_get(srslte_pscch_t* q, cf_t* sf_buffer, uint32_t prb_idx)
{
int sample_pos = 0;
int k = prb_idx * SRSLTE_NRE;
for (int i = 0; i < srslte_sl_get_num_symbols(q->tm, q->cp); ++i) {
if (srslte_pscch_is_symbol(SRSLTE_SIDELINK_DATA_SYMBOL, q->tm, i, q->cp)) {
memcpy(&q->scfdma_symbols[sample_pos],
&sf_buffer[k + i * q->nof_prb * SRSLTE_NRE],
sizeof(cf_t) * (SRSLTE_NRE * q->pscch_nof_prb));
sample_pos += (SRSLTE_NRE * q->pscch_nof_prb);
}
}
return sample_pos;
}
void srslte_pscch_free(srslte_pscch_t* q)
{
if (q != NULL) {
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->sci_crc) {
free(q->sci_crc);
}
if (q->c) {
free(q->c);
}
if (q->d) {
free(q->d);
}
if (q->d_16) {
free(q->d_16);
}
if (q->e) {
free(q->e);
}
if (q->e_16) {
free(q->e_16);
}
if (q->e_bytes) {
free(q->e_bytes);
}
if (q->interleaver_lut) {
free(q->interleaver_lut);
}
if (q->codeword) {
free(q->codeword);
}
if (q->codeword_bytes) {
free(q->codeword_bytes);
}
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_pscch_t));
}
}

@ -0,0 +1,170 @@
/*
* 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 <strings.h>
#include "srslte/phy/phch/sci.h"
#include "srslte/phy/utils/bit.h"
int srslte_sci_init(srslte_sci_t* q,
uint32_t nof_prb,
srslte_sl_tm_t tm,
uint32_t size_sub_channel,
uint32_t num_sub_channel)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_sci_t));
q->nof_prb = nof_prb;
q->tm = tm;
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
q->format = SRSLTE_SCI_FORMAT0;
q->sci_len = srslte_sci_format0_sizeof(nof_prb);
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
q->format = SRSLTE_SCI_FORMAT1;
q->sci_len = SRSLTE_SCI_TM34_LEN;
q->size_sub_channel = size_sub_channel;
q->num_sub_channel = num_sub_channel;
} else {
return SRSLTE_ERROR;
}
ret = SRSLTE_SUCCESS;
}
return ret;
}
int srslte_sci_format0_pack(srslte_sci_t* q, uint8_t* output)
{
if (!q) {
printf("Error packing SCI Format 0\n");
return SRSLTE_ERROR;
}
bzero(output, sizeof(uint8_t) * SRSLTE_SCI_MAX_LEN);
srslte_bit_unpack((uint32_t)q->freq_hopping_flag, &output, 1);
if (q->freq_hopping_flag) {
printf("Frequency Hopping in Sidelink is not supported\n");
return SRSLTE_ERROR;
} else {
srslte_bit_unpack(q->riv, &output, (uint32_t)ceil(log2(((q->nof_prb) * (q->nof_prb + 1) / 2))));
}
srslte_bit_unpack(q->trp_idx, &output, 7);
srslte_bit_unpack(q->mcs_idx, &output, 5);
srslte_bit_unpack(q->timing_advance, &output, 11);
srslte_bit_unpack(q->N_sa_id, &output, 8);
return SRSLTE_SUCCESS;
}
int srslte_sci_format1_pack(srslte_sci_t* q, uint8_t* output)
{
if (!q) {
printf("Error packing SCI Format 1\n");
return SRSLTE_ERROR;
}
bzero(output, sizeof(uint8_t) * SRSLTE_SCI_MAX_LEN);
srslte_bit_unpack(q->priority, &output, 3);
srslte_bit_unpack(q->resource_reserv, &output, 4);
srslte_bit_unpack(q->riv, &output, (uint32_t)ceil(log2(((q->num_sub_channel) * (q->num_sub_channel + 1) / 2))));
srslte_bit_unpack(q->time_gap, &output, 4);
srslte_bit_unpack(q->mcs_idx, &output, 5);
srslte_bit_unpack(q->retransmission, &output, 1);
return SRSLTE_SUCCESS;
}
int srslte_sci_format0_unpack(srslte_sci_t* q, uint8_t* input)
{
if (!q) {
printf("Error unpacking SCI Format 0\n");
return SRSLTE_ERROR;
}
q->freq_hopping_flag = (bool)srslte_bit_pack(&input, 1);
if (q->freq_hopping_flag) {
printf("Frequency Hopping in Sidelink is not supported\n");
return SRSLTE_ERROR;
} else {
q->riv = srslte_bit_pack(&input, (uint32_t)ceil(log2(((q->nof_prb) * (q->nof_prb + 1) / 2))));
}
q->trp_idx = srslte_bit_pack(&input, 7);
q->mcs_idx = srslte_bit_pack(&input, 5);
q->timing_advance = srslte_bit_pack(&input, 11);
q->N_sa_id = srslte_bit_pack(&input, 8);
return SRSLTE_SUCCESS;
}
int srslte_sci_format1_unpack(srslte_sci_t* q, uint8_t* input)
{
if (!q) {
printf("Error unpacking SCI Format 1\n");
return SRSLTE_ERROR;
}
q->priority = srslte_bit_pack(&input, 3);
q->resource_reserv = srslte_bit_pack(&input, 4);
q->riv = srslte_bit_pack(&input, (uint32_t)ceil(log2(((q->num_sub_channel) * (q->num_sub_channel + 1) / 2))));
q->time_gap = srslte_bit_pack(&input, 4);
q->mcs_idx = srslte_bit_pack(&input, 5);
q->retransmission = srslte_bit_pack(&input, 1);
return SRSLTE_SUCCESS;
}
void srslte_sci_info(char* str, srslte_sci_t* q)
{
uint32_t n = snprintf(str, 20, "SCI%i: riv=%i, mcs=%i", q->format, q->riv, q->mcs_idx);
if (q->format == SRSLTE_SCI_FORMAT0) {
n = srslte_print_check(str,
SRSLTE_SCI_MSG_MAX_LEN,
n,
", trp_idx=%i, t_adv=%i, n_sa_id=%i, freqhoppflg=%s\n",
q->trp_idx,
q->timing_advance,
q->N_sa_id,
q->freq_hopping_flag ? "true" : "false");
} else if (q->format == SRSLTE_SCI_FORMAT1) {
n = srslte_print_check(str,
SRSLTE_SCI_MSG_MAX_LEN,
n,
", priority=%i, res_rsrv=%i, t_gap=%i, rtx=%i\n",
q->priority,
q->resource_reserv,
q->time_gap,
q->retransmission);
}
}
void srslte_sci_free(srslte_sci_t* q)
{
if (q != NULL) {
bzero(q, sizeof(srslte_sci_t));
}
}

@ -53,15 +53,75 @@ add_executable(psbch_file_test psbch_file_test.c)
target_link_libraries(psbch_file_test srslte_phy) target_link_libraries(psbch_file_test srslte_phy)
# TM2 file tests # TM2 file tests
#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_p6_c0 psbch_file_test -p 6 -t 2 -c 0 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.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_p15_c84 psbch_file_test -p 15 -t 2 -c 84 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.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_p25_c168 psbch_file_test -p 25 -t 2 -c 168 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.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_p50_c252 psbch_file_test -p 50 -t 2 -c 252 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.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) add_test(psbch_file_test_ideal_tm2_p100_c335 psbch_file_test -p 100 -t 2 -c 335 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
# TM4 file tests # TM4 file tests
add_test(psbch_file_test_cmw_tm4_p50_c169 psbch_file_test -p 50 -c 169 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_slss_id169.dat) add_test(psbch_file_test_cmw_tm4_p50_c169 psbch_file_test -p 50 -c 169 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_slss_id169.dat)
########################################################################
# PSCCH TEST
########################################################################
add_executable(pscch_test pscch_test.c)
target_link_libraries(pscch_test srslte_phy)
# TM2 self tests
add_test(pscch_test_tm2_p6 pscch_test -p 6)
add_test(pscch_test_tm2_p15 pscch_test -p 15)
add_test(pscch_test_tm2_p25 pscch_test -p 25)
add_test(pscch_test_tm2_p50 pscch_test -p 50)
add_test(pscch_test_tm2_p75 pscch_test -p 75)
add_test(pscch_test_tm2_p100 pscch_test -p 100)
# TM4 self tests
add_test(pscch_test_tm4_p6 pscch_test -p 6 -t 4)
add_test(pscch_test_tm4_p15 pscch_test -p 15 -t 4)
add_test(pscch_test_tm4_p25 pscch_test -p 25 -t 4)
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)
# 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")
# TM4 file tests
add_test(pscch_file_test_ideal_tm4_p100 pscch_file_test -p 100 -t 4 -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(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(pscch_test_tm4_p50_cmw pscch_file_test -p 50 -t 4 -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")
# 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")
# With PHY ReTx (0 TTI offset?)
add_test(pscch_test_tm4_p50_uxm1 pscch_file_test -p 50 -d -t 4 -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 "num_decoded_sci=2")
# 100 PRB startOffset 1 MCS12 MAC padding
add_test(pscch_test_tm4_p100_uxm2 pscch_file_test -p 100 -t 4 -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 "num_decoded_sci=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 -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 "num_decoded_sci=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 -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 "num_decoded_sci=5")
######################################################################## ########################################################################
# NPBCH TEST # NPBCH TEST
######################################################################## ########################################################################

@ -0,0 +1,319 @@
/*
* 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 <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "srslte/phy/ch_estimation/chest_sl.h"
#include "srslte/phy/channel/ch_awgn.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/dft/ofdm.h"
#include "srslte/phy/io/filesource.h"
#include "srslte/phy/phch/pscch.h"
#include "srslte/phy/phch/sci.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
char* input_file_name;
srslte_cp_t cp = SRSLTE_CP_NORM;
uint32_t nof_prb = 6;
bool use_standard_lte_rates = false;
srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2;
uint32_t size_sub_channel = 10;
uint32_t num_sub_channel = 5;
uint32_t file_offset = 0;
uint32_t sf_n_samples;
uint32_t sf_n_re;
cf_t* sf_buffer;
cf_t* equalized_sf_buffer;
cf_t* input_buffer;
srslte_sci_t sci;
srslte_pscch_t pscch;
srslte_chest_sl_t pscch_chest;
srslte_ofdm_t fft;
srslte_filesource_t fsrc;
void usage(char* prog)
{
printf("Usage: %s [deioptxzn]\n", prog);
printf("\t-i input_file_name\n");
printf("\t-o File offset samples [Default %d]\n", file_offset);
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-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (tm + 1));
printf("\t-z Size of sub-channels [Default %i]\n", size_sub_channel);
printf("\t-n Number of sub-channels [Default %i]\n", num_sub_channel);
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, "deioptznv")) != -1) {
switch (opt) {
case 'd':
use_standard_lte_rates = true;
break;
case 'o':
file_offset = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'e':
cp = SRSLTE_CP_EXT;
break;
case 'i':
input_file_name = argv[optind];
break;
case 'p':
nof_prb = (int32_t)strtol(argv[optind], NULL, 10);
break;
case 't':
switch ((int32_t)strtol(argv[optind], NULL, 10)) {
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 'z':
size_sub_channel = (int32_t)strtol(argv[optind], NULL, 10);
break;
case 'n':
num_sub_channel = (int32_t)strtol(argv[optind], NULL, 10);
case 'v':
srslte_verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int base_init()
{
sf_n_samples = srslte_symbol_sz(nof_prb) * 15;
sf_n_re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE * 2 * nof_prb;
sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
if (!sf_buffer) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
equalized_sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
if (!equalized_sf_buffer) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
input_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
if (!input_buffer) {
ERROR("Error allocating memory\n");
return SRSLTE_ERROR;
}
srslte_sci_init(&sci, nof_prb, tm, size_sub_channel, num_sub_channel);
if (srslte_pscch_init(&pscch, nof_prb, tm, cp) != SRSLTE_SUCCESS) {
ERROR("Error in PSCCH init\n");
return SRSLTE_ERROR;
}
if (srslte_chest_sl_init_pscch_dmrs(&pscch_chest) != SRSLTE_SUCCESS) {
ERROR("Error in PSCCH DMRS 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);
return SRSLTE_ERROR;
}
} else {
ERROR("Invalid input file name\n");
return SRSLTE_ERROR;
}
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);
return SRSLTE_SUCCESS;
}
void base_free()
{
srslte_filesource_free(&fsrc);
srslte_ofdm_rx_free(&fft);
srslte_sci_free(&sci);
srslte_pscch_free(&pscch);
srslte_chest_sl_free(&pscch_chest);
if (sf_buffer) {
free(sf_buffer);
}
if (equalized_sf_buffer) {
free(equalized_sf_buffer);
}
if (input_buffer) {
free(input_buffer);
}
}
int main(int argc, char** argv)
{
uint8_t sci_rx[SRSLTE_SCI_MAX_LEN] = {};
int ret = SRSLTE_ERROR;
parse_args(argc, argv);
srslte_use_standard_symbol_size(use_standard_lte_rates);
if (base_init()) {
ERROR("Error initializing\n");
base_free();
return SRSLTE_ERROR;
}
uint32_t num_decoded_sci = 0;
char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = "";
int max_num_subframes = 128;
int num_subframes = 0;
int nread = 0;
if (file_offset > 0) {
printf("Offsetting file by %d samples.\n", file_offset);
srslte_filesource_seek(&fsrc, file_offset * sizeof(cf_t));
}
do {
nread = srslte_filesource_read(&fsrc, input_buffer, sf_n_samples);
if (nread < 0) {
fprintf(stderr, "Error reading from file\n");
return ret;
} else if (nread == 0) {
goto clean_exit;
} else if (nread < sf_n_samples) {
fprintf(stderr, "Couldn't read entire subframe. Still processing ..\n");
nread = -1;
}
// CFO estimation and correction
srslte_sl_cfo_est_corr_cp(input_buffer, nof_prb, cp);
srslte_ofdm_rx_sf(&fft);
if (tm == SRSLTE_SIDELINK_TM1 || tm == SRSLTE_SIDELINK_TM2) {
uint32_t prb_num = (uint32_t)ceil(nof_prb / 2);
uint32_t prb_start = 0;
uint32_t prb_end = nof_prb - 1;
uint32_t cyclic_shift = 0;
srslte_chest_sl_gen_pscch_dmrs(&pscch_chest, cyclic_shift, tm);
for (uint32_t pscch_prb_idx = prb_start; pscch_prb_idx <= prb_end; pscch_prb_idx++) {
if (pscch_prb_idx == (prb_start + prb_num)) {
pscch_prb_idx = (prb_end + 1) - prb_num;
}
// PSCCH Channel estimation
srslte_chest_sl_pscch_ls_estimate_equalize(
&pscch_chest, sf_buffer, pscch_prb_idx, equalized_sf_buffer, nof_prb, tm, cp);
if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_idx) == SRSLTE_SUCCESS) {
if (srslte_sci_format0_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) {
printf("Error unpacking sci format 0\n");
return SRSLTE_ERROR;
}
srslte_sci_info(sci_msg, &sci);
fprintf(stdout, "%s", sci_msg);
num_decoded_sci++;
}
}
} else if (tm == SRSLTE_SIDELINK_TM3 || tm == SRSLTE_SIDELINK_TM4) {
for (int i = 0; i < num_sub_channel; i++) {
uint32_t pscch_prb_idx = size_sub_channel * i;
for (uint32_t cyclic_shift = 0; cyclic_shift <= 9; cyclic_shift += 3) {
// PSCCH Channel estimation
srslte_chest_sl_gen_pscch_dmrs(&pscch_chest, cyclic_shift, tm);
srslte_chest_sl_pscch_ls_estimate_equalize(
&pscch_chest, sf_buffer, pscch_prb_idx, equalized_sf_buffer, nof_prb, tm, cp);
if (srslte_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_idx) == SRSLTE_SUCCESS) {
if (srslte_sci_format1_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) {
printf("Error unpacking sci format 1\n");
return SRSLTE_ERROR;
}
srslte_sci_info(sci_msg, &sci);
fprintf(stdout, "%s", sci_msg);
num_decoded_sci++;
}
if (SRSLTE_VERBOSE_ISDEBUG()) {
char filename[64];
snprintf(
filename, 64, "pscch_rx_syms_sf%d_shift%d_prbidx%d.bin", num_subframes, cyclic_shift, pscch_prb_idx);
printf("Saving PSCCH symbols (%d) to %s\n", pscch.E / SRSLTE_PSCCH_QM, filename);
srslte_vec_save_file(filename, pscch.mod_symbols, pscch.E / SRSLTE_PSCCH_QM * sizeof(cf_t));
}
}
}
}
num_subframes++;
} while (nread > 0 && num_subframes < max_num_subframes);
clean_exit:
base_free();
printf("num_decoded_sci=%d\n", num_decoded_sci);
ret = (num_decoded_sci > 0) ? SRSLTE_SUCCESS : SRSLTE_ERROR;
return ret;
}

@ -0,0 +1,169 @@
/*
* 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 <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include "srslte/phy/phch/pscch.h"
#include "srslte/phy/phch/sci.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
int32_t N_sl_id = 168;
uint32_t nof_prb = 6;
srslte_cp_t cp = SRSLTE_CP_NORM;
srslte_sl_tm_t tm = SRSLTE_SIDELINK_TM2;
uint32_t size_sub_channel = 10;
uint32_t num_sub_channel = 5;
uint32_t prb_idx = 0;
void usage(char* prog)
{
printf("Usage: %s [cdeipt]\n", prog);
printf("\t-p nof_prb [Default %d]\n", nof_prb);
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, "ceiptv")) != -1) {
switch (opt) {
case 'c':
N_sl_id = (int32_t)strtol(argv[optind], NULL, 10);
break;
case 'p':
nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 't':
switch (strtol(argv[optind], NULL, 10)) {
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);
char sci_msg[SRSLTE_SCI_MSG_MAX_LEN] = "";
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);
// SCI
srslte_sci_t sci;
srslte_sci_init(&sci, nof_prb, tm, size_sub_channel, num_sub_channel);
// PSCCH
srslte_pscch_t pscch;
if (srslte_pscch_init(&pscch, nof_prb, tm, cp) != SRSLTE_SUCCESS) {
ERROR("Error in PSCCH init\n");
return SRSLTE_ERROR;
}
// SCI message bits
uint8_t sci_tx[SRSLTE_SCI_MAX_LEN] = {};
if (sci.format == SRSLTE_SCI_FORMAT0) {
if (srslte_sci_format0_pack(&sci, sci_tx) != SRSLTE_SUCCESS) {
printf("Error packing sci format 0\n");
return SRSLTE_ERROR;
}
} else if (sci.format == SRSLTE_SCI_FORMAT1) {
if (srslte_sci_format1_pack(&sci, sci_tx) != SRSLTE_SUCCESS) {
printf("Error packing sci format 1\n");
return SRSLTE_ERROR;
}
}
printf("Tx payload: ");
srslte_vec_fprint_hex(stdout, sci_tx, sci.sci_len);
// Put SCI into PSCCH
srslte_pscch_encode(&pscch, sci_tx, sf_buffer, prb_idx);
// Prepare Rx buffer
uint8_t sci_rx[SRSLTE_SCI_MAX_LEN] = {};
// Decode PSCCH
if (srslte_pscch_decode(&pscch, sf_buffer, sci_rx, prb_idx) == SRSLTE_SUCCESS) {
printf("Rx payload: ");
srslte_vec_fprint_hex(stdout, sci_rx, sci.sci_len);
uint32_t riv_txed = sci.riv;
if (sci.format == SRSLTE_SCI_FORMAT0) {
if (srslte_sci_format0_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) {
printf("Error unpacking sci format 0\n");
return SRSLTE_ERROR;
}
} else if (sci.format == SRSLTE_SCI_FORMAT1) {
if (srslte_sci_format1_unpack(&sci, sci_rx) != SRSLTE_SUCCESS) {
printf("Error unpacking sci format 1\n");
return SRSLTE_ERROR;
}
}
srslte_sci_info(sci_msg, &sci);
fprintf(stdout, "%s", sci_msg);
if (sci.riv == riv_txed) {
ret = SRSLTE_SUCCESS;
}
}
free(sf_buffer);
srslte_sci_free(&sci);
srslte_pscch_free(&pscch);
return ret;
}

@ -147,3 +147,49 @@ float srslte_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb)
srslte_vec_apply_cfo(input_buffer, (float)(1 / (nFFT * 15e3)) * ((-15e3 / 2.0) - cfo), input_buffer, sf_n_samples); srslte_vec_apply_cfo(input_buffer, (float)(1 / (nFFT * 15e3)) * ((-15e3 / 2.0) - cfo), input_buffer, sf_n_samples);
return cfo; return cfo;
} }
/*
* Sidelink CFO estimation and correction based on cp
*/
float srslte_sl_cfo_est_corr_cp(cf_t* input_buffer, uint32_t nof_prb, srslte_cp_t cp)
{
int symbol_sz = srslte_symbol_sz(nof_prb);
int sf_n_samples = SRSLTE_SF_LEN_PRB(nof_prb);
float tFFT = (float)(1 / 15000.0);
int cp_size = SRSLTE_CP_SZ(symbol_sz, cp);
int cp_size_0 = (cp == SRSLTE_CP_NORM) ? SRSLTE_CP_LEN_NORM(0, symbol_sz) : cp_size;
// Compensate for initial SC-FDMA half subcarrier shift, cfo = 7500 / (15000 * symbol_sz) <=> 1 / (symbol_sz * 2.0)
srslte_vec_apply_cfo(input_buffer, (1 / (float)(symbol_sz * 2.0)), input_buffer, sf_n_samples);
uint32_t p1 = 0;
uint32_t p2 = symbol_sz;
uint32_t cp_len = 0;
uint32_t sf_n_symbols = (cp == SRSLTE_CP_NORM)
? (14 - 1)
: (12 - 1); // // 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.
cf_t average_cfo = 0.0f;
for (int i = 0; i < sf_n_symbols; i++) {
// Calculate CP length
cp_len = (i == 0 || i == SRSLTE_CP_NSYMB(cp)) ? cp_size_0 : cp_size;
// Correlate CP with tail
average_cfo += srslte_vec_dot_prod_conj_ccc(&input_buffer[p2], &input_buffer[p1], cp_len);
// Increment pointers for next symbol
p1 += cp_len + symbol_sz;
p2 += cp_len + symbol_sz;
}
float cfo = (float)(carg(average_cfo) / (float)(2 * M_PI * tFFT));
// Compensate for initial SC-FDMA half subcarrier shift, cfo = - 7500 / (15000 * symbol_sz) <=> 1 / (symbol_sz * 2.0)
srslte_vec_apply_cfo(
input_buffer, (-1 / (float)(symbol_sz * 2.0)) + (-cfo / (float)(15e3 * symbol_sz)), input_buffer, sf_n_samples);
return cfo;
}
Loading…
Cancel
Save