mirror of https://github.com/PentHertz/srsLTE.git
adding NPDCCH
This commit is contained in:
parent
073c57dc3d
commit
81b46723f6
|
@ -45,7 +45,9 @@
|
|||
|
||||
#define SRSLTE_PC_MAX 23 // Maximum TX power for Category 1 UE (in dBm)
|
||||
|
||||
#define SRSLTE_NUM_PCI 504
|
||||
#define SRSLTE_NOF_NID_1 (168)
|
||||
#define SRSLTE_NOF_NID_2 (3)
|
||||
#define SRSLTE_NUM_PCI (SRSLTE_NOF_NID_1 * SRSLTE_NOF_NID_2)
|
||||
|
||||
#define SRSLTE_MAX_RADIOS 3 // Maximum number of supported RF devices
|
||||
#define SRSLTE_MAX_CARRIERS 5 // Maximum number of supported simultaneous carriers
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file dci_nbiot.h
|
||||
*
|
||||
* @brief Downlink control information (DCI) for NB-IoT.
|
||||
*
|
||||
* Packing/Unpacking functions to convert between bit streams
|
||||
* and packed DCI UL/DL grants defined in ra_nbiot.h
|
||||
*
|
||||
* Reference: 3GPP TS 36.212 version 13.2.0 Release 13 Sec. 6.4.3
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_DCI_NBIOT_H
|
||||
#define SRSLTE_DCI_NBIOT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/phch/dci.h"
|
||||
#include "srslte/phy/phch/ra_nbiot.h"
|
||||
|
||||
#define SRSLTE_DCI_MAX_BITS 128
|
||||
#define SRSLTE_NBIOT_RAR_GRANT_LEN 15
|
||||
|
||||
SRSLTE_API void srslte_nbiot_dci_rar_grant_unpack(srslte_nbiot_dci_rar_grant_t* rar,
|
||||
const uint8_t grant[SRSLTE_NBIOT_RAR_GRANT_LEN]);
|
||||
|
||||
SRSLTE_API int srslte_nbiot_dci_msg_to_dl_grant(const srslte_dci_msg_t* msg,
|
||||
const uint16_t msg_rnti,
|
||||
srslte_ra_nbiot_dl_dci_t* dl_dci,
|
||||
srslte_ra_nbiot_dl_grant_t* grant,
|
||||
const uint32_t sfn,
|
||||
const uint32_t sf_idx,
|
||||
const uint32_t r_max,
|
||||
const srslte_nbiot_mode_t mode);
|
||||
|
||||
SRSLTE_API int srslte_nbiot_dci_msg_to_ul_grant(const srslte_dci_msg_t* msg,
|
||||
srslte_ra_nbiot_ul_dci_t* ul_dci,
|
||||
srslte_ra_nbiot_ul_grant_t* grant,
|
||||
const uint32_t rx_tti,
|
||||
const srslte_npusch_sc_spacing_t spacing);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_nbiot_dci_rar_to_ul_grant(srslte_nbiot_dci_rar_grant_t* rar, srslte_ra_nbiot_ul_grant_t* grant, uint32_t rx_tti);
|
||||
|
||||
SRSLTE_API bool srslte_nbiot_dci_location_isvalid(const srslte_dci_location_t* c);
|
||||
|
||||
SRSLTE_API int srslte_dci_msg_pack_npdsch(const srslte_ra_nbiot_dl_dci_t* data,
|
||||
const srslte_dci_format_t format,
|
||||
srslte_dci_msg_t* msg,
|
||||
const bool crc_is_crnti);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_dci_msg_unpack_npdsch(const srslte_dci_msg_t* msg, srslte_ra_nbiot_dl_dci_t* data, const bool crc_is_crnti);
|
||||
|
||||
SRSLTE_API int srslte_dci_msg_unpack_npusch(const srslte_dci_msg_t* msg, srslte_ra_nbiot_ul_dci_t* data);
|
||||
|
||||
SRSLTE_API uint32_t srslte_dci_nbiot_format_sizeof(srslte_dci_format_t format);
|
||||
|
||||
#endif // SRSLTE_DCI_NBIOT_H
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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_NPDCCH_H
|
||||
#define SRSLTE_NPDCCH_H
|
||||
|
||||
#include "srslte/config.h"
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/fec/convcoder.h"
|
||||
#include "srslte/phy/fec/crc.h"
|
||||
#include "srslte/phy/fec/rm_conv.h"
|
||||
#include "srslte/phy/fec/viterbi.h"
|
||||
#include "srslte/phy/mimo/layermap.h"
|
||||
#include "srslte/phy/mimo/precoding.h"
|
||||
#include "srslte/phy/modem/demod_soft.h"
|
||||
#include "srslte/phy/modem/mod.h"
|
||||
#include "srslte/phy/phch/dci.h"
|
||||
#include "srslte/phy/phch/regs.h"
|
||||
#include "srslte/phy/scrambling/scrambling.h"
|
||||
|
||||
#define SRSLTE_RARNTI_END_NBIOT 0x0100
|
||||
#define SRSLTE_NBIOT_NUM_NRS_SYMS 8
|
||||
#define SRSLTE_NPDCCH_MAX_RE (SRSLTE_NRE * SRSLTE_CP_NORM_SF_NSYMB - SRSLTE_NBIOT_NUM_NRS_SYMS)
|
||||
|
||||
#define SRSLTE_NBIOT_DCI_MAX_SIZE 23
|
||||
#define SRSLTE_AL_REPETITION_USS 64 // Higher layer configured parameter al-Repetition-USS
|
||||
|
||||
typedef enum SRSLTE_API {
|
||||
SRSLTE_NPDCCH_FORMAT1 = 0,
|
||||
SRSLTE_NPDCCH_FORMAT0_LOWER_HALF,
|
||||
SRSLTE_NPDCCH_FORMAT0_UPPER_HALF,
|
||||
SRSLTE_NPDCCH_FORMAT_NITEMS
|
||||
} srslte_npdcch_format_t;
|
||||
static const char srslte_npdcch_format_text[SRSLTE_NPDCCH_FORMAT_NITEMS][30] = {"Format 1",
|
||||
"Format 0 (Lower Half)",
|
||||
"Format 0 (Upper Half)"};
|
||||
|
||||
/**
|
||||
* @brief Narrowband Physical downlink control channel (NPDCCH)
|
||||
*
|
||||
* Reference: 3GPP TS 36.211 version 13.2.0 Release 11 Sec. 6.8 and 10.2.5
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_nbiot_cell_t cell;
|
||||
uint32_t nof_cce;
|
||||
uint32_t ncce_bits;
|
||||
uint32_t max_bits;
|
||||
uint32_t i_n_start; /// start of the first OFDM symbol (signalled through NB-SIB1)
|
||||
uint32_t nof_nbiot_refs; /// number of NRS symbols per OFDM symbol
|
||||
uint32_t nof_lte_refs; /// number of CRS symbols per OFDM symbol
|
||||
uint32_t num_decoded_symbols;
|
||||
|
||||
/* buffers */
|
||||
cf_t* ce[SRSLTE_MAX_PORTS];
|
||||
cf_t* symbols[SRSLTE_MAX_PORTS];
|
||||
cf_t* x[SRSLTE_MAX_PORTS];
|
||||
cf_t* d;
|
||||
uint8_t* e;
|
||||
float rm_f[3 * (SRSLTE_DCI_MAX_BITS + 16)];
|
||||
float* llr[2]; // Two layers of LLRs for Format0 and Format1 NPDCCH
|
||||
|
||||
/* tx & rx objects */
|
||||
srslte_modem_table_t mod;
|
||||
srslte_sequence_t seq[SRSLTE_NOF_SF_X_FRAME];
|
||||
srslte_viterbi_t decoder;
|
||||
srslte_crc_t crc;
|
||||
|
||||
} srslte_npdcch_t;
|
||||
|
||||
SRSLTE_API int srslte_npdcch_init(srslte_npdcch_t* q);
|
||||
|
||||
SRSLTE_API void srslte_npdcch_free(srslte_npdcch_t* q);
|
||||
|
||||
SRSLTE_API int srslte_npdcch_set_cell(srslte_npdcch_t* q, srslte_nbiot_cell_t cell);
|
||||
|
||||
/// Encoding function
|
||||
SRSLTE_API int srslte_npdcch_encode(srslte_npdcch_t* q,
|
||||
srslte_dci_msg_t* msg,
|
||||
srslte_dci_location_t location,
|
||||
uint16_t rnti,
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS],
|
||||
uint32_t nsubframe);
|
||||
|
||||
/// Decoding functions: Extract the LLRs and save them in the srslte_npdcch_t object
|
||||
SRSLTE_API int srslte_npdcch_extract_llr(srslte_npdcch_t* q,
|
||||
cf_t* sf_symbols,
|
||||
cf_t* ce[SRSLTE_MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint32_t sf_idx);
|
||||
|
||||
/// Decoding functions: Try to decode a DCI message after calling srslte_npdcch_extract_llr
|
||||
SRSLTE_API int srslte_npdcch_decode_msg(srslte_npdcch_t* q,
|
||||
srslte_dci_msg_t* msg,
|
||||
srslte_dci_location_t* location,
|
||||
srslte_dci_format_t format,
|
||||
uint16_t* crc_rem);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_npdcch_dci_decode(srslte_npdcch_t* q, float* e, uint8_t* data, uint32_t E, uint32_t nof_bits, uint16_t* crc);
|
||||
|
||||
SRSLTE_API int
|
||||
srslte_npdcch_dci_encode(srslte_npdcch_t* q, uint8_t* data, uint8_t* e, uint32_t nof_bits, uint32_t E, uint16_t rnti);
|
||||
|
||||
SRSLTE_API void
|
||||
srslte_npdcch_dci_encode_conv(srslte_npdcch_t* q, uint8_t* data, uint32_t nof_bits, uint8_t* coded_data, uint16_t rnti);
|
||||
|
||||
SRSLTE_API uint32_t srslte_npdcch_ue_locations(srslte_dci_location_t* c, uint32_t max_candidates);
|
||||
|
||||
SRSLTE_API uint32_t srslte_npdcch_common_locations(srslte_dci_location_t* c, uint32_t max_candidates);
|
||||
|
||||
int srslte_npdcch_cp(srslte_npdcch_t* q, cf_t* input, cf_t* output, bool put, srslte_npdcch_format_t format);
|
||||
int srslte_npdcch_put(srslte_npdcch_t* q, cf_t* symbols, cf_t* sf_symbols, srslte_npdcch_format_t format);
|
||||
int srslte_npdcch_get(srslte_npdcch_t* q, cf_t* symbols, cf_t* sf_symbols, srslte_npdcch_format_t format);
|
||||
|
||||
#endif // SRSLTE_NPDCCH_H
|
|
@ -190,7 +190,6 @@ typedef struct SRSLTE_API {
|
|||
|
||||
/// Functions
|
||||
SRSLTE_API int srslte_ra_nbiot_dl_dci_to_grant(srslte_ra_nbiot_dl_dci_t* dci,
|
||||
uint16_t msg_rnti,
|
||||
srslte_ra_nbiot_dl_grant_t* grant,
|
||||
uint32_t sfn,
|
||||
uint32_t sf_idx,
|
||||
|
|
|
@ -52,4 +52,6 @@ SRSLTE_API int rf_search_and_decode_mib(srslte_rf_t* rf,
|
|||
srslte_cell_t* cell,
|
||||
float* cfo);
|
||||
|
||||
SRSLTE_API int rf_cell_search_nbiot(srslte_rf_t* rf, cell_search_cfg_t* config, srslte_nbiot_cell_t* cell, float* cfo);
|
||||
|
||||
#endif // SRSLTE_RF_UTILS_H
|
||||
|
|
|
@ -1446,6 +1446,12 @@ char* srslte_dci_format_string(srslte_dci_format_t format)
|
|||
return "Format2A";
|
||||
case SRSLTE_DCI_FORMAT2B:
|
||||
return "Format2B";
|
||||
case SRSLTE_DCI_FORMATN0:
|
||||
return "FormatN0";
|
||||
case SRSLTE_DCI_FORMATN1:
|
||||
return "FormatN1";
|
||||
case SRSLTE_DCI_FORMATN2:
|
||||
return "FormatN2";
|
||||
default:
|
||||
return "N/A"; // fatal error
|
||||
}
|
||||
|
|
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* 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 <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/phch/dci_nbiot.h"
|
||||
#include "srslte/phy/utils/bit.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
||||
/* Creates the UL NPUSCH resource allocation grant from the random access respone message
|
||||
*/
|
||||
int srslte_nbiot_dci_rar_to_ul_grant(srslte_nbiot_dci_rar_grant_t* rar,
|
||||
srslte_ra_nbiot_ul_grant_t* grant,
|
||||
uint32_t rx_tti)
|
||||
{
|
||||
// create DCI from rar grant
|
||||
srslte_ra_nbiot_ul_dci_t dci;
|
||||
bzero(&dci, sizeof(srslte_ra_nbiot_ul_dci_t));
|
||||
dci.i_rep = rar->n_rep;
|
||||
dci.i_sc = rar->i_sc;
|
||||
dci.i_mcs = rar->i_mcs;
|
||||
dci.i_delay = rar->i_delay;
|
||||
dci.sc_spacing = (rar->sc_spacing == 1) ? SRSLTE_NPUSCH_SC_SPACING_15000 : SRSLTE_NPUSCH_SC_SPACING_3750;
|
||||
|
||||
// use DCI to fill default UL grant values
|
||||
grant->format = SRSLTE_NPUSCH_FORMAT1; // UL-SCH is always format 1
|
||||
if (srslte_ra_nbiot_ul_rar_dci_to_grant(&dci, grant, rx_tti)) {
|
||||
fprintf(stderr, "Error converting RAR DCI to grant.\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||
srslte_ra_nbiot_ul_grant_fprint(stdout, grant);
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* Unpack RAR UL grant as defined in Section 16.3.3 of 36.213 */
|
||||
void srslte_nbiot_dci_rar_grant_unpack(srslte_nbiot_dci_rar_grant_t* rar,
|
||||
const uint8_t grant[SRSLTE_NBIOT_RAR_GRANT_LEN])
|
||||
{
|
||||
uint8_t* grant_ptr = (uint8_t*)grant;
|
||||
rar->sc_spacing = srslte_bit_pack(&grant_ptr, 1);
|
||||
rar->i_sc = srslte_bit_pack(&grant_ptr, 6);
|
||||
rar->i_delay = srslte_bit_pack(&grant_ptr, 2);
|
||||
rar->n_rep = srslte_bit_pack(&grant_ptr, 3);
|
||||
rar->i_mcs = srslte_bit_pack(&grant_ptr, 3);
|
||||
}
|
||||
|
||||
// Creates the UL NPUSCH resource allocation grant from a DCI format N0 message
|
||||
int srslte_nbiot_dci_msg_to_ul_grant(const srslte_dci_msg_t* msg,
|
||||
srslte_ra_nbiot_ul_dci_t* ul_dci,
|
||||
srslte_ra_nbiot_ul_grant_t* grant,
|
||||
const uint32_t rx_tti,
|
||||
const srslte_npusch_sc_spacing_t spacing)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (msg != NULL && ul_dci != NULL && grant != NULL) {
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
bzero(ul_dci, sizeof(srslte_ra_nbiot_ul_dci_t));
|
||||
bzero(grant, sizeof(srslte_ra_nbiot_ul_grant_t));
|
||||
|
||||
if (srslte_dci_msg_unpack_npusch(msg, ul_dci)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (srslte_ra_nbiot_ul_dci_to_grant(ul_dci, grant, rx_tti, spacing)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||
srslte_ra_npusch_fprint(stdout, ul_dci);
|
||||
srslte_ra_nbiot_ul_grant_fprint(stdout, grant);
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Unpacks a NB-IoT DCI message and configures the DL grant object
|
||||
*/
|
||||
int srslte_nbiot_dci_msg_to_dl_grant(const srslte_dci_msg_t* msg,
|
||||
const uint16_t msg_rnti,
|
||||
srslte_ra_nbiot_dl_dci_t* dl_dci,
|
||||
srslte_ra_nbiot_dl_grant_t* grant,
|
||||
const uint32_t sfn,
|
||||
const uint32_t sf_idx,
|
||||
const uint32_t r_max,
|
||||
const srslte_nbiot_mode_t mode)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (msg != NULL && grant != NULL && dl_dci != NULL) {
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
bzero(dl_dci, sizeof(srslte_ra_nbiot_dl_dci_t));
|
||||
bzero(grant, sizeof(srslte_ra_nbiot_dl_grant_t));
|
||||
|
||||
bool crc_is_crnti = false;
|
||||
if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) {
|
||||
crc_is_crnti = true;
|
||||
}
|
||||
srslte_dci_format_t tmp = msg->format;
|
||||
ret = srslte_dci_msg_unpack_npdsch(msg, dl_dci, crc_is_crnti);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Can't unpack DCI message %s (%d)\n", srslte_dci_format_string(tmp), tmp);
|
||||
return ret;
|
||||
}
|
||||
ret = srslte_ra_nbiot_dl_dci_to_grant(dl_dci, grant, sfn, sf_idx, r_max, false, mode);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Can't convert DCI %s to grant (%d)\n", srslte_dci_format_string(tmp), tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||
srslte_nbiot_dl_dci_fprint(stdout, dl_dci);
|
||||
srslte_ra_nbiot_dl_grant_fprint(stdout, grant);
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// For NB-IoT there are only three possible combinations, i.e.
|
||||
// L' L nNCCE
|
||||
// #1 1 0 0
|
||||
// #2 1 0 1
|
||||
// #3 2 1 0
|
||||
bool srslte_nbiot_dci_location_isvalid(const srslte_dci_location_t* c)
|
||||
{
|
||||
if ((c->L == 1 && c->ncce <= 1) || (c->L == 2 && c->ncce == 0)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t dci_formatN0_sizeof()
|
||||
{
|
||||
return 23;
|
||||
}
|
||||
|
||||
uint32_t dci_formatN1_sizeof()
|
||||
{
|
||||
// same as for formatN0
|
||||
return dci_formatN0_sizeof();
|
||||
}
|
||||
|
||||
uint32_t dci_formatN2_sizeof()
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
|
||||
/* Packs DCI format N0 data to a sequence of bits and store them in msg according
|
||||
* to 36.212 13.2.0 clause 6.4.3.1
|
||||
*
|
||||
* TODO: TPC and cyclic shift for DM RS not implemented
|
||||
*/
|
||||
int dci_formatN0_pack(srslte_ra_nbiot_ul_dci_t* data, srslte_dci_msg_t* msg, uint32_t nof_prb)
|
||||
{
|
||||
// pack bits
|
||||
uint8_t* y = msg->payload;
|
||||
|
||||
*y++ = 0; // format differentiation
|
||||
|
||||
// TODO: Implement packing
|
||||
|
||||
// Subcarrier indication – 6 bits
|
||||
|
||||
// Resource assignment – 3 bits
|
||||
|
||||
// Scheduling delay – 2 bits
|
||||
|
||||
// Modulation and coding scheme – 4 bits
|
||||
|
||||
// Redundancy version – 1 bit
|
||||
|
||||
// Repetition number – 3 bits
|
||||
|
||||
// New data indicator – 1 bit
|
||||
|
||||
// DCI subframe repetition number – 2 bits
|
||||
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
/* Packs DCI format N1 data to a sequence of bits and store them in msg according
|
||||
* to 36.212 v13.2.0 clause 6.4.3.2
|
||||
*
|
||||
* TODO: implement packing for NPRACH case
|
||||
*/
|
||||
int dci_formatN1_pack(const srslte_ra_nbiot_dl_dci_t* data, srslte_dci_msg_t* msg, bool crc_is_crnti)
|
||||
{
|
||||
int last_bits_val = 0;
|
||||
uint8_t* y = (uint8_t*)msg->payload;
|
||||
|
||||
*y++ = 1; // format differentiation
|
||||
|
||||
// NPDCCH order indicator – 1 bit
|
||||
*y++ = data->alloc.is_ra;
|
||||
if (data->alloc.is_ra) {
|
||||
// Starting number of NPRACH repetitions – 2 bits
|
||||
|
||||
// Subcarrier indication of NPRACH – 6 bits
|
||||
|
||||
// All the remaining bits in format N1
|
||||
last_bits_val = 1;
|
||||
} else {
|
||||
// default NPDSCH scheduling
|
||||
|
||||
// Scheduling delay – 3 bits
|
||||
srslte_bit_unpack(data->alloc.i_delay, &y, 3);
|
||||
|
||||
// Resource assignment – 3 bits
|
||||
srslte_bit_unpack(data->alloc.i_sf, &y, 3);
|
||||
|
||||
// Modulation and coding scheme – 4 bits
|
||||
srslte_bit_unpack(data->mcs_idx, &y, 4);
|
||||
|
||||
// Repetition number – 4 bits
|
||||
srslte_bit_unpack(data->alloc.i_rep, &y, 4);
|
||||
|
||||
// New data indicator – 1 bit
|
||||
if (crc_is_crnti) {
|
||||
*y++ = 0;
|
||||
} else {
|
||||
*y++ = data->ndi;
|
||||
}
|
||||
|
||||
// HARQ-ACK resource – 4 bits
|
||||
if (crc_is_crnti) {
|
||||
// reserved
|
||||
y += 4;
|
||||
} else {
|
||||
srslte_bit_unpack(data->alloc.harq_ack, &y, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Padding with zeros until reaching final size
|
||||
uint32_t n = dci_formatN1_sizeof();
|
||||
while (y - msg->payload < n) {
|
||||
*y++ = last_bits_val;
|
||||
}
|
||||
msg->nof_bits = (y - msg->payload);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
// According to Section 6.4.3.1 in TS36.212 v13.2.0
|
||||
int dci_formatN0_unpack(const srslte_dci_msg_t* msg, srslte_ra_nbiot_ul_dci_t* data)
|
||||
{
|
||||
uint8_t* y = (uint8_t*)msg->payload;
|
||||
|
||||
// make sure it has the expected length
|
||||
if (msg->nof_bits != dci_formatN1_sizeof()) {
|
||||
fprintf(stderr, "Invalid message length for format N1\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Format differentiation - 1 bit
|
||||
data->format = srslte_bit_pack(&y, 1);
|
||||
|
||||
// Subcarrier indication – 6 bits
|
||||
data->i_sc = srslte_bit_pack(&y, 6);
|
||||
|
||||
// Resource assignment – 3 bits
|
||||
data->i_ru = srslte_bit_pack(&y, 3);
|
||||
|
||||
// Scheduling delay – 2 bits
|
||||
data->i_delay = srslte_bit_pack(&y, 2);
|
||||
|
||||
// Modulation and coding scheme – 4
|
||||
data->i_mcs = srslte_bit_pack(&y, 4);
|
||||
|
||||
// Redundancy version – 1 bit
|
||||
data->i_rv = srslte_bit_pack(&y, 1);
|
||||
|
||||
// Repetition number – 3 bits
|
||||
data->i_rep = srslte_bit_pack(&y, 3);
|
||||
|
||||
// New data indicator – 1 bit
|
||||
data->ndi = srslte_bit_pack(&y, 1);
|
||||
|
||||
// DCI subframe repetition number – 2 bits
|
||||
data->dci_sf_rep_num = srslte_bit_pack(&y, 2);
|
||||
|
||||
// According to 16.5.1.1, SC spacing is determined by RAR grant
|
||||
// TODO: Add support for 3.75kHz
|
||||
data->sc_spacing = SRSLTE_NPUSCH_SC_SPACING_15000;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int dci_formatN1_unpack(const srslte_dci_msg_t* msg, srslte_ra_nbiot_dl_dci_t* data, bool crc_is_crnti)
|
||||
{
|
||||
uint8_t* y = (uint8_t*)msg->payload;
|
||||
|
||||
// make sure it has the expected length
|
||||
if (msg->nof_bits != dci_formatN1_sizeof()) {
|
||||
fprintf(stderr, "Invalid message length for format N1\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Format differentiation - 1 bit
|
||||
data->format = srslte_bit_pack(&y, 1);
|
||||
data->dci_is_n2 = false;
|
||||
|
||||
// The NPDCCH order indicator (if bit is one, this is for RA procedure)
|
||||
data->alloc.is_ra = srslte_bit_pack(&y, 1);
|
||||
|
||||
if (data->alloc.is_ra) {
|
||||
// This is a RA precedure, set field according to Section 6.4.3.2 in TS36.212
|
||||
data->alloc.nprach_start = srslte_bit_pack(&y, 2);
|
||||
data->alloc.nprach_sc = srslte_bit_pack(&y, 6);
|
||||
// set remaining field to 1
|
||||
data->alloc.i_delay = 0xffff;
|
||||
data->alloc.i_sf = 0xffff;
|
||||
data->mcs_idx = 0xffff;
|
||||
data->alloc.i_rep = 0xffff;
|
||||
data->ndi = true;
|
||||
data->alloc.harq_ack = 0xffff;
|
||||
data->alloc.dci_sf_rep_num = 0xffff;
|
||||
} else {
|
||||
// default NPDSCH scheduling
|
||||
|
||||
// Scheduling delay – 3 bits
|
||||
data->alloc.i_delay = srslte_bit_pack(&y, 3);
|
||||
|
||||
// Resource assignment – 3 bits
|
||||
data->alloc.i_sf = srslte_bit_pack(&y, 3);
|
||||
|
||||
// Modulation and coding scheme – 4 bits
|
||||
data->mcs_idx = srslte_bit_pack(&y, 4);
|
||||
|
||||
// Repetition number – 4 bits
|
||||
data->alloc.i_rep = srslte_bit_pack(&y, 4);
|
||||
|
||||
// New data indicator – 1 bit
|
||||
if (crc_is_crnti) {
|
||||
data->ndi = *y++ ? true : false;
|
||||
} else {
|
||||
y++; // NDI reserved
|
||||
}
|
||||
|
||||
// HARQ-ACK resource – 4 bits
|
||||
data->alloc.harq_ack = srslte_bit_pack(&y, 4);
|
||||
|
||||
// DCI subframe repetition number – 2 bits
|
||||
data->alloc.dci_sf_rep_num = srslte_bit_pack(&y, 2);
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int dci_formatN2_unpack(const srslte_dci_msg_t* msg, srslte_ra_nbiot_dl_dci_t* data)
|
||||
{
|
||||
uint8_t* y = (uint8_t*)msg->payload;
|
||||
|
||||
// make sure it has the expected length
|
||||
if (msg->nof_bits != dci_formatN2_sizeof()) {
|
||||
fprintf(stderr, "Invalid message length for format N2\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
data->dci_is_n2 = true;
|
||||
|
||||
// Flag for paging/direct indication differentiation – 1 bit, with value 0 for direct indication and value 1 for
|
||||
// paging
|
||||
data->format = srslte_bit_pack(&y, 1);
|
||||
|
||||
if (data->format == 0) {
|
||||
// Direct Indication information – 8 bits provide direct indication of system information update and other fields
|
||||
data->dir_indication_info = srslte_bit_pack(&y, 8);
|
||||
} else {
|
||||
// Paging
|
||||
|
||||
// Resource assignment – 3 bits
|
||||
data->alloc.i_sf = srslte_bit_pack(&y, 3);
|
||||
|
||||
// Modulation and coding scheme – 4 bits
|
||||
data->mcs_idx = srslte_bit_pack(&y, 4);
|
||||
|
||||
// Repetition number – 4 bits
|
||||
data->alloc.i_rep = srslte_bit_pack(&y, 4);
|
||||
|
||||
// DCI subframe repetition number – 3 bits
|
||||
data->alloc.dci_sf_rep_num = srslte_bit_pack(&y, 3);
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t srslte_dci_nbiot_format_sizeof(const srslte_dci_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case SRSLTE_DCI_FORMATN0:
|
||||
return dci_formatN0_sizeof();
|
||||
case SRSLTE_DCI_FORMATN1:
|
||||
return dci_formatN1_sizeof();
|
||||
case SRSLTE_DCI_FORMATN2:
|
||||
return dci_formatN2_sizeof();
|
||||
default:
|
||||
printf("Error computing DCI bits: Unknown format %d\n", format);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_dci_msg_unpack_npdsch(const srslte_dci_msg_t* msg, srslte_ra_nbiot_dl_dci_t* data, const bool crc_is_crnti)
|
||||
{
|
||||
switch (msg->format) {
|
||||
case SRSLTE_DCI_FORMATN1:
|
||||
return dci_formatN1_unpack(msg, data, crc_is_crnti);
|
||||
case SRSLTE_DCI_FORMATN2:
|
||||
return dci_formatN2_unpack(msg, data);
|
||||
default:
|
||||
fprintf(stderr, "DCI unpack npdsch: Invalid DCI format %s\n", srslte_dci_format_string(msg->format));
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_dci_msg_unpack_npusch(const srslte_dci_msg_t* msg, srslte_ra_nbiot_ul_dci_t* data)
|
||||
{
|
||||
switch (msg->format) {
|
||||
case SRSLTE_DCI_FORMATN0:
|
||||
return dci_formatN0_unpack(msg, data);
|
||||
default:
|
||||
fprintf(stderr, "DCI unpack npusch: Invalid DCI format %s\n", srslte_dci_format_string(msg->format));
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_dci_msg_pack_npdsch(const srslte_ra_nbiot_dl_dci_t* data,
|
||||
const srslte_dci_format_t format,
|
||||
srslte_dci_msg_t* msg,
|
||||
const bool crc_is_crnti)
|
||||
{
|
||||
msg->format = format;
|
||||
switch (format) {
|
||||
case SRSLTE_DCI_FORMATN1:
|
||||
return dci_formatN1_pack(data, msg, crc_is_crnti);
|
||||
default:
|
||||
fprintf(stderr, "DCI pack npdsch: Invalid DCI format %s in \n", srslte_dci_format_string(format));
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,800 @@
|
|||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "prb_dl.h"
|
||||
#include "srslte/phy/common/phy_common.h"
|
||||
#include "srslte/phy/phch/dci_nbiot.h"
|
||||
#include "srslte/phy/phch/npdcch.h"
|
||||
#include "srslte/phy/utils/bit.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
||||
#define DUMP_SIGNALS 0
|
||||
#define RE_EXT_DEBUG 0
|
||||
|
||||
/** Initializes the NPDCCH transmitter and receiver */
|
||||
int srslte_npdcch_init(srslte_npdcch_t* q)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
ret = SRSLTE_ERROR;
|
||||
bzero(q, sizeof(srslte_npdcch_t));
|
||||
q->nof_cce = 2; // One Format1 NPDCCH occupying both NCCEs
|
||||
|
||||
// Allocate memory for the maximum number of NPDCCH bits, i.e. one full PRB
|
||||
q->max_bits = SRSLTE_CP_NORM_SF_NSYMB * SRSLTE_NRE * 2;
|
||||
q->ncce_bits = q->max_bits / 2;
|
||||
|
||||
INFO("Init NPDCCH: Max bits: %d, %d ports.\n", q->max_bits, q->cell.nof_ports);
|
||||
|
||||
if (srslte_modem_table_lte(&q->mod, SRSLTE_MOD_QPSK)) {
|
||||
goto clean;
|
||||
}
|
||||
if (srslte_crc_init(&q->crc, SRSLTE_LTE_CRC16, 16)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
int poly[3] = {0x6D, 0x4F, 0x57};
|
||||
if (srslte_viterbi_init(&q->decoder, SRSLTE_VITERBI_37, poly, SRSLTE_NBIOT_DCI_MAX_SIZE + 16, true)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
q->e = srslte_vec_malloc(sizeof(uint8_t) * q->max_bits);
|
||||
if (!q->e) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
q->llr[i] = srslte_vec_malloc(sizeof(float) * q->max_bits);
|
||||
if (!q->llr[i]) {
|
||||
goto clean;
|
||||
}
|
||||
bzero(q->llr[i], sizeof(float) * q->max_bits);
|
||||
}
|
||||
|
||||
q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->d) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
q->ce[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->ce[i]) {
|
||||
goto clean;
|
||||
}
|
||||
for (uint32_t k = 0; k < q->max_bits / 2; k++) {
|
||||
q->ce[i][k] = 1;
|
||||
}
|
||||
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->x[i]) {
|
||||
goto clean;
|
||||
}
|
||||
q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
|
||||
if (!q->symbols[i]) {
|
||||
goto clean;
|
||||
}
|
||||
memset(q->symbols[i], 0, sizeof(cf_t) * q->max_bits / 2);
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
clean:
|
||||
if (ret == SRSLTE_ERROR) {
|
||||
srslte_npdcch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void srslte_npdcch_free(srslte_npdcch_t* q)
|
||||
{
|
||||
if (q->e) {
|
||||
free(q->e);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
if (q->llr[i]) {
|
||||
free(q->llr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (q->d) {
|
||||
free(q->d);
|
||||
}
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
if (q->x[i]) {
|
||||
free(q->x[i]);
|
||||
}
|
||||
if (q->symbols[i]) {
|
||||
free(q->symbols[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
|
||||
srslte_sequence_free(&q->seq[i]);
|
||||
}
|
||||
|
||||
srslte_modem_table_free(&q->mod);
|
||||
srslte_viterbi_free(&q->decoder);
|
||||
|
||||
bzero(q, sizeof(srslte_npdcch_t));
|
||||
}
|
||||
|
||||
int srslte_npdcch_set_cell(srslte_npdcch_t* q, srslte_nbiot_cell_t cell)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL && srslte_nbiot_cell_isvalid(&cell)) {
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
if (q->cell.n_id_ncell != cell.n_id_ncell || q->cell.base.nof_prb == 0) {
|
||||
q->cell = cell;
|
||||
|
||||
if (q->cell.mode == SRSLTE_NBIOT_MODE_INBAND_SAME_PCI || q->cell.mode == SRSLTE_NBIOT_MODE_INBAND_DIFFERENT_PCI) {
|
||||
q->i_n_start = 3;
|
||||
} else {
|
||||
q->i_n_start = 0;
|
||||
}
|
||||
|
||||
// FIXME: Add case for LTE cell with 4 ports
|
||||
if (q->cell.nof_ports == 1) {
|
||||
q->nof_nbiot_refs = 2;
|
||||
} else {
|
||||
q->nof_nbiot_refs = 4;
|
||||
}
|
||||
|
||||
if (q->cell.base.nof_ports == 1) {
|
||||
q->nof_lte_refs = 2;
|
||||
} else {
|
||||
q->nof_lte_refs = 4;
|
||||
}
|
||||
|
||||
// Update the maximum number of NPDCCH bits, i.e. one PRB minus the starting offset minus the reference symbols
|
||||
q->max_bits = srslte_ra_nbiot_dl_grant_nof_re(q->cell, q->i_n_start) * 2;
|
||||
q->ncce_bits = q->max_bits / 2;
|
||||
|
||||
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
|
||||
if (srslte_sequence_npdcch(&q->seq[i], 2 * i, q->cell.n_id_ncell, q->max_bits)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srslte_npdcch_dci_decode(srslte_npdcch_t* q, float* e, uint8_t* data, uint32_t E, uint32_t nof_bits, uint16_t* crc)
|
||||
{
|
||||
uint16_t p_bits, crc_res;
|
||||
uint8_t* x;
|
||||
|
||||
if (q != NULL) {
|
||||
if (data != NULL && E <= q->max_bits && nof_bits <= SRSLTE_DCI_MAX_BITS) {
|
||||
bzero(q->rm_f, sizeof(float) * 3 * (SRSLTE_DCI_MAX_BITS + 16));
|
||||
|
||||
uint32_t coded_len = 3 * (nof_bits + 16);
|
||||
|
||||
// unrate matching
|
||||
srslte_rm_conv_rx(e, E, q->rm_f, coded_len);
|
||||
|
||||
// viterbi decoder
|
||||
srslte_viterbi_decode_f(&q->decoder, q->rm_f, data, nof_bits + 16);
|
||||
|
||||
x = &data[nof_bits];
|
||||
p_bits = (uint16_t)srslte_bit_pack(&x, 16);
|
||||
crc_res = ((uint16_t)srslte_crc_checksum(&q->crc, data, nof_bits) & 0xffff);
|
||||
|
||||
if (crc) {
|
||||
*crc = p_bits ^ crc_res;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits);
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
} else {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
/** Tries to decode a DCI message from the LLRs stored in the srslte_npdcch_t structure by the function
|
||||
* srslte_npdcch_extract_llr(). This function can be called multiple times.
|
||||
* The decoded message is stored in msg and the CRC remainder in crc_rem pointer
|
||||
*
|
||||
*/
|
||||
int srslte_npdcch_decode_msg(srslte_npdcch_t* q,
|
||||
srslte_dci_msg_t* msg,
|
||||
srslte_dci_location_t* location,
|
||||
srslte_dci_format_t format,
|
||||
uint16_t* crc_rem)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
int num_decoded_symbols = 0;
|
||||
if (q != NULL && msg != NULL && srslte_nbiot_dci_location_isvalid(location)) {
|
||||
uint32_t nof_bits = (format == SRSLTE_DCI_FORMATN2) ? 15 : 23;
|
||||
uint32_t e_bits = q->ncce_bits * location->L;
|
||||
|
||||
// Get the right softbits for this aggregation level
|
||||
float* llr = (location->L == 1) ? q->llr[0] : q->llr[1];
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("LLR:\n");
|
||||
srslte_vec_fprint_f(stdout, llr, q->max_bits);
|
||||
}
|
||||
|
||||
double mean = 0;
|
||||
for (int i = 0; i < e_bits; i++) {
|
||||
mean += fabsf(llr[location->ncce * q->ncce_bits + i]);
|
||||
}
|
||||
mean /= e_bits;
|
||||
if (mean > 0.3) {
|
||||
ret = srslte_npdcch_dci_decode(q, &llr[location->ncce * q->ncce_bits], msg->payload, e_bits, nof_bits, crc_rem);
|
||||
if (ret == SRSLTE_SUCCESS) {
|
||||
num_decoded_symbols = e_bits / 2;
|
||||
msg->nof_bits = nof_bits;
|
||||
// Check format differentiation
|
||||
if (format == SRSLTE_DCI_FORMATN0 || format == SRSLTE_DCI_FORMATN1) {
|
||||
msg->format = (msg->payload[0] == 0) ? SRSLTE_DCI_FORMATN0 : SRSLTE_DCI_FORMATN1;
|
||||
} else {
|
||||
msg->format = format;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error calling npdcch_dci_decode\n");
|
||||
}
|
||||
if (crc_rem) {
|
||||
DEBUG("Decoded DCI: nCCE=%d, L=%d, format=%s, msg_len=%d, mean=%f, crc_rem=0x%x\n",
|
||||
location->ncce,
|
||||
location->L,
|
||||
srslte_dci_format_string(msg->format),
|
||||
nof_bits,
|
||||
mean,
|
||||
*crc_rem);
|
||||
}
|
||||
} else {
|
||||
DEBUG("Skipping DCI: nCCE=%d, L=%d, msg_len=%d, mean=%f\n", location->ncce, location->L, nof_bits, mean);
|
||||
}
|
||||
ret = SRSLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid parameters, location=%d,%d\n", location->ncce, location->L);
|
||||
}
|
||||
|
||||
q->num_decoded_symbols = num_decoded_symbols;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Extracts the LLRs from srslte_dci_location_t location of the subframe and stores them in the srslte_npdcch_t
|
||||
* structure. DCI messages can be extracted from this location calling the function srslte_npdcch_decode_msg(). Every
|
||||
* time this function is called (with a different location), the last demodulated symbols are overwritten and new
|
||||
* messages from other locations can be decoded
|
||||
*/
|
||||
int srslte_npdcch_extract_llr(srslte_npdcch_t* q,
|
||||
cf_t* sf_symbols,
|
||||
cf_t* ce[SRSLTE_MAX_PORTS],
|
||||
float noise_estimate,
|
||||
uint32_t sf_idx)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
/* Set pointers for layermapping & precoding */
|
||||
uint32_t num_symbols, e_bits;
|
||||
float* llr;
|
||||
cf_t* x[SRSLTE_MAX_LAYERS];
|
||||
|
||||
if (q != NULL && sf_idx < 10) {
|
||||
ret = SRSLTE_ERROR;
|
||||
|
||||
for (int i = 0; i < SRSLTE_NPDCCH_FORMAT_NITEMS; i++) {
|
||||
// set parameters according to NPDCCH format
|
||||
switch (i) {
|
||||
case SRSLTE_NPDCCH_FORMAT0_LOWER_HALF:
|
||||
e_bits = q->ncce_bits;
|
||||
llr = q->llr[0];
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT0_UPPER_HALF:
|
||||
e_bits = q->ncce_bits;
|
||||
llr = &q->llr[0][q->ncce_bits];
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT1:
|
||||
e_bits = q->ncce_bits * 2;
|
||||
llr = q->llr[1];
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
num_symbols = e_bits / 2;
|
||||
|
||||
DEBUG("Extracting LLRs for NPDCCH %s: E: %d, SF: %d\n", srslte_npdcch_format_text[i], e_bits, sf_idx);
|
||||
|
||||
if (i != SRSLTE_NPDCCH_FORMAT0_UPPER_HALF) {
|
||||
// don't overwrite lower half LLRs
|
||||
bzero(llr, sizeof(float) * q->max_bits);
|
||||
}
|
||||
|
||||
// number of layers equals number of ports
|
||||
for (int f = 0; f < q->cell.nof_ports; f++) {
|
||||
x[f] = q->x[f];
|
||||
}
|
||||
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
|
||||
|
||||
// extract symbols
|
||||
int n = srslte_npdcch_get(q, sf_symbols, q->symbols[0], i);
|
||||
if (num_symbols != n) {
|
||||
fprintf(stderr, "Expected %d NPDCCH symbols but got %d symbols\n", num_symbols, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_rx_mapping_output.bin: NPDCCH after extracting symbols\n");
|
||||
srslte_vec_save_file("npdcch_rx_mapping_output.bin", q->symbols[0], n * sizeof(cf_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
// extract channel estimates
|
||||
for (int p = 0; p < q->cell.nof_ports; p++) {
|
||||
n = srslte_npdcch_get(q, ce[p], q->ce[p], i);
|
||||
if (num_symbols != n) {
|
||||
fprintf(stderr, "Expected %d NPDCCH symbols but got %d symbols\n", num_symbols, n);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// in control channels, only diversity is supported
|
||||
if (q->cell.nof_ports == 1) {
|
||||
// no need for layer demapping
|
||||
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, NULL, num_symbols, 1.0, noise_estimate);
|
||||
} else {
|
||||
srslte_predecoding_diversity(q->symbols[0], q->ce, x, q->cell.nof_ports, num_symbols, 1.0);
|
||||
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, num_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_rx_predecode_output.bin: NPDCCH after predecoding symbols\n");
|
||||
srslte_vec_save_file("npdcch_rx_predecode_output.bin", q->d, q->num_decoded_symbols * sizeof(cf_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
// demodulate symbols
|
||||
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, llr, num_symbols);
|
||||
|
||||
// descramble
|
||||
srslte_scrambling_f_offset(&q->seq[sf_idx], llr, 0, e_bits);
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_rx_descramble_output.bin: NPDCCH after de-scrambling\n");
|
||||
srslte_vec_save_file("npdcch_rx_descramble_output.bin", llr, e_bits);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void crc_set_mask_rnti(uint8_t* crc, uint16_t rnti)
|
||||
{
|
||||
uint8_t mask[16] = {};
|
||||
uint8_t* r = mask;
|
||||
|
||||
DEBUG("Mask CRC with RNTI 0x%x\n", rnti);
|
||||
|
||||
srslte_bit_unpack(rnti, &r, 16);
|
||||
for (uint32_t i = 0; i < 16; i++) {
|
||||
crc[i] = (crc[i] + mask[i]) % 2;
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_npdcch_dci_encode_conv(srslte_npdcch_t* q,
|
||||
uint8_t* data,
|
||||
uint32_t nof_bits,
|
||||
uint8_t* coded_data,
|
||||
uint16_t rnti)
|
||||
{
|
||||
srslte_convcoder_t encoder;
|
||||
int poly[3] = {0x6D, 0x4F, 0x57};
|
||||
encoder.K = 7;
|
||||
encoder.R = 3;
|
||||
encoder.tail_biting = true;
|
||||
memcpy(encoder.poly, poly, 3 * sizeof(int));
|
||||
|
||||
srslte_crc_attach(&q->crc, data, nof_bits);
|
||||
crc_set_mask_rnti(&data[nof_bits], rnti);
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_tx_convcoder_input.bin: NPDCCH before convolution coding\n");
|
||||
srslte_vec_save_file("npdcch_tx_convcoder_input.bin", data, nof_bits + 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
srslte_convcoder_encode(&encoder, data, coded_data, nof_bits + 16);
|
||||
}
|
||||
|
||||
/** 36.212 5.3.3.2 to 5.3.3.4
|
||||
* TODO: UE transmit antenna selection CRC mask
|
||||
*/
|
||||
int srslte_npdcch_dci_encode(srslte_npdcch_t* q,
|
||||
uint8_t* data,
|
||||
uint8_t* e,
|
||||
uint32_t nof_bits,
|
||||
uint32_t E,
|
||||
uint16_t rnti)
|
||||
{
|
||||
uint8_t tmp[3 * (SRSLTE_DCI_MAX_BITS + 16)];
|
||||
|
||||
if (q != NULL && data != NULL && e != NULL && nof_bits < SRSLTE_DCI_MAX_BITS && E <= q->max_bits) {
|
||||
srslte_npdcch_dci_encode_conv(q, data, nof_bits, tmp, rnti);
|
||||
|
||||
DEBUG("CConv output: ");
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
srslte_vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
|
||||
}
|
||||
|
||||
srslte_rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
} else {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int srslte_npdcch_encode(srslte_npdcch_t* q,
|
||||
srslte_dci_msg_t* msg,
|
||||
srslte_dci_location_t location,
|
||||
uint16_t rnti,
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS],
|
||||
uint32_t nsubframe)
|
||||
{
|
||||
int ret = SRSLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL && sf_symbols != NULL && nsubframe < 10 && srslte_nbiot_dci_location_isvalid(&location)) {
|
||||
ret = SRSLTE_ERROR;
|
||||
uint32_t e_bits = q->nof_cce * q->ncce_bits;
|
||||
uint32_t nof_symbols = e_bits / 2;
|
||||
|
||||
if (msg->nof_bits < SRSLTE_DCI_MAX_BITS - 16) {
|
||||
DEBUG("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x, sf_idx: %d\n",
|
||||
msg->nof_bits,
|
||||
e_bits,
|
||||
location.ncce,
|
||||
location.L,
|
||||
rnti,
|
||||
nsubframe);
|
||||
|
||||
if (srslte_npdcch_dci_encode(q, msg->payload, q->e, msg->nof_bits, e_bits, rnti) != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "Error encoding DCI\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// number of layers equals number of ports
|
||||
cf_t* x[SRSLTE_MAX_LAYERS] = {NULL};
|
||||
for (int i = 0; i < q->cell.nof_ports; i++) {
|
||||
x[i] = q->x[i];
|
||||
}
|
||||
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_tx_scramble_input.bin: NPDCCH before scrambling\n");
|
||||
srslte_vec_save_file("npdcch_tx_scramble_input.bin", q->e, e_bits);
|
||||
}
|
||||
#endif
|
||||
|
||||
srslte_scrambling_b_offset(&q->seq[nsubframe], q->e, 72 * location.ncce, e_bits);
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_tx_mod_input.bin: NPDCCH before modulation\n");
|
||||
srslte_vec_save_file("npdcch_tx_mod_input.bin", q->e, e_bits);
|
||||
}
|
||||
#endif
|
||||
|
||||
srslte_mod_modulate(&q->mod, q->e, q->d, e_bits);
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_tx_precode_input.bin: NPDCCH before precoding symbols\n");
|
||||
srslte_vec_save_file("npdcch_tx_precode_input.bin", q->d, nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
// layer mapping & precoding
|
||||
if (q->cell.nof_ports > 1) {
|
||||
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols);
|
||||
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports, 1.0);
|
||||
} else {
|
||||
memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
|
||||
#if DUMP_SIGNALS
|
||||
if (SRSLTE_VERBOSE_ISDEBUG()) {
|
||||
DEBUG("SAVED FILE npdcch_tx_mapping_input.bin: NPDCCH before mapping to resource elements\n");
|
||||
srslte_vec_save_file("npdcch_tx_mapping_input.bin", q->symbols[0], nof_symbols * sizeof(cf_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
// mapping to resource elements
|
||||
for (int i = 0; i < q->cell.nof_ports; i++) {
|
||||
srslte_npdcch_put(q, q->symbols[i], sf_symbols[i], SRSLTE_NPDCCH_FORMAT1);
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
} else {
|
||||
fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Invalid parameters: L=%d, nCCE=%d\n", location.L, location.ncce);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** 36.213 v9.1.1
|
||||
* Computes up to max_candidates UE-specific candidates for DCI messages and saves them
|
||||
* in the structure pointed by c.
|
||||
* Returns the number of candidates saved in the array c.
|
||||
*/
|
||||
uint32_t srslte_npdcch_ue_locations(srslte_dci_location_t* c, uint32_t max_candidates)
|
||||
{
|
||||
// NPDCCH format 1 takes both NCCE
|
||||
c[0].L = 2;
|
||||
c[0].ncce = 0;
|
||||
|
||||
// NPDCCH format 0 only takes one NCCE so two of them may be transmitted in one subframe
|
||||
c[1].L = 1;
|
||||
c[1].ncce = 0;
|
||||
|
||||
c[2].L = 1;
|
||||
c[2].ncce = 1;
|
||||
|
||||
return max_candidates;
|
||||
}
|
||||
|
||||
uint32_t srslte_npdcch_common_locations(srslte_dci_location_t* c, uint32_t max_candidates)
|
||||
{
|
||||
return srslte_npdcch_ue_locations(c, max_candidates);
|
||||
}
|
||||
|
||||
int srslte_npdcch_cp(srslte_npdcch_t* q, cf_t* input, cf_t* output, bool put, srslte_npdcch_format_t format)
|
||||
{
|
||||
// sanity check
|
||||
if (q == NULL || input == NULL || output == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
#if RE_EXT_DEBUG
|
||||
int num_extracted = 0;
|
||||
#endif
|
||||
|
||||
cf_t *in_ptr = input, *out_ptr = output;
|
||||
bool skip_crs = false;
|
||||
|
||||
if (put) {
|
||||
out_ptr += (q->i_n_start * q->cell.base.nof_prb * SRSLTE_NRE) + q->cell.nbiot_prb * SRSLTE_NRE;
|
||||
} else {
|
||||
in_ptr += (q->i_n_start * q->cell.base.nof_prb * SRSLTE_NRE) + q->cell.nbiot_prb * SRSLTE_NRE;
|
||||
}
|
||||
|
||||
if (q->cell.mode == SRSLTE_NBIOT_MODE_INBAND_SAME_PCI || q->cell.mode == SRSLTE_NBIOT_MODE_INBAND_DIFFERENT_PCI) {
|
||||
skip_crs = true;
|
||||
}
|
||||
|
||||
// start mapping at specified OFDM symbol
|
||||
for (int l = q->i_n_start; l < SRSLTE_CP_NORM_SF_NSYMB; l++) {
|
||||
uint32_t delta = (q->cell.base.nof_prb - 1) * SRSLTE_NRE; // the number of REs skipped in each OFDM symbol
|
||||
uint32_t offset = 0; // the number of REs left out before start of the REF signal RE
|
||||
if (l == 5 || l == 6 || l == 12 || l == 13) {
|
||||
// always skip NRS
|
||||
if (q->nof_nbiot_refs == 2) {
|
||||
if (l == 5 || l == 12) {
|
||||
offset = q->cell.n_id_ncell % 6;
|
||||
delta = q->cell.n_id_ncell % 6 == 5 ? 1 : 0;
|
||||
} else {
|
||||
offset = (q->cell.n_id_ncell + 3) % 6;
|
||||
delta = (q->cell.n_id_ncell + 3) % 6 == 5 ? 1 : 0;
|
||||
}
|
||||
} else if (q->nof_nbiot_refs == 4) {
|
||||
offset = q->cell.n_id_ncell % 3;
|
||||
delta = (q->cell.n_id_ncell + ((q->cell.n_id_ncell >= 5) ? 0 : 3)) % 6 == 5 ? 1 : 0;
|
||||
} else {
|
||||
// FIXME: not handled right now
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case SRSLTE_NPDCCH_FORMAT0_LOWER_HALF:
|
||||
prb_cp_ref(&in_ptr, &out_ptr, offset, q->nof_nbiot_refs, q->nof_nbiot_refs, put);
|
||||
// we have copied too much, rewind ptr
|
||||
if (put) {
|
||||
in_ptr -= (SRSLTE_NRE - q->nof_nbiot_refs) / 2;
|
||||
} else {
|
||||
out_ptr -= (SRSLTE_NRE - q->nof_nbiot_refs) / 2;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT0_UPPER_HALF:
|
||||
// FIXME: this causes valgrind to detect an invalid memory access
|
||||
#if 0
|
||||
// skip lower half
|
||||
if (put) {
|
||||
out_ptr += SRSLTE_NRE / 2;
|
||||
} else {
|
||||
in_ptr += SRSLTE_NRE / 2;
|
||||
}
|
||||
#endif
|
||||
// copy REs
|
||||
prb_cp_ref(&in_ptr, &out_ptr, offset, q->nof_nbiot_refs, q->nof_nbiot_refs, put);
|
||||
// we have copied too much, rewind ptr
|
||||
if (put) {
|
||||
in_ptr -= (SRSLTE_NRE - q->nof_nbiot_refs) / 2;
|
||||
} else {
|
||||
out_ptr -= (SRSLTE_NRE - q->nof_nbiot_refs) / 2;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT1:
|
||||
prb_cp_ref(&in_ptr, &out_ptr, offset, q->nof_nbiot_refs, q->nof_nbiot_refs, put);
|
||||
break;
|
||||
default:
|
||||
printf("Wrong NPDCCH format!\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
} else if ((l == 0 || l == 4 || l == 7 || l == 11) && skip_crs) {
|
||||
// skip LTE's CRS (FIXME: use base cell ID?)
|
||||
if (q->nof_lte_refs == 2) {
|
||||
if (l == 0 || l == 7) {
|
||||
offset = q->cell.base.id % 6;
|
||||
delta = (q->cell.base.id + 3) % 6 == 2 ? 1 : 0;
|
||||
} else if (l == 4 || l == 11) {
|
||||
offset = (q->cell.base.id + 3) % 6;
|
||||
delta = (q->cell.base.id + ((q->cell.base.id <= 5) ? 3 : 0)) % 6 == 5 ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
offset = q->cell.base.id % 3;
|
||||
delta = q->cell.base.id % 3 == 2 ? 1 : 0;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case SRSLTE_NPDCCH_FORMAT0_LOWER_HALF:
|
||||
prb_cp_ref(&in_ptr, &out_ptr, offset, q->nof_lte_refs, q->nof_lte_refs, put);
|
||||
// we have copied too much, rewind ptr
|
||||
if (put) {
|
||||
in_ptr -= (SRSLTE_NRE - q->nof_lte_refs) / 2;
|
||||
} else {
|
||||
out_ptr -= (SRSLTE_NRE - q->nof_lte_refs) / 2;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT0_UPPER_HALF:
|
||||
// skip lower half
|
||||
if (put) {
|
||||
out_ptr += SRSLTE_NRE / 2;
|
||||
} else {
|
||||
in_ptr += SRSLTE_NRE / 2;
|
||||
}
|
||||
// copy REs
|
||||
prb_cp_ref(&in_ptr, &out_ptr, offset, q->nof_lte_refs, q->nof_lte_refs, put);
|
||||
// we have copied too much, rewind ptr
|
||||
if (put) {
|
||||
in_ptr -= (SRSLTE_NRE - q->nof_lte_refs) / 2;
|
||||
} else {
|
||||
out_ptr -= (SRSLTE_NRE - q->nof_lte_refs) / 2;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT1:
|
||||
prb_cp_ref(&in_ptr, &out_ptr, offset, q->nof_lte_refs, q->nof_lte_refs, put);
|
||||
break;
|
||||
default:
|
||||
printf("Wrong NPDCCH format!\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
} else {
|
||||
switch (format) {
|
||||
case SRSLTE_NPDCCH_FORMAT0_LOWER_HALF:
|
||||
prb_cp_half(&in_ptr, &out_ptr, 1);
|
||||
// skip upper half
|
||||
if (put) {
|
||||
out_ptr += SRSLTE_NRE / 2;
|
||||
} else {
|
||||
in_ptr += SRSLTE_NRE / 2;
|
||||
}
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT0_UPPER_HALF:
|
||||
// skip lower half
|
||||
if (put) {
|
||||
out_ptr += SRSLTE_NRE / 2;
|
||||
} else {
|
||||
in_ptr += SRSLTE_NRE / 2;
|
||||
}
|
||||
prb_cp_half(&in_ptr, &out_ptr, 1);
|
||||
break;
|
||||
case SRSLTE_NPDCCH_FORMAT1:
|
||||
// occupy entire symbol
|
||||
prb_cp(&in_ptr, &out_ptr, 1);
|
||||
break;
|
||||
default:
|
||||
printf("Wrong NPDCCH format!\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (put) {
|
||||
out_ptr += delta;
|
||||
} else {
|
||||
in_ptr += delta;
|
||||
}
|
||||
|
||||
#if RE_EXT_DEBUG
|
||||
printf("\nl=%d, delta=%d offset=%d\n", l, delta, offset);
|
||||
uint32_t num_extracted_this_sym = abs((int)(output - out_ptr)) - num_extracted;
|
||||
printf(" - extracted total of %d RE after symbol %d (this symbol=%d)\n",
|
||||
abs((int)(output - out_ptr)),
|
||||
l,
|
||||
num_extracted_this_sym);
|
||||
srslte_vec_fprint_c(stdout, &output[num_extracted], num_extracted_this_sym);
|
||||
num_extracted = abs((int)(output - out_ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
int r;
|
||||
if (put) {
|
||||
r = abs((int)(input - in_ptr));
|
||||
} else {
|
||||
r = abs((int)(output - out_ptr));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts NPDCCH in the subframe
|
||||
*
|
||||
* Returns the number of symbols written to sf_symbols
|
||||
*
|
||||
* 36.211 10.3 section 6.3.5
|
||||
*/
|
||||
int srslte_npdcch_put(srslte_npdcch_t* q, cf_t* symbols, cf_t* sf_symbols, srslte_npdcch_format_t format)
|
||||
{
|
||||
return srslte_npdcch_cp(q, symbols, sf_symbols, true, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts NPDCCH from the subframe
|
||||
*
|
||||
* Returns the number of symbols read
|
||||
*
|
||||
* 36.211 10.3 section 6.3.5
|
||||
*/
|
||||
int srslte_npdcch_get(srslte_npdcch_t* q, cf_t* sf_symbols, cf_t* symbols, srslte_npdcch_format_t format)
|
||||
{
|
||||
return srslte_npdcch_cp(q, sf_symbols, symbols, false, format);
|
||||
}
|
|
@ -265,13 +265,16 @@ bool srslte_ra_nbiot_dl_has_ref_signal_inband(uint32_t tti)
|
|||
return srslte_ra_nbiot_dl_has_ref_signal(tti);
|
||||
}
|
||||
|
||||
/// Valid NB-IoT DL subframes are subframes that DON'T carry:
|
||||
/// - NPBCH (subframe 0)
|
||||
/// - NPSS (subframe 5)
|
||||
/// - NSSS (subframe 9 in all even frames)
|
||||
bool srslte_ra_nbiot_is_valid_dl_sf(uint32_t tti)
|
||||
{
|
||||
return (tti % 10 == 0 || tti % 10 == 5 || (tti % 10 == 9 && (tti / 10 % 2 == 0)));
|
||||
return !(tti % 10 == 0 || tti % 10 == 5 || (tti % 10 == 9 && ((tti / 10) % 2 == 0)));
|
||||
}
|
||||
|
||||
int srslte_ra_nbiot_dl_dci_to_grant(srslte_ra_nbiot_dl_dci_t* dci,
|
||||
uint16_t msg_rnti,
|
||||
srslte_ra_nbiot_dl_grant_t* grant,
|
||||
uint32_t sfn,
|
||||
uint32_t sf_idx,
|
||||
|
|
|
@ -282,6 +282,19 @@ add_test(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_
|
|||
add_test(pdsch_pdcch_file_test pdsch_pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat)
|
||||
add_test(pmch_file_test pmch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/pmch_100prbs_MCS2_SR0.bin)
|
||||
|
||||
########################################################################
|
||||
# NPDCCH TEST
|
||||
########################################################################
|
||||
|
||||
add_executable(npdcch_test npdcch_test.c)
|
||||
target_link_libraries(npdcch_test srslte_phy)
|
||||
add_test(npdcch_formatN1_test npdcch_test -o FormatN1)
|
||||
|
||||
add_executable(npdcch_file_test npdcch_file_test.c)
|
||||
target_link_libraries(npdcch_file_test srslte_phy)
|
||||
add_test(npdcch_formatN0_file_test npdcch_file_test -c 0 -t 8624 -r 258 -L 1 -l 0 -v -o FormatN0 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_nbiot_dci_formatN0_L_1_nid0_tti_8624_rnti_0x102.bin)
|
||||
add_test(npdcch_formatN1_file_test npdcch_file_test -c 0 -t 5461 -r 137 -L 2 -l 0 -v -o FormatN1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_nbiot_dci_formatN1_nid0_tti_5461_rnti_0x89.bin)
|
||||
|
||||
########################################################################
|
||||
# PUSCH TEST
|
||||
########################################################################
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/phy/ch_estimation/chest_dl_nbiot.h"
|
||||
#include "srslte/phy/dft/ofdm.h"
|
||||
#include "srslte/phy/io/filesource.h"
|
||||
#include "srslte/phy/phch/dci_nbiot.h"
|
||||
#include "srslte/phy/phch/npdcch.h"
|
||||
#include "srslte/phy/phch/ra_nbiot.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
char* input_file_name = NULL;
|
||||
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMATN0;
|
||||
uint16_t rnti = 0;
|
||||
uint32_t tti = 0;
|
||||
int nof_frames = 1;
|
||||
srslte_dci_location_t dci_location = {};
|
||||
|
||||
srslte_nbiot_cell_t cell = {.base = {.nof_prb = 1, .nof_ports = 1, .cp = SRSLTE_CP_NORM, .id = 0},
|
||||
.nbiot_prb = 0,
|
||||
.n_id_ncell = 0,
|
||||
.nof_ports = 1,
|
||||
.mode = SRSLTE_NBIOT_MODE_STANDALONE};
|
||||
|
||||
void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [cprndv] -i input_file\n", prog);
|
||||
printf("\t-c cell id [Default %d]\n", cell.base.id);
|
||||
printf("\t-p cell.nof_ports [Default %d]\n", cell.base.nof_ports);
|
||||
printf("\t-o DCI Format [Default %s]\n", srslte_dci_format_string(dci_format));
|
||||
printf("\t-L DCI location L value [Default %d]\n", dci_location.L);
|
||||
printf("\t-l DCI location ncee value [Default %d]\n", dci_location.ncce);
|
||||
printf("\t-r rnti [Default %d]\n", rnti);
|
||||
printf("\t-t tti [Default %d]\n", tti);
|
||||
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, "icplLrontv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'p':
|
||||
cell.base.nof_ports = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'c':
|
||||
cell.base.id = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'l':
|
||||
dci_location.ncce = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'L':
|
||||
dci_location.L = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'r':
|
||||
rnti = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'o':
|
||||
dci_format = srslte_dci_format_from_string(argv[optind]);
|
||||
if (dci_format == SRSLTE_DCI_NOF_FORMATS) {
|
||||
ERROR("Error unsupported format %s\n", argv[optind]);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
tti = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!input_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
cf_t * input_buffer = NULL, *fft_buffer = NULL, *ce[SRSLTE_MAX_PORTS] = {NULL};
|
||||
srslte_filesource_t fsrc;
|
||||
srslte_chest_dl_nbiot_t chest;
|
||||
srslte_ofdm_t fft;
|
||||
srslte_npdcch_t npdcch = {};
|
||||
srslte_dci_msg_t dci_rx = {};
|
||||
int ret = SRSLTE_ERROR;
|
||||
int frame_cnt = 0;
|
||||
int nof_decoded_dcis = 0;
|
||||
int nread = 0;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
// we need to allocate RE's for a full 6 PRB cell
|
||||
int nof_re = 6 * SRSLTE_SF_LEN_RE(cell.base.nof_prb, cell.base.cp);
|
||||
|
||||
// init memory
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
ce[i] = srslte_vec_cf_malloc(nof_re);
|
||||
if (!ce[i]) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
for (int j = 0; j < nof_re; j++) {
|
||||
ce[i][j] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (srslte_filesource_init(&fsrc, input_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) {
|
||||
fprintf(stderr, "Error opening file %s\n", input_file_name);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
uint32_t sf_len = SRSLTE_SF_LEN(srslte_symbol_sz(cell.base.nof_prb));
|
||||
|
||||
input_buffer = srslte_vec_cf_malloc(sf_len);
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
fft_buffer = srslte_vec_cf_malloc(sf_len);
|
||||
if (!fft_buffer) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (srslte_chest_dl_nbiot_init(&chest, SRSLTE_NBIOT_MAX_PRB)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
goto quit;
|
||||
}
|
||||
if (srslte_chest_dl_nbiot_set_cell(&chest, cell) != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "Error setting equalizer cell configuration\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (srslte_ofdm_rx_init(&fft, cell.base.cp, input_buffer, fft_buffer, cell.base.nof_prb)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
goto quit;
|
||||
}
|
||||
srslte_ofdm_set_freq_shift(&fft, SRSLTE_NBIOT_FREQ_SHIFT_FACTOR);
|
||||
|
||||
if (srslte_npdcch_init(&npdcch)) {
|
||||
fprintf(stderr, "Error creating NPDCCH object\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (srslte_npdcch_set_cell(&npdcch, cell)) {
|
||||
fprintf(stderr, "Error configuring NPDCCH object\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
do {
|
||||
nread = srslte_filesource_read(&fsrc, input_buffer, sf_len);
|
||||
|
||||
if (nread == sf_len) {
|
||||
// Run FFT and estimate channel
|
||||
srslte_ofdm_rx_sf(&fft);
|
||||
|
||||
INFO("%d.%d: Estimating channel.\n", frame_cnt, tti % 10);
|
||||
srslte_chest_dl_nbiot_estimate(&chest, fft_buffer, ce, tti % 10);
|
||||
|
||||
// Extract LLR
|
||||
float noise_est = srslte_chest_dl_nbiot_get_noise_estimate(&chest);
|
||||
if (srslte_npdcch_extract_llr(&npdcch, fft_buffer, ce, noise_est, tti % 10)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
uint16_t crc_rem = 0;
|
||||
if (srslte_npdcch_decode_msg(&npdcch, &dci_rx, &dci_location, dci_format, &crc_rem)) {
|
||||
fprintf(stderr, "Error decoding DCI message\n");
|
||||
goto quit;
|
||||
}
|
||||
if (crc_rem != rnti) {
|
||||
printf("Received invalid DCI CRC 0x%x\n", crc_rem);
|
||||
goto quit;
|
||||
} else {
|
||||
if (dci_format == SRSLTE_DCI_FORMATN0) {
|
||||
// process as UL grant
|
||||
srslte_ra_nbiot_ul_dci_t dci_unpacked;
|
||||
srslte_ra_nbiot_ul_grant_t grant;
|
||||
// Creates the UL NPUSCH resource allocation grant from a DCI format N0 message
|
||||
if (srslte_nbiot_dci_msg_to_ul_grant(&dci_rx, &dci_unpacked, &grant, tti, SRSLTE_NPUSCH_SC_SPACING_15000)) {
|
||||
fprintf(stderr, "Error unpacking DCI\n");
|
||||
goto quit;
|
||||
}
|
||||
} else {
|
||||
// process as DL grant
|
||||
srslte_ra_nbiot_dl_dci_t dci_unpacked;
|
||||
srslte_ra_nbiot_dl_grant_t grant;
|
||||
if (srslte_nbiot_dci_msg_to_dl_grant(
|
||||
&dci_rx, rnti, &dci_unpacked, &grant, tti / 10, tti % 10, 64 /* TODO: remove */, cell.mode)) {
|
||||
fprintf(stderr, "Error unpacking DCI\n");
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
nof_decoded_dcis++;
|
||||
}
|
||||
|
||||
tti++;
|
||||
if (tti == 10240) {
|
||||
tti = 0;
|
||||
frame_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
} while (nread > 0 && frame_cnt < nof_frames);
|
||||
|
||||
quit:
|
||||
srslte_npdcch_free(&npdcch);
|
||||
srslte_filesource_free(&fsrc);
|
||||
free(input_buffer);
|
||||
free(fft_buffer);
|
||||
srslte_chest_dl_nbiot_free(&chest);
|
||||
srslte_ofdm_rx_free(&fft);
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
if (ce[i]) {
|
||||
free(ce[i]);
|
||||
}
|
||||
}
|
||||
if (nof_decoded_dcis > 0) {
|
||||
printf("Ok\n");
|
||||
ret = SRSLTE_SUCCESS;
|
||||
} else {
|
||||
printf("Error\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "srslte/phy/phch/dci_nbiot.h"
|
||||
#include "srslte/phy/phch/npdcch.h"
|
||||
#include "srslte/phy/phch/ra_nbiot.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
||||
#define RNTI (0x1234)
|
||||
#define HAVE_OFDM 0
|
||||
|
||||
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMATN0;
|
||||
|
||||
srslte_nbiot_cell_t cell = {.base = {.nof_prb = 1, .nof_ports = 1, .cp = SRSLTE_CP_NORM, .id = 0},
|
||||
.nbiot_prb = 0,
|
||||
.n_id_ncell = 0,
|
||||
.nof_ports = 1,
|
||||
.mode = SRSLTE_NBIOT_MODE_STANDALONE};
|
||||
|
||||
void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [cpndv]\n", prog);
|
||||
printf("\t-c cell id [Default %d]\n", cell.base.id);
|
||||
printf("\t-o DCI Format [Default %s]\n", srslte_dci_format_string(dci_format));
|
||||
printf("\t-p cell.nof_ports [Default %d]\n", cell.base.nof_ports);
|
||||
printf("\t-n cell.nof_prb [Default %d]\n", cell.base.nof_prb);
|
||||
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, "cpnov")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
cell.base.nof_ports = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'n':
|
||||
cell.base.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'c':
|
||||
cell.base.id = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'o':
|
||||
dci_format = srslte_dci_format_from_string(argv[optind]);
|
||||
if (dci_format == SRSLTE_DCI_NOF_FORMATS) {
|
||||
ERROR("Error unsupported format %s\n", argv[optind]);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
srslte_npdcch_t npdcch = {};
|
||||
srslte_dci_msg_t dci_tx = {}, dci_rx = {};
|
||||
srslte_dci_location_t dci_location = {};
|
||||
|
||||
uint32_t tti = 6521;
|
||||
uint16_t rnti = 0x1234;
|
||||
|
||||
cf_t* ce[SRSLTE_MAX_PORTS] = {NULL};
|
||||
cf_t* slot_symbols[SRSLTE_MAX_PORTS] = {NULL};
|
||||
int ret = SRSLTE_ERROR;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
// we need to allocate RE's for a full 6 PRB cell
|
||||
int nof_re = 6 * SRSLTE_SF_LEN_RE(cell.base.nof_prb, cell.base.cp);
|
||||
|
||||
// init memory
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
ce[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!ce[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
for (int j = 0; j < nof_re; j++) {
|
||||
ce[i][j] = 1;
|
||||
}
|
||||
slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
|
||||
if (!slot_symbols[i]) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_OFDM
|
||||
cf_t td_signal[nof_re * 2];
|
||||
#endif
|
||||
|
||||
if (srslte_npdcch_init(&npdcch)) {
|
||||
fprintf(stderr, "Error creating NPDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (srslte_npdcch_set_cell(&npdcch, cell)) {
|
||||
fprintf(stderr, "Error configuring NPDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (dci_format == SRSLTE_DCI_FORMATN0) {
|
||||
// UL grant
|
||||
srslte_ra_nbiot_ul_dci_t dci = {};
|
||||
dci.format = dci_format;
|
||||
|
||||
srslte_ra_nbiot_ul_grant_t grant;
|
||||
if (srslte_ra_nbiot_ul_dci_to_grant(&dci, &grant, tti, SRSLTE_NPUSCH_SC_SPACING_15000)) {
|
||||
fprintf(stderr, "Error converting DCI message\n");
|
||||
}
|
||||
|
||||
fprintf(stderr, "FormatN0 packing not supported\n");
|
||||
return SRSLTE_ERROR;
|
||||
} else if (dci_format == SRSLTE_DCI_FORMATN1) {
|
||||
// DL grant
|
||||
srslte_ra_nbiot_dl_dci_t ra_dl = {};
|
||||
ra_dl.mcs_idx = 5;
|
||||
ra_dl.ndi = 0;
|
||||
ra_dl.rv_idx = 0;
|
||||
|
||||
// NB-IoT specific fields
|
||||
ra_dl.alloc.has_sib1 = false;
|
||||
ra_dl.alloc.is_ra = false;
|
||||
ra_dl.alloc.i_delay = 4;
|
||||
ra_dl.alloc.i_sf = 0;
|
||||
ra_dl.alloc.i_rep = 0;
|
||||
ra_dl.alloc.harq_ack = 1;
|
||||
ra_dl.alloc.i_n_start = 0;
|
||||
srslte_nbiot_dl_dci_fprint(stdout, &ra_dl);
|
||||
|
||||
// pack DCI
|
||||
srslte_dci_msg_pack_npdsch(&ra_dl, dci_format, &dci_tx, false);
|
||||
srslte_dci_location_set(&dci_location, 2, 0);
|
||||
} else {
|
||||
fprintf(stderr, "FormatN2 packing not supported\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_npdcch_encode(&npdcch, &dci_tx, dci_location, RNTI, slot_symbols, 0)) {
|
||||
fprintf(stderr, "Error encoding DCI message\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
// combine outputs
|
||||
for (int i = 1; i < cell.base.nof_ports; i++) {
|
||||
for (int j = 0; j < nof_re; j++) {
|
||||
slot_symbols[0][j] += slot_symbols[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_OFDM
|
||||
srslte_ofdm_t ofdm_tx;
|
||||
srslte_ofdm_t ofdm_rx;
|
||||
|
||||
if (srslte_ofdm_tx_init(&ofdm_tx, SRSLTE_CP_NORM, slot_symbols[0], td_signal, cell.base.nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
exit(-1);
|
||||
}
|
||||
// srslte_ofdm_set_normalize(&ofdm_tx, true);
|
||||
|
||||
if (srslte_ofdm_rx_init(&ofdm_rx, SRSLTE_CP_NORM, td_signal, slot_symbols[0], cell.base.nof_prb)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// transfer into time doamin and back
|
||||
srslte_ofdm_tx_sf(&ofdm_tx);
|
||||
srslte_ofdm_rx_sf(&ofdm_rx);
|
||||
|
||||
srslte_ofdm_tx_free(&ofdm_tx);
|
||||
srslte_ofdm_rx_free(&ofdm_rx);
|
||||
#endif
|
||||
|
||||
if (srslte_npdcch_extract_llr(&npdcch, slot_symbols[0], ce, 0, 0)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
goto quit;
|
||||
}
|
||||
uint16_t crc_rem = 0;
|
||||
if (srslte_npdcch_decode_msg(&npdcch, &dci_rx, &dci_location, dci_format, &crc_rem)) {
|
||||
fprintf(stderr, "Error decoding DCI message\n");
|
||||
goto quit;
|
||||
}
|
||||
if (crc_rem != RNTI) {
|
||||
printf("Received invalid DCI CRC 0x%x\n", crc_rem);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
// compare DCIs
|
||||
if (memcmp(dci_tx.payload, dci_rx.payload, dci_tx.nof_bits)) {
|
||||
printf("Error in DCI: Received data does not match\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (dci_format == SRSLTE_DCI_FORMATN0) {
|
||||
// UL grant
|
||||
// ..
|
||||
} else {
|
||||
// DL grant
|
||||
srslte_ra_nbiot_dl_dci_t dci_unpacked;
|
||||
srslte_ra_nbiot_dl_grant_t grant;
|
||||
if (srslte_nbiot_dci_msg_to_dl_grant(
|
||||
&dci_rx, rnti, &dci_unpacked, &grant, tti / 10, tti % 10, 64 /* fixme: remove */, cell.mode)) {
|
||||
fprintf(stderr, "Error unpacking DCI\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
srslte_nbiot_dl_dci_fprint(stdout, &dci_unpacked);
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
quit:
|
||||
srslte_npdcch_free(&npdcch);
|
||||
|
||||
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
|
||||
if (ce[i]) {
|
||||
free(ce[i]);
|
||||
}
|
||||
if (slot_symbols[i]) {
|
||||
free(slot_symbols[i]);
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
printf("Error\n");
|
||||
} else {
|
||||
printf("Ok\n");
|
||||
}
|
||||
exit(ret);
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "srslte/phy/rf/rf.h"
|
||||
#include "srslte/phy/rf/rf_utils.h"
|
||||
#include "srslte/phy/ue/ue_cell_search_nbiot.h"
|
||||
|
||||
int rf_rssi_scan(srslte_rf_t* rf, float* freqs, float* rssi, int nof_bands, double fs, int nsamp)
|
||||
{
|
||||
|
@ -88,9 +89,9 @@ int srslte_rf_recv_wrapper_cs(void* h, cf_t* data[SRSLTE_MAX_PORTS], uint32_t ns
|
|||
return srslte_rf_recv_with_time_multi(h, ptr, nsamples, 1, NULL, NULL);
|
||||
}
|
||||
|
||||
double srslte_rf_set_rx_gain_th_wrapper(void* h, double f)
|
||||
static SRSLTE_AGC_CALLBACK(srslte_rf_set_rx_gain_wrapper)
|
||||
{
|
||||
return srslte_rf_set_rx_gain_th((srslte_rf_t*)h, f);
|
||||
srslte_rf_set_rx_gain((srslte_rf_t*)h, gain_db);
|
||||
}
|
||||
|
||||
/** This function is simply a wrapper to the ue_cell_search module for rf devices
|
||||
|
@ -264,3 +265,82 @@ int rf_search_and_decode_mib(srslte_rf_t* rf,
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rf_cell_search_nbiot(srslte_rf_t* rf, cell_search_cfg_t* config, srslte_nbiot_cell_t* cell, float* cfo)
|
||||
{
|
||||
int ret = SRSLTE_ERROR;
|
||||
srslte_ue_cellsearch_nbiot_t cs = {};
|
||||
srslte_nbiot_ue_cellsearch_result_t found_cells[3] = {};
|
||||
|
||||
if (srslte_ue_cellsearch_nbiot_init(&cs, config->max_frames_pss, srslte_rf_recv_wrapper_cs, (void*)rf)) {
|
||||
fprintf(stderr, "Error initiating UE cell detect\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (config->nof_valid_pss_frames) {
|
||||
srslte_ue_cellsearch_nbiot_set_nof_valid_frames(&cs, config->nof_valid_pss_frames);
|
||||
}
|
||||
if (config->init_agc > 0) {
|
||||
srslte_ue_sync_nbiot_start_agc(&cs.ue_sync, srslte_rf_set_rx_gain_wrapper, config->init_agc);
|
||||
}
|
||||
|
||||
DEBUG("Setting sampling frequency %.2f MHz for NPSS search\n", SRSLTE_CS_SAMP_FREQ / 1000000);
|
||||
srslte_rf_set_rx_srate(rf, SRSLTE_CS_SAMP_FREQ);
|
||||
|
||||
INFO("Starting receiver...\n");
|
||||
srslte_rf_start_rx_stream(rf, false);
|
||||
|
||||
ret = srslte_ue_cellsearch_nbiot_scan(&cs);
|
||||
if (ret == SRSLTE_ERROR) {
|
||||
fprintf(stderr, "Could not find any cell in this frequency\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
INFO("Stopping receiver...\n");
|
||||
srslte_rf_stop_rx_stream(rf);
|
||||
|
||||
// Find a cell
|
||||
INFO("Running N_id_ncell detection\n");
|
||||
|
||||
uint32_t max_peak_cell = 0;
|
||||
ret = srslte_ue_cellsearch_nbiot_detect(&cs, found_cells);
|
||||
if (ret != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "Could not detect cell ID\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// Only show first cell
|
||||
for (int i = 0; i < 1; i++) {
|
||||
if (i == max_peak_cell) {
|
||||
printf("*");
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("Found n_id_ncell: %3d DetectRatio=%2.0f%% PSR=%.2f, Power=%.1f dBm\n",
|
||||
found_cells[i].n_id_ncell,
|
||||
found_cells[i].mode * 100,
|
||||
found_cells[i].psr,
|
||||
20 * log10(found_cells[i].peak * 1000));
|
||||
}
|
||||
|
||||
// Save result
|
||||
if (cell) {
|
||||
cell->n_id_ncell = found_cells[max_peak_cell].n_id_ncell;
|
||||
}
|
||||
|
||||
// Save CFO
|
||||
if (cfo) {
|
||||
*cfo = found_cells[max_peak_cell].cfo;
|
||||
}
|
||||
|
||||
// Save AGC value for MIB decoding
|
||||
if (config->init_agc > 0) {
|
||||
config->init_agc = srslte_agc_get_gain(&cs.ue_sync.agc);
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
srslte_rf_stop_rx_stream(rf);
|
||||
srslte_ue_cellsearch_nbiot_free(&cs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -130,11 +130,9 @@ int srslte_ue_sync_nbiot_start_agc(srslte_nbiot_ue_sync_t* q,
|
|||
SRSLTE_AGC_CALLBACK(set_gain_callback),
|
||||
float init_gain_value)
|
||||
{
|
||||
uint32_t nframes;
|
||||
uint32_t nframes = 0;
|
||||
if (q->nof_recv_sf == 1) {
|
||||
nframes = 10;
|
||||
} else {
|
||||
nframes = 0;
|
||||
}
|
||||
int n = srslte_agc_init_uhd(&q->agc, SRSLTE_AGC_MODE_PEAK_AMPLITUDE, nframes, set_gain_callback, q->stream);
|
||||
q->do_agc = n == 0 ? true : false;
|
||||
|
|
Loading…
Reference in New Issue