Commit 6a725d6e authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

Merge remote-tracking branch 'origin/oran_beamforming_static_weights' into...

Merge remote-tracking branch 'origin/oran_beamforming_static_weights' into integration_2026_w13 (!3681)

Configure DigitalBeamTable in OAI and pass down to Aerial L1

With this MR it will be possible to define a Beamtable in OAI and pass it down
to a L1 (Aerial or OAI) which then will either use them locally to apply
static beamforming (Split 8 with USRP) or pass them down to the RU using 7.2
split with Section Extension 1.
parents a2f0cef8 878f6b3d
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <sys/epoll.h> #include <sys/epoll.h>
#include "fapi_nvIPC.h" #include "fapi_nvIPC.h"
#include <nfapi_vnf.h> #include <nfapi_vnf.h>
#include <nr_fapi_p5.h>
#include <nr_fapi_p7_utils.h> #include <nr_fapi_p7_utils.h>
#include "nfapi_interface.h" #include "nfapi_interface.h"
#include "nfapi.h" #include "nfapi.h"
...@@ -66,6 +67,7 @@ nv_ipc_t *ipc; ...@@ -66,6 +67,7 @@ nv_ipc_t *ipc;
static nv_ipc_config_t nv_ipc_config; static nv_ipc_config_t nv_ipc_config;
static int cpu_msg_buf_size = 0; static int cpu_msg_buf_size = 0;
static int cpu_data_buf_size = 0; static int cpu_data_buf_size = 0;
static int cpu_large_buf_size = 0;
void nvIPC_Stop() void nvIPC_Stop()
{ {
...@@ -238,11 +240,21 @@ bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_messa ...@@ -238,11 +240,21 @@ bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_messa
// Create the message // Create the message
nv_ipc_msg_t send_msg = {.msg_id = msg->message_id, nv_ipc_msg_t send_msg = {.msg_id = msg->message_id,
.cell_id = 0, .cell_id = 0,
// For P5 we don't need CPU_DATA // By default, P5 uses only message pool.
.data_pool = NV_IPC_MEMPOOL_CPU_MSG, .data_pool = NV_IPC_MEMPOOL_CPU_MSG,
.data_len = 0, .data_len = 0,
.data_buf = NULL}; .data_buf = NULL};
bool has_separate_dbt_payload = false;
nfapi_nr_config_request_scf_t *config_req = NULL;
if (msg->message_id == NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST) {
config_req = (nfapi_nr_config_request_scf_t *)msg;
has_separate_dbt_payload = config_req->dbt_config.num_dig_beams > 0;
if (has_separate_dbt_payload) {
send_msg.data_pool = NV_IPC_MEMPOOL_CPU_LARGE;
}
}
// Allocate the message // Allocate the message
if (!allocate_msg(&send_msg)) { if (!allocate_msg(&send_msg)) {
return false; return false;
...@@ -263,6 +275,31 @@ bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_messa ...@@ -263,6 +275,31 @@ bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_messa
} }
// Set the length // Set the length
send_msg.msg_len = packedMessageLengthFAPI + 8; // adding 8 to account for the size of the FAPI header send_msg.msg_len = packedMessageLengthFAPI + 8; // adding 8 to account for the size of the FAPI header
if (has_separate_dbt_payload) {
AssertFatal(send_msg.data_buf != NULL, "CONFIG.request DBT path: data buffer is NULL\n");
AssertFatal(cpu_large_buf_size > 0, "CONFIG.request DBT path: CPU_LARGE buffer size is not set\n");
uint8_t *write_ptr = send_msg.data_buf;
uint8_t *buffer_end = send_msg.data_buf + cpu_large_buf_size;
nfapi_nr_dbt_tlv_ve_t dbt_tlv = {
.tl.tag = NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG,
.value = config_req->dbt_config
};
bool ok = pack_dbt_table_tlv_value(&dbt_tlv, &write_ptr, buffer_end);
if (!ok) {
LOG_E(NFAPI_VNF, "Failed to pack CONFIG.request DBT payload into separate buffer\n");
release_msg(&send_msg);
return false;
}
send_msg.data_len = (uint32_t)(write_ptr - (uint8_t *)send_msg.data_buf);
LOG_I(NFAPI_VNF,
"CONFIG.request DBT sent in separate pool: num_beams=%u num_txrus=%u data_len=%d pool=%d\n",
config_req->dbt_config.num_dig_beams,
config_req->dbt_config.num_txrus,
send_msg.data_len,
send_msg.data_pool);
}
// Send // Send
return send_nvipc_msg(&send_msg); return send_nvipc_msg(&send_msg);
} else { } else {
...@@ -386,6 +423,7 @@ int nvIPC_Init(nvipc_params_t nvipc_params_s) ...@@ -386,6 +423,7 @@ int nvIPC_Init(nvipc_params_t nvipc_params_s)
// save the mempool sizes for later use in packing // save the mempool sizes for later use in packing
cpu_msg_buf_size = nv_ipc_get_buf_size(&nv_ipc_config, NV_IPC_MEMPOOL_CPU_MSG); cpu_msg_buf_size = nv_ipc_get_buf_size(&nv_ipc_config, NV_IPC_MEMPOOL_CPU_MSG);
cpu_data_buf_size = nv_ipc_get_buf_size(&nv_ipc_config, NV_IPC_MEMPOOL_CPU_DATA); cpu_data_buf_size = nv_ipc_get_buf_size(&nv_ipc_config, NV_IPC_MEMPOOL_CPU_DATA);
cpu_large_buf_size = nv_ipc_get_buf_size(&nv_ipc_config, NV_IPC_MEMPOOL_CPU_LARGE);
// Create nv_ipc_t instance // Create nv_ipc_t instance
LOG_I(NFAPI_VNF, "%s: creating IPC interface with prefix %s\n", __func__, nvipc_params_s.nvipc_shm_prefix); LOG_I(NFAPI_VNF, "%s: creating IPC interface with prefix %s\n", __func__, nvipc_params_s.nvipc_shm_prefix);
......
...@@ -54,4 +54,5 @@ uint8_t pack_nr_stop_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t * ...@@ -54,4 +54,5 @@ uint8_t pack_nr_stop_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *
uint8_t unpack_nr_stop_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config); uint8_t unpack_nr_stop_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config);
uint8_t pack_nr_error_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config); uint8_t pack_nr_error_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config);
uint8_t unpack_nr_error_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config); uint8_t unpack_nr_error_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config);
uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end);
#endif // OPENAIRINTERFACE_NR_FAPI_P5_H #endif // OPENAIRINTERFACE_NR_FAPI_P5_H
...@@ -721,8 +721,7 @@ uint8_t unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void * ...@@ -721,8 +721,7 @@ uint8_t unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *
config, config,
&pNfapiMsg->vendor_extension)); &pNfapiMsg->vendor_extension));
} }
#ifndef ENABLE_AERIAL uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end)
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_tlv_ve_t *dbt_ve = (nfapi_nr_dbt_tlv_ve_t *)tlv;
nfapi_nr_dbt_pdu_t *dbt_config = &dbt_ve->value; nfapi_nr_dbt_pdu_t *dbt_config = &dbt_ve->value;
...@@ -744,6 +743,7 @@ static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, u ...@@ -744,6 +743,7 @@ static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, u
return 1; return 1;
} }
#ifndef ENABLE_AERIAL
static uint8_t pack_pm_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) 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_tlv_ve_t *pm_ve = (nfapi_nr_pm_tlv_ve_t *)tlv;
...@@ -1143,15 +1143,35 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e ...@@ -1143,15 +1143,35 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
&pack_uint8_tlv_value); &pack_uint8_tlv_value);
numTLVs++; numTLVs++;
// END Measurement Config // END Measurement Config
#ifndef ENABLE_AERIAL
// START Digital Beam Table (DBT) PDU // START Digital Beam Table (DBT) PDU
if (pNfapiMsg->dbt_config.num_dig_beams != 0) { 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}; 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); #ifdef ENABLE_AERIAL
// For Aerial, DBT payload is sent in a separate nvIPC data buffer.
dbt_tlv.value.num_dig_beams = 0;
dbt_tlv.value.num_txrus = 0;
#endif
retval &= pack_nr_tlv(NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, &dbt_tlv, ppWritePackedMsg, end, &pack_dbt_table_tlv_value);
numTLVs++; numTLVs++;
} }
// END Digital Beam Table (DBT) PDU // END Digital Beam Table (DBT) PDU
#ifdef ENABLE_AERIAL
retval &= pack_nr_tlv(NFAPI_NR_CONFIG_NUM_TX_PORT_TAG,
&(pNfapiMsg->carrier_config.num_tx_port),
ppWritePackedMsg,
end,
&pack_uint16_tlv_value);
numTLVs++;
retval &= pack_nr_tlv(NFAPI_NR_CONFIG_NUM_RX_PORT_TAG,
&(pNfapiMsg->carrier_config.num_rx_port),
ppWritePackedMsg,
end,
&pack_uint16_tlv_value);
numTLVs++;
#else
// START Precoding Matrix (PM) PDU // START Precoding Matrix (PM) PDU
if (pNfapiMsg->pmi_list.num_pm_idx != 0) { 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}; nfapi_nr_pm_tlv_ve_t pm_tlv = {.tl.tag = NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, .value = pNfapiMsg->pmi_list};
...@@ -1209,9 +1229,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e ...@@ -1209,9 +1229,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Packing CONFIG.request vendor_extension_tlv %d\n", pNfapiMsg->vendor_extension->tag); NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Packing CONFIG.request vendor_extension_tlv %d\n", pNfapiMsg->vendor_extension->tag);
numTLVs++; numTLVs++;
} }
#endif
AssertFatal(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag == 0, "BF Vendor extension shouldn't be set!");
// The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set,
// so, it's safe to add the call to pack_nr_tlv even if it is not always set // so, it's safe to add the call to pack_nr_tlv even if it is not always set
retval &= pack_nr_tlv(NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, retval &= pack_nr_tlv(NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG,
...@@ -1222,7 +1240,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e ...@@ -1222,7 +1240,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
// only increase if it was set // only increase if it was set
numTLVs += pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag == NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG; numTLVs += pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag == NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG;
AssertFatal(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == 0, "BF Vendor extension shouldn't be set!");
// The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set,
// so, it's safe to add the call to pack_nr_tlv even if it is not always set // so, it's safe to add the call to pack_nr_tlv even if it is not always set
retval &= pack_nr_tlv(NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, retval &= pack_nr_tlv(NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG,
...@@ -1232,7 +1250,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e ...@@ -1232,7 +1250,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
&pack_uint8_tlv_value); &pack_uint8_tlv_value);
// only increase if it was set // only increase if it was set
numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG;
#endif
retval &= pack_nr_tlv(NFAPI_NR_FAPI_SSB_CASE_VENDOR_EXTENSION_TAG, retval &= pack_nr_tlv(NFAPI_NR_FAPI_SSB_CASE_VENDOR_EXTENSION_TAG,
&(pNfapiMsg->ssb_table.case_v3), &(pNfapiMsg->ssb_table.case_v3),
ppWritePackedMsg, ppWritePackedMsg,
......
...@@ -330,8 +330,14 @@ typedef struct ...@@ -330,8 +330,14 @@ typedef struct
#define NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG 0x1028 #define NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG 0x1028
#define NFAPI_NR_CONFIG_TDD_TABLE 0x1035 #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 ) #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 )
#ifdef ENABLE_AERIAL
#define NFAPI_NR_CONFIG_NUM_TX_PORT_TAG 0xA016
#define NFAPI_NR_CONFIG_NUM_RX_PORT_TAG 0xA017
#define NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG 0xA010
#else
#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 )
#endif
//table 3-21 //table 3-21
typedef struct typedef struct
...@@ -347,6 +353,8 @@ typedef struct ...@@ -347,6 +353,8 @@ typedef struct
nfapi_uint16_tlv_t ul_grid_size[5];//Grid size 𝑁𝑔𝑟𝑖𝑑 𝑠𝑖𝑧𝑒,𝜇 for each of the numerologies [38.211, sec 4.4.2]. Value: 0->275 0 = this numerology not used nfapi_uint16_tlv_t ul_grid_size[5];//Grid size 𝑁𝑔𝑟𝑖𝑑 𝑠𝑖𝑧𝑒,𝜇 for each of the numerologies [38.211, sec 4.4.2]. Value: 0->275 0 = this numerology not used
nfapi_uint16_tlv_t num_rx_ant;// nfapi_uint16_tlv_t num_rx_ant;//
nfapi_uint8_tlv_t frequency_shift_7p5khz;//Indicates presence of 7.5KHz frequency shift. Value: 0 = false 1 = true nfapi_uint8_tlv_t frequency_shift_7p5khz;//Indicates presence of 7.5KHz frequency shift. Value: 0 = false 1 = true
nfapi_uint16_tlv_t num_tx_port; //used by Aerial L1 when BF mode is enabled to signal the number of logical antenna ports
nfapi_uint16_tlv_t num_rx_port; //used by Aerial L1 when BF mode is enabled to signal the number of logical antenna ports
} nfapi_nr_carrier_config_t; } nfapi_nr_carrier_config_t;
......
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
#define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration" #define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration"
#define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period" #define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period"
#define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights" #define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights"
#define CONFIG_STRING_MACRLC_DBT_FILE "dbt_file"
#define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue" #define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue"
...@@ -97,6 +98,7 @@ ...@@ -97,6 +98,7 @@
#define HLP_MACRLC_AB "Flag to enable analog beamforming" #define HLP_MACRLC_AB "Flag to enable analog beamforming"
#define HLP_MACRLC_BEAM_DURATION "number of consecutive slots for a given set of beams" #define HLP_MACRLC_BEAM_DURATION "number of consecutive slots for a given set of beams"
#define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period" #define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period"
#define HLP_MACRLC_DBT_FILE "File path to CSV file to read digital beamforming table"
#define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS"
#define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS"
#define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)" #define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)"
...@@ -147,6 +149,7 @@ ...@@ -147,6 +149,7 @@
{CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \ {CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \
{CONFIG_STRING_MACRLC_DBT_FILE, HLP_MACRLC_DBT_FILE, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \
{CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \ {CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \
0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \ {CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \
...@@ -195,9 +198,10 @@ ...@@ -195,9 +198,10 @@
#define MACRLC_ANALOG_BEAM_DURATION_IDX 37 #define MACRLC_ANALOG_BEAM_DURATION_IDX 37
#define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38 #define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38
#define MACRLC_BEAMWEIGHTS_IDX 39 #define MACRLC_BEAMWEIGHTS_IDX 39
#define MACRLC_PUSCH_RSSI_THRES_IDX 40 #define MACRLC_DBT_FILE_IDX 40
#define MACRLC_PUCCH_RSSI_THRES_IDX 41 #define MACRLC_PUSCH_RSSI_THRES_IDX 41
#define MACRLC_STATS_MAX_UE_IDX 42 #define MACRLC_PUCCH_RSSI_THRES_IDX 42
#define MACRLC_STATS_MAX_UE_IDX 43
#define MACRLCPARAMS_CHECK { \ #define MACRLCPARAMS_CHECK { \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
...@@ -243,6 +247,7 @@ ...@@ -243,6 +247,7 @@
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
*/ */
#include "gnb_config.h" #include "gnb_config.h"
#include <ctype.h>
#include <complex.h>
#include <errno.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -1366,6 +1369,166 @@ static void get_bwp_config(nr_mac_config_t *configuration, const NR_ServingCellC ...@@ -1366,6 +1369,166 @@ static void get_bwp_config(nr_mac_config_t *configuration, const NR_ServingCellC
} }
} }
static bool parse_complex_token(const char *tok, double complex *out)
{
double re = 0.0;
double im = 0.0;
if (sscanf(tok, "%lf%lfi", &re, &im) == 2 || sscanf(tok, "%lf%lfj", &re, &im) == 2) {
*out = re + I * im;
return true;
}
if (sscanf(tok, "%lfi", &im) == 1 || sscanf(tok, "%lfj", &im) == 1) {
*out = I * im;
return true;
}
if (sscanf(tok, "%lf", &re) == 1) {
*out = re;
return true;
}
return false;
}
static double complex **read_dbt_from_csv(const char *filename,
int *num_beams,
int *num_weights_per_beam,
uint16_t **beam_ids)
{
FILE *fp = fopen(filename, "r");
AssertFatal(fp != NULL, "Failed to open DBT CSV file '%s'\n", filename);
char line[16384];
AssertFatal(fgets(line, sizeof(line), fp) != NULL, "Failed to read DBT CSV header from '%s'\n", filename);
int weights = 1;
for (char *p = line; *p; ++p)
if (*p == ',')
weights++;
weights -= 1; // first column is beam ID
AssertFatal(weights > 0, "DBT CSV '%s' has no weight columns\n", filename);
int beams = 0;
while (fgets(line, sizeof(line), fp))
beams++;
AssertFatal(beams > 0, "No DBT beam rows found in CSV file '%s'\n", filename);
rewind(fp);
AssertFatal(fgets(line, sizeof(line), fp) != NULL, "Failed to reread DBT CSV header from '%s'\n", filename);
double complex **table = calloc_or_fail(beams, sizeof(*table));
uint16_t *ids = calloc_or_fail(beams, sizeof(*ids));
int b = 0;
while (fgets(line, sizeof(line), fp)) {
line[strcspn(line, "\r\n")] = '\0';
char *saveptr = NULL;
char *tok = strtok_r(line, ",", &saveptr);
AssertFatal(tok != NULL, "Malformed DBT row %d in '%s'\n", b + 1, filename);
errno = 0;
char *endptr = NULL;
long beam_id = strtol(tok, &endptr, 10);
AssertFatal(endptr != tok && errno != ERANGE && *endptr == '\0' && beam_id >= 0 && beam_id <= UINT16_MAX,
"Invalid DBT beam id '%s' in file '%s', beam row %d\n",
tok,
filename,
b + 1);
ids[b] = (uint16_t)beam_id;
table[b] = calloc_or_fail(weights, sizeof(*table[b]));
for (int w = 0; w < weights; ++w) {
tok = strtok_r(NULL, ",", &saveptr);
AssertFatal(tok != NULL, "Missing DBT weight in file '%s', beam row %d column %d\n", filename, b + 1, w + 1);
AssertFatal(parse_complex_token(tok, &table[b][w]),
"Invalid DBT complex weight '%s' in file '%s', beam row %d column %d\n",
tok,
filename,
b + 1,
w + 1);
}
AssertFatal(strtok_r(NULL, ",", &saveptr) == NULL,
"Too many DBT columns in file '%s', beam row %d\n",
filename,
b + 1);
b++;
}
AssertFatal(b == beams, "Parsed %d DBT rows but counted %d in file '%s'\n", b, beams, filename);
fclose(fp);
*num_beams = beams;
*num_weights_per_beam = weights;
*beam_ids = ids;
return table;
}
#define DBT_PARAMS_DESC { \
{"", "beam", 0, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
}
static double complex **read_dbt_from_config(const char *prefix,
int *num_beams,
int *num_weights_per_beam,
uint16_t **beam_ids)
{
paramdef_t dbt_params[] = DBT_PARAMS_DESC;
paramlist_def_t dbt_list = {"dbt", NULL, 0};
int ret = config_getlist(config_get_if(), &dbt_list, dbt_params, sizeofArray(dbt_params), prefix);
if (ret <= 0) {
*num_beams = 0;
*num_weights_per_beam = 0;
*beam_ids = NULL;
return NULL;
}
const int beams = ret;
int weights = 0;
double complex **table = calloc_or_fail(beams, sizeof(*table));
uint16_t *ids = calloc_or_fail(beams, sizeof(*ids));
for (int b = 0; b < beams; ++b) {
paramdef_t *row = &dbt_list.paramarray[b][0];
AssertFatal(row->strlistptr != NULL, "Invalid dbt row %d in section '%s': missing string list\n", b, prefix);
AssertFatal(row->numelt >= 2,
"Invalid dbt row %d in section '%s': expected beam_id + >=1 weights, got %d elements\n",
b,
prefix,
row->numelt);
const int row_weights = row->numelt - 1;
if (weights == 0)
weights = row_weights;
AssertFatal(weights == row_weights,
"Inconsistent dbt row width in section '%s': row %d has %d weights, expected %d\n",
prefix,
b,
row_weights,
weights);
errno = 0;
char *endptr = NULL;
long beam_id = strtol(row->strlistptr[0], &endptr, 10);
AssertFatal(endptr != row->strlistptr[0] && errno != ERANGE && *endptr == '\0' && beam_id >= 0 && beam_id <= UINT16_MAX,
"Invalid dbt beam id '%s' in section '%s', row %d\n",
row->strlistptr[0],
prefix,
b);
ids[b] = (uint16_t)beam_id;
table[b] = calloc_or_fail(weights, sizeof(*table[b]));
for (int w = 0; w < weights; ++w)
AssertFatal(parse_complex_token(row->strlistptr[w + 1], &table[b][w]),
"Invalid dbt complex weight '%s' in section '%s', row %d col %d\n",
row->strlistptr[w + 1],
prefix,
b,
w + 1);
}
*num_beams = beams;
*num_weights_per_beam = weights;
*beam_ids = ids;
return table;
}
void RCconfig_nr_macrlc(configmodule_interface_t *cfg) void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
{ {
int j = 0; int j = 0;
...@@ -1634,6 +1797,21 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) ...@@ -1634,6 +1797,21 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
for (int b = 0; b < n; b++) for (int b = 0; b < n; b++)
config.bw_list[b] = b; config.bw_list[b] = b;
} }
config.bt.num_beams = 0;
config.bt.num_weights_per_beam = 0;
config.bt.beam_ids = NULL;
config.bt.beam_weights = NULL;
char **fptr = MacRLC_ParamList.paramarray[j][MACRLC_DBT_FILE_IDX].strptr;
if (fptr && *fptr && **fptr != '\0') {
LOG_I(GNB_APP, "loading DBT table from file %s\n", *fptr);
config.bt.beam_weights =
read_dbt_from_csv(*fptr, &config.bt.num_beams, &config.bt.num_weights_per_beam, &config.bt.beam_ids);
} else {
char prefix[MAX_OPTNAME_SIZE * 2 + 8];
snprintf(prefix, sizeof(prefix), CONFIG_STRING_MACRLC_LIST ".[%d]", j);
config.bt.beam_weights =
read_dbt_from_config(prefix, &config.bt.num_beams, &config.bt.num_weights_per_beam, &config.bt.beam_ids);
}
// triggers also PHY initialization in case we have L1 via FAPI // triggers also PHY initialization in case we have L1 via FAPI
nr_mac_config_scc(RC.nrmac[j], scc, &config); nr_mac_config_scc(RC.nrmac[j], scc, &config);
} // for (j=0;j<RC.nb_nr_macrlc_inst;j++) } // for (j=0;j<RC.nb_nr_macrlc_inst;j++)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
*/ */
#include <complex.h> #include <complex.h>
#include <limits.h>
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
...@@ -64,6 +65,41 @@ c16_t convert_precoder_weight(double complex c_in) ...@@ -64,6 +65,41 @@ c16_t convert_precoder_weight(double complex c_in)
return (c16_t) {.r = round(SHRT_MAX*creal(c_in)), .i = round(SHRT_MAX*cimag(c_in))}; return (c16_t) {.r = round(SHRT_MAX*creal(c_in)), .i = round(SHRT_MAX*cimag(c_in))};
} }
static void free_dbt_config(nfapi_nr_dbt_pdu_t *dbt)
{
if (!dbt || !dbt->dig_beam_list)
return;
for (int i = 0; i < dbt->num_dig_beams; ++i)
free(dbt->dig_beam_list[i].txru_list);
free(dbt->dig_beam_list);
dbt->dig_beam_list = NULL;
dbt->num_dig_beams = 0;
dbt->num_txrus = 0;
}
static void log_dbt_table(const nr_beam_table_t *bt)
{
if (!bt || bt->num_beams <= 0 || bt->num_weights_per_beam <= 0 || !bt->beam_weights)
return;
LOG_I(NR_MAC, "DBT: num_beams=%d num_weights_per_beam=%d\n", bt->num_beams, bt->num_weights_per_beam);
for (int b = 0; b < bt->num_beams; ++b) {
uint16_t beam_id = bt->beam_ids ? bt->beam_ids[b] : b;
const int max_line = 2048;
char line[max_line];
int off = snprintf(line, sizeof(line), "DBT beam[%d] id=%u:", b, beam_id);
for (int w = 0; w < bt->num_weights_per_beam && off > -1 && off < max_line - 1; ++w)
off += snprintf(line + off,
sizeof(line) - off,
" w[%d]=(%0.6f,%0.6f)",
w,
creal(bt->beam_weights[b][w]),
cimag(bt->beam_weights[b][w]));
LOG_D(NR_MAC, "%s\n", line);
}
}
void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers) void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers)
{ {
// num of allowed k1 and k2 according to 5.2.2.2.1-3 and -4 in 38.214 // num of allowed k1 and k2 according to 5.2.2.2.1-3 and -4 in 38.214
...@@ -395,6 +431,45 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR ...@@ -395,6 +431,45 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR
{ {
nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0]; nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0];
nrmac->common_channels[0].ServingCellConfigCommon = scc; nrmac->common_channels[0].ServingCellConfigCommon = scc;
free_dbt_config(&cfg->dbt_config);
if (config->bt.num_beams > 0) {
AssertFatal(config->bt.beam_weights != NULL,
"DBT config invalid: num_beams=%d but beam_weights is NULL\n",
config->bt.num_beams);
AssertFatal(config->bt.num_weights_per_beam > 0,
"DBT config invalid: num_weights_per_beam=%d\n",
config->bt.num_weights_per_beam);
AssertFatal(config->bt.num_weights_per_beam <= UINT16_MAX,
"DBT num_weights_per_beam %d exceeds uint16 max\n",
config->bt.num_weights_per_beam);
AssertFatal(config->bt.num_beams <= UINT16_MAX,
"DBT num_beams %d exceeds uint16 max\n",
config->bt.num_beams);
cfg->dbt_config.num_dig_beams = (uint16_t)config->bt.num_beams;
cfg->dbt_config.num_txrus = (uint16_t)config->bt.num_weights_per_beam;
cfg->dbt_config.dig_beam_list = calloc_or_fail(cfg->dbt_config.num_dig_beams, sizeof(*cfg->dbt_config.dig_beam_list));
for (uint16_t b = 0; b < cfg->dbt_config.num_dig_beams; ++b) {
nfapi_nr_dig_beam_t *beam = &cfg->dbt_config.dig_beam_list[b];
beam->beam_idx = config->bt.beam_ids ? config->bt.beam_ids[b] : b;
beam->txru_list = calloc_or_fail(cfg->dbt_config.num_txrus, sizeof(*beam->txru_list));
for (uint16_t w = 0; w < cfg->dbt_config.num_txrus; ++w) {
float re = crealf(config->bt.beam_weights[b][w]);
float im = cimagf(config->bt.beam_weights[b][w]);
AssertFatal(re >= -1.0f && re <= 1.0f, "DBT real weight out of range [-1,1]: %f\n", re);
AssertFatal(im >= -1.0f && im <= 1.0f, "DBT imag weight out of range [-1,1]: %f\n", im);
c16_t q15 = convert_precoder_weight(config->bt.beam_weights[b][w]);
beam->txru_list[w].dig_beam_weight_Re = (uint16_t)q15.r;
beam->txru_list[w].dig_beam_weight_Im = (uint16_t)q15.i;
}
}
LOG_I(NR_MAC,
"Loaded DBT: num_beams=%d num_weights_per_beam=%d\n",
config->bt.num_beams,
config->bt.num_weights_per_beam);
log_dbt_table(&config->bt);
}
// Carrier configuration // Carrier configuration
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
...@@ -691,7 +766,19 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR ...@@ -691,7 +766,19 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR
cfg->carrier_config.num_tx_ant.value); cfg->carrier_config.num_tx_ant.value);
cfg->num_tlv++; cfg->num_tlv++;
cfg->num_tlv++; cfg->num_tlv++;
#ifdef ENABLE_AERIAL
if (nrmac->beam_info.beam_mode == PRECONFIGURED_BEAM_IDX) {
// if we are doing BF in Aerial we need these Custom TLV
cfg->carrier_config.num_rx_ant.value = 64; //TOOD: Read number of baseband ports (phy ant) from Config?
cfg->carrier_config.num_tx_ant.value = 64; //TOOD: Read number of baseband ports (phy ant) from Config?
}else{
// In CAT-A Mode these are equal to num_rx_ant (and Aerial ignores the value)
cfg->carrier_config.num_rx_port.value = pusch_AntennaPorts;
cfg->carrier_config.num_rx_port.tl.tag = NFAPI_NR_CONFIG_NUM_RX_PORT_TAG;
cfg->carrier_config.num_tx_port.value = num_pdsch_antenna_ports;
cfg->carrier_config.num_tx_port.tl.tag = NFAPI_NR_CONFIG_NUM_TX_PORT_TAG;
}
#endif
// Frame structure configuration // Frame structure configuration
uint8_t mu = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; uint8_t mu = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
if (cfg->cell_config.frame_duplex_type.value == TDD) { if (cfg->cell_config.frame_duplex_type.value == TDD) {
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <complex.h>
#include <pthread.h> #include <pthread.h>
#include "common/utils/ds/seq_arr.h" #include "common/utils/ds/seq_arr.h"
#include "common/utils/nr/nr_common.h" #include "common/utils/nr/nr_common.h"
...@@ -184,6 +185,13 @@ typedef enum { ...@@ -184,6 +185,13 @@ typedef enum {
SSB_SINR, SSB_SINR,
} nr_config_report_type_t; } nr_config_report_type_t;
typedef struct nr_beam_table {
int num_weights_per_beam;
int num_beams;
uint16_t *beam_ids;
double complex **beam_weights;
} nr_beam_table_t;
typedef struct nr_mac_config_s { typedef struct nr_mac_config_s {
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts; nr_pdsch_AntennaPorts_t pdsch_AntennaPorts;
int pusch_AntennaPorts; int pusch_AntennaPorts;
...@@ -213,6 +221,7 @@ typedef struct nr_mac_config_s { ...@@ -213,6 +221,7 @@ typedef struct nr_mac_config_s {
nr_redcap_config_t *redcap; nr_redcap_config_t *redcap;
nr_ptrs_config_t *ptrs; nr_ptrs_config_t *ptrs;
nr_config_report_type_t report_type; nr_config_report_type_t report_type;
nr_beam_table_t bt;
} nr_mac_config_t; } nr_mac_config_t;
typedef struct NR_preamble_ue { typedef struct NR_preamble_ue {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment