mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
O-RU: PRACH RX and PRACH UP packet generation
This commit is contained in:
@@ -1834,7 +1834,7 @@ target_link_libraries(nr-oru PRIVATE
|
||||
radio_common softmodem_common)
|
||||
target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
|
||||
barrier actor)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management PHY_NR)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management PHY_NR MAC_NR_COMMON)
|
||||
|
||||
# nr-softmodem
|
||||
###################################################
|
||||
|
||||
@@ -207,6 +207,23 @@ int main(int argc, char **argv)
|
||||
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp);
|
||||
ru->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
|
||||
|
||||
/* set PRACH configuration */
|
||||
nfapi_nr_prach_config_t *prach_config = &ru->config.prach_config;
|
||||
prach_config->prach_ConfigurationIndex.value = oru.prach_config_index;
|
||||
prach_config->num_prach_fd_occasions_list[0].k1.value = oru.prach_msg1_freq;
|
||||
prach_config->prach_sequence_length.value = 1;
|
||||
prach_config->prach_sub_c_spacing.value = 1;
|
||||
prach_config->num_prach_fd_occasions.value = 1;
|
||||
|
||||
reset_meas(&oru.rx_prach);
|
||||
oru.prach_info = get_nr_prach_occasion_info_from_index(oru.prach_config_index, FR1, fp->frame_type);
|
||||
LOG_A(PHY, "PRACH configuration index %d\n", oru.prach_config_index);
|
||||
LOG_A(PHY,
|
||||
"PRACH format %d start_symbol %d duration %d\n",
|
||||
oru.prach_info.format,
|
||||
oru.prach_info.start_symbol,
|
||||
oru.prach_info.N_dur);
|
||||
prepare_prach_item(&oru);
|
||||
|
||||
ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
|
||||
AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport potocol\n", ru->idx, ret);
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#include "PHY/defs_RU.h"
|
||||
#include "assertions.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "nr-oru.h"
|
||||
#include "openair1/PHY/defs_nr_common.h"
|
||||
#include "openair1/PHY/MODULATION/nr_modulation.h"
|
||||
#include "openair1/SCHED_NR/sched_nr.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
|
||||
#define CONFIG_SECTION_ORU "ORUs.[0]"
|
||||
|
||||
@@ -103,6 +105,16 @@ typedef struct {
|
||||
} dl_symbol_process_t;
|
||||
|
||||
extern void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols);
|
||||
extern void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int beam_id,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep_index,
|
||||
uint reps);
|
||||
|
||||
static void oru_downlink_processing(ORU_t *oru,
|
||||
c16_t *txDataF_ptr[oru->ru->nb_tx],
|
||||
int frame,
|
||||
@@ -270,6 +282,48 @@ static openair0_timestamp_t get_timestamp(ORU_t *oru, sense_of_time_t *sense_of_
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void receive_prach(ORU_t *oru, int frame, int slot, int prach_symbol)
|
||||
{
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
oru->prach_item.frame = frame;
|
||||
oru->prach_item.slot = slot;
|
||||
|
||||
|
||||
rx_nr_prach_ru_internal(&oru->prach_item,
|
||||
0,
|
||||
oru->prach_info.start_symbol,
|
||||
0,
|
||||
ru->common.rxdata,
|
||||
fp,
|
||||
ru->N_TA_offset,
|
||||
prach_symbol,
|
||||
1);
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
ru->ifdevice.xran_api.write_prach((uint32_t *)oru->prach_item.rxsigF[0][aarx], aarx, frame, slot, prach_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns PRACH symbol that was received in current frame, slot and symbol.
|
||||
// If no PRACH symbol was received, returns -1
|
||||
int get_prach_symbol(ORU_t *oru, int frame, int slot, int symbol, int numerology)
|
||||
{
|
||||
uint16_t RA_sfn_index;
|
||||
AssertFatal(oru->ru->nr_frame_parms->frame_type == TDD, "Only supports TDD\n");
|
||||
if (get_nr_prach_sched_from_info(oru->prach_info, oru->prach_config_index, frame, slot, numerology, FR1, &RA_sfn_index, true)) {
|
||||
int format = oru->prach_item.pdu.prach_format;
|
||||
int start_symbol = oru->prach_item.pdu.prach_start_symbol;
|
||||
symbol -= start_symbol;
|
||||
// TODO: Support more PRACH formats
|
||||
AssertFatal(format == 8, "only support format B4\n");
|
||||
// TODO: This is not exactly the case but it is correct
|
||||
if (symbol > 0 && symbol < 12) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *oru_north_read_thread(void *arg)
|
||||
{
|
||||
ORU_t *oru = (ORU_t *)arg;
|
||||
@@ -400,6 +454,49 @@ void *oru_south_read_thread(void *arg)
|
||||
rx_initial_sync(oru, &slot, &frame);
|
||||
LOG_A(PHY, "ORU South read thread started at frame %d, slot %d\n", frame, slot);
|
||||
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
while (!oai_exit) {
|
||||
int rx_slot_type = nr_slot_select(&ru->config, frame, slot);
|
||||
for (int symbol = 0; symbol < 14; symbol++) {
|
||||
int samples_to_read = get_samples_symbol_duration(fp, slot, symbol, 1);
|
||||
size_t offset = get_samples_slot_timestamp(fp, slot) + get_samples_symbol_timestamp(fp, slot, symbol);
|
||||
c16_t *rxp[fp->nb_antennas_rx];
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
rxp[aarx] = (c16_t *)&ru->common.rxdata[aarx][offset];
|
||||
}
|
||||
|
||||
openair0_timestamp_t timestamp;
|
||||
int num_samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, ×tamp, (void **)rxp, samples_to_read, ru->nb_rx);
|
||||
AssertFatal(num_samples_read == samples_to_read, "Unexpected number of samples received\n");
|
||||
LOG_D(PHY,
|
||||
"[ORU south] read data: frame %d, slot %d, symbol %d, timestamp %ld num_symbols %d, samples %d\n",
|
||||
frame,
|
||||
slot,
|
||||
symbol,
|
||||
timestamp,
|
||||
1,
|
||||
num_samples_read);
|
||||
|
||||
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
|
||||
int prach_symbol = get_prach_symbol(oru, frame, slot, symbol, ru->numerology);
|
||||
if (prach_symbol == 11) {
|
||||
receive_prach(oru, frame, slot, prach_symbol);
|
||||
}
|
||||
stop_meas(&oru->rx);
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
if (slot == fp->slots_per_frame) {
|
||||
slot = 0;
|
||||
frame++;
|
||||
if (frame == 1024) {
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform RX processing
|
||||
return NULL;
|
||||
}
|
||||
@@ -511,3 +608,83 @@ static void oru_downlink_processing(ORU_t *oru,
|
||||
tx_rf_symbols(ru, frame, slot, timestamp_tx, start_symbol, num_symbols);
|
||||
stop_meas(&ru->tx_fhaul);
|
||||
}
|
||||
|
||||
void prepare_prach_item(ORU_t *oru)
|
||||
{
|
||||
AssertFatal(oru->ru != NULL, "ORU not configured\n");
|
||||
AssertFatal(oru->ru->nr_frame_parms != NULL, "ORU not configured\n");
|
||||
NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
|
||||
RU_t *ru = oru->ru;
|
||||
prach_item_t *prach_item = &oru->prach_item;
|
||||
prach_item->num_slots = oru->prach_info.format < 4 ? get_long_prach_dur(oru->prach_info.format, fp->numerology_index) : 1;
|
||||
prach_item->msg1_frequencystart = oru->prach_msg1_freq;
|
||||
prach_item->mu = fp->numerology_index;
|
||||
nfapi_nr_config_request_scf_t *cfg = &ru->config;
|
||||
prach_item->prach_sequence_length = cfg->prach_config.prach_sequence_length.value;
|
||||
prach_item->restricted_set = 0;
|
||||
prach_item->numerology_index = fp->numerology_index;
|
||||
prach_item->nb_rx = ru->nb_rx;
|
||||
prach_item->rx_prach = &oru->rx_prach;
|
||||
prach_item->beams[0] = 0; // TODO: Beamforming not supported yet
|
||||
|
||||
// Fill PRACH PDU
|
||||
nfapi_nr_prach_pdu_t *prach_pdu = &prach_item->pdu;
|
||||
prach_pdu->prach_start_symbol = oru->prach_info.start_symbol;
|
||||
prach_pdu->num_prach_ocas = 1; // TODO: Hardcoded.
|
||||
|
||||
uint16_t format0 = oru->prach_info.format & 0xff;
|
||||
uint16_t format1 = (oru->prach_info.format >> 8) & 0xff;
|
||||
if (format1 != 0xff) {
|
||||
switch (format0) {
|
||||
case 0xa1:
|
||||
prach_pdu->prach_format = 11;
|
||||
break;
|
||||
case 0xa2:
|
||||
prach_pdu->prach_format = 12;
|
||||
break;
|
||||
case 0xa3:
|
||||
prach_pdu->prach_format = 13;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
|
||||
}
|
||||
} else {
|
||||
switch (format0) {
|
||||
case 0:
|
||||
prach_pdu->prach_format = 0;
|
||||
break;
|
||||
case 1:
|
||||
prach_pdu->prach_format = 1;
|
||||
break;
|
||||
case 2:
|
||||
prach_pdu->prach_format = 2;
|
||||
break;
|
||||
case 3:
|
||||
prach_pdu->prach_format = 3;
|
||||
break;
|
||||
case 0xa1:
|
||||
prach_pdu->prach_format = 4;
|
||||
break;
|
||||
case 0xa2:
|
||||
prach_pdu->prach_format = 5;
|
||||
break;
|
||||
case 0xa3:
|
||||
prach_pdu->prach_format = 6;
|
||||
break;
|
||||
case 0xb1:
|
||||
prach_pdu->prach_format = 7;
|
||||
break;
|
||||
case 0xb4:
|
||||
prach_pdu->prach_format = 8;
|
||||
break;
|
||||
case 0xc0:
|
||||
prach_pdu->prach_format = 9;
|
||||
break;
|
||||
case 0xc2:
|
||||
prach_pdu->prach_format = 10;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Invalid PRACH format");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
*/
|
||||
#ifndef __NR_ORU_H__
|
||||
#define __NR_ORU_H__
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "openair1/PHY/defs_RU.h"
|
||||
#include "thread-pool.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h"
|
||||
|
||||
typedef struct {
|
||||
RU_t *ru;
|
||||
@@ -57,6 +60,12 @@ typedef struct {
|
||||
int num_sync_messages_needed;
|
||||
notifiedFIFO_t sync_fifo;
|
||||
tpool_t tpool;
|
||||
|
||||
// PRACH related
|
||||
nr_prach_info_t prach_info;
|
||||
time_stats_t rx_prach;
|
||||
time_stats_t rx;
|
||||
prach_item_t prach_item;
|
||||
} ORU_t;
|
||||
|
||||
int get_oru_options(ORU_t *oru);
|
||||
@@ -64,5 +73,6 @@ void oru_init_frame_parms(ORU_t *oru);
|
||||
void *oru_north_read_thread(void *arg);
|
||||
void *oru_south_read_thread(void *arg);
|
||||
void *oru_sync_thread(void *arg);
|
||||
void prepare_prach_item(ORU_t *oru);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -125,15 +125,15 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n
|
||||
return prach;
|
||||
}
|
||||
|
||||
static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int beam_id,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep_index,
|
||||
uint reps)
|
||||
void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int beam_id,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep_index,
|
||||
uint reps)
|
||||
{
|
||||
int sample_offset_slot;
|
||||
const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples;
|
||||
|
||||
@@ -680,6 +680,16 @@ struct openair0_device {
|
||||
* \param num_symbols number of symbols
|
||||
*/
|
||||
void (*north_in_func)(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols);
|
||||
|
||||
/*!
|
||||
* \brief Write prach data for one PRACH symbol
|
||||
* \param prachF Frequency domain PRACH data size 139 (only short format support)
|
||||
* \param aarx
|
||||
* \param frame
|
||||
* \param slot
|
||||
* \param symbol
|
||||
*/
|
||||
void (*write_prach)(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
|
||||
} xran_api;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#include "xran_fh_o_ru.h"
|
||||
#include "xran_compression.h"
|
||||
#include "armral_bfp_compression.h"
|
||||
#include <xran_pkt.h>
|
||||
#include <xran_pkt_up.h>
|
||||
#include <xran_transport.h>
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
#else
|
||||
@@ -53,6 +56,10 @@
|
||||
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
|
||||
#define RATE_LIMIT(n) if (({ static int _counter = 0; _counter++ % (n) == 0; }))
|
||||
#define ETHER_TYPE_ECPRI 0xAEFE
|
||||
#define MAX_NUM_ANTENNAS 4
|
||||
|
||||
notifiedFIFO_t ru_dl_sync_fifo;
|
||||
extern volatile bool first_call_set;
|
||||
|
||||
@@ -231,6 +238,22 @@ static void print_statistics(packet_processor_context_t *context)
|
||||
LOG_I(HW, "RU: packets dropped %lu\n", context->up_dropped);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
int slot;
|
||||
int frame;
|
||||
int mu;
|
||||
int filter_id;
|
||||
} oran_prach_cplane_config_t;
|
||||
|
||||
oran_prach_cplane_config_t prach_config_per_antenna[MAX_NUM_ANTENNAS] = {0};
|
||||
static uint8_t prach_seq_id[MAX_NUM_ANTENNAS] = {0};
|
||||
|
||||
extern int32_t xran_ethdi_mbuf_send(struct rte_mbuf *mb, uint16_t ethertype, uint16_t vf_id);
|
||||
extern uint16_t xran_map_ecpriPcid_to_vf(void *p_dev_ctx, int32_t dir, int32_t cc_id, int32_t ru_port_id);
|
||||
|
||||
void symbol_callback(void *args, struct xran_sense_of_time *p_sense_of_time)
|
||||
{
|
||||
if (!first_call_set) {
|
||||
@@ -478,7 +501,58 @@ int process_ru_uplane(struct rte_mbuf *pkt,
|
||||
|
||||
int32_t process_ru_cplane(struct rte_mbuf *pkt, void *handle, uint16_t port_id, struct xran_sense_of_time *p_sense_of_time)
|
||||
{
|
||||
return MBUF_FREE;
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(port_id);
|
||||
struct xran_ecpri_hdr *ecpri_hdr;
|
||||
struct xran_recv_packet_info xran_recv_packet_info;
|
||||
int ret = xran_parse_ecpri_hdr(pkt, &ecpri_hdr, &xran_recv_packet_info);
|
||||
if (ret != XRAN_STATUS_SUCCESS) {
|
||||
return MBUF_FREE;
|
||||
}
|
||||
struct xran_cp_radioapp_common_header *apphdr = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_ecpri_hdr));
|
||||
if (apphdr == NULL) {
|
||||
LOG_W(HW, "issue extracting apphdr\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
apphdr->field.all_bits = rte_be_to_cpu_32(apphdr->field.all_bits);
|
||||
if (apphdr->field.payloadVer != XRAN_PAYLOAD_VER) {
|
||||
LOG_W(HW, "Invalid payloadVer field %d\n", apphdr->field.payloadVer);
|
||||
return MBUF_FREE;
|
||||
}
|
||||
|
||||
switch (apphdr->sectionType) {
|
||||
case XRAN_CP_SECTIONTYPE_3: {
|
||||
struct xran_cp_radioapp_section3_header *hdr = (struct xran_cp_radioapp_section3_header *)apphdr;
|
||||
if (hdr->cmnhdr.numOfSections != 1) {
|
||||
LOG_W(HW, "Only support one section\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
|
||||
hdr->timeOffset = rte_be_to_cpu_16(hdr->timeOffset);
|
||||
hdr->cpLength = rte_be_to_cpu_16(hdr->cpLength);
|
||||
|
||||
struct xran_cp_radioapp_section3 *section = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_cp_radioapp_section3_header));
|
||||
if (section == NULL) {
|
||||
LOG_W(HW, "Issue extracting section\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
*((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
|
||||
int mu = hdr->frameStructure.uScs;
|
||||
int aarx = xran_recv_packet_info.eaxc.ruPortId - fh_cfg->prach_conf.eAxC_offset;
|
||||
oran_prach_cplane_config_t prach_config = {
|
||||
.frame = hdr->cmnhdr.field.frameId,
|
||||
.slot = hdr->cmnhdr.field.slotId + hdr->cmnhdr.field.subframeId + hdr->cmnhdr.field.subframeId * hdr->frameStructure.uScs,
|
||||
.num_prb = section->hdr.u1.common.numPrbc,
|
||||
.start_prb = section->hdr.u1.common.startPrbc,
|
||||
.section_id = section->hdr.u1.common.sectionId,
|
||||
.mu = mu,
|
||||
.filter_id = hdr->cmnhdr.field.filterIndex
|
||||
};
|
||||
prach_config_per_antenna[aarx] = prach_config;
|
||||
return MBUF_FREE;
|
||||
}
|
||||
default:
|
||||
return MBUF_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
void init_oru_packet_processor(void *handle, int callbacks_per_slot)
|
||||
@@ -489,6 +563,13 @@ void init_oru_packet_processor(void *handle, int callbacks_per_slot)
|
||||
static bool installed = false;
|
||||
AssertFatal(!installed, "Cannot init oru twice\n");
|
||||
installed = true;
|
||||
for (int aarx = 0; aarx < MAX_NUM_ANTENNAS; aarx++) {
|
||||
prach_config_per_antenna[aarx].section_id = -1;
|
||||
prach_config_per_antenna[aarx].num_prb = -1;
|
||||
prach_config_per_antenna[aarx].start_prb = -1;
|
||||
prach_config_per_antenna[aarx].slot = -1;
|
||||
prach_config_per_antenna[aarx].frame = -1;
|
||||
}
|
||||
|
||||
|
||||
// Represents RX window end
|
||||
@@ -525,3 +606,112 @@ void init_oru_packet_processor(void *handle, int callbacks_per_slot)
|
||||
}
|
||||
xran_hook_install(handle, process_ru_uplane, NULL, process_ru_cplane, NULL, symbol_callback, &args, mu);
|
||||
}
|
||||
|
||||
extern void *xran_ethdi_mbuf_alloc(void);
|
||||
|
||||
void fill_ecpri_header(struct xran_ecpri_hdr *ecpri_header,
|
||||
uint8_t ecpri_mesg_type,
|
||||
size_t ecpri_payload_size,
|
||||
uint8_t CC_ID,
|
||||
uint8_t Ant_ID,
|
||||
uint8_t seq_id,
|
||||
uint8_t oxu_port_id)
|
||||
{
|
||||
ecpri_header->cmnhdr.data.data_num_1 = 0x0;
|
||||
ecpri_header->cmnhdr.bits.ecpri_ver = XRAN_ECPRI_VER;
|
||||
ecpri_header->cmnhdr.bits.ecpri_mesg_type = ecpri_mesg_type;
|
||||
ecpri_header->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(ecpri_payload_size);
|
||||
ecpri_header->ecpri_xtc_id = xran_compose_cid(0, 0, CC_ID, Ant_ID);
|
||||
ecpri_header->ecpri_seq_id.bits.seq_id = seq_id;
|
||||
ecpri_header->ecpri_seq_id.bits.e_bit = 1;
|
||||
ecpri_header->ecpri_seq_id.bits.sub_seq_id = 0;
|
||||
/// No byteswap for ecpri_seq_id. Possibly because of inverse definition in xran
|
||||
}
|
||||
|
||||
void fill_radio_app_header(struct radio_app_common_hdr *radio_app_header,
|
||||
int filter_id,
|
||||
int direction,
|
||||
int frame,
|
||||
int slot,
|
||||
int symbol,
|
||||
int mu)
|
||||
{
|
||||
radio_app_header->frame_id = frame & 0xff;
|
||||
radio_app_header->sf_slot_sym.slot_id = slot % (1 << mu);
|
||||
radio_app_header->sf_slot_sym.subframe_id = slot / (1 << mu);
|
||||
radio_app_header->sf_slot_sym.symb_id = symbol;
|
||||
radio_app_header->sf_slot_sym.value = rte_cpu_to_be_16(radio_app_header->sf_slot_sym.value);
|
||||
radio_app_header->data_feature.data_direction = direction;
|
||||
radio_app_header->data_feature.payl_ver = 1;
|
||||
radio_app_header->data_feature.filter_id = filter_id;
|
||||
}
|
||||
|
||||
void fill_data_section_header(struct data_section_hdr *data_section_hdr, int num_prb, int start_prb, int section_id)
|
||||
{
|
||||
data_section_hdr->fields.all_bits = 0;
|
||||
data_section_hdr->fields.num_prbu = (uint8_t)XRAN_CONVERT_NUMPRBC(num_prb);
|
||||
data_section_hdr->fields.start_prbu = (start_prb & 0x03ff);
|
||||
data_section_hdr->fields.sect_id = section_id;
|
||||
data_section_hdr->fields.all_bits = rte_cpu_to_be_32(data_section_hdr->fields.all_bits);
|
||||
}
|
||||
|
||||
void xran_oru_send_prach(uint32_t *prachF, int aarx, int frame, int slot, int symbol)
|
||||
{
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
uint8_t mu = fh_cfg->frame_conf.nNumerology;
|
||||
|
||||
AssertFatal(fh_cfg->ru_conf.compMeth_PRACH == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
|
||||
// TODO: With compression, have to add compression header to header_len
|
||||
size_t header_length = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr);
|
||||
|
||||
// TODO: For compression, have to re-evaluate data size;
|
||||
// TODO: Only support short format PRACH
|
||||
const uint prach_length = 139;
|
||||
size_t data_len = sizeof(int32_t) * prach_length;
|
||||
|
||||
oran_prach_cplane_config_t *prach_config = &prach_config_per_antenna[aarx];
|
||||
if (prach_config->section_id == -1) {
|
||||
RATE_LIMIT(1000)
|
||||
LOG_W(HW, "PRACH was not yet configured by the O-DU\n");
|
||||
return;
|
||||
}
|
||||
if (prach_config->frame != (frame & 0xff) || prach_config->slot != slot) {
|
||||
RATE_LIMIT(1000)
|
||||
LOG_W(HW,
|
||||
"PRACH was not configured for frame.slot %d.%d, configuration is for frame.slot %d.%d\n",
|
||||
frame,
|
||||
slot,
|
||||
prach_config->frame,
|
||||
prach_config->slot);
|
||||
return;
|
||||
}
|
||||
|
||||
struct rte_mbuf *mbuf = xran_ethdi_mbuf_alloc();
|
||||
AssertFatal(mbuf != NULL, "out of mbufs\n");
|
||||
char *buf = rte_pktmbuf_append(mbuf, header_length + data_len);
|
||||
AssertFatal(buf, "incorrect mbuf size\n");
|
||||
|
||||
struct xran_ecpri_hdr *ecpri_header = (struct xran_ecpri_hdr *)rte_pktmbuf_mtod(mbuf, char *);
|
||||
uint16_t ecpri_payload_size = xran_get_ecpri_hdr_size() + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr) + data_len;
|
||||
fill_ecpri_header(ecpri_header, ECPRI_IQ_DATA, ecpri_payload_size, 0, aarx + fh_cfg->prach_conf.eAxC_offset, prach_seq_id[aarx]++, 0);
|
||||
|
||||
struct radio_app_common_hdr *radio_app_header = (struct radio_app_common_hdr *)(ecpri_header + 1);
|
||||
fill_radio_app_header(radio_app_header, prach_config->filter_id, XRAN_DIR_UL, frame, slot, symbol, mu);
|
||||
|
||||
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
|
||||
fill_data_section_header(data_section_header, prach_config->num_prb, prach_config->start_prb, prach_config->section_id);
|
||||
|
||||
void *iq_data_start = (void *)(data_section_header + 1);
|
||||
int16_t *dest = (int16_t *)iq_data_start;
|
||||
uint16_t *src = (uint16_t *)prachF;
|
||||
for (int i = 0; i < prach_length * 2; i++) {
|
||||
dest[i] = (int16_t)htons(src[i]);
|
||||
}
|
||||
|
||||
buf = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
AssertFatal(buf != NULL, "incorrect mbuf size\n");
|
||||
|
||||
int vf_id = xran_map_ecpriPcid_to_vf(gxran_handle, XRAN_DIR_UL, 0, aarx + fh_cfg->prach_conf.eAxC_offset);
|
||||
int ret = xran_ethdi_mbuf_send(mbuf, ETHER_TYPE_ECPRI, vf_id);
|
||||
AssertFatal(ret == 1, "Error sending mbuf\n");
|
||||
}
|
||||
|
||||
@@ -32,5 +32,6 @@ void init_oru_packet_processor(void* handle, int callbacks_per_slot);
|
||||
|
||||
// Read samples DL IQ samples for frame slot symbol for all antennas
|
||||
int xran_oru_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, int *num_symbols, struct timespec *ts);
|
||||
void xran_oru_send_prach(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
|
||||
|
||||
#endif
|
||||
|
||||
53
radio/fhi_72/oran_debug.c
Normal file
53
radio/fhi_72/oran_debug.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "oran_debug.h"
|
||||
#include "openair1/PHY/TOOLS/tools_defs.h"
|
||||
|
||||
void dump_nonzero_symbol(c16_t *txdataF, uint32_t ofdm_symbol_size, int frame, int slot, int symbol, const char* loc)
|
||||
{
|
||||
float signal_energy = signal_energy_nodc(txdataF, ofdm_symbol_size);
|
||||
if (signal_energy > 1) {
|
||||
// Prepare a buffer to hold the formatted string for the symbol
|
||||
const int num_chars_per_sample = 4 + 6 * 2;
|
||||
char symbol_buf[ofdm_symbol_size * num_chars_per_sample]; // Enough for "(r,i) " per sample
|
||||
int offset = 0;
|
||||
bool is_zero_block = true;
|
||||
for (int i = 0; i < ofdm_symbol_size; i++) {
|
||||
bool is_zero = txdataF[i].r == 0 && txdataF[i].i == 0;
|
||||
if (is_zero_block && !is_zero) {
|
||||
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "[sc %d]: ", i);
|
||||
is_zero_block = false;
|
||||
}
|
||||
if (!is_zero_block && is_zero) {
|
||||
is_zero_block = true;
|
||||
}
|
||||
if (!is_zero) {
|
||||
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "(%d,%d) ", txdataF[i].r, txdataF[i].i);
|
||||
}
|
||||
}
|
||||
symbol_buf[offset] = '\0';
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
|
||||
LOG_D(HW, "dump_nonzero_symbol: Frame.Slot.Symbol %d.%d.%d (%s) signal_energy %.3f time %ld.%09ld samples: %s\n", frame, slot, symbol, loc, 10 * log10(signal_energy), ts.tv_sec, ts.tv_nsec, symbol_buf);
|
||||
}
|
||||
}
|
||||
@@ -408,6 +408,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device_t
|
||||
device->priv = eth;
|
||||
device->openair0_cfg = &openair0_cfg[0];
|
||||
device->xran_api.north_in_func = oran_fh_if4p5_north_in;
|
||||
device->xran_api.write_prach = xran_oru_send_prach;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user