Compare commits

...

6 Commits

Author SHA1 Message Date
francescomani
1617c32e3c symbol based RU control function
Signed-off-by: francescomani <email@francescomani.it>
2026-05-01 06:20:03 +02:00
francescomani
ae780bae57 adapt FR2 RFsim CI test to use beam features
Signed-off-by: francescomani <email@francescomani.it>
2026-05-01 06:20:01 +02:00
francescomani
2834088ea0 do not send beam information to USRP if the beam is the same as before
this keeps the same logic as before, the understanding is that executing the GPIO command requires time or at least have an impact on the timing, so it is better not to execute it if not necessary

Signed-off-by: francescomani <email@francescomani.it>
2026-05-01 06:19:59 +02:00
francescomani
0b320c8dce function to set GPIO beam for USRP using new API
Signed-off-by: francescomani <email@francescomani.it>
2026-05-01 06:19:57 +02:00
francescomani
9fc066394e RU control function for beam information
Signed-off-by: francescomani <email@francescomani.it>
2026-05-01 06:19:55 +02:00
francescomani
04ce714f37 modification in tx_rf and rx_rf to use read/write beams_func in case of concurrent beams
Signed-off-by: francescomani <email@francescomani.it>
2026-05-01 06:19:52 +02:00
8 changed files with 218 additions and 110 deletions

View File

@@ -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 = (

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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,

View File

@@ -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: