diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 5db6e44d8d..fdd7435e9b 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -328,6 +328,7 @@ The following features are valid for the gNB and the 5G-NR UE. - HARQ procedures for uplink - Scheduler procedures for SRS reception - Periodic SRS reception + - TPMI computation based on SRS up 4 antenna ports and 1 layer - MAC procedures to handle CSI measurement report - evalution of RSRP report - evaluation of CQI report diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h index e1cfc26336..f14d5220bd 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h @@ -4060,4 +4060,42 @@ int nfapi_p7_update_checksum(uint8_t* buffer, uint32_t len); */ int nfapi_p7_update_transmit_timestamp(uint8_t* buffer, uint32_t timestamp); +/*! \brief Encodes a nfapi_nr_srs_normalized_channel_iq_matrix_t to a buffer + * + * \param pMessageBuf A pointer to a nfapi_nr_srs_normalized_channel_iq_matrix_t structure + * \param pPackedBuf A pointer to the buffer that the nfapi_nr_srs_normalized_channel_iq_matrix_t will be packed into + * \param packedBufLen The size of the buffer + * \return number of bytes written to the buffer + */ +int pack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen); + +/*! \brief Decodes a nfapi_nr_srs_normalized_channel_iq_matrix_t from a buffer + * + * \param pMessageBuf A pointer to an encoded nfapi_nr_srs_normalized_channel_iq_matrix_t + * \param messageBufLen The size of the encoded nfapi_nr_srs_normalized_channel_iq_matrix_t + * \param pUnpackedBuf A pointer to the nfapi_nr_srs_normalized_channel_iq_matrix_t + * \param unpackedBufLen The size of nfapi_nr_srs_normalized_channel_iq_matrix_t structure. + * \return 0 means success, -1 means failure. + */ +int unpack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen); + +/*! \brief Encodes a nfapi_nr_srs_beamforming_report_t to a buffer + * + * \param pMessageBuf A pointer to a nfapi_nr_srs_beamforming_report_t structure + * \param pPackedBuf A pointer to the buffer that the nfapi_nr_srs_beamforming_report_t will be packed into + * \param packedBufLen The size of the buffer + * \return number of bytes written to the buffer + */ +int pack_nr_srs_beamforming_report(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen); + +/*! \brief Decodes a nfapi_nr_srs_beamforming_report_t from a buffer + * + * \param pMessageBuf A pointer to an encoded nfapi_nr_srs_beamforming_report_t + * \param messageBufLen The size of the encoded nfapi_nr_srs_beamforming_report_t + * \param pUnpackedBuf A pointer to the nfapi_nr_srs_beamforming_report_t + * \param unpackedBufLen The size of nfapi_nr_srs_beamforming_report_t structure. + * \return 0 means success, -1 means failure. + */ +int unpack_nr_srs_beamforming_report(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen); + #endif /* _NFAPI_INTERFACE_H_ */ diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 205e107bf9..cf17d6cdd4 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1107,17 +1107,15 @@ typedef struct { typedef struct { nfapi_nr_dig_bf_interface_t* dig_bf_interface_list; - } nfapi_nr_ul_beamforming_number_of_prgs_t; typedef struct { - uint16_t num_prgs; - uint16_t prg_size; - //watchout: dig_bf_interface here, in table 3-43 it's dig_bf_interfaces - uint8_t dig_bf_interface; - nfapi_nr_ul_beamforming_number_of_prgs_t* prgs_list;// - + uint8_t trp_scheme; // This field shall be set to 0, to identify that this table is used. + uint16_t num_prgs; // Number of PRGs spanning this allocation. Value : 1->275 + uint16_t prg_size; // Size in RBs of a precoding resource block group (PRG) – to which the same digital beamforming gets applied. Value: 1->275 + uint8_t dig_bf_interface; // Number of logical antenna ports (parallel streams) resulting from the Rx combining. Value: 0->255 + nfapi_nr_ul_beamforming_number_of_prgs_t *prgs_list; } nfapi_nr_ul_beamforming_t; typedef struct @@ -1292,6 +1290,28 @@ typedef struct } nfapi_nr_pucch_pdu_t; +typedef struct { + uint16_t srs_bandwidth_start; // PRB index for the start of SRS signal transmission. The PRB index is relative to the CRB0 or reference Point A. 3GPP TS 38.211, section 6.4.1.4.3. Value: 0->268 + uint8_t sequence_group; // Sequence group (u) as defined in 3GPP TS 38.211, section 6.4.1.4.2. Value: 0->29 + uint8_t sequence_number; // Sequence number (v) as defined in 3GPP TS 38.211, section 6.4.1.4.2 TS 38.211. Value: 0->1 +} nfapi_v4_srs_parameters_symbols_t; + +typedef struct { + uint16_t srs_bandwidth_size; // mSRS,b: Number of PRB’s that are sounded for each SRS symbol, per 3GPP TS 38.211, section 6.4.1.4.3. Value: 4->272 + nfapi_v4_srs_parameters_symbols_t *symbol_list; + uint32_t usage; // Bitmap indicating the type of report(s) expected at L2 from the SRS signaled by this PDU. Bit positions: 0 – beamManagement; 1 – codebook; 2 – nonCodebook; 3 – antennaSwitching; 4 – 255: reserved. For each of this bit positions: 1 = requested; 0 = not requested. nUsage = sum(all bits in usage) + uint8_t report_type[4]; // Interpretation of each Report Type depends on usage: beamManagement (1 = PRG SNR, 2-255 reserved); codebook (1 = PRG I and Q channel estimate, per srs Tx port and gNB antenna element, 2-255 reserved); nonCodebook (1 = PRG I and Q channel estimate, per SRI and gNB antenna element, 2-255 reserved); antennaSwitching (1 = SVD representation UE Rx and gNB sets of antenna element, 2-255 reserved); all (0 – no report required). + uint8_t singular_Value_representation; // 0 – 8-bit dB; 1 – 16-bit linear; 255 – not applicable + uint8_t iq_representation; // 0 – 16 bit; 1 – 32-bit; 255 - not applicable + uint16_t prg_size; // 1-272; 0 – reserved + uint8_t num_total_ue_antennas; // 1 … 16 in this release. This is the total number of UE antennas for the usage. + uint32_t ue_antennas_in_this_srs_resource_set; // Bitmap of UE antenna indices for the SRS Resource set, to which the SRS Resource for this PDU corresponds. + uint32_t sampled_ue_antennas; // Bitmap of UE antenna indices sampled by the SRS waveform corresponding to this PDU’s SRS Resource. Codebook: corresponds to antenna ports in SRS Resources; non-overlapping indices; Non-codebook: corresponds to SRIs; Antennas-switch: indices of UE Rx antennas in the total number of antennas. + uint8_t report_scope; // Which antennas Report (in ReportType) should account for: Value: 0: ports in sampledUeAntennas (i.e. SRS Resource); 1: ports in ueAntennasInSrsResourceSet (i.e. SRS Resource set. For antSwith reports of SVD type, value 0 is only allowed if sampledUeAntennas = ueAntennasInSrsResourceSet. + uint8_t num_ul_spatial_streams_ports; // In this release, L2 may set this number to 0 to leave spatial stream index assignment to L1 (e.g. L1 uses spatial streams reserved for SRS), regardless of the information in capability maxNumberUlSpatialStreams. + uint8_t Ul_spatial_stream_ports[256]; // Number of ports used for signaling this SRS allocation. Value: 0 --> (max # spatial streams - 1, per TLV) +} nfapi_v4_srs_parameters_t; + typedef struct { uint16_t rnti; // UE RNTI, Value: 1->65535 uint32_t handle; // An opaque handling returned in the SRS.indication @@ -1317,6 +1337,7 @@ typedef struct { uint16_t t_srs; // SRS-Periodicity in slots [3GPP TS 38.211, Sec 6.4.1.4.4], Value: 1,2,3,4,5,8,10,16,20,32,40,64,80,160,320,640,1280,2560 uint16_t t_offset; // Slot offset value [3GPP TS 38.211, Sec 6.4.1.4.3], Value:0->2559 nfapi_nr_ul_beamforming_t beamforming; + nfapi_v4_srs_parameters_t srs_parameters_v4; } nfapi_nr_srs_pdu_t; typedef enum { @@ -1660,33 +1681,63 @@ typedef struct } nfapi_nr_uci_indication_t; -/// 5G PHY FAPI Specification: SRS indication - Section 3.4.10, Table 3-73 +/// 5G PHY FAPI Specification: SRS indication - Section 3.4.10 + +// Normalized channel I/Q matrix typedef struct { - uint8_t rb_snr; // SNR value in dB. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB, 0xff will be set if this field is invalid. -} nfapi_nr_srs_indication_reported_symbol_resource_block_t; + uint8_t normalized_iq_representation; // 0: 16-bit normalized complex number (iqSize = 2); 1: 32-bit normalized complex number (iqSize = 4) + uint16_t num_gnb_antenna_elements; // Ng: Number of gNB antenna elements. Value: 0511 + uint16_t num_ue_srs_ports; // Nu: Number of sampled UE SRS ports. Value: 07 + uint16_t prg_size; // Size in RBs of a precoding resource block group (PRG) – to which the same digital beamforming gets applied. Value: 1->272 + uint16_t num_prgs; // Number of PRGs Np to be reported for this SRS PDU. Value: 0-> 272 + uint8_t channel_matrix[272*512*8*4]; // Array of (numPRGs*Nu*Ng) entries of the type denoted by iqRepresentation H{PRG pI} [ueAntenna uI, gNB antenna gI] = array[uI*Ng*Np + gI*Np + pI]; uI: 0…Nu-1 (UE antenna index); gI: 0…Ng-1 (gNB antenna index); pI: 0…Np-1 (PRG index) +} nfapi_nr_srs_normalized_channel_iq_matrix_t; + +// Beamforming report typedef struct { - uint16_t num_rbs; // Number of PRBs to be reported for this SRS PDU. Value: 0 -> 272. - nfapi_nr_srs_indication_reported_symbol_resource_block_t* rb_list; -} nfapi_nr_srs_indication_reported_symbol_t; + uint8_t rb_snr; // SNR value in dB. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB, 0xff will be set if this field is invalid. +} nfapi_nr_srs_reported_symbol_prgs_t; typedef struct { - uint32_t handle; // The handle passed to the PHY in the the UL_TTI.request SRS PDU. - uint16_t rnti; // The RNTI passed to the PHY in the UL_TTI.request SRS PDU. Value: 1 -> 65535. - uint16_t timing_advance; // Timing advance TA measured for the UE [TS 38.213, Section 4.2]. NTA_new = NTA_old + (TA − 31) * 16 * 64 / (2^u). Value: 0 -> 63. 0xffff should be set if this field is invalid. - uint8_t num_symbols; // Number of symbols for SRS. Value: 1 -> 4. If a PHY does not report for individual symbols then this parameter should be set to 1. - uint8_t wide_band_snr; // SNR value in dB measured within configured SRS bandwidth on each symbol. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB. 0xff will be set if this field is invalid. - uint8_t num_reported_symbols; // Number of symbols reported in this message. This allows PHY to report individual symbols or aggregated symbols where this field will be set to 1. Value: 1 -> 4. - nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list; + uint16_t num_prgs; // Number of PRBs to be reported for this SRS PDU. Value: 0 -> 272. + nfapi_nr_srs_reported_symbol_prgs_t *prg_list; +} nfapi_nr_srs_reported_symbol_t; + +typedef struct { + uint16_t prg_size; // Size in RBs of a precoding resource block group (PRG) – to which the same digital beamforming gets applied. Value: 1->275 + uint8_t num_symbols; // Number of symbols for SRS. Value: 1 -> 4. If a PHY does not report for individual symbols then this parameter should be set to 1. + uint8_t wide_band_snr; // SNR value in dB measured within configured SRS bandwidth on each symbol. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB. 0xff will be set if this field is invalid. + uint8_t num_reported_symbols; // Number of symbols reported in this message. This allows PHY to report individual symbols or aggregated symbols where this field will be set to 1. Value: 1 -> 4. + nfapi_nr_srs_reported_symbol_t *prgs; +} nfapi_nr_srs_beamforming_report_t; + +// SRS indication + +typedef struct { + uint16_t tag; // 0: Report is carried directly in the value field; 3: The offset from the end of the control portion of the message to the beginning of the report. Other values are reserved. + uint32_t length; // Length of the actual report in bytes, without the padding bytes. + uint32_t value[16384]; // tag=0: Only the most significant bytes of the size indicated by ‘length’ field are valid. Remaining bytes are zero padded to the nearest 32-bit bit boundary; Tag=2 Offset from the end of the control portion of the message to the payload is in the value field. Occupies 32-bits. +} nfapi_srs_report_tlv_t; + +typedef struct { + uint32_t handle; // The handle passed to the PHY in the the UL_TTI.request SRS PDU. + uint16_t rnti; // The RNTI passed to the PHY in the UL_TTI.request SRS PDU. Value: 1 -> 65535. + uint16_t timing_advance_offset; // Timing advance TA measured for the UE in multiples of 16 * 64 * Tc / (2^u) [TS 38.213, Section 4.2]. Value: 0 -> 63. 0xffff will be set if this field is invalid. + int16_t timing_advance_offset_nsec; // Timing advance measured for the UE between the reference uplink time and the observed arrival time for the UE. Value: -16800 … +16800 nanoseconds. 0xffff should be set if this field is invalid. + uint8_t srs_usage; // 0 – beamManagement; 1 – codebook; 2 – nonCodebook; 3 – antennaSwitching; 4 – 255: reserved; Note: This field matches the SRS usage field of the SRS PDU to which this report is linked. + uint8_t report_type; // The type of report included in or pointed to by Report TLV depends on the SRS usage: Beam management (1: Beamforming report); Codebook (1: Normalized Channel I/Q Matrix); nonCodebook (1: Normalized Channel I/Q Matrix); antennaSwitch (1: Channel SVD Representation); all (0: null report) + nfapi_srs_report_tlv_t *report_tlv; } nfapi_nr_srs_indication_pdu_t; typedef struct { nfapi_p7_message_header_t header; - uint16_t sfn; // SFN. Value: 0 -> 1023 - uint16_t slot; // Slot. Value: 0 -> 159 - uint8_t number_of_pdus; // Number of PDUs included in this message. Value: 0 -> 255 - nfapi_nr_srs_indication_pdu_t* pdu_list; + uint16_t sfn; // SFN. Value: 0 -> 1023 + uint16_t slot; // Slot. Value: 0 -> 159 + uint16_t control_length; // Size of control portion of SRS indication. 0 if reports are included inline; >0 if reports are concatenated to the end of the message. + uint8_t number_of_pdus; // Number of PDUs included in this message. Value: 0 -> 255 + nfapi_nr_srs_indication_pdu_t *pdu_list; } nfapi_nr_srs_indication_t; diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index 98f89f599c..e183736578 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -3099,42 +3099,131 @@ return 1; //SRS INDICATION -static uint8_t pack_nr_srs_indication_body(nfapi_nr_srs_indication_pdu_t *value, uint8_t **ppWritePackedMsg, uint8_t *end) -{ - if(!(push32(value->handle, ppWritePackedMsg, end) && - push16(value->rnti, ppWritePackedMsg, end) && - push16(value->timing_advance, ppWritePackedMsg, end) && - push8(value->num_symbols, ppWritePackedMsg, end) && - push8(value->wide_band_snr, ppWritePackedMsg, end) && - push8(value->num_reported_symbols, ppWritePackedMsg, end) && - push8(value->reported_symbol_list->num_rbs, ppWritePackedMsg, end) - )) - return 0; - for(int i = 0; i < value->reported_symbol_list->num_rbs; i++) - { - if (!push8(value->reported_symbol_list->rb_list[i].rb_snr, ppWritePackedMsg, end)) - return 0; - } - return 1; +int pack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen) { + + nfapi_nr_srs_normalized_channel_iq_matrix_t *nr_srs_normalized_channel_iq_matrix = (nfapi_nr_srs_normalized_channel_iq_matrix_t*)pMessageBuf; + + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *end = pPackedBuf + packedBufLen; + + if(!(push8(nr_srs_normalized_channel_iq_matrix->normalized_iq_representation, &pWritePackedMessage, end) && + push16(nr_srs_normalized_channel_iq_matrix->num_gnb_antenna_elements, &pWritePackedMessage, end) && + push16(nr_srs_normalized_channel_iq_matrix->num_ue_srs_ports, &pWritePackedMessage, end) && + push16(nr_srs_normalized_channel_iq_matrix->prg_size, &pWritePackedMessage, end) && + push16(nr_srs_normalized_channel_iq_matrix->num_prgs, &pWritePackedMessage, end))) { + return 0; + } + + uint16_t channel_matrix_size = nr_srs_normalized_channel_iq_matrix->num_prgs*nr_srs_normalized_channel_iq_matrix->num_ue_srs_ports*nr_srs_normalized_channel_iq_matrix->num_gnb_antenna_elements; + if (nr_srs_normalized_channel_iq_matrix->normalized_iq_representation == 0) { + channel_matrix_size <<= 1; + } else { + channel_matrix_size <<= 2; + } + + for(int i = 0; i < channel_matrix_size; i++) { + if (!push8(nr_srs_normalized_channel_iq_matrix->channel_matrix[i], &pWritePackedMessage, end)) { + return 0; + } + } + + // Message length + uintptr_t msgHead = (uintptr_t)pPackedBuf; + uintptr_t msgEnd = (uintptr_t)pWritePackedMessage; + return (msgEnd-msgHead); } -static uint8_t pack_nr_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) -{ - nfapi_nr_srs_indication_t *pNfapiMsg = (nfapi_nr_srs_indication_t*)msg; +static uint8_t pack_nr_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *prgs, uint8_t **ppWritePackedMsg, uint8_t *end) { - if (!(push16(pNfapiMsg->sfn , ppWritePackedMsg, end) && - push16(pNfapiMsg->slot , ppWritePackedMsg, end) && - push16(pNfapiMsg->number_of_pdus, ppWritePackedMsg, end) - )) - return 0; + if(!push16(prgs->num_prgs, ppWritePackedMsg, end)) { + return 0; + } - for(int i=0; inumber_of_pdus;i++) - { - if(!pack_nr_srs_indication_body(&(pNfapiMsg->pdu_list[i]),ppWritePackedMsg,end)) - return 0; - } + for(int i = 0; i < prgs->num_prgs; i++) { + if (!push8(prgs->prg_list[i].rb_snr, ppWritePackedMsg, end)) { + return 0; + } + } -return 1; + return 1; +} + +int pack_nr_srs_beamforming_report(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen) { + + nfapi_nr_srs_beamforming_report_t *nr_srs_beamforming_report = (nfapi_nr_srs_beamforming_report_t*)pMessageBuf; + + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *end = pPackedBuf + packedBufLen; + + if(!(push16(nr_srs_beamforming_report->prg_size, &pWritePackedMessage, end) && + push8(nr_srs_beamforming_report->num_symbols, &pWritePackedMessage, end) && + push8(nr_srs_beamforming_report->wide_band_snr, &pWritePackedMessage, end) && + push8(nr_srs_beamforming_report->num_reported_symbols, &pWritePackedMessage, end))) { + return 0; + } + + if(!pack_nr_srs_reported_symbol(nr_srs_beamforming_report->prgs, &pWritePackedMessage, end)) { + return 0; + } + + // Message length + uintptr_t msgHead = (uintptr_t)pPackedBuf; + uintptr_t msgEnd = (uintptr_t)pWritePackedMessage; + return (msgEnd-msgHead); +} + +static uint8_t pack_nr_srs_report_tlv(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppWritePackedMsg, uint8_t *end) { + + if(!(push16(report_tlv->tag, ppWritePackedMsg, end) && + push32(report_tlv->length, ppWritePackedMsg, end))) { + return 0; + } + + for(int i = 0; i < report_tlv->length; i++) { + if (!push32(report_tlv->value[i], ppWritePackedMsg, end)) { + return 0; + } + } + + return 1; +} + +static uint8_t pack_nr_srs_indication_body(nfapi_nr_srs_indication_pdu_t *value, uint8_t **ppWritePackedMsg, uint8_t *end) { + + if(!(push32(value->handle, ppWritePackedMsg, end) && + push16(value->rnti, ppWritePackedMsg, end) && + push16(value->timing_advance_offset, ppWritePackedMsg, end) && + pushs16(value->timing_advance_offset_nsec, ppWritePackedMsg, end) && + push8(value->srs_usage, ppWritePackedMsg, end) && + push8(value->report_type, ppWritePackedMsg, end))) { + return 0; + } + + if(!pack_nr_srs_report_tlv(value->report_tlv,ppWritePackedMsg, end)) { + return 0; + } + + return 1; +} + +static uint8_t pack_nr_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config) { + + nfapi_nr_srs_indication_t *pNfapiMsg = (nfapi_nr_srs_indication_t*)msg; + + if (!(push16(pNfapiMsg->sfn , ppWritePackedMsg, end) && + push16(pNfapiMsg->slot , ppWritePackedMsg, end) && + push16(pNfapiMsg->control_length , ppWritePackedMsg, end) && + push8(pNfapiMsg->number_of_pdus, ppWritePackedMsg, end))) { + return 0; + } + + for(int i=0; inumber_of_pdus;i++) { + if(!pack_nr_srs_indication_body(&(pNfapiMsg->pdu_list[i]),ppWritePackedMsg, end)) { + return 0; + } + } + + return 1; } //RACH INDICATION @@ -5793,40 +5882,133 @@ return 1; //SRS INDICATION -static uint8_t unpack_nr_srs_indication_body(nfapi_nr_srs_indication_pdu_t* value, uint8_t **ppReadPackedMsg, uint8_t *end) -{ - if(!(pull32(ppReadPackedMsg, &value->handle, end) && - pull16(ppReadPackedMsg, &value->rnti, end) && - pull16(ppReadPackedMsg, &value->timing_advance, end) && - pull8(ppReadPackedMsg, &value->num_symbols, end) && - pull8(ppReadPackedMsg, &value->wide_band_snr, end) && - pull8(ppReadPackedMsg, &value->num_reported_symbols, end) && - pull16(ppReadPackedMsg, &value->reported_symbol_list->num_rbs, end) - )) - return 0; - for(int i = 0; i < value->reported_symbol_list->num_rbs; i++) - { - if (!pull8(ppReadPackedMsg, &value->reported_symbol_list->rb_list[i].rb_snr, end)) - return 0; - } - return 1; +int unpack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen) { + + nfapi_nr_srs_normalized_channel_iq_matrix_t *nr_srs_normalized_channel_iq_matrix = (nfapi_nr_srs_normalized_channel_iq_matrix_t*)pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + memset(pUnpackedBuf, 0, unpackedBufLen); + + if(!(pull8(&pReadPackedMessage, &nr_srs_normalized_channel_iq_matrix->normalized_iq_representation, end) && + pull16(&pReadPackedMessage, &nr_srs_normalized_channel_iq_matrix->num_gnb_antenna_elements, end) && + pull16(&pReadPackedMessage, &nr_srs_normalized_channel_iq_matrix->num_ue_srs_ports, end) && + pull16(&pReadPackedMessage, &nr_srs_normalized_channel_iq_matrix->prg_size, end) && + pull16(&pReadPackedMessage, &nr_srs_normalized_channel_iq_matrix->num_prgs, end))) { + return -1; + } + + uint16_t channel_matrix_size = nr_srs_normalized_channel_iq_matrix->num_prgs*nr_srs_normalized_channel_iq_matrix->num_ue_srs_ports*nr_srs_normalized_channel_iq_matrix->num_gnb_antenna_elements; + if (nr_srs_normalized_channel_iq_matrix->normalized_iq_representation == 0) { + channel_matrix_size <<= 1; + } else { + channel_matrix_size <<= 2; + } + + for(int i = 0; i < channel_matrix_size; i++) { + if (!pull8(&pReadPackedMessage, &nr_srs_normalized_channel_iq_matrix->channel_matrix[i], end)) { + return 0; + } + } + + return 0; } -static uint8_t unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_nr_srs_indication_t *pNfapiMsg, nfapi_p7_codec_config_t* config) -{ - if (!(pull16(ppReadPackedMsg,&pNfapiMsg->sfn , end) && - pull16(ppReadPackedMsg,&pNfapiMsg->slot , end) && - pull8(ppReadPackedMsg,&pNfapiMsg->number_of_pdus, end) - )) - return 0; +static uint8_t unpack_nr_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *prgs, uint8_t **ppReadPackedMsg, uint8_t *end) { - for(int i=0; inumber_of_pdus;i++) - { - if (!unpack_nr_srs_indication_body(&pNfapiMsg->pdu_list[i], ppReadPackedMsg, end)) - return 0; - } + if(!pull16(ppReadPackedMsg, &prgs->num_prgs, end)) { + return 0; + } -return 1; + if(!prgs->prg_list) { + prgs->prg_list = (nfapi_nr_srs_reported_symbol_prgs_t*) calloc(1, prgs->num_prgs*sizeof(nfapi_nr_srs_reported_symbol_prgs_t)); + } + + for(int i = 0; i < prgs->num_prgs; i++) { + if (!pull8(ppReadPackedMsg, &prgs->prg_list[i].rb_snr, end)) { + return 0; + } + } + + return 1; +} + +int unpack_nr_srs_beamforming_report(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen) { + + nfapi_nr_srs_beamforming_report_t *nr_srs_beamforming_report = (nfapi_nr_srs_beamforming_report_t*)pUnpackedBuf; + uint8_t *pReadPackedMessage = pMessageBuf; + uint8_t *end = pMessageBuf + messageBufLen; + + memset(pUnpackedBuf, 0, unpackedBufLen); + + if(!(pull16(&pReadPackedMessage, &nr_srs_beamforming_report->prg_size, end) && + pull8(&pReadPackedMessage, &nr_srs_beamforming_report->num_symbols, end) && + pull8(&pReadPackedMessage, &nr_srs_beamforming_report->wide_band_snr, end) && + pull8(&pReadPackedMessage, &nr_srs_beamforming_report->num_reported_symbols, end))) { + return -1; + } + + if(!nr_srs_beamforming_report->prgs) { + nr_srs_beamforming_report->prgs = (nfapi_nr_srs_reported_symbol_t*) calloc(1, sizeof(nfapi_nr_srs_reported_symbol_t)); + } + + if(!unpack_nr_srs_reported_symbol(nr_srs_beamforming_report->prgs, &pReadPackedMessage, end)) { + return -1; + } + + return 0; +} + +static uint8_t unpack_nr_srs_report_tlv(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end) { + + if(!(pull16(ppReadPackedMsg, &report_tlv->tag, end) && + pull32(ppReadPackedMsg, &report_tlv->length, end))) { + return 0; + } + + for(int i = 0; i < report_tlv->length; i++) { + if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) { + return 0; + } + } + + return 1; +} + +static uint8_t unpack_nr_srs_indication_body(nfapi_nr_srs_indication_pdu_t *value, uint8_t **ppReadPackedMsg, uint8_t *end) { + + if(!(pull32(ppReadPackedMsg, &value->handle, end) && + pull16(ppReadPackedMsg, &value->rnti, end) && + pull16(ppReadPackedMsg, &value->timing_advance_offset, end) && + pulls16(ppReadPackedMsg, &value->timing_advance_offset_nsec, end) && + pull8(ppReadPackedMsg, &value->srs_usage, end) && + pull8(ppReadPackedMsg, &value->report_type, end))) { + return 0; + } + + if(!unpack_nr_srs_report_tlv(value->report_tlv, ppReadPackedMsg, end)) { + return 0; + } + + return 1; +} + +static uint8_t unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_nr_srs_indication_t *pNfapiMsg, nfapi_p7_codec_config_t* config) { + + if (!(pull16(ppReadPackedMsg,&pNfapiMsg->sfn, end) && + pull16(ppReadPackedMsg,&pNfapiMsg->slot, end) && + pull16(ppReadPackedMsg,&pNfapiMsg->control_length, end) && + pull8(ppReadPackedMsg,&pNfapiMsg->number_of_pdus, end))) { + return 0; + } + + for(int i=0; inumber_of_pdus; i++) { + if (!unpack_nr_srs_indication_body(&pNfapiMsg->pdu_list[i], ppReadPackedMsg, end)) { + return 0; + } + } + + return 1; } //NR RACH diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 4133875139..fef8583000 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -89,7 +89,7 @@ __attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t * int localOffset1=*offset1; int localOffset2=*offset2; - c32_t cumul={0}; + c32_t cumul={0}; for (int i=0; inrOfLayers == 1; - + for (int aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { c16_t *rxdataF = (c16_t *)&gNB->common_vars.rxdataF[aarx][symbol_offset]; c16_t *ul_ch = &ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; @@ -221,20 +221,20 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, LOG_I(PHY, "In %s bwp_start_subcarrier %d, k0 %d, first_carrier %d, nb_rb_pusch %d\n", __FUNCTION__, bwp_start_subcarrier, k0, gNB->frame_parms.first_carrier_offset, nb_rb_pusch); LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift); #endif - + if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && chest_freq == 0) { - c16_t *pil = pilot; + c16_t *pil = pilot; int re_offset = k0; LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation"); // For configuration type 1: k = 4*n + 2*k' + delta, // where k' is 0 or 1, and delta is in Table 6.4.1.1.3-1 from TS 38.211 int pilot_cnt = 0; int delta = nr_pusch_dmrs_delta(pusch_dmrs_type1, p); - + for (int n = 0; n < 3*nb_rb_pusch; n++) { // LS estimation c32_t ch = {0}; - + for (int k_line = 0; k_line <= 1; k_line++) { re_offset = (k0 + (n << 2) + (k_line << 1) + delta) % symbolSize; ch=c32x16maddShift(*pil, @@ -243,9 +243,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, 15+b_shift); pil++; } - + c16_t ch16= {.r=(int16_t)ch.r, .i=(int16_t)ch.i}; - + // Channel interpolation for (int k_line = 0; k_line <= 1; k_line++) { #ifdef DEBUG_PUSCH @@ -254,7 +254,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, printf("pilot %4u: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d)\n", pilot_cnt, pil->r, pil->i, rxF->r, rxF->i, ch.r, ch.i); #endif - + if (pilot_cnt == 0) { c16multaddVectRealComplex(fl, &ch16, ul_ch, 8); } else if (pilot_cnt == 1) { @@ -270,7 +270,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } else { c16multaddVectRealComplex(fm, &ch16, ul_ch, 8); } - + pilot_cnt++; } } @@ -365,7 +365,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ch_offset++; re_offset = (re_offset + 1)%symbolSize; } - + // Treat last pilot specially (right edge) c16_t ch_l=c16mulShift(*pil, rxdataF[soffset+nushift+re_offset], @@ -381,7 +381,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ul_ch); __m128i *ul_ch_128 = (__m128i *)&ul_ch_estimates[p*gNB->frame_parms.nb_antennas_rx+aarx][ch_offset]; ul_ch_128[0] = _mm_slli_epi16 (ul_ch_128[0], 2); - } + } else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1) { // this is case without frequency-domain linear interpolation, just take average of LS channel estimates of 6 DMRS REs and use a common value for the whole PRB LOG_D(PHY,"PUSCH estimation DMRS type 1, no Freq-domain interpolation\n"); @@ -389,7 +389,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, int pil_offset = 0; int re_offset = k0; c16_t ch; - + // First PRB ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6); @@ -428,20 +428,20 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, } // Last PRB ch=c32x16cumulVectVectWithSteps(pilot, &pil_offset, 1, rxF, &re_offset, 2, symbolSize, 6); - + #if NO_INTERP for (c16_t *end=ul_ch+12; ul_ch>15; // 1/12*16384 ul_ch[3].i += (ch.i * 1365)>>15; // 1/12*16384 - + ul_ch += 4; c16multaddVectRealComplex(filt8_avlip3, ch, ul_ch, 8); - + ul_ch += 8; c16multaddVectRealComplex(filt8_avlip6, ch, @@ -529,19 +529,19 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, ch0=c32x16mulShift(*pil, rxdataF[nushift+re_offset], 15); pil++; re_offset = (re_offset+1) % symbolSize; - + ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15); pil++; re_offset = (re_offset+5) % symbolSize; - + ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15); pil++; re_offset = (re_offset+1) % symbolSize; - + ch0=c32x16maddShift(*pil, rxdataF[nushift+re_offset], ch0, 15); pil++; re_offset = (re_offset+5) % symbolSize; - + ch=c16x32div(ch0, 4); #if NO_INTERP for (c16_t *end=ul_ch+12; ul_chframe_parms.nb_antennas_rx+aarx][ch_offset]; @@ -727,13 +727,9 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, const nr_srs_info_t *nr_srs_info, const int32_t **srs_generated_signal, int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], - int32_t srs_ls_estimated_channel[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], int32_t srs_estimated_channel_freq[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], int32_t srs_estimated_channel_time[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size], int32_t srs_estimated_channel_time_shifted[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - uint32_t *signal_power, - uint32_t *noise_power_per_rb, - uint32_t *noise_power, int8_t *snr_per_rb, int8_t *snr) { @@ -753,11 +749,12 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, fd_cdm = 2; } + c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size*(1<num_symbols)]; + uint32_t noise_power_per_rb[srs_pdu->bwp_size]; int16_t ch_real[frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS]; int16_t ch_imag[frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS]; int16_t noise_real[frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS]; int16_t noise_imag[frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS]; - int16_t ls_estimated[2]; uint8_t mem_offset = ((16 - ((long)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t) @@ -772,7 +769,7 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, for (int p_index = 0; p_index < N_ap; p_index++) { - memset(srs_ls_estimated_channel[ant][p_index], 0, frame_parms->ofdm_symbol_size*(1<num_symbols)*sizeof(int32_t)); + memset(srs_ls_estimated_channel, 0, frame_parms->ofdm_symbol_size*(1<num_symbols)*sizeof(c16_t)); memset(srs_est, 0, (frame_parms->ofdm_symbol_size*(1<num_symbols) + mem_offset)*sizeof(int32_t)); #ifdef SRS_DEBUG @@ -815,7 +812,8 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, } } - srs_ls_estimated_channel[ant][p_index][subcarrier] = ls_estimated[0] + (((int32_t)ls_estimated[1] << 16) & 0xFFFF0000); + srs_ls_estimated_channel[subcarrier].r = ls_estimated[0]; + srs_ls_estimated_channel[subcarrier].i = ls_estimated[1]; #ifdef SRS_DEBUG int subcarrier_log = subcarrier-subcarrier_offset; @@ -828,8 +826,8 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, } LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", subcarrier_log, - (int16_t)(srs_generated_signal[p_index][subcarrier] & 0xFFFF), (int16_t)((srs_generated_signal[p_index][subcarrier] >> 16) & 0xFFFF), - (int16_t)(srs_received_signal[ant][subcarrier] & 0xFFFF), (int16_t)((srs_received_signal[ant][subcarrier] >> 16) & 0xFFFF), + ((c16_t*)srs_generated_signal[p_index])[subcarrier].r, ((c16_t*)srs_generated_signal[p_index])[subcarrier].i, + ((c16_t*)srs_received_signal[ant])[subcarrier].r, ((c16_t*)srs_received_signal[ant])[subcarrier].i, ls_estimated[0], ls_estimated[1]); #endif @@ -896,8 +894,8 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, for (int k = 0; k < M_sc_b_SRS; k++) { ch_real[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r; ch_imag[base_idx+k] = ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i; - noise_real[base_idx+k] = abs(((c16_t*)srs_ls_estimated_channel[ant][p_index])[subcarrier].r - ch_real[base_idx+k]); - noise_imag[base_idx+k] = abs(((c16_t*)srs_ls_estimated_channel[ant][p_index])[subcarrier].i - ch_imag[base_idx+k]); + noise_real[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].r - ch_real[base_idx+k]); + noise_imag[base_idx+k] = abs(srs_ls_estimated_channel[subcarrier].i - ch_imag[base_idx+k]); subcarrier += K_TC; if (subcarrier >= frame_parms->ofdm_symbol_size) { subcarrier=subcarrier-frame_parms->ofdm_symbol_size; @@ -924,10 +922,10 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, LOG_I(NR_PHY,"(%4i) %6i\t%6i | %6i\t%6i | %6i\t%6i\n", subcarrier_log, - (int16_t)(srs_ls_estimated_channel[ant][p_index][subcarrier]&0xFFFF), - (int16_t)((srs_ls_estimated_channel[ant][p_index][subcarrier]>>16)&0xFFFF), - (int16_t)(srs_estimated_channel_freq[ant][p_index][subcarrier]&0xFFFF), - (int16_t)((srs_estimated_channel_freq[ant][p_index][subcarrier]>>16)&0xFFFF), + srs_ls_estimated_channel[subcarrier].r, + srs_ls_estimated_channel[subcarrier].i, + ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].r, + ((c16_t*)srs_estimated_channel_freq[ant][p_index])[subcarrier].i, noise_real[base_idx+(k/K_TC)], noise_imag[base_idx+(k/K_TC)]); // Subcarrier increment @@ -955,21 +953,21 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, } // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) // Compute signal power - *signal_power = calc_power(ch_real,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS) - + calc_power(ch_imag,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS); + uint32_t signal_power = calc_power(ch_real,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS) + + calc_power(ch_imag,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS); #ifdef SRS_DEBUG - LOG_I(NR_PHY,"signal_power = %u\n", *signal_power); + LOG_I(NR_PHY,"signal_power = %u\n", signal_power); #endif - if (*signal_power == 0) { + if (signal_power == 0) { LOG_W(NR_PHY, "Received SRS signal power is 0\n"); return -1; } // Compute noise power - const uint8_t signal_power_bits = log2_approx(*signal_power); + const uint8_t signal_power_bits = log2_approx(signal_power); const uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x) const int32_t factor_dB = dB_fixed(1<nb_antennas_rx*N_ap*M_sc_b_SRS) - + calc_power(noise_imag,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS), 1); + uint32_t noise_power = max(calc_power(noise_real,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS) + + calc_power(noise_imag,frame_parms->nb_antennas_rx*N_ap*M_sc_b_SRS), 1); - *snr = dB_fixed((int32_t)((*signal_power<frame_parms.ofdm_symbol_size*(1<num_symbols)], - int32_t srs_ls_estimated_channel[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], int32_t srs_estimated_channel_freq[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], int32_t srs_estimated_channel_time[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size], int32_t srs_estimated_channel_time_shifted[][1<num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - uint32_t *signal_power, - uint32_t *noise_power_per_rb, - uint32_t *noise_power, int8_t *snr_per_rb, int8_t *snr); #endif diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 6b81575fee..0c2bdd69be 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -53,7 +53,7 @@ #define mulhi_s1_int16(a,b) vshlq_n_s16(vqdmulhq_s16(a,b),1) #define adds_int16(a,b) vqaddq_s16(a,b) #define mullo_int16(a,b) vmulq_s16(a,b) -#define _mm_empty() +#define _mm_empty() #define _m_empty() #endif @@ -74,6 +74,11 @@ extern "C" { float i; } cf_t; + typedef struct complex8 { + int8_t r; + int8_t i; + } c8_t; + typedef struct complex16 { int16_t r; int16_t i; @@ -98,14 +103,14 @@ extern "C" { .i = (int16_t)((a.r * b.i + a.i * b.r) >> Shift) }; } - + __attribute__((always_inline)) inline c16_t c16divShift(const c16_t a, const c16_t b, const int Shift) { return (c16_t) { .r = (int16_t)((a.r * b.r + a.i * b.i) >> Shift), .i = (int16_t)((a.r * b.i - a.i * b.r) >> Shift) }; } - + __attribute__((always_inline)) inline c16_t c16maddShift(const c16_t a, const c16_t b, c16_t c, const int Shift) { return (c16_t) { .r = (int16_t)(((a.r * b.r - a.i * b.i ) >> Shift) + c.r), @@ -136,8 +141,8 @@ extern "C" { // On N complex numbers - // y.r += (x * alpha.r) >> 14 - // y.i += (x * alpha.i) >> 14 + // y.r += (x * alpha.r) >> 14 + // y.i += (x * alpha.i) >> 14 // See regular C implementation at the end __attribute__((always_inline)) inline void c16multaddVectRealComplex(const int16_t *x, const c16_t *alpha, @@ -153,7 +158,7 @@ extern "C" { 10,11,10+16,11+16, 12,13,12+16,13+16, 14,15,14+16,15+16}; - + __m256i alpha256= _mm256_set1_epi32(*(int32_t *)alpha); __m128i *x128=(__m128i *)x; __m128i *y128=(__m128i *)y; @@ -169,11 +174,11 @@ extern "C" { *y128= _mm_adds_epi16(_mm256_extracti128_si256(x_mul_alpha_x2,1),*y128); y128++; x128++; - } - + } + #elif defined(__x86_64__) || defined(__i386__) || defined(__arm__) uint32_t i; - + // do 8 multiplications at a time simd_q15_t alpha_r_128,alpha_i_128,yr,yi,*x_128=(simd_q15_t*)x,*y_128=(simd_q15_t*)y; int j; @@ -199,7 +204,7 @@ extern "C" { y_128[j] = adds_int16(y_128[j],yint.val[0]); j++; y_128[j] = adds_int16(y_128[j],yint.val[1]); - + j++; #endif } @@ -260,7 +265,7 @@ __attribute__((always_inline)) inline void multadd_real_four_symbols_vector_comp _mm_storeu_si128((simd_q15_t*)y, y_128); } - + /*!\fn void multadd_complex_vector_real_scalar(int16_t *x,int16_t alpha,int16_t *y,uint8_t zero_flag,uint32_t N) This function performs componentwise multiplication and accumulation of a real scalar and a complex vector. @param x Vector input (Q1.15) in the format |Re0 Im0|Re1 Im 1| ... diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index 892fb7c864..13306d07d6 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -98,6 +98,7 @@ #define NB_RX_ANTENNAS_MAX 64 +#define TC_NSEC_x32768 16667 typedef enum {TDD=1,FDD=0} frame_type_t; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index d0270ba9a0..2ef231f5f5 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -584,27 +584,77 @@ void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } -int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t *reported_symbol_list, +int fill_srs_reported_symbol_list(nfapi_nr_srs_reported_symbol_t *prgs, const nfapi_nr_srs_pdu_t *srs_pdu, const int N_RB_UL, const int8_t *snr_per_rb, const int srs_est) { - reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; + prgs->num_prgs = srs_pdu->beamforming.num_prgs; - if (!reported_symbol_list->rb_list) { - reported_symbol_list->rb_list = (nfapi_nr_srs_indication_reported_symbol_resource_block_t*) calloc(1, N_RB_UL*sizeof(nfapi_nr_srs_indication_reported_symbol_resource_block_t)); + if (!prgs->prg_list) { + prgs->prg_list = (nfapi_nr_srs_reported_symbol_prgs_t*) calloc(1, N_RB_UL*sizeof(nfapi_nr_srs_reported_symbol_prgs_t)); } - for(int rb = 0; rb < reported_symbol_list->num_rbs; rb++) { + for(int prg_idx = 0; prg_idx < prgs->num_prgs; prg_idx++) { if (srs_est<0) { - reported_symbol_list->rb_list[rb].rb_snr = 0xFF; - } else if (snr_per_rb[rb] < -64) { - reported_symbol_list->rb_list[rb].rb_snr = 0; - } else if (snr_per_rb[rb] > 63) { - reported_symbol_list->rb_list[rb].rb_snr = 0xFE; + prgs->prg_list[prg_idx].rb_snr = 0xFF; + } else if (snr_per_rb[prg_idx] < -64) { + prgs->prg_list[prg_idx].rb_snr = 0; + } else if (snr_per_rb[prg_idx] > 63) { + prgs->prg_list[prg_idx].rb_snr = 0xFE; } else { - reported_symbol_list->rb_list[rb].rb_snr = (snr_per_rb[rb] + 64)<<1; + prgs->prg_list[prg_idx].rb_snr = (snr_per_rb[prg_idx] + 64) << 1; + } + } + + return 0; +} + +int fill_srs_channel_matrix(uint8_t *channel_matrix, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const uint8_t normalized_iq_representation, + const uint16_t num_gnb_antenna_elements, + const uint16_t num_ue_srs_ports, + const uint16_t prg_size, + const uint16_t num_prgs, + const NR_DL_FRAME_PARMS *frame_parms, + const int32_t srs_estimated_channel_freq[][1<num_ant_ports][frame_parms->ofdm_symbol_size*(1<num_symbols)]) { + + const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB; + const uint16_t step = prg_size*NR_NB_SC_PER_RB; + + c16_t *channel_matrix16 = (c16_t*)channel_matrix; + c8_t *channel_matrix8 = (c8_t*)channel_matrix; + + for(int uI = 0; uI < num_ue_srs_ports; uI++) { + for(int gI = 0; gI < num_gnb_antenna_elements; gI++) { + + uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[uI][0]; + if (subcarrier>frame_parms->ofdm_symbol_size) { + subcarrier -= frame_parms->ofdm_symbol_size; + } + + for(int pI = 0; pI < num_prgs; pI++) { + + c16_t *srs_estimated_channel16 = (c16_t *)&srs_estimated_channel_freq[gI][uI][subcarrier]; + uint16_t index = uI*num_gnb_antenna_elements*num_prgs + gI*num_prgs + pI; + + if (normalized_iq_representation == 0) { + channel_matrix8[index].r = (int8_t)(srs_estimated_channel16->r>>8); + channel_matrix8[index].i = (int8_t)(srs_estimated_channel16->i>>8); + } else { + channel_matrix16[index].r = srs_estimated_channel16->r; + channel_matrix16[index].i = srs_estimated_channel16->i; + } + + // Subcarrier increment + subcarrier += step; + if (subcarrier >= frame_parms->ofdm_symbol_size) { + subcarrier=subcarrier-frame_parms->ofdm_symbol_size; + } + } } } @@ -796,29 +846,24 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } } - for (int i=0;isrs[i]; if (srs) { if ((srs->active == 1) && (srs->frame == frame_rx) && (srs->slot == slot_rx)) { - LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; - uint8_t N_symb_SRS = 1<num_symbols; - int32_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; - int32_t srs_ls_estimated_channel[frame_parms->nb_antennas_rx][1<num_ant_ports][frame_parms->ofdm_symbol_size*N_symb_SRS]; - int32_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][1<num_ant_ports][frame_parms->ofdm_symbol_size*N_symb_SRS] __attribute__ ((aligned(32))); - int32_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][1<num_ant_ports][frame_parms->ofdm_symbol_size] __attribute__ ((aligned(32))); - int32_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][1<num_ant_ports][frame_parms->ofdm_symbol_size]; - uint32_t noise_power_per_rb[srs_pdu->bwp_size]; + uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; + int32_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size * N_symb_SRS]; + int32_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); + int32_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + int32_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size]; int8_t snr_per_rb[srs_pdu->bwp_size]; - uint32_t signal_power; - uint32_t noise_power; int8_t snr; // At least currently, the configuration is constant, so it is enough to generate the sequence just once. - if(gNB->nr_srs_info[i]->srs_generated_signal_bits == 0) { + if (gNB->nr_srs_info[i]->srs_generated_signal_bits == 0) { generate_srs_nr(srs_pdu, frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, 0, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } @@ -830,15 +875,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { slot_rx, srs_pdu, gNB->nr_srs_info[i], - (const int32_t **) gNB->nr_srs_info[i]->srs_generated_signal, + (const int32_t **)gNB->nr_srs_info[i]->srs_generated_signal, srs_received_signal, - srs_ls_estimated_channel, srs_estimated_channel_freq, srs_estimated_channel_time, srs_estimated_channel_time_shifted, - &signal_power, - noise_power_per_rb, - &noise_power, snr_per_rb, &snr); } @@ -870,31 +911,143 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { nfapi_nr_srs_indication_pdu_t *srs_indication = &gNB->srs_pdu_list[gNB->UL_INFO.srs_ind.number_of_pdus]; srs_indication->handle = srs_pdu->handle; srs_indication->rnti = srs_pdu->rnti; - srs_indication->timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, srs_estimated_channel_time[0]) : 0xFFFF; - srs_indication->num_symbols = 1 << srs_pdu->num_symbols; - srs_indication->wide_band_snr = srs_est >= 0 ? (snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid - srs_indication->num_reported_symbols = 1 << srs_pdu->num_symbols; - if (!srs_indication->reported_symbol_list) { - srs_indication->reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t *)calloc(1, srs_indication->num_reported_symbols * sizeof(nfapi_nr_srs_indication_reported_symbol_t)); + srs_indication->timing_advance_offset = srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, srs_estimated_channel_time[0]) : 0xFFFF; + srs_indication->timing_advance_offset_nsec = srs_est >= 0 ? (int16_t)((((int32_t)srs_indication->timing_advance_offset - 31) * ((int32_t)TC_NSEC_x32768)) >> 15) : 0xFFFF; + switch (srs_pdu->srs_parameters_v4.usage) { + case 0: + LOG_W(NR_PHY, "SRS report was not requested by MAC\n"); + return 0; + case 1 << NR_SRS_ResourceSet__usage_beamManagement: + srs_indication->srs_usage = NR_SRS_ResourceSet__usage_beamManagement; + break; + case 1 << NR_SRS_ResourceSet__usage_codebook: + srs_indication->srs_usage = NR_SRS_ResourceSet__usage_codebook; + break; + case 1 << NR_SRS_ResourceSet__usage_nonCodebook: + srs_indication->srs_usage = NR_SRS_ResourceSet__usage_nonCodebook; + break; + case 1 << NR_SRS_ResourceSet__usage_antennaSwitching: + srs_indication->srs_usage = NR_SRS_ResourceSet__usage_antennaSwitching; + break; + default: + LOG_E(NR_PHY, "Invalid srs_pdu->srs_parameters_v4.usage %i\n", srs_pdu->srs_parameters_v4.usage); } - fill_srs_reported_symbol_list(&srs_indication->reported_symbol_list[0], srs_pdu, frame_parms->N_RB_UL, snr_per_rb, srs_est); - - gNB->UL_INFO.srs_ind.number_of_pdus += 1; + srs_indication->report_type = srs_pdu->srs_parameters_v4.report_type[0]; #ifdef SRS_IND_DEBUG LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.sfn = %i\n", gNB->UL_INFO.srs_ind.sfn); LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].timing_advance = %i\n", num_srs, gNB->srs_pdu_list[num_srs].timing_advance); - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].wide_band_snr = %i\n", num_srs, gNB->srs_pdu_list[num_srs].wide_band_snr); - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].num_rbs = %i\n", num_srs, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs); - for (int rb = 0; rb < gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs; rb++) { - LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].rb_list[%3i].rb_snr = %i\n", num_srs, rb, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].rb_list[rb].rb_snr); + LOG_I(NR_PHY, "srs_indication->rnti = %04x\n", srs_indication->rnti); + LOG_I(NR_PHY, "srs_indication->timing_advance = %i\n", srs_indication->timing_advance_offset); + LOG_I(NR_PHY, "srs_indication->timing_advance_offset_nsec = %i\n", srs_indication->timing_advance_offset_nsec); + LOG_I(NR_PHY, "srs_indication->srs_usage = %i\n", srs_indication->srs_usage); + LOG_I(NR_PHY, "srs_indication->report_type = %i\n", srs_indication->report_type); +#endif + + if (!srs_indication->report_tlv) { + srs_indication->report_tlv = (nfapi_srs_report_tlv_t *)calloc(1, sizeof(nfapi_srs_report_tlv_t)); + } + srs_indication->report_tlv->tag = 0; + srs_indication->report_tlv->length = 0; + + switch (srs_indication->srs_usage) { + case NR_SRS_ResourceSet__usage_beamManagement: { + nfapi_nr_srs_beamforming_report_t nr_srs_beamforming_report; + nr_srs_beamforming_report.prg_size = srs_pdu->beamforming.prg_size; + nr_srs_beamforming_report.num_symbols = 1 << srs_pdu->num_symbols; + nr_srs_beamforming_report.wide_band_snr = srs_est >= 0 ? (snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid + nr_srs_beamforming_report.num_reported_symbols = 1 << srs_pdu->num_symbols; + nr_srs_beamforming_report.prgs = (nfapi_nr_srs_reported_symbol_t *)calloc(1, nr_srs_beamforming_report.num_reported_symbols * sizeof(nfapi_nr_srs_reported_symbol_t)); + fill_srs_reported_symbol_list(&nr_srs_beamforming_report.prgs[0], srs_pdu, frame_parms->N_RB_UL, snr_per_rb, srs_est); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "nr_srs_beamforming_report.prg_size = %i\n", nr_srs_beamforming_report.prg_size); + LOG_I(NR_PHY, "nr_srs_beamforming_report.num_symbols = %i\n", nr_srs_beamforming_report.num_symbols); + LOG_I(NR_PHY, "nr_srs_beamforming_report.wide_band_snr = %i (%i dB)\n", nr_srs_beamforming_report.wide_band_snr, (nr_srs_beamforming_report.wide_band_snr >> 1) - 64); + LOG_I(NR_PHY, "nr_srs_beamforming_report.num_reported_symbols = %i\n", nr_srs_beamforming_report.num_reported_symbols); + LOG_I(NR_PHY, "nr_srs_beamforming_report.prgs[0].num_prgs = %i\n", nr_srs_beamforming_report.prgs[0].num_prgs); + for (int prg_idx = 0; prg_idx < nr_srs_beamforming_report.prgs[0].num_prgs; prg_idx++) { + LOG_I(NR_PHY, + "nr_srs_beamforming_report.prgs[0].prg_list[%3i].rb_snr = %i (%i dB)\n", + prg_idx, + nr_srs_beamforming_report.prgs[0].prg_list[prg_idx].rb_snr, + (nr_srs_beamforming_report.prgs[0].prg_list[prg_idx].rb_snr >> 1) - 64); + } +#endif + + srs_indication->report_tlv->length = pack_nr_srs_beamforming_report(&nr_srs_beamforming_report, srs_indication->report_tlv->value, 16384 * sizeof(uint32_t)); + break; + } + + case NR_SRS_ResourceSet__usage_codebook: { + nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_normalized_channel_iq_matrix; + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation = srs_pdu->srs_parameters_v4.iq_representation; + nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements = gNB->frame_parms.nb_antennas_rx; + nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports = srs_pdu->srs_parameters_v4.num_total_ue_antennas; + nr_srs_normalized_channel_iq_matrix.prg_size = srs_pdu->srs_parameters_v4.prg_size; + nr_srs_normalized_channel_iq_matrix.num_prgs = srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size; + fill_srs_channel_matrix(nr_srs_normalized_channel_iq_matrix.channel_matrix, + srs_pdu, + gNB->nr_srs_info[i], + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation, + nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements, + nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports, + nr_srs_normalized_channel_iq_matrix.prg_size, + nr_srs_normalized_channel_iq_matrix.num_prgs, + &gNB->frame_parms, + srs_estimated_channel_freq); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "nr_srs_normalized_channel_iq_matrix.normalized_iq_representation = %i\n", nr_srs_normalized_channel_iq_matrix.normalized_iq_representation); + LOG_I(NR_PHY, "nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements = %i\n", nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements); + LOG_I(NR_PHY, "nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports); + LOG_I(NR_PHY, "nr_srs_normalized_channel_iq_matrix.prg_size = %i\n", nr_srs_normalized_channel_iq_matrix.prg_size); + LOG_I(NR_PHY, "nr_srs_normalized_channel_iq_matrix.num_prgs = %i\n", nr_srs_normalized_channel_iq_matrix.num_prgs); + c16_t *channel_matrix16 = (c16_t *)nr_srs_normalized_channel_iq_matrix.channel_matrix; + c8_t *channel_matrix8 = (c8_t *)nr_srs_normalized_channel_iq_matrix.channel_matrix; + for (int uI = 0; uI < nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports; uI++) { + for (int gI = 0; gI < nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements; gI++) { + for (int pI = 0; pI < nr_srs_normalized_channel_iq_matrix.num_prgs; pI++) { + uint16_t index = + uI * nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_normalized_channel_iq_matrix.num_prgs + gI * nr_srs_normalized_channel_iq_matrix.num_prgs + pI; + LOG_I(NR_PHY, + "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n", + uI, + gI, + pI, + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r, + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i : channel_matrix16[index].i); + } + } + } +#endif + + srs_indication->report_tlv->length = pack_nr_srs_normalized_channel_iq_matrix(&nr_srs_normalized_channel_iq_matrix, + srs_indication->report_tlv->value, + 16384 * sizeof(uint32_t)); + + break; + } + + case NR_SRS_ResourceSet__usage_nonCodebook: + case NR_SRS_ResourceSet__usage_antennaSwitching: + LOG_W(NR_PHY, "PHY procedures for this SRS usage are not implemented yet!\n"); + break; + + default: + AssertFatal(1 == 0, "Invalid SRS usage\n"); + } + +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "srs_indication->report_tlv->tag = %i\n", srs_indication->report_tlv->tag); + LOG_I(NR_PHY, "srs_indication->report_tlv->length = %i\n", srs_indication->report_tlv->length); + char *value = (char *)srs_indication->report_tlv->value; + for (int b = 0; b < srs_indication->report_tlv->length; b++) { + LOG_I(NR_PHY, "value[%i] = 0x%02x\n", b, value[b] & 0xFF); } #endif + gNB->UL_INFO.srs_ind.number_of_pdus += 1; srs->active = 0; } } diff --git a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c index 75e3d998ff..ca9cf61115 100644 --- a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c +++ b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c @@ -5,25 +5,73 @@ int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) { re int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req) { return(0); } int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) { return(0); } //int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) { return(0); } -int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) { return(0); } -int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req){ return(0); } -int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req){ return(0); } -int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req){ return(0); } -int oai_nfapi_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind) { return(0); } -int oai_nfapi_nr_crc_indication(nfapi_nr_crc_indication_t *ind) { return(0); } -int oai_nfapi_nr_srs_indication(nfapi_nr_srs_indication_t *ind) { return(0); } -int oai_nfapi_nr_uci_indication(nfapi_nr_uci_indication_t *ind) { return(0); } -int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind) { return(0); } +int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) +{ + return (0); +} +int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req) +{ + return (0); +} +int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) +{ + return (0); +} +int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) +{ + return (0); +} +int oai_nfapi_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind) +{ + return (0); +} +int oai_nfapi_nr_crc_indication(nfapi_nr_crc_indication_t *ind) +{ + return (0); +} +int oai_nfapi_nr_srs_indication(nfapi_nr_srs_indication_t *ind) +{ + return (0); +} +int oai_nfapi_nr_uci_indication(nfapi_nr_uci_indication_t *ind) +{ + return (0); +} +int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind) +{ + return (0); +} -int32_t get_uldl_offset(int nr_bandP) { return(0); } -NR_IF_Module_t *NR_IF_Module_init(int Mod_id) {return(NULL);} +int pack_nr_srs_beamforming_report(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen) +{ + return 0; +} +int pack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen) +{ + return 0; +} + +int32_t get_uldl_offset(int nr_bandP) +{ + return (0); +} +NR_IF_Module_t *NR_IF_Module_init(int Mod_id) +{ + return (NULL); +} nfapi_mode_t nfapi_mod; -nfapi_mode_t nfapi_getmode(void) { +nfapi_mode_t nfapi_getmode(void) +{ return nfapi_mod; } -void nfapi_setmode(nfapi_mode_t nfapi_mode) {} +void nfapi_setmode(nfapi_mode_t nfapi_mode) +{ +} -int dummy_nr_ue_dl_indication(nr_downlink_indication_t *dl_info) { return(0); } +int dummy_nr_ue_dl_indication(nr_downlink_indication_t *dl_info) +{ + return (0); +} int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } void nr_fill_dl_indication(nr_downlink_indication_t *dl_ind, fapi_nr_dci_indication_t *dci_ind, diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 01c1d39de9..ef9e6360b6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -540,5 +540,29 @@ typedef struct nr_csi_report { int N2; } nr_csi_report_t; +typedef enum { + NR_SRS_SRI_0 = 0, + NR_SRS_SRI_1, + NR_SRS_SRI_2, + NR_SRS_SRI_3, + NR_SRS_SRI_0_1, + NR_SRS_SRI_0_2, + NR_SRS_SRI_0_3, + NR_SRS_SRI_1_2, + NR_SRS_SRI_1_3, + NR_SRS_SRI_2_3, + NR_SRS_SRI_0_1_2, + NR_SRS_SRI_0_1_3, + NR_SRS_SRI_0_2_3, + NR_SRS_SRI_1_2_3, + NR_SRS_SRI_0_1_2_3 +} nr_srs_sri_t; + +typedef struct nr_srs_feedback { + uint8_t sri; + uint8_t ul_ri; + uint8_t tpmi; +} nr_srs_feedback_t; + #endif /*__LAYER2_MAC_H__ */ diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 7275a0a4e5..94bb084f89 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -312,6 +312,80 @@ const uint8_t table_5_1_2_1_1_5_time_dom_res_alloc_C_dmrs_typeA_pos3[16][4]={ {1,0,2,6} // row index 16 }; +// TS 38.211 - Table 6.3.1.5-1: Precoding matrix W for single-layer transmission using two antenna ports, 'n' = -1 and 'o' = -j +const char table_38211_6_3_1_5_1[6][2][1] = { + {{'1'}, {'0'}}, // tpmi 0 + {{'0'}, {'1'}}, // tpmi 1 + {{'1'}, {'1'}}, // tpmi 2 + {{'1'}, {'n'}}, // tpmi 3 + {{'1'}, {'j'}}, // tpmi 4 + {{'1'}, {'o'}} // tpmi 5 +}; + +// TS 38.211 - Table 6.3.1.5-2: Precoding matrix W for single-layer transmission using four antenna ports with transform precoding enabled, 'n' = -1 and 'o' = -j +const char table_38211_6_3_1_5_2[28][4][1] = { + {{'1'}, {'0'}, {'0'}, {'0'}}, // tpmi 0 + {{'0'}, {'1'}, {'0'}, {'0'}}, // tpmi 1 + {{'0'}, {'0'}, {'1'}, {'0'}}, // tpmi 2 + {{'0'}, {'0'}, {'0'}, {'1'}}, // tpmi 3 + {{'1'}, {'0'}, {'1'}, {'0'}}, // tpmi 4 + {{'1'}, {'0'}, {'n'}, {'0'}}, // tpmi 5 + {{'1'}, {'0'}, {'j'}, {'0'}}, // tpmi 6 + {{'1'}, {'0'}, {'o'}, {'0'}}, // tpmi 7 + {{'0'}, {'1'}, {'0'}, {'1'}}, // tpmi 8 + {{'0'}, {'1'}, {'0'}, {'n'}}, // tpmi 9 + {{'0'}, {'1'}, {'0'}, {'j'}}, // tpmi 10 + {{'0'}, {'1'}, {'0'}, {'o'}}, // tpmi 11 + {{'1'}, {'1'}, {'1'}, {'n'}}, // tpmi 12 + {{'1'}, {'1'}, {'j'}, {'j'}}, // tpmi 13 + {{'1'}, {'1'}, {'n'}, {'1'}}, // tpmi 14 + {{'1'}, {'1'}, {'o'}, {'o'}}, // tpmi 15 + {{'1'}, {'j'}, {'1'}, {'j'}}, // tpmi 16 + {{'1'}, {'j'}, {'j'}, {'1'}}, // tpmi 17 + {{'1'}, {'j'}, {'n'}, {'o'}}, // tpmi 18 + {{'1'}, {'j'}, {'o'}, {'n'}}, // tpmi 19 + {{'1'}, {'n'}, {'1'}, {'1'}}, // tpmi 20 + {{'1'}, {'n'}, {'j'}, {'o'}}, // tpmi 21 + {{'1'}, {'n'}, {'n'}, {'n'}}, // tpmi 22 + {{'1'}, {'n'}, {'o'}, {'j'}}, // tpmi 23 + {{'1'}, {'o'}, {'1'}, {'o'}}, // tpmi 24 + {{'1'}, {'o'}, {'j'}, {'n'}}, // tpmi 25 + {{'1'}, {'o'}, {'n'}, {'j'}}, // tpmi 26 + {{'1'}, {'o'}, {'o'}, {'1'}} // tpmi 27 +}; + +// TS 38.211 - Table 6.3.1.5-3: Precoding matrix W for single-layer transmission using four antenna ports with transform precoding disabled, 'n' = -1 and 'o' = -j +const char table_38211_6_3_1_5_3[28][4][1] = { + {{'1'}, {'0'}, {'0'}, {'0'}}, // tpmi 0 + {{'0'}, {'1'}, {'0'}, {'0'}}, // tpmi 1 + {{'0'}, {'0'}, {'1'}, {'0'}}, // tpmi 2 + {{'0'}, {'0'}, {'0'}, {'1'}}, // tpmi 3 + {{'1'}, {'0'}, {'1'}, {'0'}}, // tpmi 4 + {{'1'}, {'0'}, {'n'}, {'0'}}, // tpmi 5 + {{'1'}, {'0'}, {'j'}, {'0'}}, // tpmi 6 + {{'1'}, {'0'}, {'o'}, {'0'}}, // tpmi 7 + {{'0'}, {'1'}, {'0'}, {'1'}}, // tpmi 8 + {{'0'}, {'1'}, {'0'}, {'n'}}, // tpmi 9 + {{'0'}, {'1'}, {'0'}, {'j'}}, // tpmi 10 + {{'0'}, {'1'}, {'0'}, {'o'}}, // tpmi 11 + {{'1'}, {'1'}, {'1'}, {'1'}}, // tpmi 12 + {{'1'}, {'1'}, {'j'}, {'j'}}, // tpmi 13 + {{'1'}, {'1'}, {'n'}, {'n'}}, // tpmi 14 + {{'1'}, {'1'}, {'o'}, {'o'}}, // tpmi 15 + {{'1'}, {'j'}, {'1'}, {'j'}}, // tpmi 16 + {{'1'}, {'j'}, {'j'}, {'n'}}, // tpmi 17 + {{'1'}, {'j'}, {'n'}, {'o'}}, // tpmi 18 + {{'1'}, {'j'}, {'o'}, {'1'}}, // tpmi 19 + {{'1'}, {'n'}, {'1'}, {'n'}}, // tpmi 20 + {{'1'}, {'n'}, {'j'}, {'o'}}, // tpmi 21 + {{'1'}, {'n'}, {'n'}, {'1'}}, // tpmi 22 + {{'1'}, {'n'}, {'o'}, {'j'}}, // tpmi 23 + {{'1'}, {'o'}, {'1'}, {'o'}}, // tpmi 24 + {{'1'}, {'o'}, {'j'}, {'1'}}, // tpmi 25 + {{'1'}, {'o'}, {'n'}, {'j'}}, // tpmi 26 + {{'1'}, {'o'}, {'o'}, {'n'}} // tpmi 27 +}; + void get_info_from_tda_tables(int default_abc, int tda, int dmrs_TypeA_Position, @@ -1956,6 +2030,46 @@ int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l [12][8] = { {0, 3072, -1, -1, 3, 1539, -1, -1}, //14 // (DMRS l' position) }; +// TS 38.212 +uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; +uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55}; +uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59}; +uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61}; +uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25}; +uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32}; +uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33}; +uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35}; +uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22}; +uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29}; +uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15}; +uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6}; +uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8}; +uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3}; +uint16_t table_7_3_1_1_2_28[3][15] = { + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; +uint16_t table_7_3_1_1_2_29[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0}, +}; +uint16_t table_7_3_1_1_2_30[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0}, +}; +uint16_t table_7_3_1_1_2_31[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, +}; +uint16_t table_7_3_1_1_2_32[3][15] = { + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; void get_delta_arfcn(int i, uint32_t nrarfcn, uint64_t N_OFFs){ @@ -2599,13 +2713,18 @@ uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config, n_antenna_port = *pusch_Config->maxRank; } else { - if(srs_config != NULL && srs_resource_indicator.nbits > 0) { + uint8_t sri = srs_resource_indicator.nbits > 0 ? srs_resource_indicator.val : 0; + if(srs_config != NULL) { for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; - if(srs_resource_set->usage == NR_SRS_ResourceSet__usage_codebook) { - NR_SRS_Resource_t *srs_resource = srs_config->srs_ResourceToAddModList->list.array[srs_resource_indicator.val]; - AssertFatal(srs_resource != NULL,"SRS resource indicated by DCI does not exist\n"); - n_antenna_port = 1<nrofSRS_Ports; + // When multiple SRS resources are configured by SRS-ResourceSet with usage set to 'codebook', + // the UE shall expect that higher layer parameters nrofSRS-Ports in SRS-Resource in SRS-ResourceSet + // shall be configured with the same value for all these SRS resources. + if (srs_resource_set->usage == NR_SRS_ResourceSet__usage_codebook) { + NR_SRS_Resource_t *srs_resource = srs_config->srs_ResourceToAddModList->list.array[sri]; + AssertFatal(srs_resource != NULL, "SRS resource indicated by DCI does not exist\n"); + n_antenna_port = 1 << srs_resource->nrofSRS_Ports; + break; } } } @@ -2613,6 +2732,372 @@ uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config, return n_antenna_port; } +// #define DEBUG_SRS_RESOURCE_IND +uint8_t compute_srs_resource_indicator(NR_PUSCH_ServingCellConfig_t *pusch_servingcellconfig, + NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + nr_srs_feedback_t *srs_feedback, + uint16_t *val) +{ + uint8_t nbits = 0; + + // SRI occupies a number of bits which is dependent upon the uplink transmission scheme, and it is used to determine + // the antenna ports and uplink transmission beam to use for PUSCH transmission. In the case of codebook based + // transmission, the SRI is used to select between SRS Resources belonging to different antenna panels + // (kind of directional antenna). There can be up to 2 SRS Resources (2 antenna panels). In the case of non-codebook + // based transmission, the SRI is used to select one or more SRS Resources from a set of N_SRS resources. The number + // of SRS Resources selected corresponds to the number of layers (rank) to be transmitted. + if (val) { + *val = 0; + } + + if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) { + + if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) { + +#ifdef DEBUG_SRS_RESOURCE_IND + LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_codebook\n"); +#endif + + // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to + // Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook, + // where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer + // parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook. + int count = 0; + for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) { + if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) { + count++; + } + } + if (count>0) { + nbits = ceil(log2(count)); + if (val && srs_feedback && nbits > 0) { + *val = table_7_3_1_1_2_32[count-2][srs_feedback->sri]; + } + } + +#ifdef DEBUG_SRS_RESOURCE_IND + LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count); + LOG_I(NR_MAC, "count = %i\n", count); +#endif + + } else { + +#ifdef DEBUG_SRS_RESOURCE_IND + LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_nonCodebook\n"); +#endif + + // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k)))) + // bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where + // N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter + // srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value nonCodeBook and: + // + // - if UE supports operation with maxMIMO-Layers and the higher layer parameter maxMIMO-Layers of + // PUSCH-ServingCellConfig of the serving cell is configured, Lmax is given by that parameter; + // + // - otherwise, Lmax is given by the maximum number of layers for PUSCH supported by the UE for the serving cell + // for non-codebook based operation. + int Lmax = 0; + if (pusch_servingcellconfig != NULL) { + if (pusch_servingcellconfig->ext1->maxMIMO_Layers != NULL) { + Lmax = *pusch_servingcellconfig->ext1->maxMIMO_Layers; + } else { + AssertFatal(1 == 0, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); + } + } else { + AssertFatal(1 == 0, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); + } + int lmin = 0; + int lsum = 0; + int count = 0; + for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { + if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) { + count++; + } + } + lmin = count < Lmax ? count : Lmax; + for (int k=1;k<=lmin;k++) { + lsum += binomial(count,k); + } + if (lsum>0) { + nbits = ceil(log2(lsum)); + if (val && srs_feedback && nbits > 0) { + switch(Lmax) { + case 1: + *val = table_7_3_1_1_2_28[count-2][srs_feedback->sri]; + break; + case 2: + *val = table_7_3_1_1_2_29[count-2][srs_feedback->sri]; + break; + case 3: + *val = table_7_3_1_1_2_30[count-2][srs_feedback->sri]; + break; + case 4: + *val = table_7_3_1_1_2_31[count-2][srs_feedback->sri]; + break; + default: + LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax); + } + } + } + +#ifdef DEBUG_SRS_RESOURCE_IND + LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count); + LOG_I(NR_MAC, "count = %i\n", count); + LOG_I(NR_MAC, "Lmax = %i\n", Lmax); + LOG_I(NR_MAC, "lsum = %i\n", lsum); +#endif + + } + } + + return nbits; +} + +uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator, + nr_srs_feedback_t *srs_feedback, + const uint8_t *nrOfLayers, + uint16_t *val) { + + // It is only applicable to codebook based transmission. This field occupies 0 bits for non-codebook based + // transmission. It also occupies 0 bits for codebook based transmission using a single antenna port. + uint8_t nbits = 0; + if (val) { + *val = 0; + } + + uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator); + if ((pusch_Config && pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook) || + pusch_antenna_ports == 1) { + return nbits; + } + + long max_rank = *pusch_Config->maxRank; + long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL; + long *codebookSubset = pusch_Config->codebookSubset; + + if (pusch_antenna_ports == 2) { + + if (max_rank == 1) { + // - 1 or 3 bits according to Table 7.3.1.1.2-5 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset; + // - 2 bits according to Table 7.3.1.1.2-5A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values + // of higher layer parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + nbits = 2; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 2,"TPMI %d is invalid!\n", srs_feedback->tpmi); + *val = srs_feedback->tpmi; + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 1; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 1,"TPMI %d is invalid!\n", srs_feedback->tpmi); + *val = srs_feedback->tpmi; + } + } else { + nbits = 3; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 5,"TPMI %d is invalid!\n", srs_feedback->tpmi); + *val = srs_feedback->tpmi; + } + } + } + } else { + // - 2 or 4 bits according to Table 7.3.1.1.2-4 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset; + // - 2 bits according to Table 7.3.1.1.2-4A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + nbits = 2; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 2) || (*nrOfLayers==2 && srs_feedback->tpmi == 0), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + *val = *nrOfLayers==1 ? table_7_3_1_1_2_4A_1layer[srs_feedback->tpmi] : 2; + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 2; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 1) || (*nrOfLayers==2 && srs_feedback->tpmi == 0), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + *val = *nrOfLayers==1 ? srs_feedback->tpmi : 2; + } + } else { + nbits = 4; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 5) || (*nrOfLayers==2 && srs_feedback->tpmi <= 2), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + *val = *nrOfLayers==1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[srs_feedback->tpmi] : + table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[srs_feedback->tpmi]; + } + } + } + } + + } else if (pusch_antenna_ports == 4) { + + if (max_rank == 1) { + // - 2, 4, or 5 bits according to Table 7.3.1.1.2-3 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset; + // - 3 or 4 bits according to Table 7.3.1.1.2-3A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values + // of higher layer parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 3; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 3 || srs_feedback->tpmi == 13, "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else { + nbits = 4; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 15, "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } + if (val && srs_feedback) { + *val = table_7_3_1_1_2_3A[srs_feedback->tpmi]; + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 2; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 3, "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + nbits = 4; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 11, "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else { + nbits = 5; + if (val && srs_feedback) { + AssertFatal(srs_feedback->tpmi <= 27, "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } + if (val && srs_feedback) { + *val = srs_feedback->tpmi; + } + } + } else { + // - 4, 5, or 6 bits according to Table 7.3.1.1.2-2 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset; + // - 4 or 5 bits according to Table 7.3.1.1.2-2A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=2, transform precoder is disabled, and according to the values of higher layer parameter + // codebookSubset; + // - 4 or 6 bits according to Table 7.3.1.1.2-2B for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=3 or 4, transform precoder is disabled, and according to the values of higher layer + // parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (max_rank == 2) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 4; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && (srs_feedback->tpmi <= 3 || srs_feedback->tpmi==13)) || (*nrOfLayers==2 && srs_feedback->tpmi <= 6), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else { + nbits = 5; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 15) || (*nrOfLayers==2 && srs_feedback->tpmi <= 13), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } + if (val && srs_feedback) { + *val = *nrOfLayers==1 ? table_7_3_1_1_2_2A_1layer[srs_feedback->tpmi] : table_7_3_1_1_2_2A_2layers[srs_feedback->tpmi]; + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 4; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && (srs_feedback->tpmi <= 3 || srs_feedback->tpmi == 13)) || (*nrOfLayers==2 && srs_feedback->tpmi <= 6) || + (*nrOfLayers==3 && srs_feedback->tpmi <= 1) || (*nrOfLayers==4 && srs_feedback->tpmi == 0), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else { + nbits = 6; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 15) || (*nrOfLayers==2 && srs_feedback->tpmi <= 13) || + (*nrOfLayers==3 && srs_feedback->tpmi <= 2) || (*nrOfLayers==4 && srs_feedback->tpmi <= 2), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } + if (val && srs_feedback) { + switch (*nrOfLayers) { + case 1: + *val = table_7_3_1_1_2_2B_1layer[srs_feedback->tpmi]; + break; + case 2: + *val = table_7_3_1_1_2_2B_2layers[srs_feedback->tpmi]; + break; + case 3: + *val = table_7_3_1_1_2_2B_3layers[srs_feedback->tpmi]; + break; + case 4: + *val = table_7_3_1_1_2_2B_4layers[srs_feedback->tpmi]; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + nbits = 4; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 3) || (*nrOfLayers==2 && srs_feedback->tpmi <= 5) || + (*nrOfLayers==3 && srs_feedback->tpmi == 0) || (*nrOfLayers==4 && srs_feedback->tpmi == 0), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + nbits = 5; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 11) || (*nrOfLayers==2 && srs_feedback->tpmi <= 13) || + (*nrOfLayers==3 && srs_feedback->tpmi <= 2) || (*nrOfLayers==4 && srs_feedback->tpmi <= 2), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } else { + nbits = 6; + if (val && srs_feedback) { + AssertFatal((*nrOfLayers==1 && srs_feedback->tpmi <= 28) || (*nrOfLayers==2 && srs_feedback->tpmi <= 22) || + (*nrOfLayers==3 && srs_feedback->tpmi <= 7) || (*nrOfLayers==4 && srs_feedback->tpmi <= 5), + "TPMI %d is invalid!\n", srs_feedback->tpmi); + } + } + if (val && srs_feedback) { + switch (*nrOfLayers) { + case 1: + *val = table_7_3_1_1_2_2_1layer[srs_feedback->tpmi]; + break; + case 2: + *val = table_7_3_1_1_2_2_2layers[srs_feedback->tpmi]; + break; + case 3: + *val = table_7_3_1_1_2_2_3layers[srs_feedback->tpmi]; + break; + case 4: + *val = table_7_3_1_1_2_2_4layers[srs_feedback->tpmi]; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } + } + + } + + return nbits; +} + uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, const NR_BWP_UplinkCommon_t *initialUplinkBWP, const NR_CellGroupConfig_t *cg, @@ -2629,6 +3114,11 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, long rbg_size_config; int num_entries = 0; + NR_UplinkConfig_t *uplinkConfig = NULL; + if (cg && cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated) { + uplinkConfig = cg->spCellConfig->spCellConfigDedicated->uplinkConfig; + } + const NR_BWP_DownlinkDedicated_t *bwpd = NULL; const NR_BWP_UplinkDedicated_t *ubwpd = NULL; const NR_BWP_DownlinkCommon_t *bwpc = NULL; @@ -2640,23 +3130,21 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, NR_SRS_Config_t *srs_config = NULL; if(bwp_id > 0) { AssertFatal(cg!=NULL,"Cellgroup is null and bwp_id!=0"); - bwpd=cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; - bwpc=cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Common; - ubwpd=cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; - ubwpc=cg->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Common; + bwpd = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated; + bwpc = cg->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Common; + ubwpd = uplinkConfig ? uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Dedicated : NULL; + ubwpc = uplinkConfig ? uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1]->bwp_Common : NULL; pdsch_Config = (bwpd->pdsch_Config) ? bwpd->pdsch_Config->choice.setup : NULL; pdcch_Config = (bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; pucch_Config = (ubwpd->pucch_Config) ? ubwpd->pucch_Config->choice.setup : NULL; pusch_Config = (ubwpd->pusch_Config) ? ubwpd->pusch_Config->choice.setup : NULL; srs_config = (ubwpd->srs_Config) ? ubwpd->srs_Config->choice.setup : NULL; - } - else if (cg){ + } else if (cg) { bwpc = initialDownlinkBWP; ubwpc = initialUplinkBWP; bwpd = cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated ? cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL; - ubwpd = cg->spCellConfig && cg->spCellConfig->spCellConfigDedicated && cg->spCellConfig->spCellConfigDedicated->uplinkConfig ? - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP : NULL; + ubwpd = uplinkConfig ? uplinkConfig->initialUplinkBWP : NULL; pdsch_Config = (bwpd && bwpd->pdsch_Config) ? bwpd->pdsch_Config->choice.setup : NULL; pdcch_Config = (bwpd && bwpd->pdcch_Config) ? bwpd->pdcch_Config->choice.setup : NULL; pucch_Config = (ubwpd && ubwpd->pucch_Config) ? ubwpd->pucch_Config->choice.setup : NULL; @@ -2739,101 +3227,35 @@ uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDownlinkBWP, size += 1; } // 1st DAI - if (cg->physicalCellGroupConfig && - cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook==NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) + if (cg->physicalCellGroupConfig && cg->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook == NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) dci_pdu->dai[0].nbits = 2; else dci_pdu->dai[0].nbits = 1; size += dci_pdu->dai[0].nbits; - LOG_D(NR_MAC,"DAI1 nbits %d\n",dci_pdu->dai[0].nbits); + LOG_D(NR_MAC, "DAI1 nbits %d\n", dci_pdu->dai[0].nbits); // 2nd DAI - if (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig && - cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup && - cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { //TODO not sure about that + if (cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig && cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup + && cg->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup->codeBlockGroupTransmission != NULL) { // TODO not sure about that dci_pdu->dai[1].nbits = 2; size += dci_pdu->dai[1].nbits; } // SRS resource indicator - if (srs_config && - pusch_Config && - pusch_Config->txConfig != NULL){ - int count=0; - if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){ - for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) { - if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) - count++; - } - if (count>1) { - dci_pdu->srs_resource_indicator.nbits = 1; - size += dci_pdu->srs_resource_indicator.nbits; - } - } - else { - int lmin,Lmax = 0; - int lsum = 0; - if ( cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig != NULL) { - if ( cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers != NULL) - Lmax = *cg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers; - else - AssertFatal(1==0,"MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); - } - else - AssertFatal(1==0,"MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); - for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) { - if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) - count++; - if (count < Lmax) lmin = count; - else lmin = Lmax; - for (int k=1;k<=lmin;k++) { - lsum += binomial(count,k); - } - } - dci_pdu->srs_resource_indicator.nbits = (int)ceil(log2(lsum)); - size += dci_pdu->srs_resource_indicator.nbits; - } - } else dci_pdu->srs_resource_indicator.nbits = 0; - LOG_D(NR_MAC,"dci_pdu->srs_resource_indicator.nbits %d\n",dci_pdu->srs_resource_indicator.nbits); + NR_PUSCH_ServingCellConfig_t *pusch_servingcellconfig = uplinkConfig && uplinkConfig->pusch_ServingCellConfig ? uplinkConfig->pusch_ServingCellConfig->choice.setup : NULL; + dci_pdu->srs_resource_indicator.nbits = compute_srs_resource_indicator(pusch_servingcellconfig, pusch_Config, srs_config, NULL, NULL); + size += dci_pdu->srs_resource_indicator.nbits; + LOG_D(NR_MAC, "dci_pdu->srs_resource_indicator.nbits %d\n", dci_pdu->srs_resource_indicator.nbits); // Precoding info and number of layers - long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t*)&format, rnti_type, 0); - - uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, dci_pdu->srs_resource_indicator); - - dci_pdu->precoding_information.nbits=0; - if (pusch_Config && - pusch_Config->txConfig != NULL){ - if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){ - if (pusch_antenna_ports > 1) { - if (pusch_antenna_ports == 4) { - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank>1)) - dci_pdu->precoding_information.nbits = 6-(*pusch_Config->codebookSubset); - else { - if(*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) - dci_pdu->precoding_information.nbits = 2; - else - dci_pdu->precoding_information.nbits = 5-(*pusch_Config->codebookSubset); - } - } - else { - AssertFatal(pusch_antenna_ports==2,"Not valid number of antenna ports"); - if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank==2)) - dci_pdu->precoding_information.nbits = 4-(*pusch_Config->codebookSubset); - else - dci_pdu->precoding_information.nbits = 3-(*pusch_Config->codebookSubset); - } - } - } - } + dci_pdu->precoding_information.nbits = compute_precoding_information(pusch_Config, srs_config, dci_pdu->srs_resource_indicator, NULL, NULL, NULL); size += dci_pdu->precoding_information.nbits; - LOG_D(NR_MAC,"dci_pdu->precoding_informaiton.nbits=%d\n",dci_pdu->precoding_information.nbits); + LOG_D(NR_MAC, "dci_pdu->precoding_informaiton.nbits=%d\n", dci_pdu->precoding_information.nbits); // Antenna ports + long transformPrecoder = get_transformPrecoding(initialUplinkBWP, pusch_Config, ubwpd, (uint8_t *)&format, rnti_type, 0); NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = NULL; - int xa=0; - int xb=0; - if(pusch_Config && - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL){ + int xa = 0; + int xb = 0; + if (pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL) { NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup; - xa = ul_ant_bits(NR_DMRS_UplinkConfig,transformPrecoder); + xa = ul_ant_bits(NR_DMRS_UplinkConfig, transformPrecoder); } if(pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL){ diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index a55bbee74d..9a8750ae51 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -64,6 +64,19 @@ int is_nr_DL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon,slo int is_nr_UL_slot(NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, slot_t slotP, frame_type_t frame_type); +uint8_t compute_srs_resource_indicator(NR_PUSCH_ServingCellConfig_t *pusch_servingcellconfig, + NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + nr_srs_feedback_t *srs_feedback, + uint16_t *val); + +uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator, + nr_srs_feedback_t *srs_feedback, + const uint8_t *nrOfLayers, + uint16_t *val); + uint16_t nr_dci_size(const NR_BWP_DownlinkCommon_t *initialDLBWP, const NR_BWP_UplinkCommon_t *initialULBWP, const NR_CellGroupConfig_t *cg, diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h index 7bbe8d68a7..01864f02c5 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h @@ -143,4 +143,7 @@ extern const float table_38213_13_12_c3[16]; extern const int32_t table_38213_10_1_1_c2[5]; +extern const char table_38211_6_3_1_5_1[6][2][1]; +extern const char table_38211_6_3_1_5_2[28][4][1]; +extern const char table_38211_6_3_1_5_3[28][4][1]; #endif //DEF_H diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 72b7f2a565..a88926c3fa 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -830,6 +830,7 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t scc, pusch_pdu, &uldci_payload, + NULL, ra->Msg3_tda_id, ra->msg3_TPC, &ra->UL_BWP); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5a7f5f973f..690bb2211b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -882,6 +882,7 @@ void config_uldci(const NR_SIB1_t *sib1, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, + nr_srs_feedback_t *srs_feedback, int time_domain_assignment, uint8_t tpc, NR_UE_UL_BWP_t *ul_bwp) { @@ -916,13 +917,14 @@ void config_uldci(const NR_SIB1_t *sib1, pusch_Config->txConfig != NULL) { AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook, "Non Codebook configuration non supported\n"); - dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS + compute_srs_resource_indicator(ul_bwp->pusch_servingcellconfig, pusch_Config, ul_bwp->srs_Config, srs_feedback, &dci_pdu_rel15->srs_resource_indicator.val); } - dci_pdu_rel15->precoding_information.val= 0; - if (pusch_pdu->nrOfLayers == 2) - dci_pdu_rel15->precoding_information.val = 4; - else if (pusch_pdu->nrOfLayers == 4) - dci_pdu_rel15->precoding_information.val = 11; + compute_precoding_information(pusch_Config, + ul_bwp->srs_Config, + dci_pdu_rel15->srs_resource_indicator, + srs_feedback, + &pusch_pdu->nrOfLayers, + &dci_pdu_rel15->precoding_information.val); // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 // Antenna Ports @@ -1018,7 +1020,7 @@ int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, // This function configures pucch pdu fapi structure void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, NR_ServingCellConfigCommon_t *scc, - NR_UE_info_t* UE, + NR_UE_info_t *UE, uint8_t pucch_resource, uint16_t O_csi, uint16_t O_ack, @@ -2456,6 +2458,12 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, false); } +void reset_srs_stats(NR_UE_info_t *UE) { + if (UE) { + UE->mac_stats.srs_stats[0] = '\0'; + } +} + //------------------------------------------------------------------------------ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup) { @@ -2522,6 +2530,8 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf create_nr_list(&sched_ctrl->feedback_ul_harq, 16); create_nr_list(&sched_ctrl->retrans_ul_harq, 16); + reset_srs_stats(UE); + pthread_mutex_lock(&UE_info->mutex); int i; for(i=0; irrc_processing_timer == 0) { LOG_I(NR_MAC, "(%d.%d) De-activating RRC processing timer for UE %04x\n", frame, slot, UE->rnti); + reset_srs_stats(UE); + NR_CellGroupConfig_t *cg = NULL; uper_decode(NULL, &asn_DEF_NR_CellGroupConfig, //might be added prefix later diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 65bf2a4ae9..8eddea2eab 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -35,7 +35,12 @@ extern RAN_CONTEXT_t RC; -void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_UE_info_t* UE, NR_SRS_Resource_t *srs_resource) { +const uint16_t m_SRS[64] = { 4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56, 60, 64, 72, 72, 76, 80, 88, + 96, 96, 104, 112, 120, 120, 120, 128, 128, 128, 132, 136, 144, 144, 144, 144, 152, 160, + 160, 160, 168, 176, 184, 192, 192, 192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, + 256, 264, 272, 272, 272 }; + +void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_UE_info_t* UE, NR_SRS_ResourceSet_t *srs_resource_set, NR_SRS_Resource_t *srs_resource) { NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; @@ -74,9 +79,22 @@ void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_U srs_pdu->resource_type = srs_resource->resourceType.present - 1; srs_pdu->t_srs = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; srs_pdu->t_offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); + + // TODO: This should be completed + srs_pdu->srs_parameters_v4.srs_bandwidth_size = m_SRS[srs_pdu->config_index]; + srs_pdu->srs_parameters_v4.usage = 1<usage; + srs_pdu->srs_parameters_v4.report_type[0] = 1; + srs_pdu->srs_parameters_v4.iq_representation = 1; + srs_pdu->srs_parameters_v4.prg_size = 1; + srs_pdu->srs_parameters_v4.num_total_ue_antennas = 1<num_ant_ports; + if (srs_resource_set->usage == NR_SRS_ResourceSet__usage_beamManagement) { + srs_pdu->beamforming.trp_scheme = 0; + srs_pdu->beamforming.num_prgs = m_SRS[srs_pdu->config_index]; + srs_pdu->beamforming.prg_size = 1; + } } -void nr_fill_nfapi_srs(int module_id, int CC_id, NR_UE_info_t* UE, sub_frame_t slot, NR_SRS_Resource_t *srs_resource) { +void nr_fill_nfapi_srs(int module_id, int CC_id, NR_UE_info_t* UE, sub_frame_t slot, NR_SRS_ResourceSet_t *srs_resource_set, NR_SRS_Resource_t *srs_resource) { nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_id]->UL_tti_req_ahead[0][slot]; AssertFatal(future_ul_tti_req->n_pdus < @@ -88,7 +106,7 @@ void nr_fill_nfapi_srs(int module_id, int CC_id, NR_UE_info_t* UE, sub_frame_t s memset(srs_pdu, 0, sizeof(nfapi_nr_srs_pdu_t)); future_ul_tti_req->n_pdus += 1; - nr_configure_srs(srs_pdu, module_id, CC_id, UE, srs_resource); + nr_configure_srs(srs_pdu, module_id, CC_id, UE, srs_resource_set, srs_resource); } /******************************************************************* @@ -158,7 +176,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { LOG_D(NR_MAC,"Scheduling SRS reception for %d.%d\n", frame, offset%n_slots_frame); - nr_fill_nfapi_srs(module_id, CC_id, UE, offset%n_slots_frame, srs_resource); + nr_fill_nfapi_srs(module_id, CC_id, UE, offset%n_slots_frame, srs_resource_set, srs_resource); sched_ctrl->sched_srs.frame = frame; sched_ctrl->sched_srs.slot = offset%n_slots_frame; sched_ctrl->sched_srs.srs_scheduled = true; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index ddfe59023d..7f15adca94 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -786,60 +786,460 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, } } +uint32_t calc_power_complex(const int16_t *x, const int16_t *y, const uint32_t size) { + + // Real part value + int64_t sum_x = 0; + int64_t sum_x2 = 0; + for(int k = 0; ktxConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook) || + num_ue_srs_ports == 1) { + return max_tpmi; + } + + long max_rank = *pusch_Config->maxRank; + long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL; + long *codebookSubset = pusch_Config->codebookSubset; + + if (num_ue_srs_ports == 2) { + + if (max_rank == 1) { + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + max_tpmi = 2; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + max_tpmi = 1; + } else { + max_tpmi = 5; + } + } + } else { + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + max_tpmi = *nrOfLayers == 1 ? 2 : 0; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + max_tpmi = *nrOfLayers == 1 ? 1 : 0; + } else { + max_tpmi = *nrOfLayers == 1 ? 5 : 2; + } + } + } + + } else if (num_ue_srs_ports == 4) { + + if (max_rank == 1) { + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + max_tpmi = 3; + *additional_max_tpmi = 13; + } else { + max_tpmi = 15; + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + max_tpmi = 3; + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + max_tpmi = 11; + } else { + max_tpmi = 27; + } + } + } else { + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (max_rank == 2) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + max_tpmi = *nrOfLayers == 1 ? 3 : 6; + if (*nrOfLayers == 1) { + *additional_max_tpmi = 13; + } + } else { + max_tpmi = *nrOfLayers == 1 ? 15 : 13; + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + switch (*nrOfLayers) { + case 1: + max_tpmi = 3; + *additional_max_tpmi = 13; + break; + case 2: + max_tpmi = 6; + break; + case 3: + max_tpmi = 1; + break; + case 4: + max_tpmi = 0; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } else { + switch (*nrOfLayers) { + case 1: + max_tpmi = 15; + break; + case 2: + max_tpmi = 13; + break; + case 3: + case 4: + max_tpmi = 2; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + switch (*nrOfLayers) { + case 1: + max_tpmi = 3; + break; + case 2: + max_tpmi = 5; + break; + case 3: + case 4: + max_tpmi = 0; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + switch (*nrOfLayers) { + case 1: + max_tpmi = 11; + break; + case 2: + max_tpmi = 13; + break; + case 3: + case 4: + max_tpmi = 2; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } else { + switch (*nrOfLayers) { + case 1: + max_tpmi = 28; + break; + case 2: + max_tpmi = 22; + break; + case 3: + max_tpmi = 7; + break; + case 4: + max_tpmi = 5; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } + } + + } + + return max_tpmi; +} + +void get_precoder_matrix_coef(char *w, + const uint8_t ul_ri, + const uint16_t num_ue_srs_ports, + const uint8_t transform_precoding, + const uint8_t tpmi, + const uint8_t uI) { + if (ul_ri == 0) { + if (num_ue_srs_ports == 2) { + *w = *table_38211_6_3_1_5_1[tpmi][uI]; + } else { + if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { + *w = *table_38211_6_3_1_5_2[tpmi][uI]; + } else { + *w = *table_38211_6_3_1_5_3[tpmi][uI]; + } + } + } else { + AssertFatal(1==0,"Function get_precoder_matrix_coef() does not support %i layers yet!\n", ul_ri+1); + } +} + +int nr_srs_tpmi_estimation(const NR_PUSCH_Config_t *pusch_Config, + const uint8_t transform_precoding, + const uint8_t *channel_matrix, + const uint8_t normalized_iq_representation, + const uint16_t num_gnb_antenna_elements, + const uint16_t num_ue_srs_ports, + const uint16_t prg_size, + const uint16_t num_prgs, + const uint8_t ul_ri) { + + uint8_t tpmi_sel = 0; + int16_t precoded_channel_matrix_re[num_prgs*num_gnb_antenna_elements]; + int16_t precoded_channel_matrix_im[num_prgs*num_gnb_antenna_elements]; + c16_t *channel_matrix16 = (c16_t*)channel_matrix; + uint32_t max_precoded_signal_power = 0; + int additional_max_tpmi = -1; + char w; + + uint8_t max_tpmi = get_max_tpmi(pusch_Config, + num_ue_srs_ports, + &ul_ri, + &additional_max_tpmi); + + uint8_t end_tpmi_loop = additional_max_tpmi > max_tpmi ? additional_max_tpmi : max_tpmi; + + // channel_matrix x precoder_matrix + // [ (gI=0,uI=0) (gI=0,uI=1) ... (gI=0,uI=num_ue_srs_ports-1) ] x [uI=0] + // [ (gI=1,uI=0) (gI=1,uI=1) ... (gI=1,uI=num_ue_srs_ports-1) ] [uI=1] + // [ (gI=2,uI=0) (gI=2,uI=1) ... (gI=2,uI=num_ue_srs_ports-1) ] [uI=2] + // ... ... + + for(uint8_t tpmi = 0; tpmi<=end_tpmi_loop; tpmi++) { + + if (tpmi > max_tpmi) { + tpmi = end_tpmi_loop; + } + + for(int pI = 0; pI real %i, imag %i\n", + uI, gI, pI, channel_matrix16[index].r, channel_matrix16[index].i); +#endif + } + +#ifdef SRS_IND_DEBUG + LOG_I(NR_MAC, "(gI %i, pI %i) precoded_channel_coef --> real %i, imag %i\n", + gI, pI, precoded_channel_matrix_re[index_gI_pI], precoded_channel_matrix_im[index_gI_pI]); +#endif + } + } + + uint32_t precoded_signal_power = calc_power_complex(precoded_channel_matrix_re, + precoded_channel_matrix_im, + num_prgs*num_gnb_antenna_elements); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_MAC, "(tpmi %i) precoded_signal_power = %i\n", tpmi, precoded_signal_power); +#endif + + if (precoded_signal_power > max_precoded_signal_power) { + max_precoded_signal_power = precoded_signal_power; + tpmi_sel = tpmi; + } + } + + return tpmi_sel; +} + void handle_nr_srs_measurements(const module_id_t module_id, const frame_t frame, const sub_frame_t slot, - const rnti_t rnti, - const uint16_t timing_advance, - const uint8_t num_symbols, - const uint8_t wide_band_snr, - const uint8_t num_reported_symbols, - nfapi_nr_srs_indication_reported_symbol_t *reported_symbol_list) + const nfapi_nr_srs_indication_pdu_t *srs_ind) { - LOG_D(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); + LOG_D(NR_MAC, "(%d.%d) Received SRS indication for UE %04x\n", frame, slot, srs_ind->rnti); #ifdef SRS_IND_DEBUG LOG_I(NR_MAC, "frame = %i\n", frame); LOG_I(NR_MAC, "slot = %i\n", slot); - LOG_I(NR_MAC, "rnti = 0x%04x\n", rnti); - LOG_I(NR_MAC, "timing_advance = %i\n", timing_advance); - LOG_I(NR_MAC, "num_symbols = %i\n", num_symbols); - LOG_I(NR_MAC, "wide_band_snr = %i (%i dB)\n", wide_band_snr, (wide_band_snr >> 1) - 64); - LOG_I(NR_MAC, "num_reported_symbols = %i\n", num_reported_symbols); - LOG_I(NR_MAC, "reported_symbol_list[0].num_rbs = %i\n", reported_symbol_list[0].num_rbs); - for (int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { - LOG_I(NR_MAC, "reported_symbol_list[0].rb_list[%3i].rb_snr = %i (%i dB)\n", rb, reported_symbol_list[0].rb_list[rb].rb_snr, (reported_symbol_list[0].rb_list[rb].rb_snr >> 1) - 64); - } + LOG_I(NR_MAC, "srs_ind->rnti = %04x\n", srs_ind->rnti); + LOG_I(NR_MAC, "srs_ind->timing_advance_offset = %i\n", srs_ind->timing_advance_offset); + LOG_I(NR_MAC, "srs_ind->timing_advance_offset_nsec = %i\n", srs_ind->timing_advance_offset_nsec); + LOG_I(NR_MAC, "srs_ind->srs_usage = %i\n", srs_ind->srs_usage); + LOG_I(NR_MAC, "srs_ind->report_type = %i\n", srs_ind->report_type); #endif - NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); + NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, srs_ind->rnti); if (!UE) { - LOG_E(NR_MAC, "Could not find UE for RNTI %04x\n", rnti); + LOG_W(NR_MAC, "Could not find UE for RNTI %04x\n", srs_ind->rnti); return; } - if (wide_band_snr == 0xFF) { - LOG_W(NR_MAC, "Invalid wide_band_snr for RNTI %04x\n", rnti); + if (srs_ind->timing_advance_offset == 0xFFFF) { + LOG_W(NR_MAC, "Invalid timing advance offset for RNTI %04x\n", srs_ind->rnti); return; } - int wide_band_snr_dB = (wide_band_snr >> 1) - 64; - gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; NR_mac_stats_t *stats = &UE->mac_stats; - stats->srs_wide_band_snr = wide_band_snr_dB; - const int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; - uint16_t *ulprbbl = nr_mac->ulprbbl; + switch (srs_ind->srs_usage) { + case NR_SRS_ResourceSet__usage_beamManagement: { + nfapi_nr_srs_beamforming_report_t nr_srs_beamforming_report; + unpack_nr_srs_beamforming_report(srs_ind->report_tlv->value, + srs_ind->report_tlv->length, + &nr_srs_beamforming_report, + sizeof(nfapi_nr_srs_beamforming_report_t)); - memset(ulprbbl, 0, reported_symbol_list[0].num_rbs * sizeof(uint16_t)); + if (nr_srs_beamforming_report.wide_band_snr == 0xFF) { + LOG_W(NR_MAC, "Invalid wide_band_snr for RNTI %04x\n", srs_ind->rnti); + return; + } - for (int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { - int snr = (reported_symbol_list[0].rb_list[rb].rb_snr >> 1) - 64; - if (snr < wide_band_snr_dB - ul_prbblack_SNR_threshold) { - ulprbbl[rb] = 0x3FFF; // all symbols taken + int wide_band_snr_dB = (nr_srs_beamforming_report.wide_band_snr >> 1) - 64; + +#ifdef SRS_IND_DEBUG + LOG_I(NR_MAC, "nr_srs_beamforming_report.prg_size = %i\n", nr_srs_beamforming_report.prg_size); + LOG_I(NR_MAC, "nr_srs_beamforming_report.num_symbols = %i\n", nr_srs_beamforming_report.num_symbols); + LOG_I(NR_MAC, "nr_srs_beamforming_report.wide_band_snr = %i (%i dB)\n", nr_srs_beamforming_report.wide_band_snr, wide_band_snr_dB); + LOG_I(NR_MAC, "nr_srs_beamforming_report.num_reported_symbols = %i\n", nr_srs_beamforming_report.num_reported_symbols); + LOG_I(NR_MAC, "nr_srs_beamforming_report.prgs[0].num_prgs = %i\n", nr_srs_beamforming_report.prgs[0].num_prgs); + for (int prg_idx = 0; prg_idx < nr_srs_beamforming_report.prgs[0].num_prgs; prg_idx++) { + LOG_I(NR_MAC, + "nr_srs_beamforming_report.prgs[0].prg_list[%3i].rb_snr = %i (%i dB)\n", + prg_idx, + nr_srs_beamforming_report.prgs[0].prg_list[prg_idx].rb_snr, + (nr_srs_beamforming_report.prgs[0].prg_list[prg_idx].rb_snr >> 1) - 64); + } +#endif + + sprintf(stats->srs_stats, "UL-SNR %i dB", wide_band_snr_dB); + + const int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; + uint16_t *ulprbbl = nr_mac->ulprbbl; + + uint8_t num_rbs = nr_srs_beamforming_report.prg_size * nr_srs_beamforming_report.prgs[0].num_prgs; + memset(ulprbbl, 0, num_rbs * sizeof(uint16_t)); + for (int rb = 0; rb < num_rbs; rb++) { + int snr = (nr_srs_beamforming_report.prgs[0].prg_list[rb / nr_srs_beamforming_report.prg_size].rb_snr >> 1) - 64; + if (snr < wide_band_snr_dB - ul_prbblack_SNR_threshold) { + ulprbbl[rb] = 0x3FFF; // all symbols taken + } + LOG_D(NR_MAC, "ulprbbl[%3i] = 0x%x\n", rb, ulprbbl[rb]); + } + + break; } - LOG_D(NR_MAC, "ulprbbl[%3i] = 0x%x\n", rb, ulprbbl[rb]); + + case NR_SRS_ResourceSet__usage_codebook: { + nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_normalized_channel_iq_matrix; + unpack_nr_srs_normalized_channel_iq_matrix(srs_ind->report_tlv->value, + srs_ind->report_tlv->length, + &nr_srs_normalized_channel_iq_matrix, + sizeof(nfapi_nr_srs_normalized_channel_iq_matrix_t)); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.normalized_iq_representation = %i\n", nr_srs_normalized_channel_iq_matrix.normalized_iq_representation); + LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements = %i\n", nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements); + LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports); + LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.prg_size = %i\n", nr_srs_normalized_channel_iq_matrix.prg_size); + LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.num_prgs = %i\n", nr_srs_normalized_channel_iq_matrix.num_prgs); + c16_t *channel_matrix16 = (c16_t *)nr_srs_normalized_channel_iq_matrix.channel_matrix; + c8_t *channel_matrix8 = (c8_t *)nr_srs_normalized_channel_iq_matrix.channel_matrix; + for (int uI = 0; uI < nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports; uI++) { + for (int gI = 0; gI < nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements; gI++) { + for (int pI = 0; pI < nr_srs_normalized_channel_iq_matrix.num_prgs; pI++) { + uint16_t index = uI * nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_normalized_channel_iq_matrix.num_prgs + gI * nr_srs_normalized_channel_iq_matrix.num_prgs + pI; + LOG_I(NR_MAC, + "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n", + uI, + gI, + pI, + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r, + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i : channel_matrix16[index].i); + } + } + } +#endif + + // TODO: This should be improved + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; + sched_ctrl->srs_feedback.sri = NR_SRS_SRI_0; + sched_ctrl->srs_feedback.ul_ri = 0; // TODO: Compute this + sched_ctrl->srs_feedback.tpmi = nr_srs_tpmi_estimation(current_BWP->pusch_Config, + current_BWP->transform_precoding, + nr_srs_normalized_channel_iq_matrix.channel_matrix, + nr_srs_normalized_channel_iq_matrix.normalized_iq_representation, + nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements, + nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports, + nr_srs_normalized_channel_iq_matrix.prg_size, + nr_srs_normalized_channel_iq_matrix.num_prgs, + sched_ctrl->srs_feedback.ul_ri); + sprintf(stats->srs_stats, "UL-RI %d, TPMI %d", sched_ctrl->srs_feedback.ul_ri + 1, sched_ctrl->srs_feedback.tpmi); + break; + } + + case NR_SRS_ResourceSet__usage_nonCodebook: + case NR_SRS_ResourceSet__usage_antennaSwitching: + LOG_W(NR_MAC, "MAC procedures for this SRS usage are not implemented yet!\n"); + break; + + default: + AssertFatal(1 == 0, "Invalid SRS usage\n"); } } @@ -1851,9 +2251,11 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot) scc, pusch_pdu, &uldci_payload, + &sched_ctrl->srs_feedback, sched_pusch->time_domain_allocation, UE->UE_sched_ctrl.tpc0, current_BWP); + fill_dci_pdu_rel15(scc, cg, &UE->current_DL_BWP, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 20e3865387..4497e89030 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -189,6 +189,7 @@ void config_uldci(const NR_SIB1_t *sib1, const NR_ServingCellConfigCommon_t *scc, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, + nr_srs_feedback_t *srs_feedback, int time_domain_assignment, uint8_t tpc, NR_UE_UL_BWP_t *ul_bwp); @@ -441,12 +442,7 @@ void handle_nr_ul_harq(const int CC_idP, void handle_nr_srs_measurements(const module_id_t module_id, const frame_t frame, const sub_frame_t slot, - const rnti_t rnti, - const uint16_t timing_advance, - const uint8_t num_symbols, - const uint8_t wide_band_snr, - const uint8_t num_reported_symbols, - nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list); + const nfapi_nr_srs_indication_pdu_t *srs_ind); int16_t ssb_index_from_prach(module_id_t module_idP, frame_t frameP, diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index b103182a67..6d592b797f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -93,14 +93,14 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - "UE RNTI %04x (%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas), UL-SNR %d dB\n", + "UE RNTI %04x (%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", UE->rnti, num++, sched_ctrl->ph, sched_ctrl->pcmax, avg_rsrp, - stats->num_rsrp_meas, - stats->srs_wide_band_snr); + stats->num_rsrp_meas); + output += snprintf(output, end - output, "UE %04x: CQI %d, RI %d, PMI (%d,%d)\n", @@ -110,6 +110,10 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); + if (stats->srs_stats[0] != '\0') { + output += snprintf(output, end - output, "UE %04x: %s\n", UE->rnti, stats->srs_stats); + } + output += snprintf(output, end - output, "UE %04x: dlsch_rounds ", UE->rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 44d5ff6e34..9900546f6b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -634,7 +634,7 @@ typedef struct { NR_list_t feedback_ul_harq; /// UL HARQ processes that await retransmission NR_list_t retrans_ul_harq; - NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information + NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl; // MAC CE related information /// number of active DL LCs uint8_t dl_lc_num; /// order in which DLSCH scheduler should allocate LCs @@ -642,6 +642,9 @@ typedef struct { /// Timer for RRC processing procedures uint32_t rrc_processing_timer; + + /// sri, ul_ri and tpmi based on SRS + nr_srs_feedback_t srs_feedback; } NR_UE_sched_ctrl_t; typedef struct { @@ -668,7 +671,7 @@ typedef struct NR_mac_stats { uint32_t pucch0_DTX; int cumul_rsrp; uint8_t num_rsrp_meas; - int8_t srs_wide_band_snr; + char srs_stats[50]; // Statistics may differ depending on SRS usage } NR_mac_stats_t; typedef struct NR_bler_options { diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index f295d95184..a0a7cf5d11 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -239,12 +239,7 @@ void handle_nr_srs(NR_UL_IND_t *UL_info) { handle_nr_srs_measurements(module_id, frame, slot, - srs_ind->rnti, - srs_ind->timing_advance, - srs_ind->num_symbols, - srs_ind->wide_band_snr, - srs_ind->num_reported_symbols, - srs_ind->reported_symbol_list); + &srs_list[i]); } UL_info->srs_ind.number_of_pdus = 0; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index af7bdcfbc7..85a50710ec 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1002,9 +1002,10 @@ void fill_initial_SpCellConfig(int uid, SpCellConfig->spCellConfigDedicated = calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated)); SpCellConfig->spCellConfigDedicated->uplinkConfig = calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->uplinkConfig)); + NR_UplinkConfig_t *uplinkConfig = SpCellConfig->spCellConfigDedicated->uplinkConfig; NR_BWP_UplinkDedicated_t *initialUplinkBWP = calloc(1,sizeof(*initialUplinkBWP)); - SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP = initialUplinkBWP; + uplinkConfig->initialUplinkBWP = initialUplinkBWP; initialUplinkBWP->pucch_Config = calloc(1,sizeof(*initialUplinkBWP->pucch_Config)); initialUplinkBWP->pucch_Config->present = NR_SetupRelease_PUCCH_Config_PR_setup; NR_PUCCH_Config_t *pucch_Config = calloc(1,sizeof(*pucch_Config)); @@ -1090,9 +1091,15 @@ void fill_initial_SpCellConfig(int uid, pusch_Config->uci_OnPUSCH=NULL; pusch_Config->tp_pi2BPSK=NULL; + long maxMIMO_Layers = uplinkConfig && + uplinkConfig->pusch_ServingCellConfig && + uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 && + uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers ? + *uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers : 1; + // We are using do_srs = 0 here because the periodic SRS will only be enabled in update_cellGroupConfig() if do_srs == 1 initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); - config_srs(initialUplinkBWP->srs_Config, NULL, curr_bwp, uid, 0, 0); + config_srs(initialUplinkBWP->srs_Config, NULL, curr_bwp, uid, 0, maxMIMO_Layers, 0); scheduling_request_config(scc, pucch_Config); @@ -1216,7 +1223,7 @@ void fill_initial_SpCellConfig(int uid, n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; } if(n_ul_bwp>0) { - SpCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList = calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList)); + uplinkConfig->uplinkBWP_ToAddModList = calloc(1,sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) { NR_BWP_Uplink_t *ubwp = calloc(1, sizeof(*ubwp)); config_uplinkBWP(ubwp, bwp_loop, true, uid, @@ -1224,13 +1231,12 @@ void fill_initial_SpCellConfig(int uid, servingcellconfigdedicated, scc, NULL); - ASN_SEQUENCE_ADD(&SpCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); + ASN_SEQUENCE_ADD(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); } - SpCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id)); - *SpCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id ? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id : 1; + uplinkConfig->firstActiveUplinkBWP_Id = calloc(1,sizeof(*uplinkConfig->firstActiveUplinkBWP_Id)); + *uplinkConfig->firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id ? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id : 1; } - SpCellConfig->spCellConfigDedicated->csi_MeasConfig=calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; @@ -1585,6 +1591,12 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, if(scc) { int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); + NR_UplinkConfig_t *uplinkConfig = SpCellConfig && SpCellConfig->spCellConfigDedicated ? SpCellConfig->spCellConfigDedicated->uplinkConfig : NULL; + long maxMIMO_Layers = uplinkConfig && + uplinkConfig->pusch_ServingCellConfig && + uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 && + uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers ? + *uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers : 1; // SRS configuration if (configuration->do_SRS && SpCellConfig && @@ -1600,6 +1612,7 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, curr_bwp, uid, 0, + maxMIMO_Layers, configuration->do_SRS); } @@ -1625,6 +1638,7 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, bwp_size, uid, i+1, + maxMIMO_Layers, configuration->do_SRS); } } diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index d53288fd61..61572078ae 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -356,8 +356,9 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, const int curr_bwp, const int uid, const int res_id, - const int do_srs) { - + const long maxMIMO_Layers, + const int do_srs) +{ setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; NR_SRS_Config_t *srs_Config; @@ -419,26 +420,45 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); srs_res0->srs_ResourceId = res_id; srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; - // if (uecap && - // uecap->featureSets && - // uecap->featureSets->featureSetsUplink && - // uecap->featureSets->featureSetsUplink->list.count > 0) { - // NR_FeatureSetUplink_t *ul_feature_setup = uecap->featureSets->featureSetsUplink->list.array[0]; - // switch (ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource) { - // case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n1: - // srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; - // break; - // case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n2: - // srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports2; - // break; - // case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n4: - // srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports4; - // break; - // default: - // LOG_E(NR_RRC, "Max Number of SRS Ports Per Resource %ld is invalid!\n", - // ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource); - // } - // } + if (do_srs) { + long nrofSRS_Ports = 1; + if (uecap && + uecap->featureSets && + uecap->featureSets->featureSetsUplink && + uecap->featureSets->featureSetsUplink->list.count > 0) { + NR_FeatureSetUplink_t *ul_feature_setup = uecap->featureSets->featureSetsUplink->list.array[0]; + switch (ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource) { + case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n1: + nrofSRS_Ports = 1; + break; + case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n2: + nrofSRS_Ports = 2; + break; + case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n4: + nrofSRS_Ports = 4; + break; + default: + LOG_E(NR_RRC, "Max Number of SRS Ports Per Resource %ld is invalid!\n", + ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource); + } + nrofSRS_Ports = min(nrofSRS_Ports, maxMIMO_Layers); + switch (nrofSRS_Ports) { + case 1: + srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; + break; + case 2: + srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports2; + break; + case 4: + srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports4; + break; + default: + LOG_E(NR_RRC, "Number of SRS Ports Per Resource %ld is invalid!\n", + ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource); + } + } + LOG_I(NR_RRC, "SRS configured with %d ports\n", 1<nrofSRS_Ports); + } srs_res0->ptrs_PortIndex = NULL; srs_res0->transmissionComb.present = NR_SRS_Resource__transmissionComb_PR_n2; srs_res0->transmissionComb.choice.n2 = calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); @@ -1136,12 +1156,20 @@ void config_uplinkBWP(NR_BWP_Uplink_t *ubwp, pusch_Config->uci_OnPUSCH=NULL; pusch_Config->tp_pi2BPSK=NULL; + long maxMIMO_Layers = servingcellconfigdedicated && + servingcellconfigdedicated->uplinkConfig + && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig + && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 + && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers ? + *servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers : 1; + ubwp->bwp_Dedicated->srs_Config = calloc(1,sizeof(*ubwp->bwp_Dedicated->srs_Config)); config_srs(ubwp->bwp_Dedicated->srs_Config, NULL, curr_bwp, uid, bwp_loop+1, + maxMIMO_Layers, configuration->do_SRS); ubwp->bwp_Dedicated->configuredGrantConfig = NULL; diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index f8bdc4be53..27d6c5f080 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -150,6 +150,7 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, const int curr_bwp, const int uid, const int res_id, + const long maxMIMO_Layers, const int do_srs); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 12e5a30afd..f99e89a470 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -91,6 +91,12 @@ #define NR_RRC_RECONFIGURATION_DELAY_MS 10 #define NR_RRC_BWP_SWITCHING_DELAY_MS 6 +// 3GPP TS 38.133 - Section 8 - Table 8.2.1.2.7-2: Parameters which cause interruption other than SCS +// This table was recently added to 3GPP. It shows that changing the parameters locationAndBandwidth, nrofSRS-Ports or +// maxMIMO-Layers-r16 causes an interruption. This parameter is not yet being used in code, but has been placed here +// for future reference. +#define NR_OF_SRS_PORTS_SWITCHING_DELAY_MS 30 + #define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! #define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c index 3c61ec8dc2..01abd58659 100644 --- a/openair2/RRC/NR/rrc_gNB_reconfig.c +++ b/openair2/RRC/NR/rrc_gNB_reconfig.c @@ -479,9 +479,15 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco LOG_I(RRC,"TRANSFORM PRECODING ENABLED......\n"); } + long maxMIMO_Layers = servingcellconfigdedicated->uplinkConfig && + servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig && + servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 && + servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers ? + *servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers : 1; + int curr_bwp = NRRIV2BW(servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth,MAX_BWP_SIZE); initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); - config_srs(initialUplinkBWP->srs_Config, NULL, curr_bwp, uid, 0, configuration->do_SRS); + config_srs(initialUplinkBWP->srs_Config, NULL, curr_bwp, uid, 0, maxMIMO_Layers, configuration->do_SRS); // Downlink BWPs int n_dl_bwp = 1;