diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 8e2058f5c1..c28f75a2cf 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -1059,10 +1059,10 @@ section](.#build-oai-gnb)) to see if it resolves the problem. # Operation with multiple RUs It is possible to connect up to 4 RUs to one DU at the same time and operate -them as a (single) distributed antenna (array). This works since all RUs and -the DU are synchronized onto a common clock using PTP. The assumed -configuration is that with N RUs each having an M×M configuration, we -effectively reach an (N×M)×(N×M) configuration. +them either with a single antenna array or a distributed antenna array. This +works since all RUs and the DU are synchronized onto a common clock using PTP. +The assumed configuration is that with N RUs each having an M×M configuration, +we effectively reach an (N×M)×(N×M) configuration. Some caveats: - Since it's a distributed antenna, this implies that this setup will deploy a diff --git a/doc/README.md b/doc/README.md index 13028479cd..4786458a66 100644 --- a/doc/README.md +++ b/doc/README.md @@ -117,6 +117,7 @@ Some directories under `radio` contain READMEs: - [USRP](../radio/USRP/README.md) - [BladeRF](../radio/BLADERF/README) - [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md) +- [fhi_72](../radio/fhi_72/README.md) The other SDRs (AW2S, LimeSDR, ...) have no READMEs. diff --git a/radio/fhi_72/README.md b/radio/fhi_72/README.md new file mode 100644 index 0000000000..2f72a9aa07 --- /dev/null +++ b/radio/fhi_72/README.md @@ -0,0 +1,46 @@ +This document describes the driver for the xran driver, implementing O-RAN FHI +7.2 interface. This is for developers; for user documentation, consider the +[O-RAN 7.2 tutorial instead](../../doc/ORAN_FHI7.2_Tutorial.md). + +The main source files and their purpose are as follows: + +- `oaioran.c`: definition of xran-specific callback functions. +- `oran-config.c`: reading of 7.2-specific configuration and preparing xran + configration. +- `oran-init.c`: initialization of xran. +- `oran_isolate.c`: main entry point and definition of function pointers for OAI + callbacks. + +The entry point for the driver library is `transport_init()` in `oran_isolate.c`. +This function is concerned with setting necessary function pointers for OAI +integration, and prepares xran configuration through `get_xran_config()`. This +function reads 7.2 specific configuration and deduces some of the parameters +(e.g., frequency) from OAI-provided radio configuration in `openair0_config_t`. + +Actual xran initialization happens in `oai_oran_initialize()` in `oran-init.c`. +It calls various helper function in the same file to set up DPDK memory buffer +(pools). Notably, these callbacks are installed: + +- `oai_xran_fh_rx_callback()` through `xran_5g_fronthault_config()`: callback + for PUSCH data; used to provide timing data. +- `oai_xran_fh_rx_prach_callback()` through `xran_5g_prach_req()`: callback for + PRACH data; not currently used and implemented in PUSCH data callback. +- `oai_physide_dl_tti_call_back()` through `xran_reg_physide_cb()`: only used + to unblock timing in `oai_xran_fh_rx_callback()` upon first xran call. + +More detailed information about the xran callbacks can be taken from the xran +documentation. + +During normal operation, OAI calls into the driver through functions +`oran_fh_if4p5_south_in()` for PUSCH/PRACH and `oran_fh_if4p5_south_out()` for +PDSCH. + +For PDSCH, `oran_fh_if4p5_south_out()` calls `xran_fh_tx_send_slot()` that +optionally compresses IQ data, then writes it into IQ buffers of xran. + +For PUSCH/PRACH, `oran_fh_if4p5_south_in()` calls `xran_fh_rx_read_slot()` that +blocks and waits for the next slot. This is done through either a message +queue, or through polling, which in both cases depends on xran calling the +callback `oai_xran_fh_rx_callback()` as installed during xran initialization. +Once unblocked, it reads first PRACH data, then PUSCH data, before returning to +OAI. diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 65839fd5a0..16dd2d85de 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -44,7 +44,7 @@ #endif // Declare variable useful for the send buffer function -volatile uint8_t first_call_set = 0; +volatile bool first_call_set = false; int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id); #include "common/utils/LOG/log.h" @@ -54,6 +54,12 @@ extern notifiedFIFO_t oran_sync_fifo; #else volatile oran_sync_info_t oran_sync_info = {0}; #endif + +/** @details xran-specific callback, called when all packets for given CC and + * 1/4, 1/2, 3/4, all symbols of a slot arrived. Currently, only used to get + * timing information and unblock another thread in xran_fh_rx_read_slot() + * through either a message queue, or writing in global memory with polling, on + * a full slot boundary. */ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) { struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; @@ -150,36 +156,23 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) last_frame = frame; } // rx_sym == 7 } -void oai_xran_fh_srs_callback(void *pCallbackTag, xran_status_t status) -{ - rte_pause(); -} -void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status) -{ - rte_pause(); -} +/** @details Only used to unblock timing in oai_xran_fh_rx_callback() on first + * call. */ int oai_physide_dl_tti_call_back(void *param) { if (!first_call_set) - printf("first_call set from phy cb first_call_set=%p\n", &first_call_set); - first_call_set = 1; + LOG_I(HW, "first_call set from phy cb\n"); + first_call_set = true; return 0; } -int oai_physide_ul_half_slot_call_back(void *param) -{ - rte_pause(); - return 0; -} - -int oai_physide_ul_full_slot_call_back(void *param) -{ - rte_pause(); - return 0; -} - -int read_prach_data(ru_info_t *ru, int frame, int slot) +/** @brief Reads PRACH data from xran buffers. + * + * @details Reads PRACH data from xran-specific buffers and, if I/Q compression + * (bitwidth < 16 bits) is configured, uncompresses the data. Places PRACH data + * in OAI buffer. */ +static int read_prach_data(ru_info_t *ru, int frame, int slot) { /* calculate tti and subframe_id from frame, slot num */ int sym_idx = 0; @@ -248,6 +241,11 @@ int read_prach_data(ru_info_t *ru, int frame, int slot) return (0); } +/** @brief Check if symbol in slot is UL. + * + * @param frame_conf xran frame configuration + * @param slot the current (absolute) slot (number) + * @param sym_idx the current symbol index */ static bool is_tdd_ul_symbol(const struct xran_frame_config *frame_conf, int slot, int sym_idx) { /* in FDD, every symbol is also UL */ @@ -259,11 +257,20 @@ static bool is_tdd_ul_symbol(const struct xran_frame_config *frame_conf, int slo return frame_conf->sSlotConfig[slot_in_period].nSymbolType[sym_idx] == 1 /* UL */; } +/** @brief Check if current slot is DL or guard/mixed without UL (i.e., current + * slot is not UL). */ static bool is_tdd_dl_guard_slot(const struct xran_frame_config *frame_conf, int slot) { return !is_tdd_ul_symbol(frame_conf, slot, XRAN_NUM_OF_SYMBOL_PER_SLOT - 1); } +/** @details Read PRACH and PUSCH data from xran buffers. If + * I/Q compression (bitwidth < 16 bits) is configured, deccompresses the data + * before writing. Prints ON TIME counters every 128 frames. + * + * Function is blocking and waits for next frame/slot combination. It is unblocked + * by oai_xran_fh_rx_callback(). It writes the current slot into parameters + * frame/slot. */ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) { void *ptr = NULL; @@ -458,6 +465,9 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) return (0); } +/** @details Write PDSCH IQ-data from OAI txdataF_BF buffer to xran buffers. If + * I/Q compression (bitwidth < 16 bits) is configured, compresses the data + * before writing. */ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) { int tti = /*frame*SUBFRAMES_PER_SYSTEMFRAME*SLOTNUM_PER_SUBFRAME+*/ 20 * frame diff --git a/radio/fhi_72/oaioran.h b/radio/fhi_72/oaioran.h index a20f6c80d3..e973ce2997 100644 --- a/radio/fhi_72/oaioran.h +++ b/radio/fhi_72/oaioran.h @@ -31,7 +31,9 @@ typedef struct { uint32_t f; } oran_sync_info_t; +/** @brief xran callback for fronthaul RX, see xran_5g_fronthault_config(). */ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status); +/** @brief xran callback for time alignment, see xran_reg_physide_cb(). */ int oai_physide_dl_tti_call_back(void *param); #endif /* OAIORAN_H */ diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index a5c620e995..97930a172b 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -443,7 +443,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi pi->prach_tag = tag; pi->pusch_tag = tag; #ifdef E_RELEASE - LOG_W(PHY, "Please be aware that E release support will be removed by the end of January 2025. Instead, F release will be mandatory.\n"); + LOG_W(PHY, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n"); oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]); #elif defined F_RELEASE oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]); diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h index 7388f88f3b..174c1399a6 100644 --- a/radio/fhi_72/oran_isolate.h +++ b/radio/fhi_72/oran_isolate.h @@ -45,9 +45,13 @@ typedef struct ru_info_s { int16_t **prach_buf; } ru_info_t; +/** @brief Reads RX data (PRACH/PUSCH) of next slot. + * + * @param ru pointer to structure keeping pointers to OAI data. + * @param frame output of the frame which has been read. + * @param slot output of the slot which has been read. */ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot); +/** @brief Writes TX data (PDSCH) of given slot. */ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp); -int compute_xran_statistics(); - #endif /* _ORAN_ISOLATE_H_ */