diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c index e66ce48ac0..6bf2ff37ea 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c @@ -746,6 +746,31 @@ static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, u return 1; } +static uint8_t pack_pm_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nr_pm_tlv_ve_t *pm_ve = (nfapi_nr_pm_tlv_ve_t *)tlv; + nfapi_nr_pm_list_t *pmi_list = &pm_ve->value; + if (!( push16(pmi_list->num_pm_idx, ppWritePackedMsg, end) )) { + return 0; + } + for (int i = 0; i< pmi_list->num_pm_idx; i++) { + const nfapi_nr_pm_pdu_t *pm_pdu = &pmi_list->pmi_pdu[i]; + if (!(push16(pm_pdu->pm_idx, ppWritePackedMsg, end) && push16(pm_pdu->numLayers, ppWritePackedMsg, end) + && push16(pm_pdu->num_ant_ports, ppWritePackedMsg, end))) { + return 0; + } + for (int k = 0; k < pm_pdu->numLayers; k++) { + for (int j = 0; j < pm_pdu->num_ant_ports; j++) { + const nfapi_nr_pm_weights_t *pm_weight = &pm_pdu->weights[k][j]; + if (!(push16(pm_weight->precoder_weight_Re, ppWritePackedMsg, end) && push16(pm_weight->precoder_weight_Im, ppWritePackedMsg, end))) { + return 0; + } + } + } + } + return 1; +} + uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config) { uint8_t *pNumTLVFields = (uint8_t *)*ppWritePackedMsg; @@ -1074,7 +1099,11 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e // END Digital Beam Table (DBT) PDU // START Precoding Matrix (PM) PDU - // Struct in nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h nfapi_nr_pm_pdu_t, currently unused, tag to use for AERIAL + if (pNfapiMsg->pmi_list.num_pm_idx != 0) { + nfapi_nr_pm_tlv_ve_t pm_tlv = {.tl.tag = NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, .value = pNfapiMsg->pmi_list}; + pack_nr_tlv(NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, &pm_tlv, ppWritePackedMsg, end, &pack_pm_table_tlv_value); + numTLVs++; + } // is 0xA011 END Precoding Matrix (PM) PDU #ifndef ENABLE_AERIAL // START nFAPI TLVs included in CONFIG.request for IDLE and CONFIGURED states @@ -1209,6 +1238,35 @@ static uint8_t unpack_dbt_table_tlv_value(void *tlv, uint8_t **ppReadPackedMsg, return 1; } +static uint8_t unpack_pm_table_tlv_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nr_pm_list_t *pm_list = (nfapi_nr_pm_list_t *)tlv; + if (!(pull16(ppReadPackedMsg, &pm_list->num_pm_idx, end))) { + return 0; + } + if (pm_list->num_pm_idx > 0) { + pm_list->pmi_pdu = calloc(pm_list->num_pm_idx, sizeof(*pm_list->pmi_pdu)); + } + for (int i = 0; i < pm_list->num_pm_idx; i++) { + nfapi_nr_pm_pdu_t *pm_pdu = &pm_list->pmi_pdu[i]; + if (!(pull16(ppReadPackedMsg, &pm_pdu->pm_idx, end) && pull16(ppReadPackedMsg, &pm_pdu->numLayers, end) + && pull16(ppReadPackedMsg, &pm_pdu->num_ant_ports, end))) { + return 0; + } + AssertFatal(pm_pdu->numLayers <= 4 && pm_pdu->num_ant_ports <= 4, "Precoding matrix size limited to 4X4 for the time being\n"); + for (int k = 0; k < pm_pdu->numLayers; k++) { + for (int j = 0; j < pm_pdu->num_ant_ports; j++) { + nfapi_nr_pm_weights_t *pm_weight = &pm_pdu->weights[k][j]; + if (!(pulls16(ppReadPackedMsg, &pm_weight->precoder_weight_Re, end) + && pulls16(ppReadPackedMsg, &pm_weight->precoder_weight_Im, end))) { + return 0; + } + } + } + } + return 1; +} + uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) { // Helper vars for indexed TLVs @@ -1275,6 +1333,7 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * {NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, NULL, &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, &(pNfapiMsg->measurement_config.rssi_measurement), &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, NULL, &unpack_dbt_table_tlv_value}, + {NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, NULL, &unpack_pm_table_tlv_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), &unpack_ipv4_address_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), &unpack_ipv6_address_value}, {NFAPI_NR_NFAPI_P7_VNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_port), &unpack_uint16_tlv_value}, @@ -1326,6 +1385,10 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * unpack_fns[idx].tlv = &generic_tl; result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->dbt_config, ppReadPackedMsg, end); break; + case NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG: + unpack_fns[idx].tlv = &generic_tl; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->pmi_list, ppReadPackedMsg, end); + break; case NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG: pNfapiMsg->prach_config.num_prach_fd_occasions.tl.tag = generic_tl.tag; pNfapiMsg->prach_config.num_prach_fd_occasions.tl.length = generic_tl.length; diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c index 4df5169d8c..fc34c66df9 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c @@ -275,6 +275,24 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const } } + EQ(unpacked_req->pmi_list.num_pm_idx, req->pmi_list.num_pm_idx); + + for (int i = 0; i < req->pmi_list.num_pm_idx; i++) { + const nfapi_nr_pm_pdu_t *req_pmi_pdu = &req->pmi_list.pmi_pdu[i]; + const nfapi_nr_pm_pdu_t *unpacked_pmi_pdu = &unpacked_req->pmi_list.pmi_pdu[i]; + EQ(unpacked_pmi_pdu->pm_idx, req_pmi_pdu->pm_idx); + EQ(unpacked_pmi_pdu->numLayers, req_pmi_pdu->numLayers); + EQ(unpacked_pmi_pdu->num_ant_ports, req_pmi_pdu->num_ant_ports); + for (int j = 0; j < req_pmi_pdu->num_ant_ports; ++j) { + for (int k = 0; k < req_pmi_pdu->num_ant_ports; ++k) { + const nfapi_nr_pm_weights_t* req_pm_weight = &req_pmi_pdu->weights[j][k]; + const nfapi_nr_pm_weights_t* unpacked_pm_weight = &unpacked_pmi_pdu->weights[j][k]; + EQ(unpacked_pm_weight->precoder_weight_Re, req_pm_weight->precoder_weight_Re); + EQ(unpacked_pm_weight->precoder_weight_Im, req_pm_weight->precoder_weight_Im); + } + } + } + EQ(unpacked_req->nfapi_config.p7_vnf_address_ipv4.tl.tag, req->nfapi_config.p7_vnf_address_ipv4.tl.tag); for (int i = 0; i < NFAPI_IPV4_ADDRESS_LENGTH; ++i) { EQ(unpacked_req->nfapi_config.p7_vnf_address_ipv4.address[i], req->nfapi_config.p7_vnf_address_ipv4.address[i]); @@ -841,6 +859,26 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf } } + dst->pmi_list.num_pm_idx = src->pmi_list.num_pm_idx; + if (dst->pmi_list.num_pm_idx > 0) { + dst->pmi_list.pmi_pdu = calloc(dst->pmi_list.num_pm_idx , sizeof(*dst->pmi_list.pmi_pdu)); + for (int i = 0; i < dst->pmi_list.num_pm_idx; i++) { + nfapi_nr_pm_pdu_t * dst_pmi_pdu = &dst->pmi_list.pmi_pdu[i]; + const nfapi_nr_pm_pdu_t * src_pmi_pdu = &src->pmi_list.pmi_pdu[i]; + dst_pmi_pdu->pm_idx = src_pmi_pdu->pm_idx; + dst_pmi_pdu->numLayers = src_pmi_pdu->numLayers; + dst_pmi_pdu->num_ant_ports = src_pmi_pdu->num_ant_ports; + for (int j = 0; j < dst_pmi_pdu->numLayers; ++j) { + for (int k = 0; k < dst_pmi_pdu->num_ant_ports; ++k) { + nfapi_nr_pm_weights_t* dst_pm_weight = &dst_pmi_pdu->weights[j][k]; + const nfapi_nr_pm_weights_t* src_pm_weight = &src_pmi_pdu->weights[j][k]; + dst_pm_weight->precoder_weight_Re = src_pm_weight->precoder_weight_Re; + dst_pm_weight->precoder_weight_Im = src_pm_weight->precoder_weight_Im; + } + } + } + } + COPY_TL(dst->nfapi_config.p7_vnf_address_ipv4.tl, src->nfapi_config.p7_vnf_address_ipv4.tl); memcpy(dst->nfapi_config.p7_vnf_address_ipv4.address, src->nfapi_config.p7_vnf_address_ipv4.address, 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 7af9d07d1c..f213868328 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 @@ -329,6 +329,7 @@ typedef struct #define NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG 0x1028 #define NFAPI_NR_CONFIG_TDD_TABLE 0x1035 #define NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG 0x1043 // This tag was added in version 5 of the SCF222 standard ( Table 3-50 of SCF222.10.05 ) +#define NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG 0x104B // This tag was added in version 6 of the SCF222 standard ( Table 3-52 of SCF222.10.06 ) //table 3-21 typedef struct @@ -497,7 +498,12 @@ typedef struct { typedef struct { uint16_t num_pm_idx; nfapi_nr_pm_pdu_t *pmi_pdu; -} nfapi_nr_pm_list_t; +} nfapi_nr_pm_list_t; // This corresponds to Table 3-69 of SCF222.10.06, which introduces the num_pm_idx parameter + +typedef struct { + nfapi_tl_t tl; + nfapi_nr_pm_list_t value; +} nfapi_nr_pm_tlv_ve_t; typedef struct { nfapi_uint8_tlv_t num_beams_period_vendor_ext; diff --git a/nfapi/tests/p5/nr_fapi_config_request_test.c b/nfapi/tests/p5/nr_fapi_config_request_test.c index 7964af55c0..82ce60ca3b 100644 --- a/nfapi/tests/p5/nr_fapi_config_request_test.c +++ b/nfapi/tests/p5/nr_fapi_config_request_test.c @@ -225,6 +225,28 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap nfapi_resp->num_tlv++; } + nfapi_nr_pm_list_t *pm_list = &nfapi_resp->pmi_list; + const uint16_t num_layers = rand16_range(1, 4); + const uint16_t num_ant_ports = rand16_range(1, 4); + pm_list->num_pm_idx = rand16_range(1, 4); + if (nfapi_resp->pmi_list.num_pm_idx > 0) { + pm_list->pmi_pdu = calloc(pm_list->num_pm_idx, sizeof(*pm_list->pmi_pdu)); + for (int i = 0; i < pm_list->num_pm_idx; i++) { + nfapi_nr_pm_pdu_t *pmi_pdu = &pm_list->pmi_pdu[i]; + pmi_pdu->pm_idx = i+1; + pmi_pdu->numLayers = num_layers; + pmi_pdu->num_ant_ports = num_ant_ports; + for (int j = 0; j < num_layers; j++) { + for (int k = 0; k < num_ant_ports; k++) { + nfapi_nr_pm_weights_t* pm_weight = &pmi_pdu->weights[j][k]; + pm_weight->precoder_weight_Re = (int16_t)rand16_range(1, 0xffff); + pm_weight->precoder_weight_Im = (int16_t)rand16_range(1, 0xffff); + } + } + } + nfapi_resp->num_tlv++; + } + nfapi_resp->nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; for (int i = 0; i < NFAPI_IPV4_ADDRESS_LENGTH; ++i) { nfapi_resp->nfapi_config.p7_vnf_address_ipv4.address[i] = rand8();