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.
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
#include <sys/epoll.h>
|
||||
#include "fapi_nvIPC.h"
|
||||
#include <nfapi_vnf.h>
|
||||
#include <nr_fapi_p5.h>
|
||||
#include <nr_fapi_p7_utils.h>
|
||||
#include "nfapi_interface.h"
|
||||
#include "nfapi.h"
|
||||
@@ -66,6 +67,7 @@ nv_ipc_t *ipc;
|
||||
static nv_ipc_config_t nv_ipc_config;
|
||||
static int cpu_msg_buf_size = 0;
|
||||
static int cpu_data_buf_size = 0;
|
||||
static int cpu_large_buf_size = 0;
|
||||
|
||||
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
|
||||
// Create the message
|
||||
nv_ipc_msg_t send_msg = {.msg_id = msg->message_id,
|
||||
.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_len = 0,
|
||||
.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
|
||||
if (!allocate_msg(&send_msg)) {
|
||||
return false;
|
||||
@@ -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
|
||||
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
|
||||
return send_nvipc_msg(&send_msg);
|
||||
} else {
|
||||
@@ -386,6 +423,7 @@ int nvIPC_Init(nvipc_params_t nvipc_params_s)
|
||||
// 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_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
|
||||
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 *
|
||||
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 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
|
||||
|
||||
@@ -721,8 +721,7 @@ uint8_t unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *
|
||||
config,
|
||||
&pNfapiMsg->vendor_extension));
|
||||
}
|
||||
#ifndef ENABLE_AERIAL
|
||||
static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end)
|
||||
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;
|
||||
@@ -744,6 +743,7 @@ static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, u
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_AERIAL
|
||||
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;
|
||||
@@ -1143,15 +1143,35 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
|
||||
&pack_uint8_tlv_value);
|
||||
numTLVs++;
|
||||
// END Measurement Config
|
||||
#ifndef ENABLE_AERIAL
|
||||
|
||||
// START Digital Beam Table (DBT) PDU
|
||||
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);
|
||||
#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++;
|
||||
}
|
||||
// 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
|
||||
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};
|
||||
@@ -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);
|
||||
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,
|
||||
// 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,
|
||||
@@ -1222,7 +1240,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
|
||||
// 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;
|
||||
|
||||
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,
|
||||
// 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,
|
||||
@@ -1232,7 +1250,7 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
|
||||
&pack_uint8_tlv_value);
|
||||
// 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;
|
||||
|
||||
#endif
|
||||
retval &= pack_nr_tlv(NFAPI_NR_FAPI_SSB_CASE_VENDOR_EXTENSION_TAG,
|
||||
&(pNfapiMsg->ssb_table.case_v3),
|
||||
ppWritePackedMsg,
|
||||
|
||||
@@ -330,8 +330,14 @@ 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 )
|
||||
#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
|
||||
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 num_rx_ant;//
|
||||
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;
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
#define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration"
|
||||
#define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period"
|
||||
#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_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold"
|
||||
#define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue"
|
||||
@@ -97,6 +98,7 @@
|
||||
#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_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_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)"
|
||||
@@ -147,6 +149,7 @@
|
||||
{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_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, \
|
||||
0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
{CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \
|
||||
@@ -195,9 +198,10 @@
|
||||
#define MACRLC_ANALOG_BEAM_DURATION_IDX 37
|
||||
#define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38
|
||||
#define MACRLC_BEAMWEIGHTS_IDX 39
|
||||
#define MACRLC_PUSCH_RSSI_THRES_IDX 40
|
||||
#define MACRLC_PUCCH_RSSI_THRES_IDX 41
|
||||
#define MACRLC_STATS_MAX_UE_IDX 42
|
||||
#define MACRLC_DBT_FILE_IDX 40
|
||||
#define MACRLC_PUSCH_RSSI_THRES_IDX 41
|
||||
#define MACRLC_PUCCH_RSSI_THRES_IDX 42
|
||||
#define MACRLC_STATS_MAX_UE_IDX 43
|
||||
|
||||
#define MACRLCPARAMS_CHECK { \
|
||||
{ .s5 = { NULL } }, \
|
||||
@@ -243,6 +247,7 @@
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \
|
||||
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \
|
||||
{ .s5 = { NULL } }, \
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
*/
|
||||
|
||||
#include "gnb_config.h"
|
||||
#include <ctype.h>
|
||||
#include <complex.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
@@ -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)
|
||||
{
|
||||
int j = 0;
|
||||
@@ -1634,6 +1797,21 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
||||
for (int b = 0; b < n; 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
|
||||
nr_mac_config_scc(RC.nrmac[j], scc, &config);
|
||||
} // for (j=0;j<RC.nb_nr_macrlc_inst;j++)
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <complex.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -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))};
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0];
|
||||
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
|
||||
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
|
||||
cfg->carrier_config.num_tx_ant.value);
|
||||
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
|
||||
uint8_t mu = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
|
||||
if (cfg->cell_config.frame_duplex_type.value == TDD) {
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <complex.h>
|
||||
#include <pthread.h>
|
||||
#include "common/utils/ds/seq_arr.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
@@ -184,6 +185,13 @@ typedef enum {
|
||||
SSB_SINR,
|
||||
} 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 {
|
||||
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts;
|
||||
int pusch_AntennaPorts;
|
||||
@@ -213,6 +221,7 @@ typedef struct nr_mac_config_s {
|
||||
nr_redcap_config_t *redcap;
|
||||
nr_ptrs_config_t *ptrs;
|
||||
nr_config_report_type_t report_type;
|
||||
nr_beam_table_t bt;
|
||||
} nr_mac_config_t;
|
||||
|
||||
typedef struct NR_preamble_ue {
|
||||
|
||||
Reference in New Issue
Block a user