mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 20:50:28 +00:00
Compare commits
6 Commits
nfapi-Dela
...
beam_api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1617c32e3c | ||
|
|
ae780bae57 | ||
|
|
2834088ea0 | ||
|
|
0b320c8dce | ||
|
|
9fc066394e | ||
|
|
04ce714f37 |
@@ -70,7 +70,7 @@ gNBs =
|
||||
initialULBWPsubcarrierSpacing = 3;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 52;
|
||||
prach_ConfigurationIndex = 70;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
@@ -112,7 +112,7 @@ gNBs =
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
ssb_PositionsInBurst_Bitmap = 85;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
@@ -179,7 +179,7 @@ MACRLCs = ({
|
||||
set_analog_beamforming = "lophy";
|
||||
beam_duration = 1;
|
||||
beams_per_period = 1;
|
||||
beam_weights = [0]; // single SSB -> one analog beam
|
||||
beam_weights = [0, 1, 2, 3]; // 4 SSBs -> 4 analog beams
|
||||
});
|
||||
|
||||
L1s = (
|
||||
|
||||
@@ -99,6 +99,7 @@ services:
|
||||
- ALL
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
|
||||
--rfsimulator.[0].enable_beams --rfsimulator.[0].beam_gains 0,-20,-30,-40
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
networks:
|
||||
public_net:
|
||||
@@ -125,6 +126,7 @@ services:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim
|
||||
--rfsimulator.[0].serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
|
||||
-C 27975360000 -r 66 --numerology 3 --ssb 48 --band 257
|
||||
--rfsimulator.[0].enable_beams --rfsimulator.[0].beam_gains 0,-20,-30,-40 --rfsimulator.[0].beam_ids 2
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
|
||||
@@ -92,18 +92,17 @@ static void tx_func(processingData_L1tx_t *info)
|
||||
pushNotifiedFIFO(&gNB->resp_L1, res);
|
||||
|
||||
int tx_slot_type = nr_slot_select(cfg, frame_tx, slot_tx);
|
||||
// TODO check for analog_bf_vendor_ext set to 1 is a workaround while no beam API for beam selection is implemented
|
||||
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx
|
||||
|| IS_SOFTMODEM_RFSIM || cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) {
|
||||
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM) {
|
||||
start_meas(&info->gNB->phy_proc_tx);
|
||||
phy_procedures_gNB_TX(info->gNB, &sched_response.DL_req, &sched_response.TX_req, &sched_response.UL_dci_req, frame_tx,slot_tx);
|
||||
|
||||
PHY_VARS_gNB *gNB = info->gNB;
|
||||
processingData_RU_t syncMsgRU;
|
||||
syncMsgRU.frame_tx = frame_tx;
|
||||
syncMsgRU.slot_tx = slot_tx;
|
||||
syncMsgRU.ru = gNB->RU_list[0];
|
||||
syncMsgRU.timestamp_tx = info->timestamp_tx;
|
||||
}
|
||||
processingData_RU_t syncMsgRU;
|
||||
syncMsgRU.frame_tx = frame_tx;
|
||||
syncMsgRU.slot_tx = slot_tx;
|
||||
syncMsgRU.ru = gNB->RU_list[0];
|
||||
syncMsgRU.timestamp_tx = info->timestamp_tx;
|
||||
ru_ctrl_func((void *)&syncMsgRU);
|
||||
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM) {
|
||||
LOG_D(PHY, "gNB: %d.%d : calling RU TX function\n", syncMsgRU.frame_tx, syncMsgRU.slot_tx);
|
||||
ru_tx_func((void *)&syncMsgRU);
|
||||
stop_meas(&info->gNB->phy_proc_tx);
|
||||
|
||||
@@ -347,17 +347,28 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame);
|
||||
|
||||
start_meas(&ru->rx_fhaul);
|
||||
int nb = ru->nb_rx * ru->num_beams_period;
|
||||
void *rxp[nb];
|
||||
for (int i = 0; i < nb; i++)
|
||||
rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)];
|
||||
|
||||
openair0_timestamp_t old_ts = proc->timestamp_rx;
|
||||
LOG_D(PHY,"Reading %d samples for slot %d (%p)\n", samples_per_slot, *slot, rxp[0]);
|
||||
|
||||
openair0_timestamp_t ts;
|
||||
unsigned int rxs;
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb);
|
||||
metadata mt = {.slot = *slot, .frame = *frame};
|
||||
if (ru->num_beams_period > 1) {
|
||||
void *rxp_flat[ru->num_beams_period * ru->nb_rx];
|
||||
void **rxp[ru->num_beams_period];
|
||||
for (int j = 0; j < ru->num_beams_period; j++) {
|
||||
for (int i = 0; i < ru->nb_rx; i++)
|
||||
rxp_flat[i + j * ru->nb_rx] = (void *)&ru->common.rxdata[i + j * ru->nb_rx][get_samples_slot_timestamp(fp, *slot)];
|
||||
rxp[j] = &rxp_flat[j * ru->nb_rx];
|
||||
}
|
||||
rxs = ru->rfdevice.trx_read_beams_func(&ru->rfdevice, &ts, (void ***)rxp, samples_per_slot, ru->nb_rx, ru->num_beams_period);
|
||||
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0][0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
|
||||
} else {
|
||||
void *rxp[ru->nb_rx];
|
||||
for (int i = 0; i < ru->nb_rx; i++)
|
||||
rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)];
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, ru->nb_rx);
|
||||
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
|
||||
}
|
||||
|
||||
proc->timestamp_rx = ts-ru->ts_offset;
|
||||
|
||||
if (rxs != samples_per_slot)
|
||||
@@ -422,17 +433,28 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
proc->first_rx = 0;
|
||||
*frame = proc->frame_rx;
|
||||
*slot = proc->tti_rx;
|
||||
samples_per_slot = get_samples_per_slot(*slot, fp); // slot number might change depending on the timestamp
|
||||
|
||||
// Align to slot boundary
|
||||
uint64_t samples_to_slot_boundary = 0;
|
||||
uint64_t sample_offset_within_frame = proc->timestamp_rx % fp->samples_per_frame;
|
||||
uint64_t sample_offset_within_slot = sample_offset_within_frame - get_samples_slot_timestamp(fp, *slot);
|
||||
if (sample_offset_within_slot > 0) {
|
||||
samples_to_slot_boundary = get_samples_per_slot(*slot, fp) - sample_offset_within_slot;
|
||||
samples_to_slot_boundary = samples_per_slot - sample_offset_within_slot;
|
||||
LOG_A(NR_PHY, "Aligning to the slot boundary %lu\n", samples_to_slot_boundary);
|
||||
|
||||
// Read and discard the samples in the first_rx to align to the slot boundary
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_to_slot_boundary, nb);
|
||||
if (ru->num_beams_period > 1) {
|
||||
void *rxp_skip_b[ru->num_beams_period][ru->nb_rx];
|
||||
rxs = ru->rfdevice.trx_read_beams_func(&ru->rfdevice,
|
||||
&ts,
|
||||
(void ***)rxp_skip_b,
|
||||
samples_to_slot_boundary,
|
||||
ru->nb_rx,
|
||||
ru->num_beams_period);
|
||||
} else {
|
||||
void *rxp_skip[ru->nb_rx];
|
||||
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp_skip, samples_to_slot_boundary, ru->nb_rx);
|
||||
}
|
||||
if (rxs != samples_to_slot_boundary)
|
||||
LOG_E(PHY, "rx_rf: Asked for %ld samples, got %d from USRP\n", samples_to_slot_boundary, rxs);
|
||||
|
||||
@@ -442,59 +464,92 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
*slot = (*slot + 1) % fp->slots_per_frame;
|
||||
}
|
||||
}
|
||||
|
||||
metadata mt = {.slot = *slot, .frame = *frame};
|
||||
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
|
||||
|
||||
stop_meas(&ru->rx_fhaul);
|
||||
}
|
||||
|
||||
static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
|
||||
static void ctrl_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
radio_tx_gpio_flag_t flags_gpio = 0;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
openair0_config_t *cfg0 = &ru->openair0_cfg;
|
||||
int num_events = 0;
|
||||
int event_symbol[fp->symbols_per_slot];
|
||||
int event_counts[fp->symbols_per_slot];
|
||||
int beam_events[fp->symbols_per_slot][ru->num_beams_period];
|
||||
|
||||
switch (cfg0->gpio_controller) {
|
||||
case RU_GPIO_CONTROL_GENERIC:
|
||||
// currently we switch beams at the beginning of a slot and we take the beam index of the first symbol of this slot
|
||||
// we only send the beam to the gpio if the beam is different from the previous slot
|
||||
int last_applied_beams[ru->num_beams_period];
|
||||
for (int i = 0; i < ru->num_beams_period; i++)
|
||||
last_applied_beams[i] = -1;
|
||||
|
||||
if (ru->common.beam_id) {
|
||||
int prev_slot = (slot - 1 + fp->slots_per_frame) % fp->slots_per_frame;
|
||||
const int *beam_ids = ru->common.beam_id[0];
|
||||
int prev_beam = beam_ids[prev_slot * fp->symbols_per_slot];
|
||||
int beam = beam_ids[slot * fp->symbols_per_slot];
|
||||
if (prev_beam != beam) {
|
||||
flags_gpio = beam | TX_GPIO_CHANGE; // enable change of gpio
|
||||
LOG_I(HW, "slot %d, beam %d\n", slot, ru->common.beam_id[0][slot * fp->symbols_per_slot]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
int first_available_sym = 0;
|
||||
bool idle_beam = true;
|
||||
for (int j = 0; j < fp->symbols_per_slot; j++) {
|
||||
int current_beams[ru->num_beams_period];
|
||||
int active_count = 0;
|
||||
bool differs = false;
|
||||
|
||||
case RU_GPIO_CONTROL_INTERDIGITAL: {
|
||||
// the beam index is written in bits 8-10 of the flags
|
||||
// bit 11 enables the gpio programming
|
||||
int beam = 0;
|
||||
if ((slot % 10 == 0) && ru->common.beam_id && (ru->common.beam_id[0][slot * fp->symbols_per_slot] < 64)) {
|
||||
// beam = ru->common.beam_id[0][slot*fp->symbols_per_slot] | 64;
|
||||
beam = 1024; // hardcoded now for beam32 boresight
|
||||
// beam = 127; //for the sake of trying beam63
|
||||
LOG_D(HW, "slot %d, beam %d\n", slot, beam);
|
||||
}
|
||||
flags_gpio = beam | TX_GPIO_CHANGE;
|
||||
// flags_gpio |= beam << 8; // MSB 8 bits are used for beam
|
||||
LOG_I(HW, "slot %d, beam %d, flags_gpio %d\n", slot, beam, flags_gpio);
|
||||
break;
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
current_beams[i] = ru->common.beam_id[i][slot * fp->symbols_per_slot + j];
|
||||
if (current_beams[i] != last_applied_beams[i])
|
||||
differs = true;
|
||||
if (current_beams[i] != -1)
|
||||
active_count++;
|
||||
}
|
||||
|
||||
if (active_count > 0) {
|
||||
if (differs) {
|
||||
event_symbol[num_events] = first_available_sym;
|
||||
event_counts[num_events] = 0;
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
if (current_beams[i] != -1) {
|
||||
beam_events[num_events][event_counts[num_events]] = current_beams[i];
|
||||
event_counts[num_events]++;
|
||||
}
|
||||
last_applied_beams[i] = current_beams[i];
|
||||
}
|
||||
num_events++;
|
||||
}
|
||||
idle_beam = false;
|
||||
first_available_sym = j;
|
||||
} else {
|
||||
if (!idle_beam) {
|
||||
first_available_sym = j;
|
||||
idle_beam = true;
|
||||
for (int i = 0; i < ru->num_beams_period; i++)
|
||||
last_applied_beams[i] = -1;
|
||||
}
|
||||
}
|
||||
default:
|
||||
AssertFatal(false, "illegal GPIO controller %d\n", cfg0->gpio_controller);
|
||||
}
|
||||
|
||||
return flags_gpio;
|
||||
nfapi_nr_config_request_scf_t *cfg = &ru->config;
|
||||
uint64_t slot_base_ts = timestamp + ru->ts_offset;
|
||||
if (cfg->cell_config.frame_duplex_type.value == TDD
|
||||
&& nr_slot_select(cfg, frame, slot % fp->slots_per_frame) == NR_DOWNLINK_SLOT
|
||||
&& nr_slot_select(cfg, frame, (slot + fp->slots_per_frame - 1) % fp->slots_per_frame) == NR_UPLINK_SLOT
|
||||
&& !get_softmodem_params()->continuous_tx && !IS_SOFTMODEM_RFSIM) {
|
||||
slot_base_ts -= ru->sf_extension;
|
||||
}
|
||||
|
||||
for (int e = 0; e < num_events; e++) {
|
||||
if (e > 0 && event_symbol[e] == event_symbol[e-1])
|
||||
continue;
|
||||
|
||||
uint64_t symbol_offset = 0;
|
||||
if (event_symbol[e] > 0)
|
||||
symbol_offset = get_samples_symbol_duration(fp, slot, 0, event_symbol[e]);
|
||||
|
||||
uint64_t event_ts = slot_base_ts + symbol_offset;
|
||||
for (int n = 0; n < event_counts[e]; n++)
|
||||
LOG_D(NR_PHY,
|
||||
"RU Control [%d.%d]: Trigger Sym %d, Beam %d at TS %lu\n",
|
||||
frame,
|
||||
slot,
|
||||
event_symbol[e],
|
||||
beam_events[e][n],
|
||||
event_ts);
|
||||
ru->rfdevice.trx_set_beams2(&ru->rfdevice, beam_events[e], event_counts[e], event_ts);
|
||||
}
|
||||
}
|
||||
|
||||
void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
static void tx_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
@@ -509,7 +564,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
int sf_extension = 0;
|
||||
int siglen = get_samples_per_slot(slot, fp);
|
||||
radio_tx_burst_flag_t flags_burst = TX_BURST_INVALID;
|
||||
radio_tx_gpio_flag_t flags_gpio = 0;
|
||||
|
||||
if (cfg->cell_config.frame_duplex_type.value == TDD && !get_softmodem_params()->continuous_tx && !IS_SOFTMODEM_RFSIM) {
|
||||
int slot_type = nr_slot_select(cfg,frame,slot%fp->slots_per_frame);
|
||||
@@ -553,24 +607,41 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
|
||||
}
|
||||
|
||||
if (ru->openair0_cfg.gpio_controller != RU_GPIO_CONTROL_NONE)
|
||||
flags_gpio = get_gpio_flags(ru, slot);
|
||||
|
||||
const int flags = flags_burst | (flags_gpio << 4);
|
||||
proc->first_tx = 0;
|
||||
|
||||
int nt = ru->nb_tx * ru->num_beams_period;
|
||||
void *txp[nt];
|
||||
for (int i = 0; i < nt; i++)
|
||||
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
double sig_en = 0;
|
||||
uint32_t txs;
|
||||
if (ru->num_beams_period > 1) {
|
||||
void *txp_flat[ru->num_beams_period * ru->nb_tx];
|
||||
void **txp[ru->num_beams_period];
|
||||
for (int b = 0; b < ru->num_beams_period; b++) {
|
||||
for (int i = 0; i < ru->nb_tx; i++)
|
||||
txp_flat[b * ru->nb_tx + i] = (void *)&ru->common.txdata[i + b * ru->nb_tx][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
txp[b] = &txp_flat[b * ru->nb_tx];
|
||||
}
|
||||
sig_en = (double)signal_energy(txp[0][0], siglen + sf_extension);
|
||||
txs = ru->rfdevice.trx_write_beams_func(&ru->rfdevice,
|
||||
timestamp + ru->ts_offset - sf_extension,
|
||||
(void ***)txp,
|
||||
siglen + sf_extension,
|
||||
ru->nb_tx,
|
||||
ru->num_beams_period,
|
||||
flags_burst);
|
||||
} else {
|
||||
void *txp[ru->nb_tx];
|
||||
for (int i = 0; i < ru->nb_tx; i++)
|
||||
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
|
||||
sig_en = (double)signal_energy(txp[0], siglen + sf_extension);
|
||||
// prepare tx buffer pointers
|
||||
txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
|
||||
timestamp + ru->ts_offset - sf_extension,
|
||||
txp,
|
||||
siglen + sf_extension,
|
||||
ru->nb_tx,
|
||||
flags_burst);
|
||||
}
|
||||
|
||||
// prepare tx buffer pointers
|
||||
uint32_t txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
|
||||
timestamp + ru->ts_offset - sf_extension,
|
||||
txp,
|
||||
siglen + sf_extension,
|
||||
nt,
|
||||
flags);
|
||||
LOG_D(PHY,
|
||||
"[TXPATH] RU %d tx_rf, writing to TS %lu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, "
|
||||
"returned %d, E %f\n",
|
||||
@@ -580,10 +651,10 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
slot,
|
||||
proc->frame_tx_unwrap,
|
||||
slot,
|
||||
flags,
|
||||
flags_burst,
|
||||
siglen + sf_extension,
|
||||
txs,
|
||||
10 * log10((double)signal_energy(txp[0], siglen + sf_extension)));
|
||||
10 * log10(sig_en));
|
||||
}
|
||||
|
||||
static void fill_rf_config(RU_t *ru, char *rf_config_file)
|
||||
@@ -737,6 +808,25 @@ int setup_RU_buffers(RU_t *ru)
|
||||
return(0);
|
||||
}
|
||||
|
||||
void ru_ctrl_func(void *param)
|
||||
{
|
||||
processingData_RU_t *info = (processingData_RU_t *) param;
|
||||
int frame = info->frame_tx;
|
||||
int slot = info->slot_tx;
|
||||
LOG_D(PHY,"ru_ctrl_func: frame = %d, slot = %d\n", frame, slot);
|
||||
RU_t *ru = info->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
if (ru->gNB_list[0]->common_vars.analog_bf) {
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
memcpy((void*) &ru->common.beam_id[i][slot * fp->symbols_per_slot],
|
||||
(void*) &ru->gNB_list[0]->common_vars.beam_id[i][slot * fp->symbols_per_slot],
|
||||
(fp->symbols_per_slot) * sizeof(int));
|
||||
}
|
||||
}
|
||||
if (ru->fh_south_ctrl)
|
||||
ru->fh_south_ctrl(ru, frame, slot, info->timestamp_tx);
|
||||
}
|
||||
|
||||
void ru_tx_func(void *param)
|
||||
{
|
||||
processingData_RU_t *info = (processingData_RU_t *) param;
|
||||
@@ -1129,6 +1219,7 @@ void set_function_spec_param(RU_t *ru)
|
||||
ru->rfdevice.host_type = RAU_HOST;
|
||||
ru->fh_south_in = rx_rf; // local synchronous RF RX
|
||||
ru->fh_south_out = tx_rf; // local synchronous RF TX
|
||||
ru->fh_south_ctrl = ctrl_rf; // local sunchronous RF control
|
||||
ru->start_rf = start_rf; // need to start the local RF interface
|
||||
ru->stop_rf = stop_rf;
|
||||
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
|
||||
|
||||
@@ -310,7 +310,7 @@ extern int64_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
||||
extern int usrp_tx_thread;
|
||||
extern int sf_ahead;
|
||||
extern int oai_exit;
|
||||
|
||||
void ru_ctrl_func(void *param);
|
||||
void ru_tx_func(void *param);
|
||||
void configure_ru(void *, void *arg);
|
||||
void configure_rru(void *, void *arg);
|
||||
|
||||
@@ -490,6 +490,8 @@ typedef struct RU_t_s {
|
||||
void (*fh_south_in)(struct RU_t_s *ru, int *frame, int *subframe);
|
||||
/// function pointer to synchronous TX fronthaul function
|
||||
void (*fh_south_out)(struct RU_t_s *ru, int frame_tx, int tti_tx, uint64_t timestamp_tx);
|
||||
/// function pointer to synchronous control fronthaul function
|
||||
void (*fh_south_ctrl)(struct RU_t_s *ru, int frame, int slot, uint64_t timestamp);
|
||||
/// function pointer to synchronous RX fronthaul function (RRU)
|
||||
void (*fh_north_in)(struct RU_t_s *ru, int *frame, int *subframe);
|
||||
/// function pointer to synchronous RX fronthaul function (RRU)
|
||||
|
||||
@@ -151,14 +151,6 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx)
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
start_meas(&ru->precoding_stats);
|
||||
|
||||
if (gNB->common_vars.analog_bf) {
|
||||
for (int i = 0; i < ru->num_beams_period; i++) {
|
||||
memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot],
|
||||
(void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot],
|
||||
(fp->symbols_per_slot) * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT)
|
||||
return;
|
||||
|
||||
@@ -197,16 +189,9 @@ void nr_feptx(void *arg)
|
||||
if (tx_idx == 0)
|
||||
start_meas(&ru->precoding_stats);
|
||||
|
||||
if (ru->gNB_list[0]->common_vars.analog_bf) {
|
||||
memcpy(&ru->common.beam_id[bb][slot * fp->symbols_per_slot],
|
||||
&ru->gNB_list[0]->common_vars.beam_id[bb][slot * fp->symbols_per_slot],
|
||||
(fp->symbols_per_slot) * sizeof(int));
|
||||
}
|
||||
|
||||
// If there is no digital beamforming we just need to copy the data to RU
|
||||
if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) {
|
||||
// FFT shift
|
||||
const NR_DL_FRAME_PARMS *fp = &ru->gNB_list[0]->frame_parms;
|
||||
fft_shift(ru->gNB_list[0]->common_vars.txdataF[bb][aa],
|
||||
fp->ofdm_symbol_size,
|
||||
fp->N_RB_DL,
|
||||
|
||||
@@ -80,6 +80,7 @@ typedef struct {
|
||||
int64_t rx_count;
|
||||
int wait_for_first_pps;
|
||||
int use_gps;
|
||||
int prev_beam;
|
||||
//int first_tx;
|
||||
//int first_rx;
|
||||
//! timestamp of RX packet
|
||||
@@ -313,6 +314,7 @@ static int trx_usrp_start(openair0_device_t *device)
|
||||
//s->first_tx = 1;
|
||||
//s->first_rx = 1;
|
||||
s->rx_timestamp = 0;
|
||||
s->prev_beam = -1;
|
||||
|
||||
//wait for next pps
|
||||
uhd::time_spec_t last_pps = s->usrp->get_time_last_pps();
|
||||
@@ -359,6 +361,43 @@ static void trx_usrp_finish_rx(usrp_state_t *s)
|
||||
} while (samples > 0);
|
||||
}
|
||||
|
||||
static int trx_set_beam(openair0_device_t *device, int *beams, int num_beams, openair0_timestamp_t timestamp)
|
||||
{
|
||||
AssertFatal(beams, "Invalid input for beams %p, vector not present\n", beams);
|
||||
AssertFatal(num_beams == 1, "Cannot handle more than 1 concurrent beam in USRP\n");
|
||||
usrp_state_t *s = (usrp_state_t *)device->priv;
|
||||
// to keep consistent with previous integration where we sent beam information to GPIO
|
||||
// only if it changed to avoid unnecessary timing issues that the procedure may cause
|
||||
if (beams[0] == s->prev_beam)
|
||||
return 0;
|
||||
else
|
||||
s->prev_beam = beams[0];
|
||||
int gpio = 0;
|
||||
switch (device->openair0_cfg->gpio_controller) {
|
||||
case RU_GPIO_CONTROL_GENERIC:
|
||||
AssertFatal(beams[0] < 8, "Only 3 bits available for setting beams\n");
|
||||
gpio = s->prev_beam | TX_GPIO_CHANGE;
|
||||
break;
|
||||
case RU_GPIO_CONTROL_INTERDIGITAL:
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "illegal GPIO controller for beam handling %d\n", device->openair0_cfg->gpio_controller);
|
||||
}
|
||||
radio_tx_gpio_flag_t flags_gpio = (radio_tx_gpio_flag_t) gpio;
|
||||
// bit 13 enables gpio
|
||||
timestamp -= device->openair0_cfg->command_line_sample_advance + device->openair0_cfg->tx_sample_advance;
|
||||
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 1);
|
||||
// push GPIO bits
|
||||
s->usrp->set_command_time(s->tx_md.time_spec);
|
||||
s->usrp->set_gpio_attr(s->gpio_bank, "OUT", flags_gpio, MAN_MASK);
|
||||
s->usrp->clear_command_time();
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void trx_usrp_write_reset(openair0_thread_t *wt);
|
||||
|
||||
/*! \brief Terminate operation of the USRP transceiver -- free all associated resources
|
||||
@@ -418,7 +457,6 @@ static int trx_usrp_write(openair0_device_t *device,
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
|
||||
radio_tx_burst_flag_t flags_burst = (radio_tx_burst_flag_t) (flags & 0xf);
|
||||
radio_tx_gpio_flag_t flags_gpio = (radio_tx_gpio_flag_t) ((flags >> 4) & 0x1fff);
|
||||
|
||||
int end;
|
||||
openair0_thread_t *write_thread = &device->write_thread;
|
||||
@@ -480,16 +518,6 @@ static int trx_usrp_write(openair0_device_t *device,
|
||||
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
|
||||
s->tx_count++;
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 1);
|
||||
// bit 13 enables gpio
|
||||
if ((flags_gpio & TX_GPIO_CHANGE) != 0) {
|
||||
// push GPIO bits
|
||||
s->usrp->set_command_time(s->tx_md.time_spec);
|
||||
s->usrp->set_gpio_attr(s->gpio_bank, "OUT", flags_gpio, MAN_MASK);
|
||||
s->usrp->clear_command_time();
|
||||
}
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_BEAM_SWITCHING_GPIO, 0);
|
||||
|
||||
if (cc > 1) {
|
||||
std::vector<void *> buff_ptrs;
|
||||
|
||||
@@ -524,7 +552,7 @@ static int trx_usrp_write(openair0_device_t *device,
|
||||
write_package[end].cc = cc;
|
||||
write_package[end].first_packet = first_packet_state;
|
||||
write_package[end].last_packet = last_packet_state;
|
||||
write_package[end].flags_gpio = flags_gpio;
|
||||
//write_package[end].flags_gpio = flags_gpio;
|
||||
for (int i = 0; i < cc; i++)
|
||||
write_package[end].buff[i] = buff[i];
|
||||
write_thread->count_write++;
|
||||
@@ -1519,6 +1547,7 @@ extern "C" {
|
||||
LOG_I(HW,"Device timestamp: %f...\n", s->usrp->get_time_now().get_real_secs());
|
||||
device->trx_write_func = trx_usrp_write;
|
||||
device->trx_read_func = trx_usrp_read;
|
||||
device->trx_set_beams2 = trx_set_beam;
|
||||
s->sample_rate = openair0_cfg[0].sample_rate;
|
||||
|
||||
// TODO:
|
||||
|
||||
Reference in New Issue
Block a user