diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi.h index e8e645b8cf..ee405792d2 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi.h @@ -35,6 +35,9 @@ #include "debug.h" #define INDENTED_PRINTF(format, ...) printf("%*s" format, depth * 2, "", ##__VA_ARGS__) +#define INDENTED_GENERIC_PRINT(string, format, ...) INDENTED_PRINTF(string " = " format "\n", ##__VA_ARGS__) +#define INDENTED_TLV_PRINT(tlv_name, tlv) INDENTED_GENERIC_PRINT("(0x%04x) " tlv_name, "0x%02x", tlv.tl.tag, tlv.value) +#define INDENTED_TLV_FORMAT_PRINT(tlv_name, format, tlv) INDENTED_GENERIC_PRINT("(0x%04x) " tlv_name, format, tlv.tl.tag, tlv.value) #define EQ_TLV(_tlv_a, _tlv_b) \ do { \ diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c index 281043b6d3..6bf2ff37ea 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c @@ -724,6 +724,53 @@ uint8_t unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void * &pNfapiMsg->vendor_extension)); } +static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nr_dbt_tlv_ve_t *dbt_ve = (nfapi_nr_dbt_tlv_ve_t *)tlv; + nfapi_nr_dbt_pdu_t *dbt_config = &dbt_ve->value; + if (!( push16(dbt_config->num_dig_beams, ppWritePackedMsg, end) && push16(dbt_config->num_txrus, ppWritePackedMsg, end) )) { + return 0; + } + for (int i = 0; i< dbt_config->num_dig_beams; i++) { + const nfapi_nr_dig_beam_t *dig_beam = &dbt_config->dig_beam_list[i]; + if (!(push16(dig_beam->beam_idx, ppWritePackedMsg, end))) { + return 0; + } + for (int k = 0; k< dbt_config->num_txrus; k++) { + const nfapi_nr_txru_t *tx_ru = &dig_beam->txru_list[k]; + if (!(push16(tx_ru->dig_beam_weight_Re, ppWritePackedMsg, end) && push16(tx_ru->dig_beam_weight_Im, ppWritePackedMsg, end))) { + return 0; + } + } + } + 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; @@ -1044,11 +1091,19 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e // END Measurement Config // START Digital Beam Table (DBT) PDU - // Struct in nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h nfapi_nr_dbt_pdu_t, currently unused + if (pNfapiMsg->dbt_config.num_dig_beams != 0) { + nfapi_nr_dbt_tlv_ve_t dbt_tlv = {.tl.tag = NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, .value = pNfapiMsg->dbt_config}; + pack_nr_tlv(NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, &dbt_tlv, ppWritePackedMsg, end, &pack_dbt_table_tlv_value); + numTLVs++; + } // 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 @@ -1156,6 +1211,62 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e return retval; } +static uint8_t unpack_dbt_table_tlv_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nr_dbt_pdu_t *dbt_config = (nfapi_nr_dbt_pdu_t *)tlv; + if (!(pull16(ppReadPackedMsg, &dbt_config->num_dig_beams, end) && pull16(ppReadPackedMsg, &dbt_config->num_txrus, end))) { + return 0; + } + if (dbt_config->num_dig_beams > 0) { + dbt_config->dig_beam_list = calloc(dbt_config->num_dig_beams, sizeof(*dbt_config->dig_beam_list)); + } + for (int i = 0; i < dbt_config->num_dig_beams; i++) { + nfapi_nr_dig_beam_t *dig_beam = &dbt_config->dig_beam_list[i]; + if (!(pull16(ppReadPackedMsg, &dig_beam->beam_idx, end))) { + return 0; + } + if (dbt_config->num_txrus > 0) { + dig_beam->txru_list = calloc(dbt_config->num_txrus, sizeof(*dig_beam->txru_list)); + } + for (int k = 0; k < dbt_config->num_txrus; k++) { + nfapi_nr_txru_t *tx_ru = &dig_beam->txru_list[k]; + if (!(pull16(ppReadPackedMsg, &tx_ru->dig_beam_weight_Re, end) && pull16(ppReadPackedMsg, &tx_ru->dig_beam_weight_Im, end))) { + return 0; + } + } + } + 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 @@ -1221,6 +1332,8 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * {NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), &unpack_uint8_tlv_value}, {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}, @@ -1268,6 +1381,14 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx], ppReadPackedMsg, end); beam_ve_idx ++; break; + case NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG: + 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 1b5e3f0ad8..4c3f32ef27 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c @@ -259,6 +259,40 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const EQ_TLV(unpacked_req->measurement_config.rssi_measurement, req->measurement_config.rssi_measurement); + EQ(unpacked_req->dbt_config.num_dig_beams, req->dbt_config.num_dig_beams); + + EQ(unpacked_req->dbt_config.num_txrus, req->dbt_config.num_txrus); + + for (int i = 0; i < req->dbt_config.num_dig_beams; i++) { + const nfapi_nr_dig_beam_t *unpacked_dig_beam = &unpacked_req->dbt_config.dig_beam_list[i]; + const nfapi_nr_dig_beam_t *req_dig_beam = &req->dbt_config.dig_beam_list[i]; + EQ(unpacked_dig_beam->beam_idx, req_dig_beam->beam_idx); + for (int k = 0; k < req->dbt_config.num_txrus; ++k) { + const nfapi_nr_txru_t *unpacked_tx_ru = &unpacked_dig_beam->txru_list[k]; + const nfapi_nr_txru_t *req_tx_ru = &req_dig_beam->txru_list[k]; + EQ(unpacked_tx_ru->dig_beam_weight_Re, req_tx_ru->dig_beam_weight_Re); + EQ(unpacked_tx_ru->dig_beam_weight_Im, req_tx_ru->dig_beam_weight_Im); + } + } + + 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]); @@ -391,27 +425,20 @@ bool eq_error_indication(const nfapi_nr_error_indication_scf_t *unpacked_req, co void free_param_request(nfapi_nr_param_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_param_response(nfapi_nr_param_response_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); + + free(msg->cell_param.config_tlvs_to_report_list); - if (msg->cell_param.config_tlvs_to_report_list) { - free(msg->cell_param.config_tlvs_to_report_list); - } } void free_config_request(nfapi_nr_config_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); if (msg->prach_config.num_prach_fd_occasions_list) { for (int i = 0; i < msg->prach_config.num_prach_fd_occasions.value; i++) { @@ -430,10 +457,14 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) free(msg->tdd_table.max_tdd_periodicity_list); } - if (msg->pmi_list.pmi_pdu) { - free(msg->pmi_list.pmi_pdu); + for (int i = 0; i < msg->dbt_config.num_dig_beams; i++) { + free(msg->dbt_config.dig_beam_list[i].txru_list); } + free(msg->dbt_config.dig_beam_list); + + free(msg->pmi_list.pmi_pdu); + if (msg->analog_beamforming_ve.analog_beam_list) { free(msg->analog_beamforming_ve.analog_beam_list); } @@ -441,60 +472,40 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) void free_config_response(nfapi_nr_config_response_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); - if (msg->invalid_tlvs_list) { - free(msg->invalid_tlvs_list); - } + free(msg->invalid_tlvs_list); - if (msg->invalid_tlvs_configured_in_idle_list) { - free(msg->invalid_tlvs_configured_in_idle_list); - } + free(msg->invalid_tlvs_configured_in_idle_list); - if (msg->invalid_tlvs_configured_in_running_list) { - free(msg->invalid_tlvs_configured_in_running_list); - } + free(msg->invalid_tlvs_configured_in_running_list); - if (msg->missing_tlvs_list) { - free(msg->missing_tlvs_list); - } + free(msg->missing_tlvs_list); } void free_start_request(nfapi_nr_start_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_start_response(nfapi_nr_start_response_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_stop_request(nfapi_nr_stop_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_stop_indication(nfapi_nr_stop_indication_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_error_indication(nfapi_nr_error_indication_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void copy_param_request(const nfapi_nr_param_request_scf_t *src, nfapi_nr_param_request_scf_t *dst) @@ -810,6 +821,42 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf COPY_TLV(dst->measurement_config.rssi_measurement, src->measurement_config.rssi_measurement); + dst->dbt_config.num_dig_beams = src->dbt_config.num_dig_beams; + dst->dbt_config.num_txrus = src->dbt_config.num_txrus; + dst->dbt_config.dig_beam_list = calloc(dst->dbt_config.num_dig_beams, sizeof(*dst->dbt_config.dig_beam_list)); + for (int i = 0; i < dst->dbt_config.num_dig_beams; i++) { + nfapi_nr_dig_beam_t *dst_dig_beam = &dst->dbt_config.dig_beam_list[i]; + const nfapi_nr_dig_beam_t *src_dig_beam = &src->dbt_config.dig_beam_list[i]; + dst_dig_beam->beam_idx = src_dig_beam->beam_idx; + dst_dig_beam->txru_list = calloc(dst->dbt_config.num_txrus , sizeof(*dst_dig_beam->txru_list )); + for (int k = 0; k < dst->dbt_config.num_txrus; ++k) { + nfapi_nr_txru_t *dst_tx_ru = &dst_dig_beam->txru_list[k]; + const nfapi_nr_txru_t *src_tx_ru = &src_dig_beam->txru_list[k]; + dst_tx_ru->dig_beam_weight_Re = src_tx_ru->dig_beam_weight_Re; + dst_tx_ru->dig_beam_weight_Im = src_tx_ru->dig_beam_weight_Im; + } + } + + 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, @@ -986,22 +1033,382 @@ void dump_param_request(const nfapi_nr_param_request_scf_t *msg) void dump_param_response(const nfapi_nr_param_response_scf_t *msg) { int depth = 0; - dump_p5_message_header(&msg->header,depth); + dump_p5_message_header(&msg->header, depth); depth++; INDENTED_PRINTF("Error Code = 0x%02x\n", msg->error_code); INDENTED_PRINTF("Number of TLVs = 0x%02x\n", msg->num_tlv); /* dump all TLVs from each table */ + /* Cell Param */ + const nfapi_nr_cell_param_t *cell_param = &msg->cell_param; + depth++; + INDENTED_TLV_PRINT("Release Capability", cell_param->release_capability); + INDENTED_TLV_PRINT("PHY State", cell_param->phy_state); + INDENTED_TLV_PRINT("Skip Blank Dl Config", cell_param->skip_blank_dl_config); + INDENTED_TLV_PRINT("Skip Blank UL Config", cell_param->skip_blank_ul_config); + INDENTED_TLV_PRINT("NumConfigTLVsToReport", cell_param->num_config_tlvs_to_report); + depth++; + for (int i = 0; i < cell_param->num_config_tlvs_to_report.value; i++) { + const nfapi_uint8_tlv_t *reportedTLV = &cell_param->config_tlvs_to_report_list[i]; + INDENTED_PRINTF("(0x%04x) Reported CONFIG TLV #%d = 0x%02x\n", reportedTLV->tl.tag, i + 1, reportedTLV->value); + } + depth--; + /* Carrier Param */ + const nfapi_nr_carrier_param_t *carrier_param = &msg->carrier_param; + INDENTED_TLV_PRINT("Cyclic Prefix", carrier_param->cyclic_prefix); + INDENTED_TLV_PRINT("Supported SCS DL", carrier_param->supported_subcarrier_spacings_dl); + INDENTED_TLV_PRINT("Supported BW DL", carrier_param->supported_bandwidth_dl); + INDENTED_TLV_PRINT("Supported SCS UL", carrier_param->supported_subcarrier_spacings_ul); + INDENTED_TLV_PRINT("Supported BW UL", carrier_param->supported_bandwidth_ul); + /* PDCCH Param */ + const nfapi_nr_pdcch_param_t *pdcch_param = &msg->pdcch_param; + INDENTED_TLV_PRINT("CCE Mapping Type", pdcch_param->cce_mapping_type); + INDENTED_TLV_PRINT("CSet Outside First 3 OFDM Symbols of Slot", pdcch_param->coreset_outside_first_3_of_ofdm_syms_of_slot); + INDENTED_TLV_PRINT("Precoder Granularity Coreset", pdcch_param->coreset_precoder_granularity_coreset); + INDENTED_TLV_PRINT("PDCCH Mu MIMO", pdcch_param->pdcch_mu_mimo); + INDENTED_TLV_PRINT("PDCCH Precoder Cycling", pdcch_param->pdcch_precoder_cycling); + INDENTED_TLV_PRINT("Max PDCCH per Slot", pdcch_param->max_pdcch_per_slot); + /* PUCHH Params */ + const nfapi_nr_pucch_param_t *pucch_param = &msg->pucch_param; + INDENTED_TLV_PRINT("PUCCH Formats", pucch_param->pucch_formats); + INDENTED_TLV_PRINT("Max PUCCH per Slot", pucch_param->max_pucchs_per_slot); + /* PDSCH Params */ + const nfapi_nr_pdsch_param_t *pdsch_param = &msg->pdsch_param; + INDENTED_TLV_PRINT("PDSCH Mapping Type", pdsch_param->pdsch_mapping_type); + INDENTED_TLV_PRINT("PDSCH Allocation Types", pdsch_param->pdsch_allocation_types); + INDENTED_TLV_PRINT("PDSCH VRB to PRB Mapping", pdsch_param->pdsch_vrb_to_prb_mapping); + INDENTED_TLV_PRINT("PDSCH CBG", pdsch_param->pdsch_cbg); + INDENTED_TLV_PRINT("PDSCH DMRS Config Types", pdsch_param->pdsch_dmrs_config_types); + INDENTED_TLV_PRINT("PDSCH DMRS Max Length", pdsch_param->pdsch_dmrs_max_length); + INDENTED_TLV_PRINT("PDSCH DMRS Additional Position", pdsch_param->pdsch_dmrs_additional_pos); + INDENTED_TLV_PRINT("Max PDSCH TBs per Slot", pdsch_param->max_pdsch_tbs_per_slot); + INDENTED_TLV_PRINT("Max number MIMO Layers PDSCH", pdsch_param->max_number_mimo_layers_pdsch); + INDENTED_TLV_PRINT("Supported Max Modulation Order DL", pdsch_param->supported_max_modulation_order_dl); + INDENTED_TLV_PRINT("Max Mu MIMO Users DL", pdsch_param->max_mu_mimo_users_dl); + INDENTED_TLV_PRINT("PDSCH Data in DMRS Symbols", pdsch_param->pdsch_data_in_dmrs_symbols); + INDENTED_TLV_PRINT("Preemption Support", pdsch_param->premption_support); + INDENTED_TLV_PRINT("PDSCH Non Slot Support", pdsch_param->pdsch_non_slot_support); + /* PUSCH Params */ + const nfapi_nr_pusch_param_t *pusch_param = &msg->pusch_param; + INDENTED_TLV_PRINT("UCI Mux ULSCH in PUSCH", pusch_param->uci_mux_ulsch_in_pusch); + INDENTED_TLV_PRINT("UCI Only PUSCH", pusch_param->uci_only_pusch); + INDENTED_TLV_PRINT("PUSCH Frequency Hopping", pusch_param->pusch_frequency_hopping); + INDENTED_TLV_PRINT("PUSCH DMRS Config Types", pusch_param->pusch_dmrs_config_types); + INDENTED_TLV_PRINT("PUSCH DMRS Max Len", pusch_param->pusch_dmrs_max_len); + INDENTED_TLV_PRINT("PUSCH DMRS Additional Pos", pusch_param->pusch_dmrs_additional_pos); + INDENTED_TLV_PRINT("PUSCH CBG", pusch_param->pusch_cbg); + INDENTED_TLV_PRINT("PUSCH Mapping Type", pusch_param->pusch_mapping_type); + INDENTED_TLV_PRINT("PUSCH Allocation Types", pusch_param->pusch_allocation_types); + INDENTED_TLV_PRINT("PUSCH VRB to PRB Mapping", pusch_param->pusch_vrb_to_prb_mapping); + INDENTED_TLV_PRINT("PUSCH Max PTRS Ports", pusch_param->pusch_max_ptrs_ports); + INDENTED_TLV_PRINT("Max PUSCH TBs per Slot", pusch_param->max_pduschs_tbs_per_slot); + INDENTED_TLV_PRINT("Max Number MIMO Layers non CB PUSCH", pusch_param->max_number_mimo_layers_non_cb_pusch); + INDENTED_TLV_PRINT("Supported Modulation Order UL", pusch_param->supported_modulation_order_ul); + INDENTED_TLV_PRINT("Max MU MIMO Users UL", pusch_param->max_mu_mimo_users_ul); + INDENTED_TLV_PRINT("DTFS OFDM Support", pusch_param->dfts_ofdm_support); + INDENTED_TLV_PRINT("PUSCH Aggregation Factor", pusch_param->pusch_aggregation_factor); + /* PRACH Params */ + const nfapi_nr_prach_param_t *prach_param = &msg->prach_param; + INDENTED_TLV_PRINT("PRACH Long Formats", prach_param->prach_long_formats); + INDENTED_TLV_PRINT("PRACH Short Formats", prach_param->prach_short_formats); + INDENTED_TLV_PRINT("PRACH Restricted Sets", prach_param->prach_restricted_sets); + INDENTED_TLV_PRINT("Max PRACH Occasions in a Slot", prach_param->max_prach_fd_occasions_in_a_slot); + /* Measurement Params */ + const nfapi_nr_measurement_param_t *measurement_param = &msg->measurement_param; + INDENTED_TLV_PRINT("RSSI Measurement Support", measurement_param->rssi_measurement_support); + /* nFAPI Config */ + const nfapi_nr_nfapi_t *nfapi_config = &msg->nfapi_config; + if (nfapi_config->p7_vnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv4", + "%s", + nfapi_config->p7_vnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_vnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_vnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv6", + "%s", + nfapi_config->p7_vnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_vnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 VNF Port", "%d", nfapi_config->p7_vnf_port); + + if (nfapi_config->p7_pnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv4", + "%s", + nfapi_config->p7_pnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_pnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_pnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv6", + "%s", + nfapi_config->p7_pnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_pnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 PNF Port", "%d", nfapi_config->p7_pnf_port); + INDENTED_TLV_FORMAT_PRINT("Timing Window", "%d", nfapi_config->timing_window); + INDENTED_TLV_FORMAT_PRINT("Timing Info Mode", "%d", nfapi_config->timing_info_mode); + INDENTED_TLV_FORMAT_PRINT("Timing Info Period", "%d", nfapi_config->timing_info_period); + INDENTED_TLV_FORMAT_PRINT("DL_TTI Timing Offset", "%d", nfapi_config->dl_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_TTI Timing Offset", "%d", nfapi_config->ul_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_DCI Timing Offset", "%d", nfapi_config->ul_dci_timing_offset); + INDENTED_TLV_FORMAT_PRINT("TX_DATA Timing Offset", "%d", nfapi_config->tx_data_timing_offset); depth--; } void dump_config_request(const nfapi_nr_config_request_scf_t *msg) { int depth = 0; - dump_p5_message_header(&msg->header,depth); + dump_p5_message_header(&msg->header, depth); depth++; INDENTED_PRINTF("Number of TLVs = 0x%02x\n", msg->num_tlv); /* dump all TLVs from each table */ + /* Carrier Config */ + const nfapi_nr_carrier_config_t *carrier_config = &msg->carrier_config; + INDENTED_TLV_PRINT("DL Bandwidth", carrier_config->dl_bandwidth); + INDENTED_TLV_PRINT("DL Frequency", carrier_config->dl_frequency); + INDENTED_PRINTF("(0x%04x) DL K0 = ", NFAPI_NR_CONFIG_DL_K0_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->dl_k0[i].value); + } + printf("\n"); + INDENTED_PRINTF("(0x%04x) DL Grid Size = ", NFAPI_NR_CONFIG_DL_GRID_SIZE_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->dl_grid_size[i].value); + } + printf("\n"); + INDENTED_TLV_PRINT("Num TX Antennas", carrier_config->num_tx_ant); + INDENTED_TLV_PRINT("UL Bandwidth", carrier_config->uplink_bandwidth); + INDENTED_TLV_PRINT("UL Frequency", carrier_config->uplink_frequency); + INDENTED_PRINTF("(0x%04x) UL K0 = ", NFAPI_NR_CONFIG_UL_K0_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->ul_k0[i].value); + } + printf("\n"); + INDENTED_PRINTF("(0x%04x) UL Grid Size = ", NFAPI_NR_CONFIG_UL_GRID_SIZE_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->ul_grid_size[i].value); + } + printf("\n"); + INDENTED_TLV_PRINT("Num RX Antennas", carrier_config->num_rx_ant); + INDENTED_TLV_PRINT("Frequency Shift 7p5KHz", carrier_config->frequency_shift_7p5khz); + /* Cell Config */ + const nfapi_nr_cell_config_t *cell_config = &msg->cell_config; + INDENTED_TLV_PRINT("Physical Cell ID", cell_config->phy_cell_id); + INDENTED_TLV_PRINT("Frame Duplex Type", cell_config->frame_duplex_type); + /* SSB Config */ + const nfapi_nr_ssb_config_t *ssb_config = &msg->ssb_config; + INDENTED_TLV_PRINT("SSB Block Power", ssb_config->ss_pbch_power); + INDENTED_TLV_PRINT("BCH Payload", ssb_config->bch_payload); + INDENTED_TLV_PRINT("SCS Common", ssb_config->scs_common); + /* PRACH Config */ + const nfapi_nr_prach_config_t *prach_config = &msg->prach_config; + INDENTED_TLV_PRINT("PRACH Sequence Length", prach_config->prach_sequence_length); + INDENTED_TLV_PRINT("PRACH Subcarrier Spacing", prach_config->prach_sub_c_spacing); + INDENTED_TLV_PRINT("Restricted Set Config", prach_config->restricted_set_config); + INDENTED_TLV_PRINT("Num PRACH FD Occasions", prach_config->num_prach_fd_occasions); + INDENTED_TLV_PRINT("PRACH Config Index", prach_config->prach_ConfigurationIndex); + depth++; + for (int i = 0; i < prach_config->num_prach_fd_occasions.value; i++) { + const nfapi_nr_num_prach_fd_occasions_t *prach_fd_occasion = &(prach_config->num_prach_fd_occasions_list[i]); + INDENTED_TLV_PRINT("PRACH Root Sequence Index", prach_fd_occasion->prach_root_sequence_index); + INDENTED_TLV_PRINT("Num Root Sequences", prach_fd_occasion->num_root_sequences); + INDENTED_TLV_PRINT("K1", prach_fd_occasion->k1); + INDENTED_TLV_PRINT("PRACH Zero CorrelationZone Config", prach_fd_occasion->prach_zero_corr_conf); + INDENTED_TLV_PRINT("Num Unused Root Sequences", prach_fd_occasion->num_unused_root_sequences); + depth++; + for (int k = 0; k < prach_fd_occasion->num_unused_root_sequences.value; k++) { + INDENTED_TLV_PRINT("Unused Root Sequence", prach_fd_occasion->unused_root_sequences_list[k]); + } + depth--; + } depth--; + INDENTED_TLV_PRINT("SSB Per RACH", prach_config->ssb_per_rach); + INDENTED_TLV_PRINT("PRACH Multiple Carriers in a Band", prach_config->prach_multiple_carriers_in_a_band); + /* SSB Table */ + const nfapi_nr_ssb_table_t *ssb_table = &msg->ssb_table; + INDENTED_TLV_PRINT("SSB Offset PointA", ssb_table->ssb_offset_point_a); + INDENTED_TLV_PRINT("Beta PSS", ssb_table->beta_pss); + INDENTED_TLV_PRINT("SSB Period", ssb_table->ssb_period); + INDENTED_TLV_PRINT("SSB Subcarrier Offset", ssb_table->ssb_subcarrier_offset); + INDENTED_TLV_PRINT("MIB", ssb_table->MIB); + + INDENTED_PRINTF("SSB Mask:\n"); + depth++; + for (int i = 0; i < 2; i++) { + INDENTED_TLV_PRINT("SSB Mask", ssb_table->ssb_mask_list[i].ssb_mask); + } + depth--; + INDENTED_PRINTF("Beam ID:\n"); + depth++; + for (int i = 0; i < 64; i++) { + INDENTED_TLV_PRINT("Beam ID", ssb_table->ssb_beam_id_list[i].beam_id); + } + depth--; + INDENTED_TLV_PRINT("ssPBCH Multiple Carriers in a Band", ssb_table->ss_pbch_multiple_carriers_in_a_band); + INDENTED_TLV_PRINT("Multiple Cells ssPBCH in a Carrier", ssb_table->multiple_cells_ss_pbch_in_a_carrier); + /* TDD Table */ + const nfapi_nr_tdd_table_t *tdd_table = &msg->tdd_table; + if (cell_config->frame_duplex_type.value == 1 /* TDD */) { + INDENTED_TLV_PRINT("TDD Period", tdd_table->tdd_period); + const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160}; + // Assuming always CP_Normal, because Cyclic prefix is not included in CONFIG.request 10.02, but is present in 10.04 + uint8_t cyclicprefix = 1; + // 3GPP 38.211 Table 4.3.2.1 & Table 4.3.2.2 + uint8_t number_of_symbols_per_slot = cyclicprefix ? 14 : 12; + INDENTED_PRINTF("Slot Config:\n"); + depth++; + for (int i = 0; i < slotsperframe[ssb_config->scs_common.value]; i++) { + for (int k = 0; k < number_of_symbols_per_slot; k++) { + const uint8_t slot_type = tdd_table->max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[k].slot_config.value; + const char *slot_dir = slot_type == 0 ? "DL" : slot_type == 1 ? "UL" : "S"; + INDENTED_GENERIC_PRINT("(0x%04x) Slot Config", + "%d (%s)", + tdd_table->max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[k].slot_config.tl.tag, + slot_type, + slot_dir); + } + } + depth--; + } + /* Measurement Config */ + const nfapi_nr_measurement_config_t *measurement_config = &msg->measurement_config; + INDENTED_TLV_PRINT("RSSI Measurement", measurement_config->rssi_measurement); + /* Beamforming Table */ + const nfapi_nr_dbt_pdu_t *dbt_config = &msg->dbt_config; + INDENTED_PRINTF("Digital Beam Table\n"); + depth++; + INDENTED_GENERIC_PRINT("Num Digital Beams", "%d", dbt_config->num_dig_beams); + INDENTED_GENERIC_PRINT("Num TX RUs", "%d", dbt_config->num_txrus); + depth++; + for (int i = 0; i < dbt_config->num_dig_beams; i++) { + const nfapi_nr_dig_beam_t *dig_beam = &dbt_config->dig_beam_list[i]; + INDENTED_GENERIC_PRINT("Beam IDX", "%d", dig_beam->beam_idx); + depth++; + for (int k = 0; k < dbt_config->num_txrus; k++) { + const nfapi_nr_txru_t *tx_ru = &dig_beam->txru_list[k]; + INDENTED_GENERIC_PRINT("Dig Beam Weight Real", "0x%02x", tx_ru->dig_beam_weight_Re); + INDENTED_GENERIC_PRINT("Dig Beam Weight Imaginary", "0x%02x", tx_ru->dig_beam_weight_Im); + } + depth--; + } + depth--; + depth--; + + /* Precoding Table */ + const nfapi_nr_pm_list_t *pmi_list = &msg->pmi_list; + INDENTED_PRINTF("Precoding Matrix Table\n"); + depth++; + INDENTED_GENERIC_PRINT("Num Precoding Tables", "%d", pmi_list->num_pm_idx); + depth++; + for (int i = 0; i < pmi_list->num_pm_idx; i++) { + const nfapi_nr_pm_pdu_t *pm_pdu = &pmi_list->pmi_pdu[i]; + + INDENTED_GENERIC_PRINT("Precoding Matrix IDX", "0x%02x", pm_pdu->pm_idx); + INDENTED_GENERIC_PRINT("Number of Layers", "%d", pm_pdu->numLayers); + INDENTED_GENERIC_PRINT("Number of Antenna Ports", "%d", pm_pdu->num_ant_ports); + depth++; + for (int k = 0; k < pm_pdu->numLayers; k++) { + for (int l = 0; l < pm_pdu->num_ant_ports; l++) { + const nfapi_nr_pm_weights_t *pm_weights = &pm_pdu->weights[k][l]; + INDENTED_GENERIC_PRINT("Dig Beam Weight Real", "0x%02x", pm_weights->precoder_weight_Re); + INDENTED_GENERIC_PRINT("Dig Beam Weight Imaginary", "0x%02x", pm_weights->precoder_weight_Im); + } + } + depth--; + } + depth--; + depth--; + /* nFAPI Config */ + const nfapi_nr_nfapi_t *nfapi_config = &msg->nfapi_config; + if (nfapi_config->p7_vnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv4", + "%s", + nfapi_config->p7_vnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_vnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_vnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv6", + "%s", + nfapi_config->p7_vnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_vnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 VNF Port", "%d", nfapi_config->p7_vnf_port); + + if (nfapi_config->p7_pnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv4", + "%s", + nfapi_config->p7_pnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_pnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_pnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv6", + "%s", + nfapi_config->p7_pnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_pnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 PNF Port", "%d", nfapi_config->p7_pnf_port); + INDENTED_TLV_FORMAT_PRINT("Timing Window", "%d", nfapi_config->timing_window); + INDENTED_TLV_FORMAT_PRINT("Timing Info Mode", "%d", nfapi_config->timing_info_mode); + INDENTED_TLV_FORMAT_PRINT("Timing Info Period", "%d", nfapi_config->timing_info_period); + INDENTED_TLV_FORMAT_PRINT("DL_TTI Timing Offset", "%d", nfapi_config->dl_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_TTI Timing Offset", "%d", nfapi_config->ul_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_DCI Timing Offset", "%d", nfapi_config->ul_dci_timing_offset); + INDENTED_TLV_FORMAT_PRINT("TX_DATA Timing Offset", "%d", nfapi_config->tx_data_timing_offset); + /* Beamforming VE */ + const nfapi_nr_analog_beamforming_ve_t *analog_beamforming_ve = &msg->analog_beamforming_ve; + INDENTED_TLV_FORMAT_PRINT("Num Beams per Period", "%d", analog_beamforming_ve->num_beams_period_vendor_ext); + INDENTED_TLV_PRINT("Analog Beamforming VE", analog_beamforming_ve->analog_bf_vendor_ext); + /* Vendor Extension */ + if (msg->vendor_extension) { + const nfapi_tl_t *vendor_extension = (nfapi_tl_t *)&msg->vendor_extension; + switch (vendor_extension->tag) { + case VENDOR_EXT_TLV_1_TAG: { + vendor_ext_tlv_1 *ve = (vendor_ext_tlv_1 *)vendor_extension; + INDENTED_PRINTF("(0x%04x) Vendor extension = %d 0x%02x\n", ve->tl.tag, ve->tl.length, ve->dummy); + } break; + case VENDOR_EXT_TLV_2_TAG: { + vendor_ext_tlv_2 *ve = (vendor_ext_tlv_2 *)vendor_extension; + INDENTED_PRINTF("(0x%04x) Vendor extension = %d 0x%02x\n", ve->tl.tag, ve->tl.length, ve->dummy); + } break; + default: + break; + } + } + + depth--; +} + +static void dump_generic_tlv(const nfapi_nr_generic_tlv_scf_t* tlv, int depth) +{ + INDENTED_PRINTF("TLV tag 0x%02x , Length 0x%02x , Value ", tlv->tl.tag, tlv->tl.length); + switch (tlv->tl.length) { + case UINT_8: + printf("0x%x\n", tlv->value.u8); + break; + case UINT_16: + printf("0x%02x\n", tlv->value.u16); + break; + case UINT_32: + printf("0x%04x\n", tlv->value.u32); + break; + case ARRAY_UINT_16: + for (int i = 0; i< 5 ; i++) { + printf("0x%04x ", tlv->value.array_u16[i]); + } + printf("\n"); + break; + default: + printf("unknown length %d\n", tlv->tl.length); + DevAssert(1 == 0); + break; + } } void dump_config_response(const nfapi_nr_config_response_scf_t *msg) @@ -1016,6 +1423,25 @@ void dump_config_response(const nfapi_nr_config_response_scf_t *msg) msg->num_invalid_tlvs_configured_in_running); INDENTED_PRINTF("Number of Missing TLVs = 0x%02x\n", msg->num_missing_tlvs); /* dump all TLVs from each table */ + INDENTED_PRINTF("Invalid or Unsupported TLVs (%d) :\n",msg->num_invalid_tlvs); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } + + INDENTED_PRINTF("TLVs that can only be configured in IDLE (%d):\n", msg->num_invalid_tlvs_configured_in_idle); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } + + INDENTED_PRINTF("TLVs that can only be configured in RUNNING (%d):\n",msg->num_invalid_tlvs_configured_in_running); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } + + INDENTED_PRINTF("Missing TLVs (%d):\n",msg->num_missing_tlvs); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } depth--; } diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c index 9939a6f535..fb645707ad 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c @@ -859,9 +859,7 @@ bool eq_rach_indication(const nfapi_nr_rach_indication_t *a, const nfapi_nr_rach void free_dl_tti_request(nfapi_nr_dl_tti_request_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_ul_tti_request(nfapi_nr_ul_tti_request_t *msg) @@ -907,9 +905,7 @@ void free_rx_data_indication(nfapi_nr_rx_data_indication_t *msg) if (msg->number_of_pdus > 0) { for (int pdu_idx = 0; pdu_idx < msg->number_of_pdus; ++pdu_idx) { nfapi_nr_rx_data_pdu_t *rx_pdu = &msg->pdu_list[pdu_idx]; - if (rx_pdu->pdu) { - free(rx_pdu->pdu); - } + free(rx_pdu->pdu); } free(msg->pdu_list); } @@ -917,99 +913,75 @@ void free_rx_data_indication(nfapi_nr_rx_data_indication_t *msg) void free_crc_indication(nfapi_nr_crc_indication_t *msg) { - if (msg->crc_list) { - for (int crc_idx = 0; crc_idx < msg->number_crcs; ++crc_idx) { - nfapi_nr_crc_t *crc = &msg->crc_list[crc_idx]; - if (crc->cb_crc_status) { - free(crc->cb_crc_status); - } - } - free(msg->crc_list); + for (int crc_idx = 0; crc_idx < msg->number_crcs; ++crc_idx) { + nfapi_nr_crc_t *crc = &msg->crc_list[crc_idx]; + free(crc->cb_crc_status); } + free(msg->crc_list); } void free_uci_indication(nfapi_nr_uci_indication_t *msg) { - if (msg->uci_list) { - for (int pdu_idx = 0; pdu_idx < msg->num_ucis; ++pdu_idx) { - nfapi_nr_uci_t *uci_pdu = &msg->uci_list[pdu_idx]; - switch (uci_pdu->pdu_type) { - case NFAPI_NR_UCI_PUSCH_PDU_TYPE: { - nfapi_nr_uci_pusch_pdu_t *pdu = &uci_pdu->pusch_pdu; - // Bit 0 not used in PUSCH PDU - // HARQ - if ((pdu->pduBitmap >> 1) & 0x01) { - if (pdu->harq.harq_payload) { - free(pdu->harq.harq_payload); - } - } - // CSI Part 1 - if ((pdu->pduBitmap >> 2) & 0x01) { - if (pdu->csi_part1.csi_part1_payload) { - free(pdu->csi_part1.csi_part1_payload); - } - } - // CSI Part 2 - if ((pdu->pduBitmap >> 3) & 0x01) { - if (pdu->csi_part2.csi_part2_payload) { - free(pdu->csi_part2.csi_part2_payload); - } - } - break; + for (int pdu_idx = 0; pdu_idx < msg->num_ucis; ++pdu_idx) { + nfapi_nr_uci_t *uci_pdu = &msg->uci_list[pdu_idx]; + switch (uci_pdu->pdu_type) { + case NFAPI_NR_UCI_PUSCH_PDU_TYPE: { + nfapi_nr_uci_pusch_pdu_t *pdu = &uci_pdu->pusch_pdu; + // Bit 0 not used in PUSCH PDU + // HARQ + if ((pdu->pduBitmap >> 1) & 0x01) { + free(pdu->harq.harq_payload); } - case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: { - // Nothing to free - break; + // CSI Part 1 + if ((pdu->pduBitmap >> 2) & 0x01) { + free(pdu->csi_part1.csi_part1_payload); } - case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: { - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu = &uci_pdu->pucch_pdu_format_2_3_4; - // SR - if (pdu->pduBitmap & 0x01) { - if (pdu->sr.sr_payload) { - free(pdu->sr.sr_payload); - } - } - // HARQ - if ((pdu->pduBitmap >> 1) & 0x01) { - if (pdu->harq.harq_payload) { - free(pdu->harq.harq_payload); - } - } - // CSI Part 1 - if ((pdu->pduBitmap >> 2) & 0x01) { - if (pdu->csi_part1.csi_part1_payload) { - free(pdu->csi_part1.csi_part1_payload); - } - } - // CSI Part 2 - if ((pdu->pduBitmap >> 3) & 0x01) { - if (pdu->csi_part2.csi_part2_payload) { - free(pdu->csi_part2.csi_part2_payload); - } - } - break; + // CSI Part 2 + if ((pdu->pduBitmap >> 3) & 0x01) { + free(pdu->csi_part2.csi_part2_payload); } - default: - AssertFatal(1 == 0, "Unknown UCI.indication PDU Type %d\n", uci_pdu->pdu_type); - break; + break; } + case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: { + // Nothing to free + break; + } + case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: { + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu = &uci_pdu->pucch_pdu_format_2_3_4; + // SR + if (pdu->pduBitmap & 0x01) { + free(pdu->sr.sr_payload); + } + // HARQ + if ((pdu->pduBitmap >> 1) & 0x01) { + free(pdu->harq.harq_payload); + } + // CSI Part 1 + if ((pdu->pduBitmap >> 2) & 0x01) { + free(pdu->csi_part1.csi_part1_payload); + } + // CSI Part 2 + if ((pdu->pduBitmap >> 3) & 0x01) { + free(pdu->csi_part2.csi_part2_payload); + } + break; + } + default: + AssertFatal(1 == 0, "Unknown UCI.indication PDU Type %d\n", uci_pdu->pdu_type); + break; } - free(msg->uci_list); } + free(msg->uci_list); } void free_srs_indication(nfapi_nr_srs_indication_t *msg) { - if (msg->pdu_list) { - free(msg->pdu_list); - } + free(msg->pdu_list); } void free_rach_indication(nfapi_nr_rach_indication_t *msg) { - if (msg->pdu_list) { - free(msg->pdu_list); - } + free(msg->pdu_list); } static void copy_dl_tti_beamforming(const nfapi_nr_tx_precoding_and_beamforming_t *src, @@ -2586,6 +2558,27 @@ void dump_ul_dci_request(const nfapi_nr_ul_dci_request_t *msg) } } +static void dump_tx_data_request_tlv(const nfapi_nr_tx_data_request_tlv_t *tlv, int depth) +{ + INDENTED_PRINTF("Tag = %d\n", tlv->tag); + INDENTED_PRINTF("Length = %d\n", tlv->length); + INDENTED_PRINTF("Value = "); + switch (tlv->tag) { + case 0: + for (int i = 0; i < tlv->length; i++) { + printf("0x%02x ", ((uint8_t*)tlv->value.direct)[i]); + } + break; + case 1: + printf("%p", tlv->value.ptr); + break; + default: + printf( " Unknown tag value %d",tlv->tag); + break; + } + printf("\n"); +} + void dump_tx_data_request(const nfapi_nr_tx_data_request_t *msg) { int depth = 0; @@ -2594,15 +2587,18 @@ void dump_tx_data_request(const nfapi_nr_tx_data_request_t *msg) INDENTED_PRINTF("SFN = %d\n", msg->SFN); INDENTED_PRINTF("Slot = %d\n", msg->Slot); INDENTED_PRINTF("Number of PDUs = %d\n", msg->Number_of_PDUs); + depth++; for (int i = 0; i < msg->Number_of_PDUs; i++) { - depth++; INDENTED_PRINTF("PDU #%d\n", i); const nfapi_nr_pdu_t *pdu = &msg->pdu_list[i]; INDENTED_PRINTF("PDU Length = 0x%02x\n", pdu->PDU_length); INDENTED_PRINTF("PDU Index = 0x%02x\n", pdu->PDU_index); INDENTED_PRINTF("numTLV = 0x%02x\n", pdu->num_TLV); + for (int tlv_idx = 0; tlv_idx < pdu->num_TLV; tlv_idx++) { + const nfapi_nr_tx_data_request_tlv_t *tlv = &pdu->TLVs[tlv_idx]; /* call to dump_tx_data_request_tlv */ - depth--; + dump_tx_data_request_tlv(tlv, depth + 1); + } } } @@ -2664,6 +2660,134 @@ void dump_crc_indication(const nfapi_nr_crc_indication_t *msg) } } +static void dump_harq_2_3_4(const nfapi_nr_harq_pdu_2_3_4_t *harq, int depth) +{ + INDENTED_PRINTF("HARQ CRC = %01x\n", harq->harq_crc); + INDENTED_PRINTF("HARQ Bit Length = %d\n", harq->harq_bit_len); + INDENTED_PRINTF("HARQ Payload = "); + for (int i = 0; i < harq->harq_bit_len / 8 + 1; i++) { + printf("%x ", harq->harq_payload[i]); + } + printf("\n"); +} + +static void dump_csi_part_1(const nfapi_nr_csi_part1_pdu_t *csi, int depth) +{ + INDENTED_PRINTF("CSI Part 1 CRC = %01x\n", csi->csi_part1_crc); + INDENTED_PRINTF("CSI Part 1 Bit Length = %d\n", csi->csi_part1_bit_len); + INDENTED_PRINTF("CSI Part 1 Payload = "); + for (int i = 0; i < csi->csi_part1_bit_len / 8 + 1; i++) { + printf("%x ", csi->csi_part1_payload[i]); + } + printf("\n"); +} + +static void dump_csi_part_2(const nfapi_nr_csi_part2_pdu_t *csi, int depth) +{ + INDENTED_PRINTF("CSI Part 1 CRC = %01x\n", csi->csi_part2_crc); + INDENTED_PRINTF("CSI Part 1 Bit Length = %d\n", csi->csi_part2_bit_len); + INDENTED_PRINTF("CSI Part 1 Payload = "); + for (int i = 0; i < csi->csi_part2_bit_len / 8 + 1; i++) { + printf("%x ", csi->csi_part2_payload[i]); + } + printf("\n"); +} + +static void dump_uci_PUSCH_PDU(const nfapi_nr_uci_pusch_pdu_t *pdu, int depth) +{ + INDENTED_PRINTF("PDU Bitmap = 0x%01x\n", pdu->pduBitmap); + INDENTED_PRINTF("Handle = 0x%04x\n", pdu->handle); + INDENTED_PRINTF("RNTI = 0x%02x\n", pdu->rnti); + INDENTED_PRINTF("UL_CQI = 0x%02x\n", pdu->ul_cqi); + INDENTED_PRINTF("Timing Advance = 0x%02x\n", pdu->timing_advance); + INDENTED_PRINTF("RSSI = 0x%02x\n", pdu->rssi); + // HARQ payload, CSI Part 1 and 2 are conditionally allocated + if ((pdu->pduBitmap >> 1) & 0x01) { + INDENTED_PRINTF("HARQ Information\n"); + dump_harq_2_3_4(&pdu->harq, depth + 1); + } + if ((pdu->pduBitmap >> 2) & 0x01) { + INDENTED_PRINTF("CSI Part 1\n"); + dump_csi_part_1(&pdu->csi_part1, depth + 1); + } + if ((pdu->pduBitmap >> 3) & 0x01) { + INDENTED_PRINTF("CSI Part 1\n"); + dump_csi_part_2(&pdu->csi_part2, depth + 1); + } +} + +static void dump_sr_0_1(const nfapi_nr_sr_pdu_0_1_t *sr, int depth) +{ + INDENTED_PRINTF("SR Indication = 0x%02x\n", sr->sr_indication); + INDENTED_PRINTF("SR Confidence Level = 0x%02x\n", sr->sr_confidence_level); +} + +static void dump_harq_0_1(const nfapi_nr_harq_pdu_0_1_t *harq, int depth) +{ + INDENTED_PRINTF("Num HARQ = 0x%02x\n", harq->num_harq); + INDENTED_PRINTF("HARQ Confidence Level = 0x%02x\n", harq->harq_confidence_level); + depth++; + for (int i = 0; i < harq->num_harq; i++) { + INDENTED_PRINTF("HARQ Value[%d] : 0x%02x \n", i, harq->harq_list[i].harq_value); + } +} + +static void dump_uci_PUCCH_0_1(const nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu, int depth) +{ + INDENTED_PRINTF("PDU Bitmap = 0x%01x\n", pdu->pduBitmap); + INDENTED_PRINTF("Handle = 0x%04x\n", pdu->handle); + INDENTED_PRINTF("RNTI = 0x%02x\n", pdu->rnti); + INDENTED_PRINTF("PUCCH Format = 0x%02x\n", pdu->pucch_format); + INDENTED_PRINTF("UL_CQI = 0x%02x\n", pdu->ul_cqi); + INDENTED_PRINTF("Timing Advance = 0x%02x\n", pdu->timing_advance); + INDENTED_PRINTF("RSSI = 0x%02x\n", pdu->rssi); + if ((pdu->pduBitmap) & 0x01) { + INDENTED_PRINTF("SR Information\n"); + dump_sr_0_1(&pdu->sr, depth + 1); + } + if ((pdu->pduBitmap >> 1) & 0x01) { + INDENTED_PRINTF("HARQ Information\n"); + dump_harq_0_1(&pdu->harq, depth + 1); + } +} + +static void dump_sr_2_3_4(const nfapi_nr_sr_pdu_2_3_4_t *sr, int depth) +{ + INDENTED_PRINTF("SR Bit Length = %d\n", sr->sr_bit_len); + INDENTED_PRINTF("SR Payload "); + for (int i = 0; i < sr->sr_bit_len / 8 + 1; i++) { + printf("%x ", sr->sr_payload[i]); + } + printf("\n"); +} + +static void dump_uci_PUCCH_2_3_4(const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu, int depth) +{ + INDENTED_PRINTF("PDU Bitmap = 0x%01x\n", pdu->pduBitmap); + INDENTED_PRINTF("Handle = 0x%04x\n", pdu->handle); + INDENTED_PRINTF("RNTI = 0x%02x\n", pdu->rnti); + INDENTED_PRINTF("PUCCH Format = 0x%02x\n", pdu->pucch_format); + INDENTED_PRINTF("UL_CQI = 0x%02x\n", pdu->ul_cqi); + INDENTED_PRINTF("Timing Advance = 0x%02x\n", pdu->timing_advance); + INDENTED_PRINTF("RSSI = 0x%02x\n", pdu->rssi); + // SR + if (pdu->pduBitmap & 0x01) { + dump_sr_2_3_4(&pdu->sr, depth + 1); + } + // HARQ + if ((pdu->pduBitmap >> 1) & 0x01) { + dump_harq_2_3_4(&pdu->harq, depth + 1); + } + // CSI Part 1 + if ((pdu->pduBitmap >> 2) & 0x01) { + dump_csi_part_1(&pdu->csi_part1, depth + 1); + } + // CSI Part 2 + if ((pdu->pduBitmap >> 3) & 0x01) { + dump_csi_part_2(&pdu->csi_part2, depth + 1); + } +} + void dump_uci_indication(const nfapi_nr_uci_indication_t *msg) { int depth = 0; @@ -2680,6 +2804,20 @@ void dump_uci_indication(const nfapi_nr_uci_indication_t *msg) INDENTED_PRINTF("PDUType = 0x%02x\n", uci->pdu_type); INDENTED_PRINTF("PDUSize = 0x%02x\n", uci->pdu_size); /* call to dump_uci_indication__pdu */ + switch (uci->pdu_type) { + case NFAPI_NR_UCI_PUSCH_PDU_TYPE: + dump_uci_PUSCH_PDU(&uci->pusch_pdu, depth + 1); + break; + case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: + dump_uci_PUCCH_0_1(&uci->pucch_pdu_format_0_1, depth + 1); + break; + case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: + dump_uci_PUCCH_2_3_4(&uci->pucch_pdu_format_2_3_4, depth + 1); + break; + default: + INDENTED_PRINTF("Unknown PDU type 0x%02x\n", uci->pdu_type); + break; + } depth--; } } diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index b7e6577fa2..eb668f3e73 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -34,6 +34,7 @@ #define NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG 0xA002 #define NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG 0xA003 + typedef struct { uint16_t phy_id; uint16_t message_id; 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 0533a76c6d..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 @@ -328,6 +328,8 @@ 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 @@ -473,6 +475,11 @@ typedef struct { nfapi_nr_dig_beam_t *dig_beam_list; } nfapi_nr_dbt_pdu_t; +typedef struct { + nfapi_tl_t tl; + nfapi_nr_dbt_pdu_t value; +} nfapi_nr_dbt_tlv_ve_t; + // Table 3–62 Precoding matrix (PM) PDU (v.222.10.04) typedef struct { int16_t precoder_weight_Re; @@ -491,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 93ff5b5f3a..82ce60ca3b 100644 --- a/nfapi/tests/p5/nr_fapi_config_request_test.c +++ b/nfapi/tests/p5/nr_fapi_config_request_test.c @@ -206,6 +206,47 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->measurement_config.rssi_measurement, NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, rand8()); nfapi_resp->num_tlv++; + uint16_t nb_beams = rand16_range(1, 15); + uint16_t nb_tx = rand16_range(1, 15); + nfapi_resp->dbt_config.num_dig_beams = nb_beams; + if (nfapi_resp->dbt_config.num_dig_beams > 0) { + nfapi_resp->dbt_config.num_txrus = nb_tx; + nfapi_resp->dbt_config.dig_beam_list = calloc(nb_beams , sizeof(*nfapi_resp->dbt_config.dig_beam_list)); + for (int i = 0; i < nb_beams; i++) { + nfapi_nr_dig_beam_t *beam = &nfapi_resp->dbt_config.dig_beam_list[i]; + beam->beam_idx = i; + beam->txru_list = calloc(nb_tx , sizeof(*beam->txru_list)); + for (int j = 0; j < nb_tx; j++) { + nfapi_nr_txru_t *txru = &beam->txru_list[j]; + txru->dig_beam_weight_Re = rand16_range(1, 0xffff); + txru->dig_beam_weight_Im = rand16_range(1, 0xffff); + } + } + 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(); @@ -221,6 +262,21 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->nfapi_config.p7_vnf_port, NFAPI_NR_NFAPI_P7_VNF_PORT_TAG, rand16()); nfapi_resp->num_tlv++; + nfapi_resp->nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NR_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + for (int i = 0; i < NFAPI_IPV4_ADDRESS_LENGTH; ++i) { + nfapi_resp->nfapi_config.p7_pnf_address_ipv4.address[i] = rand8(); + } + nfapi_resp->num_tlv++; + + nfapi_resp->nfapi_config.p7_pnf_address_ipv6.tl.tag = NFAPI_NR_NFAPI_P7_PNF_ADDRESS_IPV6_TAG; + for (int i = 0; i < NFAPI_IPV6_ADDRESS_LENGTH; ++i) { + nfapi_resp->nfapi_config.p7_pnf_address_ipv6.address[i] = rand8(); + } + nfapi_resp->num_tlv++; + + FILL_TLV(nfapi_resp->nfapi_config.p7_pnf_port, NFAPI_NR_NFAPI_P7_PNF_PORT_TAG, rand16()); + nfapi_resp->num_tlv++; + FILL_TLV(nfapi_resp->nfapi_config.timing_window, NFAPI_NR_NFAPI_TIMING_WINDOW_TAG, rand8()); nfapi_resp->num_tlv++;