diff --git a/lib/include/srslte/phy/phch/dci_nr.h b/lib/include/srslte/phy/phch/dci_nr.h new file mode 100644 index 000000000..5ccca8e7b --- /dev/null +++ b/lib/include/srslte/phy/phch/dci_nr.h @@ -0,0 +1,87 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_DCI_NR_H +#define SRSLTE_DCI_NR_H + +#include "srslte/phy/common/phy_common_nr.h" +#include "srslte/phy/phch/pdsch_cfg_nr.h" + +typedef enum SRSLTE_API { + srslte_rnti_type_c = 0, + srslte_rnti_type_p, + srslte_rnti_type_si, + srslte_rnti_type_ra, + srslte_rnti_type_tc, +} srslte_rnti_type_t; + +typedef struct SRSLTE_API { + uint8_t payload[32]; + srslte_rnti_type_t rnti_type; + uint32_t nof_bits; + srslte_dci_format_nr_t format; + uint16_t rnti; +} srslte_dci_msg_nr_t; + +typedef struct SRSLTE_API { + srslte_rnti_type_t rnti_type; + + // Common fields + uint32_t freq_domain_assigment; ///< Frequency domain resource assignment + uint32_t time_domain_assigment; ///< Time domain resource assignment + uint32_t vrb_to_prb_mapping; ///< VRB-to-PRB mapping + uint32_t mcs; ///< Modulation and coding scheme + uint32_t rv; ///< Redundancy version + uint32_t reserved; ///< Reserved bits + + // C-RNTI/TC-RNTI specific fields + uint32_t ndi; ///< New data indicator + uint32_t pid; ///< HARQ process number + uint32_t dai; ///< Downlink assignment index + uint32_t tpc; ///< TPC command for scheduled PUCCH + uint32_t pucch_resource; ///< PUCCH resource indicator + uint32_t harq_feedback; ///< PDSCH-to-HARQ_feedback timing indicator + + // P-RNTI specific fields + uint32_t smi; ///< Short Messages Indicator + uint32_t sm; ///< Short Messages + uint32_t tb_scaling; ///< TB scaling + + // SI-RNTI specific fields + uint32_t sii; ///< System information indicator + +} srslte_dci_dl_t; + +SRSLTE_API SRSLTE_API int srslte_dci_nr_format_1_0_sizeof(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_rnti_type_t rnti_type); + +SRSLTE_API int srslte_dci_nr_format_1_0_pack(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + const srslte_dci_dl_t* dci, + srslte_dci_msg_nr_t* msg); + +SRSLTE_API int srslte_dci_nr_format_1_0_unpack(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_dci_msg_nr_t* msg, + srslte_dci_dl_t* dci); + +#endif // SRSLTE_DCI_NR_H diff --git a/lib/src/phy/phch/dci_nr.c b/lib/src/phy/phch/dci_nr.c new file mode 100644 index 000000000..5c929d718 --- /dev/null +++ b/lib/src/phy/phch/dci_nr.c @@ -0,0 +1,362 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srslte/phy/phch/dci_nr.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" + +static int dci_nr_format_1_0_freq_resource_size(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset0, + srslte_rnti_type_t rnti_type) +{ + if (carrier == NULL) { + return SRSLTE_ERROR; + } + + uint32_t N_DL_BWP_RB = carrier->nof_prb; + if (rnti_type == srslte_rnti_type_ra && coreset0 != NULL) { + N_DL_BWP_RB = srslte_coreset_get_bw(coreset0); + } else if (rnti_type == srslte_rnti_type_p || rnti_type == srslte_rnti_type_si) { + if (coreset0 == NULL) { + return SRSLTE_ERROR; + } + N_DL_BWP_RB = srslte_coreset_get_bw(coreset0); + } + + return (int)ceil(log2(N_DL_BWP_RB * (N_DL_BWP_RB + 1) / 2.0)); +} + +int srslte_dci_nr_format_1_0_pack(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + const srslte_dci_dl_t* dci, + srslte_dci_msg_nr_t* msg) +{ + uint8_t* y = msg->payload; + srslte_rnti_type_t rnti_type = msg->rnti_type; + + if (carrier == NULL) { + return SRSLTE_ERROR; + } + + // Identifier for DCI formats – 1 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + *y = 1; + y++; + } + + if (rnti_type == srslte_rnti_type_p) { + // Short Messages Indicator – 2 bits + srslte_bit_unpack(dci->smi, &y, 2); + + // Short Messages – 8 bits + srslte_bit_unpack(dci->sm, &y, 8); + } + + // Frequency domain resource assignment + int N = dci_nr_format_1_0_freq_resource_size(carrier, coreset, rnti_type); + if (N < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + srslte_bit_unpack(dci->freq_domain_assigment, &y, N); + + // Time domain resource assignment – 4 bits + srslte_bit_unpack(dci->time_domain_assigment, &y, 4); + + // VRB-to-PRB mapping – 1 bit + srslte_bit_unpack(dci->vrb_to_prb_mapping, &y, 1); + + // Modulation and coding scheme – 5 bits + srslte_bit_unpack(dci->mcs, &y, 5); + + // TB scaling – 2 bits + if (rnti_type == srslte_rnti_type_p || rnti_type == srslte_rnti_type_ra) { + srslte_bit_unpack(dci->tb_scaling, &y, 2); + } + + // New data indicator – 1 bit + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->ndi, &y, 1); + } + + // Redundancy version – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_si || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->rv, &y, 2); + } + + // HARQ process number – 4 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->pid, &y, 4); + } + + // System information indicator – 1 bit + if (rnti_type == srslte_rnti_type_si) { + srslte_bit_unpack(dci->sii, &y, 1); + } + + // Downlink assignment index – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->dai, &y, 2); + } + + // TPC command for scheduled PUCCH – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->tpc, &y, 2); + } + + // PUCCH resource indicator – 3 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->pucch_resource, &y, 3); + } + + // PDSCH-to-HARQ_feedback timing indicator – 3 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + srslte_bit_unpack(dci->harq_feedback, &y, 3); + } + + // Reserved bits ... + if (rnti_type == srslte_rnti_type_p) { + // ... – 6 bits + srslte_bit_unpack(dci->reserved, &y, 6); + } else if (rnti_type == srslte_rnti_type_si) { + // ... – 15 bits + srslte_bit_unpack(dci->reserved, &y, 15); + } else if (rnti_type == srslte_rnti_type_ra) { + // ... – 16 bits + srslte_bit_unpack(dci->reserved, &y, 16); + } + + msg->nof_bits = srslte_dci_nr_format_1_0_sizeof(carrier, coreset, rnti_type); + if (msg->nof_bits != y - msg->payload) { + ERROR("Unpacked bits readed (%d) do NOT match payload size (%d)\n", msg->nof_bits, (int)(y - msg->payload)); + return SRSLTE_ERROR; + } + + return SRSLTE_ERROR; +} + +int srslte_dci_nr_format_1_0_unpack(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_dci_msg_nr_t* msg, + srslte_dci_dl_t* dci) +{ + uint8_t* y = msg->payload; + srslte_rnti_type_t rnti_type = msg->rnti_type; + + if (msg->nof_bits != srslte_dci_nr_format_1_0_sizeof(carrier, coreset, rnti_type)) { + ERROR("Invalid number of bits %d, expected %d\n", + msg->nof_bits, + srslte_dci_nr_format_1_0_sizeof(carrier, coreset, rnti_type)); + return SRSLTE_ERROR; + } + + // Identifier for DCI formats – 1 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + // The value of this bit field is always set to 1, indicating a DL DCI format + if (*y != 1) { + ERROR("Wrond DCI format\n"); + return SRSLTE_ERROR; + } + y++; + } + + if (rnti_type == srslte_rnti_type_p) { + // Short Messages Indicator – 2 bits + dci->smi = srslte_bit_pack(&y, 2); + + // Short Messages – 8 bits + dci->sm = srslte_bit_pack(&y, 8); + } + + // Frequency domain resource assignment + int N = dci_nr_format_1_0_freq_resource_size(carrier, coreset, rnti_type); + if (N < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + dci->freq_domain_assigment = srslte_bit_pack(&y, N); + + // Time domain resource assignment – 4 bits + dci->time_domain_assigment = srslte_bit_pack(&y, 4); + + // VRB-to-PRB mapping – 1 bit + dci->vrb_to_prb_mapping = srslte_bit_pack(&y, 1); + + // Modulation and coding scheme – 5 bits + dci->mcs = srslte_bit_pack(&y, 5); + + // TB scaling – 2 bits + if (rnti_type == srslte_rnti_type_p || rnti_type == srslte_rnti_type_ra) { + dci->tb_scaling = srslte_bit_pack(&y, 2); + } + + // New data indicator – 1 bit + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + dci->ndi = srslte_bit_pack(&y, 1); + } + + // Redundancy version – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_si || rnti_type == srslte_rnti_type_tc) { + dci->rv = srslte_bit_pack(&y, 2); + } + + // HARQ process number – 4 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + dci->pid = srslte_bit_pack(&y, 4); + } + + // System information indicator – 1 bit + if (rnti_type == srslte_rnti_type_si) { + dci->sii = srslte_bit_pack(&y, 1); + } + + // Downlink assignment index – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + dci->dai = srslte_bit_pack(&y, 2); + } + + // TPC command for scheduled PUCCH – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + dci->tpc = srslte_bit_pack(&y, 2); + } + + // PUCCH resource indicator – 3 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + dci->pucch_resource = srslte_bit_pack(&y, 3); + } + + // PDSCH-to-HARQ_feedback timing indicator – 3 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + dci->harq_feedback = srslte_bit_pack(&y, 3); + } + + // Reserved bits ... + if (rnti_type == srslte_rnti_type_p) { + // ... – 6 bits + dci->reserved = srslte_bit_pack(&y, 6); + } else if (rnti_type == srslte_rnti_type_si) { + // ... – 15 bits + dci->reserved = srslte_bit_pack(&y, 15); + } else if (rnti_type == srslte_rnti_type_ra) { + // ... – 16 bits + dci->reserved = srslte_bit_pack(&y, 16); + } + + if (msg->nof_bits != y - msg->payload) { + ERROR("Unpacked bits readed (%d) do NOT match payload size (%d)\n", msg->nof_bits, (int)(y - msg->payload)); + return SRSLTE_ERROR; + } + + return SRSLTE_ERROR; +} + +int srslte_dci_nr_format_1_0_sizeof(const srslte_carrier_nr_t* carrier, + const srslte_coreset_t* coreset, + srslte_rnti_type_t rnti_type) +{ + uint32_t count = 0; + + // Identifier for DCI formats – 1 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 1; + } + + if (rnti_type == srslte_rnti_type_p) { + // Short Messages Indicator – 2 bits + count += 2; + + // Short Messages – 8 bits + count += 8; + } + + // Frequency domain resource assignment + int N = dci_nr_format_1_0_freq_resource_size(carrier, coreset, rnti_type); + if (N < SRSLTE_SUCCESS) { + return SRSLTE_ERROR; + } + count += N; + + // Time domain resource assignment – 4 bits + count += 4; + + // VRB-to-PRB mapping – 1 bit + count += 1; + + // Modulation and coding scheme – 5 bits + count += 5; + + // TB scaling – 2 bits + if (rnti_type == srslte_rnti_type_p || rnti_type == srslte_rnti_type_ra) { + count += 2; + } + + // New data indicator – 1 bit + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 1; + } + + // Redundancy version – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_si || rnti_type == srslte_rnti_type_tc) { + count += 2; + } + + // HARQ process number – 4 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 4; + } + + // System information indicator – 1 bit + if (rnti_type == srslte_rnti_type_si) { + count += 1; + } + + // Downlink assignment index – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 2; + } + + // TPC command for scheduled PUCCH – 2 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 2; + } + + // PUCCH resource indicator – 3 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 3; + } + + // PDSCH-to-HARQ_feedback timing indicator – 3 bits + if (rnti_type == srslte_rnti_type_c || rnti_type == srslte_rnti_type_tc) { + count += 3; + } + + // Reserved bits ... + if (rnti_type == srslte_rnti_type_p) { + // ... – 6 bits + count += 2; + } else if (rnti_type == srslte_rnti_type_si) { + // ... – 15 bits + count += 15; + } else if (rnti_type == srslte_rnti_type_ra) { + // ... – 16 bits + count += 16; + } + + return count; +} \ No newline at end of file