Compare commits

..

128 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
32471f94ba Wraparound buffer for modulo-free mapping/demapping in FFT buffers.
Added an implementation of a wraparound buffer using virtual address mapping.
With the wraparound buffer a physical address is mapped a second time to virtual
memory right after the initial mapping. That makes it so that:

  buf[i] == buff[i + size]

The offset operation is undertaken by the processor MMU instead.
2025-12-16 16:53:32 +01:00
Jaroslava Fiedlerova
479be40b30 Merge branch 'integration_2025_w50' into 'develop'
Integration `2025.w50`

* !3638 NR UE: calculate TA based on SIB19 information in NTN mode, if autonomous TA is not enabled
* !3624 NR UE: improve handling of Handover procedures
* !3807 doc: Update doc for IF setup
* !3741 Update documenation for handover
* !3798 Fix for computation of PRACH occasions and association period
* !3808 Add symbol timing functions for NR_DL_FRAME_PARMS + optimization for slot timing counterparts

Closes #981

See merge request oai/openairinterface5g!3806
2025-12-12 14:47:26 +00:00
Jaroslava Fiedlerova
44c64a2ed0 Merge remote-tracking branch 'origin/symbol-duration-functions' into integration_2025_w50 (!3808)
Add symbol timing functions for NR_DL_FRAME_PARMS + optimization for slot timing
counterparts

Add two new functions for calculation symbol timestamp and symbol duration for
NR_DL_FRAME_PARMS. Also includes an optimization focused on removing
inefficiencies related slot-related counterparts.
2025-12-12 11:41:27 +01:00
Sakthivel Velumani
b987b033d5 test: include slot functions to frame parms ctest 2025-12-10 23:40:39 +00:00
Sakthivel Velumani
c9902a8615 bugfix: length of first slot for numerology 0
For 15kHz SCS, symbols with index 0 and 7 have longer cyclic prefix.
This is now fixed in frame parms struct.
2025-12-10 23:26:03 +00:00
Sakthivel Velumani
5b92859cce phy: remove function pointers in frame param
1. Removed function pointers for functions get_samples_per_slot(),
   get_samples_slot_timestamp() and get_slot_from_timestamp() as it does
   not offer any advantage. The functions are now called directly from
   everywhere.
2. Optimized these functions by removing loops where ever possible.
2025-12-10 23:25:24 +00:00
Jaroslava Fiedlerova
be08d655b1 Merge remote-tracking branch 'origin/fix_rach_occasions' into integration_2025_w50 (!3798)
Fix for computation of PRACH occasions and association period
2025-12-10 14:23:00 +01:00
Jaroslava Fiedlerova
f744c4d4bc Merge remote-tracking branch 'origin/handover-doc' into integration_2025_w50 (!3741)
Update documenation for handover

Update documentation for handover to include the changes that were made after
upgrading the CI handover setup (attenuator, USRPs synchronization)
2025-12-10 14:19:41 +01:00
Jaroslava Fiedlerova
d569e7ddc9 Merge remote-tracking branch 'origin/if-freq-doc' into integration_2025_w50 (!3807)
doc: Update doc for IF setup

Update IF setup doc, clarify how to set if_freq with large value in the gNB
configuration file. Per the libconfig manual, 64-bit integers are represented
like regular integers but require an appended "L"
(https://www.hyperrealm.com/libconfig/libconfig_manual.html#g_t64_002dbit-Integer-Values).
2025-12-10 14:18:31 +01:00
Bartosz Podrygajlo
10852cc89b Use get_samples_symbol_duration in nr-ue.c 2025-12-09 14:10:28 +01:00
Reem Bahsoun
7688af6293 Update documenation for F1 handover to include the changes that were made after upgarding the CI handover setup (attenuator, USRPs synchronization) 2025-12-09 13:51:28 +01:00
francescomani
55c8a7bef0 rename max_association_period to association_period to better reflect the role of the field 2025-12-09 13:45:25 +01:00
francescomani
f2a7fb5336 fix computation of RA occasions and association period in gNB 2025-12-09 13:45:21 +01:00
Jaroslava Fiedlerova
45827ee213 Clarify doc for IF setup 2025-12-09 12:27:56 +01:00
francescomani
63f3fb55ae Merge remote-tracking branch 'origin/ue_ho_improve' into integration_2025_w50 2025-12-09 11:06:52 +01:00
Jaroslava Fiedlerova
e44b17668c Merge remote-tracking branch 'origin/nr_ue_sib19_ta' into integration_2025_w50 (!3638)
NR UE: calculate TA based on SIB19 information in NTN mode, if autonomous TA is not enabled

To achieve the goal, the hyper frame number (HFN) is introduced at the NR UE
PHY, MAC and RRC layers.

Besides this, we also implemented an orbit propagation to improve the accuracy
of N_UE_TA_adj, and a fix to keep the N_TA from RAR and MAC CE.

Fixes #981
2025-12-08 12:04:31 +01:00
Jaroslava Fiedlerova
91e7030cf8 Merge branch 'integration_2025_w49' into 'develop'
Integration `2025.w49`/`v2.4`

* !3786 Consistently use OAI_RNGSEED env variable for RNG
* !3758 Add yq to edit yaml files and add yaml-dev library in containers missing it
* Fix RFemulator noise device RNG initialization
* !3780 NGAP: fix PDU Session Release Response
* !3795 Increase Aerial-based L2 test core number
* !3794 Fix missing E2SM-RC message forward
* !3660 Fixes for BWP switching
* !3797 Fix FAPI WLS timing, UL counter, doc
* release notes v2.4

See merge request oai/openairinterface5g!3792
2025-12-04 07:55:07 +00:00
Robert Schmidt
e54153ef5c Add release notes v2.4.0 2025-12-03 22:25:56 +01:00
Bartosz Podrygajlo
8f88efd97c Add symbol timing functions for NR_DL_FRAME_PARMS
Add two new functions for calculation symbol timestamp and symbol
duration for NR_DL_FRAME_PARMS. These functions are not using
the existing indirection mechanism via function pointers as this
prevents the compiler from properly optimizing the code.
2025-12-03 19:42:13 +01:00
Robert Schmidt
a3a6c6d5e9 Merge remote-tracking branch 'origin/fapi-wls-fixes-timing-counter-doc' into integration_2025_w49 (!3797)
Fix FAPI WLS timing, UL counter, doc

- Fix FAPI WLS timing
- Fix periodical PNF UL throughput logs
- Update documentation to better explain how to run WLS with radio (USRP
  B210)
2025-12-03 17:32:32 +01:00
Robert Schmidt
e5050416e4 Merge remote-tracking branch 'origin/bwp_switch_fix' into integration_2025_w49 (!3660)
Fixes for BWP switching

This MR fixes some issues when performing BWP switching via
reconfiguration. It also adds a CI test for BWP switching.  # Please
enter a commit message to explain why this merge is necessary,
2025-12-03 17:31:22 +01:00
Robert Schmidt
f46ddb6aa8 Fix: CFRA: UE can always use dedicated search space
In all cases (CFRA in SA for HO, or CFRA in NSA/do-ra for access), the
UE has the full configuration already. We can therefore directly switch
to a dedicated search space, as it is already known to the UE.
2025-12-03 17:22:06 +01:00
francescomani
f5b885e803 Move BWP doc into mac-usage.md 2025-12-03 17:22:06 +01:00
Robert Schmidt
8d2478662d Add BWP switch test in CI
Trigger various BWP switches through telnet, and test traffic after each
switch.
2025-12-03 17:22:06 +01:00
Robert Schmidt
5c3c374c1b Add implementation to trigger BWP switch from external source 2025-12-03 17:22:06 +01:00
francescomani
805c968b59 Add a check for BWP start and size validity in configuration 2025-12-03 17:22:06 +01:00
francescomani
ca0cc079a6 avoid having negative BWP size if BWP start > BWP size 2025-12-03 17:22:06 +01:00
francescomani
98618a7dc8 The network must configure BWPs with consecutive IDs from 1
... so if we want to have 1 BWP configured at any given time we need to
reconfigure BWP 1 every time. This means that since the gNB has more
than 1 BWPs (for use for different UEs), that there is a "gNB BWP ID"
(as used by the gNB), which can be any BWP ID X, and one "UE BWP ID",
which is always 1. This commit implements this distinction.
2025-12-03 17:20:11 +01:00
Robert Schmidt
5d4e17f8ca doc: nFAPI: add Troubleshoot section and explain ra_responseWindow 2025-12-03 16:16:42 +01:00
Robert Schmidt
2230606f42 doc: (n)FAPI: Correct header levels to also match transport 2025-12-03 16:02:47 +01:00
Jaroslava Fiedlerova
b137478dc8 doc: FAPI WLS: provide information on performance optimization 2025-12-03 16:00:10 +01:00
francescomani
3e5d868018 set coresetID !=0 for dedicated BWP (needed if CSET0 doesn't fit that BWP) 2025-12-03 13:31:37 +01:00
francescomani
b2878f4ab1 fix BWP start for ULSCH at UE 2025-12-03 13:31:37 +01:00
francescomani
88d1964f9c Validate BWP switch
Return from triggering reconfiguration with BWP switch if BWP is the
same as before the switch, and add check to verify if BWP triggered by
switch command exists
2025-12-03 13:31:05 +01:00
Robert Schmidt
b547dfe056 apply new configuration after receiving ACK for RRCreconfiguration message 2025-12-03 13:31:05 +01:00
francescomani
eb9ac76f4d Set MCS table also in initial BWP function 2025-12-03 13:31:01 +01:00
francescomani
ca04193680 Remove hardcoded max_rank = 1 in PUSCH configuration and set it with appropriate function 2025-12-03 13:30:53 +01:00
francescomani
aa7d3668e3 Fix for segfault caused by freed csi_MeasConfig 2025-12-03 13:30:42 +01:00
francescomani
0e7e030907 Fix clean_bwp_structures
Also zero out the pointer in spCellConfigDedicated to avoid
use-after-free.
2025-12-03 13:30:11 +01:00
Robert Schmidt
18edbc0f15 Fix UL throughput counter in periodic PNF logs
Function pointer send_p7_msg() returns a bool, so correctly set the
type, and interpret it correspondingly.
2025-12-03 12:33:53 +01:00
Rúben Soares Silva
d28ae49eee Fix FAPI WLS slot.indication slot ahead
Current FAPI slot_ahead value for WLS is too low for UL, as we see these
errors:

    [NR_MAC] Unexpected ULSCH HARQ PID 14 (have 3) for RNTI 0xa68e
    [NR_MAC] UE a68e expected HARQ pid 3 feedback at  586. 7, but is at  587.17 instead (HARQ feedback is in the past)

Similarly to nFAPI, scale it by mu (for mu=1 => slot_ahead=2) to give
additional time, which removes these warnings at the VNF.
2025-12-03 12:33:47 +01:00
Robert Schmidt
04ac7eb4b9 Merge remote-tracking branch 'origin/aerial-more-cores' into integration_2025_w49 (!3795)
Increase Aerial-based L2 test core number
2025-12-02 19:13:59 +01:00
Robert Schmidt
04318f64ea Merge remote-tracking branch 'origin/fix-e2ap-compilation-rrc-rc-forward' into integration_2025_w49 (!3794)
Fix missing E2SM-RC message forward
2025-12-02 19:13:34 +01:00
Robert Schmidt
388ad30f6b Fix missing E2SM-RC message forward
E2SM-RC RRC message forwarding (e.g., to signal a new UE, measurement
reports, ...) was broken since commit d6c29b2d2c, as we accidentally
removed the E2_AGENT compilation definition from RRC layer.

Although this commit fixes the mentioned issue, it also causes undefined
references to functions defined in ran_func_rc.c file.  Therefore, we
add a hack that provides the definition, and abort if we ever hit these
functions, which in theory should not happen.

Future cleanup should avoid linking in RRC and other layers into
simulators.

Fixes: d6c29b2d2c ("Fix E2_AGENT linking w.r.t. simulators ")
2025-12-02 19:10:08 +01:00
Robert Schmidt
f35a1cd775 Increase Aerial-based L2 test core number
Testing has revealed that if PDCP drops some packets, the scheduler
falls behind with handling Slot.indication. It could be that we don't
have enough cores, which was reduced previously (from total 8 -> 2).
Reincrease to four cores to have a bit more headroom.

See-also: a18a4888ec ("Change number of cores used for OAI gNB from 8 to 2")
2025-12-02 19:05:17 +01:00
Robert Schmidt
8f89637f8c Merge remote-tracking branch 'origin/fix-pdu-session-release-transfer' into integration_2025_w49 (!3780)
NGAP: fix PDU Session Release Response

1. Refactor NG UE Context Release Request

  - Removed incorrect UE Context Release Response code (not in 3GPP TS
    38.413)
  - Fixed UE Context Release Request to use correct PDU Session Resource
    List structure
  - Removed incorrect use of pdusession_release_t type

2. Fix PDU Session Release Response

  - Added missing mandatory PDUSessionResourceReleaseResponseTransfer IE
  - Implemented encode_ngap_pdusession_release_response_transfer()
    function
  - Fixed Release Command handler to correctly decode Cause from command
    transfer
  - Split Command/Response struct type definitions to prevent mixing
2025-12-02 13:45:17 +01:00
Robert Schmidt
5af58cc686 RFemulator: initialize RNG when using noise device
After !3786, we always have to initialize the RNG when using random
numbers. This was not done for RFemulator and has been added here.
2025-12-02 13:35:49 +01:00
Guido Casati
9e45f38fbd fix PDU Sesion Release response: add missing PDUSessionResourceReleaseResponseTransfer IE
The PDUSessionResourceReleaseResponse message was missing the mandatory
pDUSessionResourceReleaseResponseTransfer IE in each released PDU session item. This caused Open5GS to send an error indication.

Changes:
- Add encode_ngap_pdusession_release_response_transfer() function to
  properly encode the transfer structure (empty since Secondary RAT Usage
  Information is optional and not used, per 9.3.4.21)
- Always include the mandatory PDUSessionResourceReleasedListRelRes IE
- Always encode the pDUSessionResourceReleaseResponseTransfer for each
  PDU session item
- Fix Release Command handler to decode and log Cause from command transfer:
  instead of incorrectly copying command data to response: the 2 transfer
  IEs in the Command and the Response messages are different and should
  not be mixed
- Split Command/Response struct type definitions
- Add missing includes
2025-12-01 23:48:06 +01:00
Guido Casati
ad1c92af4f Refactor NG UE Context Release Request
1) Remove UE Context Release Response code: there is no
such thing in the specs, it is either UE Context Release Request
(NG-RAN node initiated) or UE Context Release (AMF initiated)
(3GPP TS 38.413). The former message has only the request, no
response is defined by the specs. The code in the stack had no
purpose at all and was removed.
2) The UE Context Release Request message only contains a PDU
Session Resource List (optional) of PDU Session IDs, therefore
the use of pdusession_release_t was wrong and was refactored
2025-12-01 23:48:06 +01:00
Robert Schmidt
a9e7018b98 Merge remote-tracking branch 'origin/yaml_update' into integration_2025_w49 (!3758)
Add yq to edit yaml files and add yaml-dev library in containers missing it

- nr-cu-up and some containers were missing the yaml-config support
  libraries
- yq tool is required to manipulate YAML files from within the container
  for Helm charts
2025-12-01 17:09:25 +01:00
Robert Schmidt
1140c59bbd Merge remote-tracking branch 'origin/fix-OAI_RNGSEED-usage' into integration_2025_w49 (!3786)
Consistently use OAI_RNGSEED env variable for RNG

use OAI_RNGSEED env variable everywhere. Hide normal table
initialization of Ziggurat generator from outside. Fix atoi() to use
stroul()
2025-12-01 15:20:23 +01:00
Robert Schmidt
ce7cb165dd Fix OAI_RNGSEED to capture unsigned long
atoi() used previously does not capture all of unsigned long (so we
could not reproduce a high seed), and its use is discouraged as it does
not detect errors. Use strtoul() instead, which allows to also use other
bases (so we can e.g., write OAI_RNGSEED=0x1234)
2025-12-01 12:10:31 +01:00
Laurent THOMAS
a1b4220a91 Exclusively use OAI_RNGSEED env variable everywhere
Hide normal table initialization of Ziggurat generator from outside to
force the usage of randominit() for RNG initialization. In this step,
remove the randominit() seed parameter and only rely on OAI_RNGSEED for
a consistent RNG initialization, as this parameter was used differently
("0" as fixed number or to force a random seed).

Now, only use OAI_RNGSEED env variable to force the usage of a fixed
seed.
2025-12-01 12:10:31 +01:00
francescomani
7da7dda71b new UE state to trigger RA after reconfiguration with sync 2025-11-29 23:13:42 +08:00
francescomani
e3b0def6dc conditional scheduling of SIB1 reception when receiving reconfigurationwSync 2025-11-29 23:12:36 +08:00
francescomani
9c8274f6bd separate RRC to MAC message to trigger SIB scheduling 2025-11-29 22:39:43 +08:00
francescomani
56f20d49bc improve handling of ssb_perRACH_OccasionAndCB_PreamblesPerSSB according to need code
(also removing unused FAPI element ssb_per_rach)
2025-11-29 22:39:43 +08:00
alexjiao
d56945e45e Monitor dedicated search spaces for DCIs after C-RNTI MAC-CE in Msg3 is sent 2025-11-29 22:39:43 +08:00
francescomani
e454fc41d1 Trigger MSG3 with C-RNTI in MAC CE if CBRA with newUE-Identity (handover) 2025-11-29 22:39:43 +08:00
alexjiao
2e80700d78 Fix for servedRadioBearer to be NULL in RLC Bearer Config 2025-11-29 22:39:43 +08:00
Jaroslava Fiedlerova
1603077171 Merge branch 'integration_2025_w48' into 'develop'
Integration `2025.w48`

* !3778 CI: Update IP addresses in Aerial gNB config files
* !3659 UE NTN - Epoch time handling for Target cell
* !3772 CI: Ensure EPC is always terminated in NSA-B200 pipeline
* !3773 Fix doc for UTC timestamp
* !3759 NR UE: fix bug for SRS generation when freqDomainShift (n_shift) is not 0
* !3774 Use UL functions for Qm/R determination
* !3767 Fix DRB integrity failures during handover and re-establishment
* !3764 Avoid measGap configuration on handover in intra-freq scenarios
* !3768 Fix MIB encoding in F1SetupRequest: use encode_MIB_NR_setup instead of encode_MIB_NR
* !3771 CI build analysis: print log file errors
* !3703 Taking into account UE capabilities for TBS_lbrm layers
* !3561 Implementation of STOP exchange
* !3776 Fix reestablishment after handover
* !3763 CI: Reduce the tries to attach the UE in CI runs
* !3761 fix(FHI 7.2): PRACH frame test
* !3616 [FHI72 M-plane] Update the M-plane support to v16.01
* !3790 Correctly copy nFAPI messages
* !3779 CFRA: mark RA complete when sending Msg2 - check CI

Closes #563 and #1034

See merge request oai/openairinterface5g!3775
2025-11-29 11:16:06 +00:00
Robert Schmidt
6fe7581eed Merge remote-tracking branch 'origin/cfra-no-msg3' into integration_2025_w48
CFRA: mark RA complete when sending Msg2

The current contention-free random access forces a "Msg3" (which does
not exist in CFRA) to be received by a UE. Sometimes, this "Msg3" is not
received (for whatever reason), and the MAC declare that RA failed.

This is problematic, as the spec says that RA is complete once Msg2 is
received by the UE. Since the gNB cannot know when this is, simply mark
it as complete once we sent Msg2.

We still send Msg3 in CFRA, which is explained further in the commits.

Also, improve logging and stabilize an RFsim test by reducing sl_ahead.
2025-11-28 18:25:18 +01:00
Jaroslava Fiedlerova
2ff7a56b95 Merge remote-tracking branch 'origin/fix-nfapi-100mhz' into integration_2025_w48 (!3790)
Correctly copy nFAPI messages

All nFAPI message have copy helpers, so use that for "loading" nFAPI
messages into the L1. This also fixes a bug/error message

2. 0 no corresponding tx_data.request for dl_tti.request index 11, dropping

because the loop over DL_tti.request assumed that all messages are PDSCH
PDUs, when we can have others such as PDCCH, etc. In other words, when
looking up indices ("11" in the example above), we were checking also
inside other messages for SSB, PDCCH, etc, which is of course wrong.
That loop was an attempt to validate matching PDSCH PDUs with
TX_data.requests. This check is already done inside
phy_procedures_gNB_TX() through an assert, but this commit replaces with
the equivalent check previously inside nr_pnf_p7_get_msgs(). This is ok,
as the L1 cannot trust the scheduler (in monolithic) to provide the
correct information, either.
Fixes: eefb9da6 ("Reimplement nFAPI message exchange after msgDataTx removal")
2025-11-28 18:16:13 +01:00
Jaroslava Fiedlerova
68a4bb9a61 Merge remote-tracking branch 'origin/mplane-v16.01' into integration_2025_w48 (!3616)
[FHI72 M-plane] Update the M-plane support to v16.01

- retrieve the additional hardware states (oper-state, admin-state,
  availability-state) and update according to the received notifications
- properly configure MIMO mode if a RU supports
- update the yang models to v16.01
- tested with Benetel v1.4.1, and added an example run in the M-plane doc

Note: backwards compatible with M-plane v05.00

Also, memory leakages fixed cause by ru_session_list_t, and xml functions
xmlReadMemory() and xmlNodeGetContent().
2025-11-28 18:11:06 +01:00
Sagar Arora
662c6e1aec Install yaml-cpp-dev for CU-UP and rocky
Co-authored-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Signed-off-by: Sagar Arora <sagar.arora@openairinterface.org>
2025-11-28 16:48:08 +01:00
Jaroslava Fiedlerova
c8b4aa2abd Merge remote-tracking branch 'origin/fix_prach_frame_test_fhi72' into integration_2025_w48 (!3761)
fix(FHI 7.2): PRACH frame test

A test was missing in the PRACH RX function of the FHI 7.2 in order to know if
the frame had a PRACH occasion. This was leading to continuous warning messages
as PRACH RX was triggered on frames in which PRACH was not expected by the
scheduler.
2025-11-28 16:34:43 +01:00
Jaroslava Fiedlerova
8300ab5a61 Merge remote-tracking branch 'origin/CI-ue-attach' into integration_2025_w48 (!3763)
CI: Reduce the tries to attach the UE in CI runs

The goal of this MR is to save time in CI runs by reducing the UE attach tries
to 3 instead of 4 and UE timeout to 20 seconds, which will be incremented after
each fail, instead of 60 seconds.
2025-11-28 16:33:39 +01:00
Robert Schmidt
1368bb5a5c CFRA: handle potential Msg3
Since the parent commit, CFRA is inconditionally marked complete on Msg3
reception (successful or not). This works because the current
implementation still sends a UL grant (see parent commit for details).

In this commit, handle Msg3 if received in CFRA (notably for TA and
power). Note that since we declare RA complete, UE->ra does not exist
anymore, and so an intermediate variable is introduced to capture the
CFRA flag. The code should be such that if we are in CFRA, we never
access any UE->ra variable.
2025-11-28 15:47:23 +01:00
Robert Schmidt
923b2ec188 Correctly copy nFAPI messages
All nFAPI message have copy helpers, so use that for "loading" nFAPI
messages into the L1. This also fixes a bug/error message

    2. 0 no corresponding tx_data.request for dl_tti.request index 11, dropping

because the loop over DL_tti.request assumed that all messages are PDSCH
PDUs, when we can have others such as PDCCH, etc. In other words, when
looking up indices ("11" in the example above), we were checking also
inside other messages for SSB, PDCCH, etc, which is of course wrong.

That loop was an attempt to validate matching PDSCH PDUs with
TX_data.requests. This check is already done inside
phy_procedures_gNB_TX() through an assert, but this commit replaces with
the equivalent check previously inside nr_pnf_p7_get_msgs(). This is ok,
as the L1 cannot trust the scheduler (in monolithic) to provide the
correct information, either.

Fixes: eefb9da69a ("Reimplement nFAPI message exchange after msgDataTx removal")
2025-11-28 13:54:01 +01:00
Reem Bahsoun
d6e4e49fcb Reduce the time given to the UE to re-attach after failure
Number of tries is reduced from 4 to 3
After each failure the timeout is incremented by 20
2025-11-28 10:03:58 +01:00
Romain Beurdouche
f6135ff1ff fix(FHI 7.2): PRACH frame test
A test was missing in the PRACH RX function of the FHI 7.2 in order to
know if the frame had a PRACH occasion.
This was leading to continuous warning messages as PRACH RX was
triggered on frames in which PRACH was not expected by the scheduler.
2025-11-28 09:01:20 +01:00
Robert Schmidt
8ea95a0e52 CFRA: mark RA complete when sending Msg2
The current contention-free random access forces a "Msg3" (which does
not exist in CFRA) to be received by a UE. Sometimes, this "Msg3" is not
received (for whatever reason), and the MAC declare that RA failed.

This is problematic, as the spec says that RA is complete once Msg2 is
received by the UE. To avoid this, inconditionally mark RA as complete
as soon as we receive an indication of Msg3 (DTX or not).

Note that after this change, we still send a UL grant in Msg2. This is
because 38.321 §5.1.4 is not clear to me whether we should send UL grant
(it does not explicitly exclude it), and it says

> 3> if the Random Access Response includes a MAC subPDU with RAPID only:
> [...]
>   4> indicate the reception of an acknowledgement for SI request to
>      upper layers.

which is NOT the case (but then I don't know/think we can have CFRA for
SI request?).  Since it also works with COTS UE, I leave Msg3 for the
moment.

The reason to not directly mark RA as complete when sending Msg2 is
because of possible retransmissions in do-ra mode. In fact, in do-ra,
there might already be data awaiting. In that case, the DLSCH scheduler
schedules data _in the same slot as Msg2_, which the UE does not decode,
leading to retransmissions.
2025-11-28 08:29:44 +01:00
Robert Schmidt
f0151c21bd Remove duplicate of RAR log above 2025-11-28 08:29:44 +01:00
Robert Schmidt
d5eb935ecf Log preambles for pre-configured RA 2025-11-28 08:29:44 +01:00
Robert Schmidt
b1b120551d Lower sl_ahead in do-ra config to reduce RA timeout risk 2025-11-28 08:29:44 +01:00
Jaroslava Fiedlerova
0226510c4a Merge remote-tracking branch 'origin/fapi-stop-exchange' into integration_2025_w48 (!3561)
Implementation of STOP exchange

This implements the STOP.request/indication for all 3 transport mechanisms, the
VNF will send the STOP.request to the PNF, indicating it will disconnect, and
await a STOP.indication from the PNF

The WLS VNF is reworked to be able to start before the PNF, by calling call
rte_eal_init and rte_dev_probe to determine if dpdk has been initialized
properly, before calling rte_eal_init in the intended process when it is
appropriate to do so
2025-11-27 15:01:39 +01:00
Jaroslava Fiedlerova
0f6b567ae9 Merge remote-tracking branch 'origin/fix-reestab-ho-cleanup' into integration_2025_w48 (!3776)
Fix reestablishment after handover

- fix reestablishment by not re-creating LCIDs with priority set to 0 (see first
  commit for more details)
- cleanup code
2025-11-27 14:52:23 +01:00
Jaroslava Fiedlerova
df041a0f8c Merge remote-tracking branch 'origin/issue563' into integration_2025_w48 (!3703)
Taking into account UE capabilities for TBS_lbrm layers

Closes #563
2025-11-26 20:37:31 +01:00
Jaroslava Fiedlerova
4b7970d601 Merge remote-tracking branch 'origin/ci-build-print-errors' into integration_2025_w48 (!3771)
CI build analysis: print log file errors

The generated HTML from CI builds so far only shows the number of errors, but
not the errors themselves. This is inconvenient, as this means that developers
have to go to the logs.

This commit modifies AnalyzeBuildLogs(), which already iterates the entire file,
to store the lines containing "error:" (as it would be emitted by a compiler).
The callers of AnalyzeBuildLogs() now also print the analysis outcome in a more
concise manner.

Also, change the return parameter of AnalyzeBuildLogs() to a tuple to make the
variable handling easier, and remove the unused warnings list.
2025-11-26 20:35:59 +01:00
Robert Schmidt
110bbd10bc Simplify RLC reestablishment
The idea is to reestablish all RLC entities (it's a new UE, and we set
reestablishRLC on all bearerrs), so we should reestablish all RLC
entities on gNB side as well, without any additional loop.

Co-authored-by: Roberto Magueta <rmagueta@allbesmart.pt>
2025-11-26 18:18:25 +01:00
Robert Schmidt
87adaafcfc Refactor process_addmod_bearers_cellGroupConfig() and set priority
Move the file process_addmod_bearers_cellGroupConfig() to the file where
it is used. Correctly set priorities as requested in RLC bearer
configuration.
2025-11-26 18:18:25 +01:00
Robert Schmidt
b3c99d8ead Avoid recreation of LCIDs with wrong priority
In all cases (NSA, HO), we create LCIDs before the UE triggers random
access. Hence, process_addmod_bearers_cellGroupConfig() is not
necessary, as it just tries to recreate an LCID.

Furthermore, it includes a bug, as this function does set a wrong
priority (0), so the sorting of LCIDs is not correct. This in turn
creates problems with reestablishment, as LCID 1/SRB1 is not in the
first position, making reestablishment fail (where we assume LCID 1 be
in first position).

The actual bug of setting priorities is fixed in the next commit.
2025-11-26 18:18:25 +01:00
francescomani
10247cfbed taking into account maximum number of layers for PUSCH supported by the UE for TBSlbrm 2025-11-26 16:46:00 +01:00
francescomani
1e610af168 taking into account maximum number of layers for PDSCH supported by the UE for TBSlbrm 2025-11-26 16:45:56 +01:00
Jaroslava Fiedlerova
8966dc2c4f Merge remote-tracking branch 'Rakesh_B_B/develop' into integration_2025_w48 (!3768)
Fix MIB encoding in F1SetupRequest: use encode_MIB_NR_setup instead of encode_MIB_NR

- The DU was using encode_MIB_NR() while constructing the GNB-DU System
  Information for the F1SetupRequest.
- encode_MIB_NR() encodes a full NR_BCCH_BCH_Message_t, causing the MIB to be
  wrapped in a BCH container.
- This results in incorrect MIB values in the F1SetupRequest PCAP (e.g., wrong
  systemFrameNumber, SCS, DMRS position, cellBarred).
- According to 3GPP TS 38.473, the MIB carried in F1AP must be encoded as a raw
  NR_MIB_t.
- The correct function encode_MIB_NR_setup() encodes MIB in the required format
  but was not used.
- This patch replaces encode_MIB_NR() with encode_MIB_NR_setup() to ensure correct
  and standards-compliant MIB encoding in the F1SetupRequest.

Closes issue #1034.
2025-11-25 17:47:16 +01:00
Jaroslava Fiedlerova
c87a6ecfba Merge remote-tracking branch 'origin/fix-drb-integrity' into integration_2025_w48 (!3767)
Fix DRB integrity failures during handover and re-establishment

This MR fixes DRB integrity protection failures that occur during N2 handover
and connection re-establishment scenarios. The issues were caused by incorrect
security key handling and ciphering configuration during these procedures with
DRB integity enabled.

See merge request !3767 for more details.
2025-11-25 14:01:40 +01:00
Jaroslava Fiedlerova
0c4882940c Merge remote-tracking branch 'origin/fix-measGaps' into integration_2025_w48 (!3764)
Avoid measGap configuration on handover in intra-freq scenarios

During the handover, we are incorrectly configuring the measGap, even though
neighboring cells are on the same frequency. Since gNB is not expecting this
measGap, the SRS scheduling is performed. Therefore, we are periodically
receiving these logs after the handover:

[NR_MAC] Invalid timing advance offset for RNTI 58e2
[NR_MAC] Invalid timing advance offset for RNTI 58e2
[NR_MAC] Invalid timing advance offset for RNTI 58e2
[NR_MAC] Invalid timing advance offset for RNTI 58e2
[NR_MAC] Invalid timing advance offset for RNTI 58e2
[NR_MAC] Invalid timing advance offset for RNTI 58e2

These logs occur at a time when UE is performing a MeasGap operation and not
sending the SRS, while gNB thinks it will receive the SRS, but will not receive
any SRS.

This MR resolves this issue, and after the handover, these logs no longer
appear.
2025-11-25 13:57:24 +01:00
Guido Casati
b7454cf5d4 Enable DRB integrity and ciphering in F1 and N2 HO pipelines with Quectel 2025-11-25 09:47:24 +01:00
Jaroslava Fiedlerova
e8732ed8c8 Merge remote-tracking branch 'origin/fix-mcs-tbl' into integration_2025_w48 (!3774)
Use UL functions for Qm/R determination

During refactoring, the wrong functions and correspondingly tables have
been used to calculate UL TB size. Fix through correct functions.
This should fix these error messages:

3624774.778195 [MAC]    E (nr_get_Qm_dl:2034)             Invalid MCS table index 3 (expected in range [0,2])
3624774.778207 [MAC]    E (nr_get_code_rate_dl:2066)      Invalid MCS table index 3 (expected in range [0,2])
3624774.778211 [NR_MAC] E (nr_compute_tbs:63)             Error in compute TBS with a NULL input, returning NULL TBS

Fixes: 9449f777 ("Remove TBS table and recompute on demand")
2025-11-24 22:26:42 +01:00
Jaroslava Fiedlerova
95affc2a41 Merge remote-tracking branch 'origin/srs-freq-shift-fix' into integration_2025_w48 (!3759)
NR UE: fix bug for SRS generation when freqDomainShift (n_shift) is not 0

According to TS 38.211 section 6.4.1.4.3, the frequency domain shift value
n_shift is from higher-layer parameter freqDomainShift. The quantity n_RRC
is given by higher-layer parameter freqDomainPosition. Also corrected
k_0_overbar_p calculation formula to align with standard.
2025-11-24 22:24:56 +01:00
Jaroslava Fiedlerova
8943975eb3 Merge remote-tracking branch 'origin/fix-logging-doc' into integration_2025_w48 (!3773)
Fix doc for UTC timestamp

After merging !3751 (merged), the UTC timestamp now prints only the time.
Update the documentation to reflect this simplified format.
2025-11-24 14:45:22 +01:00
Jaroslava Fiedlerova
c9c935af01 Merge remote-tracking branch 'origin/ci-ltebox-terminate' into integration_2025_w48 (!3772)
CI: Ensure EPC is always terminated in NSA-B200 pipeline

This change avoids leaving EPC processes running after failed test.
2025-11-24 14:44:32 +01:00
Jaroslava Fiedlerova
894491f2e5 Merge remote-tracking branch 'origin/nr_ue_epoch_target' into integration_2025_w48 (!3659)
UE NTN - Epoch time handling for Target cell

In case of Handover, NTNconfig sent in RRCreconfiguration triggering handover
contains epoch time wrt timing of Target cell. NTNconfig in RRC needs to be
processed only after timing is acquired on the target cell.

In case of Target cell, epoch time is the sfn nearest to the frame timing of the
target cell.
2025-11-24 14:42:39 +01:00
Robert Schmidt
0360175042 Use UL functions for Qm/R determination
During refactoring, the wrong functions and correspondingly tables have
been used to calculate UL TB size. Fix through correct functions.

This should fix these error messages:

    3624774.778195 [MAC]    E (nr_get_Qm_dl:2034)             Invalid MCS table index 3 (expected in range [0,2])
    3624774.778207 [MAC]    E (nr_get_code_rate_dl:2066)      Invalid MCS table index 3 (expected in range [0,2])
    3624774.778211 [NR_MAC] E (nr_compute_tbs:63)             Error in compute TBS with a NULL input, returning NULL TBS

Fixes: 9449f777cc ("Remove TBS table and recompute on demand")
2025-11-24 13:04:02 +01:00
Jaroslava Fiedlerova
0386751da8 Fix UTC timestamp documentation
After merging !3751, the UTC timestamp now prints only the time.
Update the documentation to reflect this simplified format.
2025-11-24 11:45:47 +01:00
Jaroslava Fiedlerova
96ec2be887 CI: Ensure EPC is always terminated in NSA-B200 pipeline
This change updates the NSA-B200 CI pipeline to guarantee that the EPC is
properly terminated regardless of pipeline success or failure. This avoids
leaving EPC processes running after failed test.
2025-11-24 11:14:31 +01:00
Robert Schmidt
bff0e53645 CI build analysis: print log file errors
The generated HTML from CI builds so far only shows the number of
errors, but not the errors themselves. This is inconvenient, as this
means that developers have to go to the logs.

This commit modifies AnalyzeBuildLogs(), which already iterates the
entire file, to store the lines containing "error:" (as it would be
emitted by a compiler). The callers of AnalyzeBuildLogs() now also print
the analysis outcome in a more concise manner.

Also, change the return parameter of AnalyzeBuildLogs() to a tuple to make
the variable handling easier, and remove the unused warnings list.
2025-11-21 17:53:25 +01:00
rmagueta
fea86247da Do not configure NR_MeasurementTimingConfiguration during handover when neighboring cells are at the same frequency 2025-11-21 16:42:24 +00:00
Rakesh BB
176b71ae70 Fix MIB encoding in F1SetupRequest: use encode_MIB_NR_setup instead of encode_MIB_NR
- The DU was using encode_MIB_NR() while constructing the GNB-DU System Information for the F1SetupRequest.
- encode_MIB_NR() encodes a full NR_BCCH_BCH_Message_t, causing the MIB to be wrapped in a BCH container.
- This results in incorrect MIB values in the F1SetupRequest PCAP (e.g., wrong systemFrameNumber, SCS, DMRS position, cellBarred).
- According to 3GPP TS 38.473, the MIB carried in F1AP must be encoded as a raw NR_MIB_t.
- The correct function encode_MIB_NR_setup() encodes MIB in the required format but was not used.
- This patch replaces encode_MIB_NR() with encode_MIB_NR_setup() to ensure correct and standards-compliant MIB encoding in the F1SetupRequest.

Closes issue #1034.
2025-11-19 17:30:22 +00:00
Guido Casati
e1dd62df53 Fix N2 handover integrity failures by enabling ciphering during handover setup
Problem:
During N2 handover with integrity protection (NIA1/NIA2), the target gNB
was disabling ciphering when configuring SRB1 security, while the UE
continued using the old security context from the source gNB until it
received and processed the RRC Reconfiguration with masterKeyUpdate. The
first PDUs sent after CFRA were still ciphered with the old keys, but the
target gNB had ciphering disabled, causing it to skip deciphering and
attempt integrity verification on ciphered data, leading to MAC-I
mismatches and integrity failures.

Specification Reference:
According to TS 33.501 section 6.11, "the UE shall keep the K gNB used in
the source cell until the handover or a connection re-establishment has been
completed successfully". This means the UE continues using the old security
context (old KRRCint, KRRCenc) until it receives and processes the RRC
Reconfiguration with masterKeyUpdate. The target gNB must therefore enable
ciphering during handover setup to correctly decipher and verify integrity
of PDUs sent with the old security context before the UE switches to the new
keys.

Root Cause:
The code was calling nr_rrc_pdcp_config_security(UE, false) during
handover setup, which disabled ciphering. This was incorrect because:
1. The UE already has security active from the source gNB
2. The UE continues using old ciphered keys until masterKeyUpdate
3. The UE sends ciphered PDUs immediately after CFRA succeeds
4. The target gNB must be able to decipher these PDUs to verify integrity

Why it only manifested when drb_integrity = "yes":
The bug was always present, but only caused visible failures when
integrity verification was enabled. When drb_integrity = "no", the config
typically also sets integrity_algorithms to only NIA0, resulting in
UE->integrity_algorithm = 0, which causes has_integrity = 0 for SRB1,
skipping integrity verification and hiding the underlying ciphering bug.
When drb_integrity = "yes", integrity_algorithms typically includes
NIA1/NIA2, resulting in has_integrity = 1 for SRB1, causing integrity
checks to run on ciphered data and fail.

Fix:
Change nr_rrc_pdcp_config_security(UE, false) to
nr_rrc_pdcp_config_security(UE, true) during handover setup to enable
ciphering immediately, allowing the target gNB to correctly decipher and
verify integrity of PDUs sent with the old security context.

Note: This fix is specific to handover. During initial context setup,
ciphering should remain disabled until SecurityModeComplete is received,
as the UE hasn't activated ciphering yet at that point.
2025-11-19 11:37:36 +01:00
Guido Casati
6512a7a9ca Notify security keys change to CUUP during re-establishment
During re-establishment, new KgNB* is derived, requiring new UP keys (KUPint,
KUPenc) to be sent to CU-UP. When do_drb_integrity = true, CU-UP needs the
updated integrity keys to verify DRB PDUs. Without this update, CU-UP uses
old keys while the UE uses new keys, causing integrity failures.

The fix ensures security info is always sent during re-establishment,
which is critical for DRB integrity.
2025-11-19 11:36:39 +01:00
Thomas Schlichter
92107b18fe update FEATURE_SET.md 2025-11-19 10:05:45 +01:00
Thomas Schlichter
a283ef263b rfsimulator: improve calculation of ta-CommonDrift-r17 and ta-CommonDriftVariant-r17
Instead of using the projected velocity and acceleration vectors,
calculate vel_sat_gnb and acc_sat_gnb so the delay is correct for
epoch_time, epoch_time + 5 seconds and epoch_time + 10 seconds.
2025-11-19 10:05:45 +01:00
Thomas Schlichter
842b16092d NR UE: use GET_NTN_UE_K_OFFSET() instead of get_total_TA_ms() in nr_ra_procedures.c 2025-11-19 10:05:45 +01:00
Thomas Schlichter
62fe88d6f4 NR UE: make sure not to lose N_TA when updating N_common_TA_adj + N_UE_TA_adj
Separate timing_advance (N_TA) from timing_advance_ntn (N_common_TA_adj + N_UE_TA_adj)
to keep N_TA when updating N_common_TA_adj + N_UE_TA_adj.

Fixes #981
2025-11-19 10:05:45 +01:00
Thomas Schlichter
59af5e4ad2 NR UE: introduce orbit propagation to improve N_UE_TA_adj accuracy
Instead of trying to estimate N_UE_TA_adj with a second degree polynomial,
we introduce orbit propagation to calculate N_UE_TA_adj with higher accuracy.

When we receive the satellite ephemeris data consisting of the satellite position vector
and the satellite velocity vector, we calculate parameters for orbit propagation, assuming
a circular orbit in the plane created by the satellite position vector and the satellite
velocity vector. This is done in the function prepare_ue_sat_ta().

Every millisecond, we use these parameters together with the time since epoch to calculate
the satellite position on that orbit and from this the reound-trip-time between UE and the
satellite, what corresponds to N_UE_TA_adj. This is done in the function apply_ntn_timing_advance().
2025-11-19 10:05:45 +01:00
Thomas Schlichter
43722e6bac fix compiler warning: ‘phase_tdd_ncp’ may be used uninitialized 2025-11-19 10:05:45 +01:00
Thomas Schlichter
1947f4d60c remove the parameter --autonomous-ta from the UE command line and update RUNMODEM.md accordingly 2025-11-19 10:05:45 +01:00
Thomas Schlichter
b60a40ccbf NR UE: calculate TA based on SIB19 information in NTN mode, if autonomous TA is not enabled 2025-11-19 10:05:45 +01:00
Thomas Schlichter
654fadb116 NR UE: calculate the epoch_hfn whenever an ntn_Config_r17 is received 2025-11-19 10:05:45 +01:00
Thomas Schlichter
0bf99d9d16 NR UE: introduce the hyper frame number (HFN) in PHY, MAC and RRC layer
Provide it to the function configure_ntn_ta() so it can be used when a new ntn_Config_r17 is received.
2025-11-19 10:05:44 +01:00
Raghavendra Dinavahi
f9a8898e20 UE: Epoch time handling of Target cell
In case of Handover, NTNconfig sent in RRCreconfiguration triggering handover contains epoch time wrt
timing of Target cell. NTNconfig in RRC needs to be processed only after timing is acquired on the target cell
In case of Target cell, epoch time is the sfn nearest to the frame timing of the target cell.
2025-11-17 15:53:23 +01:00
Sagar Arora
389ca60d5e add yq in 5G NF Dockerfiles
Signed-off-by: Sagar Arora <sagar.arora@openairinterface.org>
2025-11-16 06:14:14 +01:00
alexjiao
19301afcb1 Fix bug for SRS generation when freqDomainShift (n_shift) is not 0
According to TS 38.211 section 6.4.1.4.3, the frequency domain shift value n_shift
is from higher-layer parameter freqDomainShift.
The quantity n_RRC is given by higher-layer parameter freqDomainPosition.
Also corrected k_0_overbar_p calculation formula to align with standard.
2025-11-14 19:21:19 +08:00
Teodora
19bb463049 Properly free the memory
1. Create a free_ru_session_list() function to free the memory allocated for the connected RUs
before closing the nr-softmodem.
2. xmlReadMemory() and xmlNodeGetContent() were causing serious memory leakages,
and now all is properly freed using xmlFreeDoc() and xmlFree().
2025-10-30 17:22:40 +01:00
Teodora
163c8de371 Do not use ru_session_list on the stack
This struct is used in multiple source files.

Previously, when stopping the nr-softmodem, the ru_session_list "disappears"
and the M-plane wasn't terminated properly (num_rus = 0 even though DU connected to at least one RU).
2025-10-30 17:22:40 +01:00
Teodora
96b944e5c9 Update the FHI M-plane doc for v16.01 support 2025-10-30 17:22:40 +01:00
Teodora
0ad393f28e Update yang models to the O-RAN.WG4.MP-YANGs-R004-v16.01
It is backwards compatible with the O-RAN.WG4.MP-YANGs-v04.00, previous supported version.
2025-10-30 17:22:40 +01:00
Teodora
4233b89530 Handle MIMO mode
MIMO mode is defined by setting separate carriers to different antenna ports.

Benetel v1.2.2 does not support MIMO mode to be set via M-plane, and therefore
we only created one Tx and one Rx carrier.

Benetel v1.4.1 supports MIMO mode setting via M-plane.

Therefore, this commit introduces the adaptation based on the number of supported carriers by a DUT RU.
2025-10-30 17:22:40 +01:00
Teodora
d542021f86 Retrieve the hardware states if available
These 3 states: "oper-state", "admin-state", "availability-state" are optional,
but shall be checked in order to activate the carriers. If an O-RU doesn't support it,
we assume the expected values:
- "oper-state" = "enabled"
- "admin-state" = "unlocked"
- "availability-state" = "NORMAL"

Implement retrieval of the hardware states if O-RU supports, i.e. Benetel release v1.4.1.
2025-10-30 17:22:40 +01:00
Teodora
d4b5291c62 Facilitate RU notification initialization
Use X macros for carriers and synchronization states,
by mapping enum with the state values.
2025-10-30 17:22:40 +01:00
Teodora
ad6d7a2220 RHEL compilation
error: implicit declaration of function ‘realloc’
2025-10-30 17:22:40 +01:00
Teodora
a96d2d0118 Properly pass the arguments in ly_ctx_destroy() v1 function 2025-10-30 17:22:40 +01:00
Rúben Soares Silva
09d9bb5b6a Fix build for simulators
This change is needed due to the previous addition of the function nfapi_stop_l1() in gnb_config.c which in turn calls 2 functions that do not exist in the simulators, since they're not linked against the nfapi libraries
2025-10-23 14:08:37 +01:00
Rúben Soares Silva
c83bd87459 Fixup WLS documentation and Makefile patch 2025-10-23 14:08:37 +01:00
Rúben Soares Silva
e08d904af0 Implementation of STOP exchange
This implements the STOP.request/indication for all 3 transport mechanisms, the VNF will send the STOP.request to the PNF, indicating it will disconnect, and await a STOP.indication from the PNF

The WLS VNF is reworked to be able to start before the PNF, by calling call rte_eal_init and rte_dev_probe to determine if dpdk has been initialized properly, before calling rte_eal_init in the intended process when it is appropriate to do so
2025-10-23 14:08:37 +01:00
Rúben Soares Silva
3247c2933f Rework WLS VNF to be able to start before the PNF
The WLS VNF is reworked to be able to start before the PNF, by calling call rte_eal_init and rte_dev_probe to determine if dpdk has been initialized properly, before calling rte_eal_init in the intended process when it is appropriate to do so
2025-10-23 14:08:37 +01:00
Rúben Soares Silva
244819c627 Allocate VNF_info directly in config instead of global variable
This allows access to the VNF configuration in the various transport mechanisms straight from config, without this, the transport specific thread would cause a segmentation fault when trying to access the pack/unpack function pointers.
Add 2 functions to access the P5 and P7 VNF structures, to avoid having to always cast user_data and p7_vnfs
2025-10-23 08:45:24 +01:00
199 changed files with 14508 additions and 3780 deletions

View File

@@ -1,5 +1,71 @@
# RELEASE NOTES: #
## [v2.4.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.4.0) -> December 2025. ##
General new features and improvements (both RAN and UE):
- Rework LDPC BBdev/AAL interface and support both AMD T2/Intel vRAN Boost
(VRB) 1 accelerators
- Add a taps client for vrtsim real-time simulator (check: vrtsim release?)
- Add new RFemulator virtual radio driver to emulate radio (including noise
generation) for gNB/UE standalone operation
- RLC AM reception improvements for high-throughput scenarios (!3512)
- Small NTN fixes (!3659, !3666, !3581, !3652)
- Improvements to imScope
Stability and bug fixes:
- RFsimulator: fix concurrency problems during multi-client connection
- USRP driver: support synchronization of USRP B200
- MAC scheduler improvements
- General L1 improvements for efficiency and stability
- Correct PRS bug and test in CI
- Upgrade Ubuntu container images to Ubuntu 24.04
- All build system targets compile (`make/ninja all`)
- Minor cleanup, harmonization, and performance improvements all over the stack
- Simplify CI code
RAN changes (gNB/CU/CU-CP/CU-UP/DU/DU-high/DU-low):
- Support of N2 handover
- Support of "UL-heavy" TDD patterns, e.g., DSUUU
- Open Fronthaul M-plane: CM improvements, PM implementation, and additional
v16.01 support
- Improve interoperability with Nvidia Aerial L1 to support 2 layer UL
- Add O-RAN OSC WLS library as FAPI transport and enable L1/L2 shared memory
split
- Implement FAPI Stop exchange
- Improve interoperability with srsRAN_Project DU
- Add new synchronized real-time data recording application (!3462)
- Support for measurement gaps and general handover fixes
- Support of RRC PDU session release procedure
- Add CU-UP load tester
- Correct BWP scheduling and support multiple BWPs per UE
nrUE changes:
- Support one additional PDU session (see !3486)
- L3 measurements for A2 measurement reports
- Support for type0 PDSCH frequency allocation
- UE symbol based PDCCH receiver
Regression or removals:
- No known regressions
- Unused L2 simulator code has been removed
- Unused Benetel radio driver code (not FHI 7.2!) has been removed
Configuration file changes:
- `gNBs.[0].servingCellConfigCommon.[0].ra_ResponseWindow` is automatically
computed and can be removed
- `gNBs.[0].bwp_list` has been added (moved from entries in
`gNBs.[0].servingCellConfigDedicated`)
- `gNBs.[0].phaseTrackingRS` has been added (moved from entries in
`gNBs.[0].servingCellConfigDedicated`)
- `gNBs.[0].local_s_portc` and `gNBs.[0].remote_s_portc` have no effect and
should be removed
- `gNBs.[0].CSI_report_type` has been added
- `MACRLCs.[0].ulsch_max_frame_inactivity` is automatically computed and can be
removed
- `MACRLCs.[0].local_n_portc` and `MACRLCs.[0].remote_n_portc` have no effect and
should be removed
- `MACRLCs.[0].stats_max_ue` has been added
## [v2.3.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.3.0) -> July 2025. ##
General new features and improvements (both RAN and UE):

View File

@@ -464,6 +464,9 @@ target_include_directories(f1ap PUBLIC F1AP_DIR)
target_link_libraries(f1ap PUBLIC asn1_f1ap GTPV1U)
target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE f1ap_lib)
target_include_directories(f1ap PRIVATE ${F1AP_DIR}/lib)
if(E2_AGENT)
target_compile_definitions(f1ap PRIVATE E2_AGENT)
endif()
# LPP
##############
@@ -1288,6 +1291,9 @@ add_library(L2
)
target_link_libraries(L2 PRIVATE x2ap s1ap lte_rrc m2ap)
target_link_libraries(L2 PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
if(E2_AGENT)
target_compile_definitions(L2 PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
endif()
add_library(MAC_UE_NR ${MAC_NR_SRC_UE})
target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs PUBLIC nr_ue_power_procedures nr_ue_ra_procedures)
@@ -1303,6 +1309,9 @@ add_library(L2_NR
target_link_libraries(L2_NR PRIVATE ds alg)
target_link_libraries(L2_NR PRIVATE f1ap_lib)
target_include_directories(L2_NR PRIVATE ${F1AP_DIR}/lib)
if(E2_AGENT)
target_compile_definitions(L2_NR PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
endif()
add_library(e1_if
${NR_RRC_DIR}/cucp_cuup_direct.c

View File

@@ -397,9 +397,9 @@ class Cluster:
# Analyze the logs
collectInfo = {}
for image, lf in log_files:
ret = cls_containerize.AnalyzeBuildLogs(image, lf)
imgStatus = ret['status']
msg = f"size {imageSize[image]}, analysis of {os.path.basename(lf)}: {ret['errors']} errors, {ret['warnings']} warnings"
imgStatus, errors = cls_containerize.AnalyzeBuildLogs(image, lf)
info = f"Analysis of {os.path.basename(lf)}: {imgStatus=}, size {imageSize[image]}, {len(errors)} errors"
msg = "\n".join([info] + errors)
HTML.CreateHtmlTestRowQueue(image, 'OK' if imgStatus else 'KO', [msg])
status = status and imgStatus

View File

@@ -86,9 +86,9 @@ def CreateTag(ranCommitID, ranBranch, ranAllowMerge):
return tagToUse
def AnalyzeBuildLogs(image, lf):
errorandwarnings = {}
committed = False
tagged = False
errors = []
with open(lf, mode='r') as inputfile:
for line in inputfile:
lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None
@@ -97,11 +97,13 @@ def AnalyzeBuildLogs(image, lf):
# the OpenShift Cluster builder prepends image registry URL
lineHasCommit = re.search(r'COMMIT [a-zA-Z0-9\.:/\-]*' + image, str(line)) is not None
committed = committed or lineHasCommit
errorandwarnings['errors'] = 0 if committed or tagged else 1
errorandwarnings['warnings'] = 0
errorandwarnings['status'] = committed or tagged
logging.info(f"Analyzing {image}, file {lf}: {errorandwarnings}")
return errorandwarnings
if re.search(r'error:|Errors|ERROR', line):
errors.append(f"=> {line.strip()}")
status = (committed or tagged) and len(errors) == 0
logging.info(f"Analyzing {image}, file {lf}: {status=}, {len(errors)} errors")
for e in errors:
logging.info(e)
return status, errors
def GetImageName(ssh, svcName, file):
ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".image'", silent=True)
@@ -460,9 +462,9 @@ class Containerize():
# Analyze the logs
for name, lf in log_files:
ret = AnalyzeBuildLogs(name, lf)
imgStatus = ret['status']
msg = f"size {allImagesSize[name]}, analysis of {os.path.basename(lf)}: {ret['errors']} errors, {ret['warnings']} warnings"
imgStatus, errors = AnalyzeBuildLogs(name, lf)
info = f"Analysis of {os.path.basename(lf)}: {imgStatus=}, size {allImagesSize[name]}, {len(errors)} errors"
msg = "\n".join([info] + errors)
HTML.CreateHtmlTestRowQueue(name, 'OK' if imgStatus else 'KO', [msg])
status = status and imgStatus

View File

@@ -111,10 +111,11 @@ class Module_UE:
return self._collectTrace(ctx)
return None
def attach(self, attach_tries = 4, attach_timeout = 60):
def attach(self, attach_tries = 3, attach_timeout = 0):
ip = None
while attach_tries > 0:
self._command(self.cmd_dict["attach"])
attach_timeout += 20
timeout = attach_timeout
logging.debug("Waiting for IP address to be assigned")
ip = self.getIP(silent=False, reportNonZero=True)

View File

@@ -53,7 +53,7 @@ security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
ciphering_algorithms = ( "nea2", "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
@@ -63,7 +63,7 @@ security = {
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
drb_integrity = "yes";
};
log_config :

View File

@@ -146,7 +146,11 @@ gNBs =
);
first_active_bwp = 1;
bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;});
bwp_list = (
{ scs = 1; bwpStart = 0; bwpSize = 106;},
{ scs = 1; bwpStart = 0; bwpSize = 36;},
{ scs = 1; bwpStart = 36; bwpSize = 70;}
);
# ------- SCTP definitions
SCTP :

View File

@@ -195,6 +195,7 @@ RUs = (
max_pdschReferenceSignalPower = -27;
max_rxgain = 50;
eNB_instances = [0];
sl_ahead = 3;
sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
}
);

View File

@@ -209,7 +209,7 @@ security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
ciphering_algorithms = ( "nea2", "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
@@ -219,7 +219,7 @@ security = {
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
drb_integrity = "yes";
};
log_config :

View File

@@ -247,6 +247,7 @@
<testCase id="060000">
<class>UndeployCoreNetwork</class>
<desc>Terminate EPC</desc>
<always_exec>true</always_exec>
<cn_id>ltebox-nepes</cn_id>
</testCase>

View File

@@ -30,20 +30,28 @@
310000
800813
330101
330102
330103
310001
400001
350000
370001
370000
370002
370003
370004
370002
360001
100002
360002
350000
410002
370012
400002
410003
370013
400003
410000
350000
400000
410001
350000
400001
310011
310002
330201
@@ -88,24 +96,10 @@
</testCase>
<testCase id="330101">
<class>Deploy_Object</class>
<desc>Deploy gNB-CU-CP in a container</desc>
<desc>Deploy gNB-CU-CP/gNB-CU-UP/gNB-DU (TDD/n76/40MHz/B200)</desc>
<node>ofqot</node>
<yaml_path>ci-scripts/yaml_files/sa_e1_b200_gnb</yaml_path>
<services>gnb_cucp</services>
</testCase>
<testCase id="330102">
<class>Deploy_Object</class>
<desc>Deploy gNB-CU-UP in a container</desc>
<node>ofqot</node>
<yaml_path>ci-scripts/yaml_files/sa_e1_b200_gnb</yaml_path>
<services>gnb_cuup</services>
</testCase>
<testCase id="330103">
<class>Deploy_Object</class>
<desc>Deploy gNB-DU (TDD/Band78/40MHz/B200) in a container</desc>
<node>ofqot</node>
<yaml_path>ci-scripts/yaml_files/sa_e1_b200_gnb</yaml_path>
<services>gnb_du_tdd</services>
<services>gnb_cucp gnb_cuup gnb_du_tdd</services>
</testCase>
<testCase id="300000">
@@ -132,16 +126,6 @@
<ping_rttavg_threshold>25</ping_rttavg_threshold>
</testCase>
<testCase id="370000">
<class>Iperf</class>
<desc>iperf (DL/80Mbps/UDP)(30 sec)</desc>
<iperf_args>-u -b 80M -t 30 -R</iperf_args>
<id>idefix</id>
<svr_id>sabox-nepes</svr_id>
<iperf_packetloss_threshold>10</iperf_packetloss_threshold>
<iperf_bitrate_threshold>95</iperf_bitrate_threshold>
</testCase>
<testCase id="400001">
<class>Custom_Command</class>
<desc>Check UE is on dedicated BWP ID 1</desc>
@@ -149,19 +133,76 @@
<command>echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 1 (dedicated) UL BWP ID 1 (dedicated)'</command>
</testCase>
<testCase id="370001">
<testCase id="410001">
<class>Custom_Command</class>
<desc>Switch to dedicated BWP ID 1</desc>
<node>ofqot</node>
<command>echo ci trigger_bwp_switch 1 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 1 for UE'</command>
</testCase>
<testCase id="400000">
<class>Custom_Command</class>
<desc>Check UE is on initial BWP ID 0</desc>
<node>ofqot</node>
<command>echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 0 (initial) UL BWP ID 0 (initial)'</command>
</testCase>
<testCase id="410002">
<class>Custom_Command</class>
<desc>Switch to dedicated BWP ID 2</desc>
<node>ofqot</node>
<command>echo ci trigger_bwp_switch 2 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 2 for UE'</command>
</testCase>
<testCase id="370012">
<class>Iperf</class>
<desc>iperf (UL/8Mbps/UDP)(30 sec)</desc>
<iperf_args>-u -b 8M -t 30</iperf_args>
<desc>iperf (DL/TCP)(10 sec)(single-ue profile)</desc>
<iperf_args>-t 10 -R</iperf_args>
<id>idefix</id>
<svr_id>sabox-nepes</svr_id>
<iperf_packetloss_threshold>1</iperf_packetloss_threshold>
<iperf_bitrate_threshold>95</iperf_bitrate_threshold>
<iperf_tcp_rate_target>35</iperf_tcp_rate_target>
</testCase>
<testCase id="400002">
<class>Custom_Command</class>
<desc>Check UE is on dedicated BWP ID 2</desc>
<node>ofqot</node>
<command>echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 2 (dedicated) UL BWP ID 2 (dedicated)'</command>
</testCase>
<testCase id="410003">
<class>Custom_Command</class>
<desc>Switch to dedicated BWP ID 3</desc>
<node>ofqot</node>
<command>echo ci trigger_bwp_switch 3 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 3 for UE'</command>
</testCase>
<testCase id="370013">
<class>Iperf</class>
<desc>iperf (DL/TCP)(10 sec)(single-ue profile)</desc>
<iperf_args>-t 10 -R</iperf_args>
<id>idefix</id>
<svr_id>sabox-nepes</svr_id>
<iperf_tcp_rate_target>85</iperf_tcp_rate_target>
</testCase>
<testCase id="400003">
<class>Custom_Command</class>
<desc>Check UE is on dedicated BWP ID 3</desc>
<node>ofqot</node>
<command>echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 3 (dedicated) UL BWP ID 3 (dedicated)'</command>
</testCase>
<testCase id="410000">
<class>Custom_Command</class>
<desc>Switch to initial BWP ID 0</desc>
<node>ofqot</node>
<command>echo ci trigger_bwp_switch 0 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 0 for UE'</command>
</testCase>
<testCase id="370002">
<class>Iperf</class>
<desc>iperf (BIDIR TCP)(10 sec)(single-ue profile)</desc>
<desc>iperf (BIDIR TCP)(20 sec)(single-ue profile)</desc>
<iperf_args>-t 20 --bidir</iperf_args>
<id>idefix</id>
<svr_id>sabox-nepes</svr_id>
@@ -169,17 +210,17 @@
<testCase id="370003">
<class>Iperf</class>
<desc>iperf (DL/TCP)(30 sec)(single-ue profile)</desc>
<iperf_args>-t 30 -R</iperf_args>
<desc>iperf (DL/TCP)(20 sec)(single-ue profile)</desc>
<iperf_args>-t 20 -R</iperf_args>
<id>idefix</id>
<svr_id>sabox-nepes</svr_id>
<iperf_tcp_rate_target>30</iperf_tcp_rate_target>
<iperf_tcp_rate_target>140</iperf_tcp_rate_target>
</testCase>
<testCase id="370004">
<class>Iperf</class>
<desc>iperf (UL/TCP)(30 sec)(single-ue profile)</desc>
<iperf_args>-t 30</iperf_args>
<desc>iperf (UL/TCP)(20 sec)(single-ue profile)</desc>
<iperf_args>-t 20</iperf_args>
<id>idefix</id>
<svr_id>sabox-nepes</svr_id>
<iperf_tcp_rate_target>15</iperf_tcp_rate_target>

View File

@@ -123,7 +123,7 @@ services:
--rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod
--rfsimulator.serveraddr 192.168.71.140
--time-sync-I 0.1 --ntn-initial-time-drift -46
--autonomous-ta --initial-fo 57340 --cont-fo-comp 2
--initial-fo 57340 --cont-fo-comp 2
--log_config.global_log_options level,nocolor,time
--num-ul-actors 1
depends_on:

View File

@@ -33,7 +33,7 @@ services:
timeout: 5s
retries: 5
oai-gnb-aerial:
cpuset: "13-14"
cpuset: "13-16"
image: ${REGISTRY-oaisoftwarealliance/}${GNB_IMG:-oai-gnb-aerial}:${TAG:-develop}
depends_on:
nv-cubb:

View File

@@ -1,5 +1,5 @@
diff --git a/wls_lib/Makefile b/wls_lib/Makefile
index 2f8e4b2..e657488 100644
index 2f8e4b2..7b99a26 100644
--- a/wls_lib/Makefile
+++ b/wls_lib/Makefile
@@ -1,20 +1,6 @@
@@ -23,7 +23,7 @@ index 2f8e4b2..e657488 100644
+################################################################
+# <COPYRIGHT_TAG>
+################################################################
MYCUSTOMTAB=' '
MYCUSTOMSPACE='============================================================================================'
@@ -24,11 +10,17 @@ MYCUSTOMSPACE1='------------------------------------------------------------'
@@ -48,9 +48,12 @@ index 2f8e4b2..e657488 100644
else ifeq ($(WIRELESS_SDK_TOOLCHAIN),icx)
CC := icx
CPP := icx
@@ -44,9 +36,9 @@ ifeq ($(WIRELESS_SDK_TARGET_ISA),sse)
@@ -42,11 +34,11 @@ endif
ifeq ($(WIRELESS_SDK_TARGET_ISA),sse)
TARGET_PROCESSOR := -xSSE4.2
else ifeq ($(WIRELESS_SDK_TARGET_ISA),avx2)
TARGET_PROCESSOR := -xCORE-AVX2
- TARGET_PROCESSOR := -xCORE-AVX2
+ TARGET_PROCESSOR := -march=core-avx2
else ifeq ($(WIRELESS_SDK_TARGET_ISA),avx512)
- TARGET_PROCESSOR := -xCORE-AVX512
+ TARGET_PROCESSOR := -march=skylake-avx512
@@ -63,7 +66,7 @@ index 2f8e4b2..e657488 100644
@@ -66,15 +58,38 @@ PROJECT_DIR := ./
BUILDDIR := make
PROJECT_BINARY := $(PROJECT_NAME).so
+PKGCONF ?= pkg-config
+LIBDPDK_VERSION=20.11.3
+
@@ -79,7 +82,7 @@ index 2f8e4b2..e657488 100644
+$(error "Please define RTE_SDK environment variable OR install DPDK version $(LIBDPDK_VERSION)")
+endif
endif
-RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk)
+# At least one of the options is defined
+
@@ -88,10 +91,10 @@ index 2f8e4b2..e657488 100644
+else ifeq ($(DPDK_INSTALLED),1)
+ RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig $(PKGCONF) --cflags-only-I libdpdk)
+endif
CC_SRC = wls_lib_dpdk.c \
syslib.c
+CC_HDR = syslib.h \
+ ttypes.h \
+ wls.h \
@@ -104,74 +107,74 @@ index 2f8e4b2..e657488 100644
@@ -84,18 +99,19 @@ CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \
-Wimplicit-function-declaration \
-g -O3 -mcmodel=large $(TARGET_PROCESSOR)
-INC := -I$(RTE_INC)
+INC := -I$(RTE_INC) -I../intel_fapi/
DEF :=
AS_FLAGS :=
AR_FLAGS := rc
PROJECT_OBJ_DIR := $(BUILDDIR)/obj
+PROJECT_DEP_DIR := $(PROJECT_OBJ_DIR)/$(PROJECT_NAME).dep.d
CC_OBJS := $(patsubst %.c,%.o,$(CC_SRC))
AS_OBJS := $(patsubst %.s,%.o,$(AS_SRC))
OBJS := $(CC_OBJS) $(AS_OBJS) $(LIBS)
-DIRLIST := $(addprefix $(PROJECT_OBJ_DIR)/,$(sort $(dir $(OBJS))))
+DIRLIST := $(addprefix $(PROJECT_OBJ_DIR)/,$(sort $(dir $(OBJS)))) $(PROJECT_DEP_DIR)
CC_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(CC_OBJS))
@@ -104,9 +120,7 @@ CC_FLAGS_FULL := $(CC_FLAGS) $(INC) $(DEF)
AS_FLAGS := $(AS_FLAGS) $(INC)
-PROJECT_DEP_FILE := $(PROJECT_OBJ_DIR)/$(PROJECT_NAME).dep
-
-ifeq ($(wildcard $(PROJECT_DEP_FILE)),$(PROJECT_DEP_FILE))
+ifeq ($(wildcard $(PROJECT_DEP_DIR)),$(PROJECT_DEP_DIR))
GENERATE_DEPS :=
else
@@ -119,11 +133,11 @@ all : welcome_line $(PROJECT_BINARY)
.PHONY : clear_dep
clear_dep:
- @$(RM) $(PROJECT_DEP_FILE)
- @echo [DEP] $(subst $(PROJECT_OBJ_DIR)/,,$(PROJECT_DEP_FILE))
+ @echo [DEP] rm $(PROJECT_DEP_DIR)/$(@F).dep
+ @$(RM) $(PROJECT_DEP_DIR)/$(@F).dep
-$(CC_DEPS) :
- @$(CC) -MM $(subst __up__,../,$(subst __dep__,,$@)) -MT $(PROJECT_OBJ_DIR)/$(patsubst %.c,%.o,$(subst __up__,../,$(subst __dep__,,$@))) $(CC_FLAGS_FULL) >> $(PROJECT_DEP_FILE)
+$(CC_DEPS) : $(PROJECT_DEP_DIR)
+ @$(CC) $(CC_FLAGS_FULL) -MM $(subst __up__,../,$(subst __dep__,,$@)) -MT $(PROJECT_OBJ_DIR)/$(patsubst %.c,%.o,$(subst __up__,../,$(subst __dep__,,$@))) >> $(PROJECT_DEP_DIR)/$(@F).dep
.PHONY : generate_deps
generate_deps : clear_dep $(CC_DEPS)
@@ -136,17 +150,17 @@ echo_start_build :
$(DIRLIST) :
-@$(MD) $@
-$(CC_OBJTARGETS) :
+$(CC_OBJTARGETS) : $(GENERATE_DEPS)
@echo [CC] $(subst $(PROJECT_OBJ_DIR)/,,$@)
@$(CC) -c $(CC_FLAGS_FULL) -o"$@" $(patsubst %.o,%.c,$(subst $(PROJECT_OBJ_DIR)/,,$@))
-$(AS_OBJTARGETS) :
+$(AS_OBJTARGETS) : $(CC_OBJTARGETS) $(CPP_OBJTARGETS)
@echo [AS] $(subst $(PROJECT_OBJ_DIR)/,,$@)
@$(AS) $(AS_FLAGS) -o"$@" $(patsubst %.o,%.s,$(subst $(PROJECT_OBJ_DIR)/,,$@))
-ifeq ($(wildcard $(PROJECT_DEP_FILE)),$(PROJECT_DEP_FILE))
+ifeq ($(wildcard $(PROJECT_DEP_DIR)),$(PROJECT_DEP_DIR))
-include $(PROJECT_DEP_FILE)
+include $(PROJECT_DEP_DIR)/*
endif
@@ -156,7 +170,7 @@ clean:
@$(RM) $(CC_OBJTARGETS) $(AS_OBJTARGETS)
ifneq ($(wildcard $(PROJECT_DIR)/$(PROJECT_MAKE)),)
@@ -179,17 +182,17 @@ index 2f8e4b2..e657488 100644
- @$(RM) $(PROJECT_BINARY) $(PROJECT_BINARY_LIB) $(PROJECT_DEP_FILE)
+ @$(RM) -rf $(PROJECT_BINARY) $(PROJECT_BINARY_LIB) $(PROJECT_DEP_DIR)
endif
xclean: clean
@@ -172,7 +186,24 @@ welcome_line :
debug : all
release : all
-$(PROJECT_BINARY) : $(DIRLIST) echo_start_build $(GENERATE_DEPS) $(PRE_BUILD) $(CC_OBJTARGETS) $(AS_OBJTARGETS)
+$(PROJECT_BINARY) : $(DIRLIST) echo_start_build $(GENERATE_DEPS) $(CC_OBJTARGETS) $(AS_OBJTARGETS)
@echo [AR] $(subst $(BUILDDIR)/,,$@)
@$(CC) $(CC_OBJTARGETS) $(AS_OBJTARGETS) -shared -fPIC -o $@
+##############################################################
+# Install configuration
+##############################################################

View File

@@ -23,3 +23,4 @@ endif()
add_subdirectory(barrier)
add_subdirectory(actor)
add_subdirectory(shm_iq_channel)
add_subdirectory(wraparound_buffer)

View File

@@ -21,7 +21,7 @@ The following options can be specified to trigger the information added in the h
- `line_num`: adds the (source code) line number
- `time`: add the time since the system started in format `ss.ssssss` (seconds and microseconds sourced from `CLOCK_MONOTONIC`)
- `wall_clock`: add the system-wide clock time that measures real (i.e., wall-clock) time in format `ss.ssssss` (seconds and microseconds since 1970-01-01 00:00:00 Coordinated Universal Time (UTC))
- `utc_time`: add the UTC (Coordinated Universal Time) time in format `YYYY-MM-DD hh:mm:ss.ssssss UTC`. Note that this time is independent of the current time zone (it shows GMT). Also, printing this time has additional overhead compared to other time methods (due to time conversion and formatting).
- `utc_time`: add the UTC (Coordinated Universal Time) time in format `[hh:mm:ss.ssssss]`. Note that this time is independent of the current time zone (it shows GMT). Also, printing this time has additional overhead compared to other time methods (due to time conversion and formatting).
Note: `time`, `utc_time` and `wall_clock` are mutually exclusive and cannot be used together.

View File

@@ -38,6 +38,7 @@
#include "openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_config.h"
#include "openair2/RRC/NR/rrc_gNB_mobility.h"
#include "openair3/NGAP/ngap_gNB_ue_context.h"
@@ -276,6 +277,8 @@ static int get_current_bwp(char *buf, int debug, telnet_printfunc_t prnt)
if (rnti < 0)
ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n");
NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, rnti);
if (!UE)
ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti);
int dl_bwp = UE->current_DL_BWP.bwp_id;
const char *dl_bwp_text = dl_bwp > 0 ? "dedicated" : "initial";
int ul_bwp = UE->current_UL_BWP.bwp_id;
@@ -348,7 +351,7 @@ static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfu
if (sid < 1 || sid > 255) {
ERROR_MSG_RET("Invalid pdusession_id(int): %s (must be between 1 and 255)\n", tokens[i]);
}
msg->pdusession_release_params[nb_sessions++].pdusession_id = sid;
msg->pdusession_ids[nb_sessions++] = sid;
}
msg->nb_pdusessions_torelease = nb_sessions;
@@ -356,7 +359,7 @@ static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfu
if (prnt) {
prnt("Triggering NGAP PDU Session Release for gNB_ue_ngap_id=%d: releasing pdusession_id=%d", gNB_ue_ngap_id);
for (int i = 0; i < nb_sessions; ++i) {
prnt(" %d,", msg->pdusession_release_params[i].pdusession_id);
prnt(" %d,", msg->pdusession_ids[i]);
}
prnt("\n");
}
@@ -365,6 +368,24 @@ static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfu
return 0;
}
static int trigger_bwp_switch(char *buf, int debug, telnet_printfunc_t prnt)
{
char *sbwpId = strtok(buf, " ");
int bwpId = atoi(sbwpId);
char *srnti = strtok(NULL, " ");
prnt("bwpId %d rnti %s\n", bwpId, srnti);
int rnti = fetch_rnti(srnti, prnt);
if (rnti < 0)
ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n");
if (!nr_trigger_bwp_switch(rnti, bwpId)) {
prnt("failed trigger BWP switch for UE %04x BWP ID %d\n", rnti, bwpId);
return -1;
} else {
prnt("triggered BWP switch to BWP ID %d for UE %04x\n", bwpId, rnti);
return 0;
}
}
static telnetshell_cmddef_t cicmds[] = {
{"get_single_rnti", "", get_single_rnti},
{"force_reestab", "[rnti(hex,opt)]", trigger_reestab},
@@ -374,6 +395,7 @@ static telnetshell_cmddef_t cicmds[] = {
{"trigger_f1_ho", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_f1_ho},
{"fetch_du_by_ue_id", "[rrc_ue_id(int,opt)]", fetch_du_by_ue_id},
{"get_current_bwp", "[rnti(hex,opt)]", get_current_bwp},
{"trigger_bwp_switch", "newBWPId [rnti(hex,opt)]", trigger_bwp_switch},
{"trigger_n2_ho", "[neighbour_pci(uint32_t),ueId(uint32_t)]", rrc_gNB_trigger_n2_ho},
{"pdu_session_release", "[gNB_ue_ngap_id(int,opt)]", trigger_ngap_pdu_session_release},
{"", "", NULL},

View File

@@ -0,0 +1,6 @@
add_library(wraparound_buffer wraparound_buffer.cpp)
target_include_directories(wraparound_buffer PUBLIC ./)
target_link_libraries(wraparound_buffer PUBLIC LOG)
if (ENABLE_TESTS)
add_subdirectory(tests)
endif()

View File

@@ -0,0 +1,5 @@
add_executable(test_wraparound_buffer test_wraparound_buffer.cpp)
add_dependencies(tests test_wraparound_buffer)
target_link_libraries(test_wraparound_buffer PRIVATE wraparound_buffer pthread LOG minimal_lib GTest::gtest)
add_test(NAME test_wraparound_buffer
COMMAND ./test_wraparound_buffer)

View File

@@ -0,0 +1,67 @@
/*
* 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 <gtest/gtest.h>
#include "wraparound_buffer.h"
#include "log.h"
#include <unistd.h>
// Thread safety can be ensured through core affinity - if two actors
// are running on the same core they are thread safe
TEST(wraparound_buffer, basic_logic)
{
size_t buf_size = getpagesize() * 2;
void *buffer = malloc_wraparound_buffer(buf_size);
ASSERT_NE(buffer, nullptr);
uint8_t *buffptr = static_cast<uint8_t *>(buffer);
memset(buffer, 0, buf_size);
buffptr[0] = 1;
EXPECT_EQ(buffptr[buf_size], 1);
free_wraparound_buffer(buffer);
}
TEST(wraparound_buffer, full_range)
{
size_t buf_size = getpagesize() * 2;
void *buffer = malloc_wraparound_buffer(buf_size);
ASSERT_NE(buffer, nullptr);
uint8_t *buffptr = static_cast<uint8_t *>(buffer);
memset(buffer, 0, buf_size);
for (auto i = 0U; i < buf_size; i++) {
buffptr[i] = (uint8_t)i;
EXPECT_EQ(buffptr[i + buf_size], (uint8_t)i);
}
free_wraparound_buffer(buffer);
}
TEST(wraparound_buffer, size)
{
size_t buf_size = getpagesize() * 2 + 1;
void *buffer = malloc_wraparound_buffer(buf_size);
ASSERT_EQ(buffer, nullptr);
}
int main(int argc, char **argv)
{
logInit();
g_log->log_component[UTIL].level = OAILOG_DEBUG;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,86 @@
/*
* 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 "wraparound_buffer.h"
#include <unistd.h>
#include <sys/mman.h>
#include <map>
#include <mutex>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include "log.h"
#include "assertions.h"
struct {
std::map<void*, size_t> map;
std::mutex mtx;
} internal_state;
extern "C" void* malloc_wraparound_buffer(size_t size)
{
size_t pagesize = getpagesize();
if (size % pagesize != 0) {
return NULL;
}
int fd = memfd_create("wraparound", MFD_CLOEXEC);
if (fd == -1) return NULL;
if (ftruncate(fd, size) != 0) {
close(fd);
return NULL;
}
void* region = mmap(NULL, size * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (region == MAP_FAILED) {
close(fd);
return NULL;
}
void* buf = mmap(region, size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
munmap(region, size * 2);
close(fd);
return NULL;
}
uint8_t *second_half = (uint8_t *)region + size;
void* mirror = mmap(second_half, size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0);
if (mirror == MAP_FAILED) {
munmap(region, size * 2);
close(fd);
return NULL;
}
close(fd);
std::lock_guard<std::mutex> lock(internal_state.mtx);
internal_state.map[buf] = size;
return buf;
}
extern "C" void free_wraparound_buffer(void* buf) {
if (buf == nullptr) return;
std::lock_guard<std::mutex> lock(internal_state.mtx);
size_t size = internal_state.map[buf];
if (munmap(buf, size * 2) != 0) {
LOG_W(UTIL, "munmap failed\n");
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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
*/
#ifndef __WRAPAROUND_BUFFER_H__
#define __WRAPAROUND_BUFFER_H__
#include <memory.h>
#ifdef __cplusplus
extern "C" {
#endif
void *malloc_wraparound_buffer(size_t size);
void free_wraparound_buffer(void *buf);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -82,7 +82,7 @@ of the FAPI 10.04 version of the SRS PDU, and RX_Beamforming PDU.
| Applicative Threads | Allocated CPUs |
|------------------------|----------------|
| PTP & PHC2SYS Services | 41 |
| OAI `nr-softmodem` | 13-14 |
| OAI `nr-softmodem` | 13-16 |
## PTP configuration

View File

@@ -352,7 +352,9 @@ These modes of operation are supported:
- Formats 0,1,2,3, A1-A3, B1-B3
* NTN
- TA adjustemt based on ntn-Config-r17 information
- Autonomous TA adjustemt between SIB19 receptions based on DL time tracking
- Different TA adjustemt algorithms between SIB19 receptions:
- Autonomous TA adjustemt based on DL time tracking
- Standard compliant epoch time based TA adjustment including orbital propagation
- UL Doppler pre-compensation based on continuous DL FO estimation
* Highly efficient 3GPP compliant LDPC encoder and decoder (BG1 and BG2 are supported)
* Highly efficient 3GPP compliant polar encoder and decoder

View File

@@ -420,3 +420,29 @@ Note that you should increase the aggregation level candidates as described in
[the corresponding section above](#pdcch-aggregation-level). This is because the
scheduler has to schedule multiple DCIs in a single DL slots for multiple UL
slots. As a suggestion, you could try `uess_agg_levels = [4, 2, 2, 0, 0]`.
## Multiple Dedicated BWPs
A maximum of 4 dedicated BWPs can be configured for a UE per standard, but only
1 BWP can be active in UL and DL direction at a given time. In the code we
only configure a single BWP for the UE at a given time and we would switch by
reconfiguring this BWP. All this procedure is transparent for users and LOGs
mark BWP switching according to the configuration file enumeration. It is
possible to configure multiple dedicated BWPs and 1st active BWP via
configuration file.
### Setup of the Configuration files ##
In the configuration file you have the option to select the 1st active BWP, the
BWP location and SCS of each BWP in the following way (example with 2
additional BWPs):
```
first_active_bwp = 1;
bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;},
{ scs = 1; bwpStart = 0; bwpSize = 24;});
```
This example configures 3 additional BWPs, with IDs from 1 to 3. A similar
example can be found in configuration file
`ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf` tested in CI.

View File

@@ -1243,8 +1243,8 @@ In OAI gNB, we support:
```
The reference specifications:
* `O-RAN.WG4.MP.0-v05.00`
* `O-RAN.WG4.MP-YANGs-v04.00`
* `O-RAN.WG4.MP.0-R004-v16.01`
* `O-RAN.WG4.MP-YANGs-R004-v16.01`
## M-plane prerequisites
Before proceeding, please make sure you have a support for 7.2 interface, as described in [Prerequisites](#prerequisites).
@@ -1366,7 +1366,7 @@ sudo ldconfig
If you would like to install these libraries in the custom path, please replace `/usr/local` default path to e.g. `/opt/mplane-v2`.
## Benetel O-RU
Note: Only v1.2.2 RAN550 and RAN650 have been successfully tested.
Note: RAN550/650 v1.2.2 and v1.4.1 have been successfully tested.
### One time steps
Connect to the RU as user `root`, enable the mplane service, and reboot:
@@ -1400,6 +1400,8 @@ The reference DU configuration file for two Benetel RAN650:
[gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf)
In order to run gNB/DU with M-plane, we need to modify Tx gain `att_tx` in RU section, as well as the `fhi_72` section in the configuration file.
**Important note: Benetel v1.4.1 requires only one VF if the same VLAN tag is used for both C-/U-planes. Otherwise, C-plane will not be properly configured. Benetel v1.2.2 will receive the C-plane packets no matter the DU MAC address value.**
Example for one RU:
```bash
fhi_72 = {
@@ -1573,14 +1575,14 @@ sequenceDiagram
<details>
<summary>4x4 MIMO and 100MHz BW with Benetel 550 RU example run</summary>
<summary>4x4 MIMO and 100MHz BW with Benetel 550 RU v1.2.2 example run</summary>
```
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <connect> with username "oranbenetel" and port ID "830".
[HW] [MPLANE] Successfuly connected to RU "192.168.80.9" with username "oranbenetel" and port ID "830".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get> operational datastore.
[HW] [MPLANE] Successfully retrieved operational datastore from RU "192.168.80.9".
[HW] [MPLANE] RU is already PTP synchronized.
[HW] [MPLANE] RU is in "LOCKED" sync state.
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <subscribe> with stream "NETCONF" and filter "(null)".
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully subscribed to all notifications from RU "192.168.80.9".
@@ -2223,6 +2225,861 @@ sequenceDiagram
```
</details>
<details>
<summary>4x4 MIMO and 100MHz BW with Benetel 550 RU v1.4.1 example run</summary>
```
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <connect> with username "oranbenetel" and port ID "830".
[HW] [MPLANE] Successfuly connected to RU "192.168.81.4" with username "oranbenetel" and port ID "830".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get> operational datastore.
[HW] [MPLANE] Successfully retrieved operational datastore from RU "192.168.81.4".
[HW] [MPLANE] RU is already PTP synchronized.
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <subscribe> with stream "NETCONF" and filter "(null)".
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully subscribed to all notifications from RU "192.168.81.4".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = "<supervision-watchdog-reset xmlns="urn:o-ran:supervision:1.0">
<supervision-notification-interval>65535</supervision-notification-interval>
<guard-timer-overhead>65535</guard-timer-overhead>
</supervision-watchdog-reset>".
[HW] [MPLANE] Successfully updated supervision timer to (65535+65535)[s] for RU "192.168.81.4".
[HW] [MPLANE] Watchdog timer answer:
<next-update-at xmlns="urn:o-ran:supervision:1.0">2025-08-29T06:49:32+02:00</next-update-at>
[HW] [MPLANE] Interface MTU 1500 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.
[HW] [MPLANE] IQ bitwidth 16 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9.
[HW] [MPLANE] Storing the following information to forward to xran:
RU MAC address 70:b3:d5:e1:5b:81
MTU 9600
IQ bitwidth 9
PRACH offset 4
DU port bitmask 61440
Band sector bitmask 3840
CC ID bitmask 240
RU port ID bitmask 15
DU port ID 0
Band sector ID 0
CC ID 0
RU port ID 0
max Tx gain 24.0
[HW] [MPLANE] Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.
[HW] [MPLANE] Successfully retreived all performance measurement names.
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-yang-metadata".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "yang".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-inet-types".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-yang-types".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-yang-schema-mount".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-yang-structure-ext".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-datastores".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "sysrepo".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-netconf-acm".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-factory-default".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "sysrepo-factory-default".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-yang-library".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "sysrepo-monitoring".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "sysrepo-plugind".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-netconf".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-netconf-with-defaults".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-netconf-notifications".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-origin".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-netconf-monitoring".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "ietf-netconf-nmda".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <get-schema> for module "nc-notifications".
[HW] [MPLANE] [LIBYANG] ERROR: Data model "notifications" not found in local searchdirs. (path: (null)).
[HW] [MPLANE] [LIBYANG] ERROR: Loading "notifications" module failed. (path: (null)).
[HW] [MPLANE] [LIBYANG] ERROR: Parsing module "nc-notifications" failed. (path: (null)).
[HW] [MPLANE] Unable to load module "nc-notifications" from RU "192.168.81.4".
[HW] [MPLANE] Unable to load all yang modules from operational datastore for RU "192.168.81.4". Using yang models present in "models" subfolder.
[HW] [MPLANE] Successfully loaded all yang modules for RU "192.168.81.4".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <edit-config>:
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>INTERFACE_0</name>
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:l2vlan</type>
<enabled>true</enabled>
<mac-address xmlns="urn:o-ran:interfaces:1.0">70:b3:d5:e1:5b:81</mac-address>
<base-interface xmlns="urn:o-ran:interfaces:1.0">eth0</base-interface>
<vlan-id xmlns="urn:o-ran:interfaces:1.0">3</vlan-id>
</interface>
</interfaces>
<performance-measurement-objects xmlns="urn:o-ran:performance-management:1.0">
<rx-window-measurement-interval>10</rx-window-measurement-interval>
<tx-measurement-interval>10</tx-measurement-interval>
<notification-interval>10</notification-interval>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_TOTAL</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME_C</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY_C</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE_C</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<tx-measurement-objects>
<measurement-object>TX_TOTAL</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</tx-measurement-objects>
</performance-measurement-objects>
<processing-elements xmlns="urn:o-ran:processing-element:1.0">
<transport-session-type>ETH-INTERFACE</transport-session-type>
<ru-elements>
<name>PLANE_0</name>
<transport-flow>
<interface-name>INTERFACE_0</interface-name>
<eth-flow>
<ru-mac-address>70:b3:d5:e1:5b:81</ru-mac-address>
<vlan-id>3</vlan-id>
<o-du-mac-address>00:11:22:33:44:66</o-du-mac-address>
</eth-flow>
</transport-flow>
</ru-elements>
</processing-elements>
<user-plane-configuration xmlns="urn:o-ran:uplane-conf:1.0">
<low-level-tx-links>
<name>PdschLink0</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray0</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint0</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-tx-links>
<name>PdschLink1</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray1</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint1</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-tx-links>
<name>PdschLink2</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray2</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint2</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-tx-links>
<name>PdschLink3</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray3</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint3</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-rx-links>
<name>PuschLink0</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint0</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink0</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint0</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PuschLink1</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray1</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint1</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink1</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray1</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint1</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PuschLink2</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray2</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint2</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink2</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray2</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint2</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PuschLink3</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray3</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint3</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink3</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray3</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint3</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint0</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>0</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint1</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>1</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint2</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>2</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint3</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>3</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint0</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>0</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint0</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>4</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint1</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>1</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint1</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>5</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint2</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>2</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint2</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>6</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint3</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>3</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint3</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>7</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<tx-array-carriers>
<name>TxArray0</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<gain>24.0</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers>
<tx-array-carriers>
<name>TxArray1</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<gain>24.0</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers>
<tx-array-carriers>
<name>TxArray2</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<gain>24.0</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers>
<tx-array-carriers>
<name>TxArray3</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<gain>24.0</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers>
<rx-array-carriers>
<name>RxArray0</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
<gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset>
</rx-array-carriers>
<rx-array-carriers>
<name>RxArray1</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
<gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset>
</rx-array-carriers>
<rx-array-carriers>
<name>RxArray2</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
<gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset>
</rx-array-carriers>
<rx-array-carriers>
<name>RxArray3</name>
<absolute-frequency-center>623334</absolute-frequency-center>
<center-of-channel-bandwidth>3350010000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
<gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset>
</rx-array-carriers>
</user-plane-configuration>
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.81.4".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <validate> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.81.4".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <commit> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully commited configuration into running datastore for RU "192.168.81.4".
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.335228846+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray0",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.368360865+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray1",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.414703766+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray2",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.452921618+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray3",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.471419021+00:00)
{
"ietf-netconf-notifications:netconf-config-change": {
"changed-by": {
"username": "root",
"session-id": 0
},
"datastore": "running",
"edit": [
{
"target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']",
"operation": "create"
},
{
"target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']/name",
"operation": "create"
},
...
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.678251110+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray0",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.715498360+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray1",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.830268973+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray2",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:19.853387657+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray3",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.515262267+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray0",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.535692962+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray1",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.557423764+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray2",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.579066867+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray3",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.604192995+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray0",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.629830498+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray1",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.651062685+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray2",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.81.4" at (2025-08-28T10:37:24.672865767+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray3",
"state": "READY"
}
]
}
}
[HW] [MPLANE] RU "192.168.81.4" is now ready.
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <edit-config>:
<performance-measurement-objects xmlns="urn:o-ran:performance-management:1.0">
<rx-window-measurement-interval>10</rx-window-measurement-interval>
<tx-measurement-interval>10</tx-measurement-interval>
<notification-interval>10</notification-interval>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_TOTAL</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME_C</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY_C</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE_C</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<tx-measurement-objects>
<measurement-object>TX_TOTAL</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</tx-measurement-objects>
</performance-measurement-objects>
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.81.4".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <validate> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.81.4".
[HW] [MPLANE] RPC request to RU "192.168.81.4" = <commit> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully commited configuration into running datastore for RU "192.168.81.4".
[HW] [MPLANE] Sucessfully activated PM after start-up procedure for RU "192.168.81.4".
```
</details>
Note: If you wish to run the fronthaul without M-plane, no need for recompilation, as the library `oran_fhlib_5g` already exists.
The only mandatory step is to link `oran_fhlib_5g` to `oai_transpro` library.

View File

@@ -356,7 +356,9 @@ sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF
For LEO satellite scenarios, the parameter `--ntn-initial-time-drift` must be provided via command line, as the UE needs this value to compensate for the time drift during initial sync, before SIB19 was received.
This parameter provides the drift rate of the complete DL timing (incl. feeder link and service link) in µs/s.
Also, to perform an autonomous TA update based on the DL drift, the boolean parameter `--autonomous-ta` should be added in case of a LEO satellite scenario.
To perform an autonomous TA update based on the DL drift, the boolean parameter `--autonomous-ta` can be added.
If that parameter is omitted, the TA is continuously computed based on the SIB19 information.
For LEO satellite scenario we assume the LO to be very accurate and the main FO contribution comes from Doppler shift.
Therefore, we use the command line parameter `--cont-fo-comp 2` to continuously compensate the DL Doppler and pre-compensate the UL Doppler.
@@ -367,7 +369,7 @@ For other information on optional NR UE command line options, please refer [here
So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, transparent LEO satellite 5G NR NTN is this:
```
cd cmake_targets
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta --initial-fo 57340 --cont-fo-comp 2
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --initial-fo 57340 --cont-fo-comp 2
```
# Specific OAI modes
@@ -468,19 +470,30 @@ The hardcoded DRBs will be treated like GBR Flows. Due to code limitations at th
## IF setup with OAI
OAI is also compatible with Intermediate Frequency (IF) equipment. This allows to use RF front-end that with arbitrary frequencies bands that do not comply with the standardised 3GPP NR bands.
OAI is also compatible with Intermediate Frequency (IF) equipment, allowing the
use of RF front-ends operating on arbitrary frequency bands that do not conform
to the standardized 3GPP NR bands.
To configure the IF frequencies it is necessary to use two command-line options at UE side:
- `if_freq`, downlink frequency in Hz
- `if_freq_off`, uplink frequency offset in Hz
### OAIUE configuration
To configure IF frequencies on the UE side, provide the following command-line
options:
- `if_freq`: DL frequency in Hz
- `if_freq_off`: UL frequency offset in Hz
Accordingly, the following parameters must be configured in the RUs section of the gNB configuration file:
- `if_freq`
- `if_offset`
### gNB configuration
On the gNB side, the corresponding parameters must be set in the RUs section of
the configuration file:
- `if_freq`: DL frequency in Hz
- `if_offset`: UL frequency offset in Hz
> Note: When using a libconfig-based configuration file for the gNB, ensure that
> `if_freq` numeric value is suffixed with "L" so it is correctly parsed as
> 64-bit integer.
### Run OAI with custom DL/UL arbitrary frequencies
The following example uses DL frequency 2169.080 MHz and UL frequency offset -400 MHz, with a configuration file for band 66 (FDD) at gNB side.
The following example uses DL frequency 2169.080 MHz and UL frequency offset
-400 MHz, with a configuration file for band 66 (FDD) at gNB side.
On two separate machines with USRPs, run:

View File

@@ -1,44 +0,0 @@
# Procedure to add dedicated Bandwidth part (BWP)
## Contributed by 5G Testbed IISc
### Developers: Abhijith A, Shruthi S
# Terminology #
## Bandwidth part (BWP) ##
Bandwidth Part (BWP) is a set of contiguous Resource Blocks in the resource grid.
Parameters of a BWP are communicated to UE using RRC parameters: BWP-Downlink and BWP-Uplink.
A UE can be configured with a set of 4 BWPs in uplink (UL) and downlink (DL) direction (3GPP TS 38.331 Annex B.2 Description of BWP configuration options). But only 1 BWP can be active in UL and DL direction at a given time.
# Procedure to run multiple dedicated BWPs #
A maximum of 4 dedicated BWPs can be configured for a UE.
To configure multiple BWPs, add the following parameters in the physical parameters section:
## Setup of the Configuration files ##
In the configuration file you have the option to select the 1st active BWP, the RIV and SCS of each BWP in the following way (example with 3 additional BWPs):
```
first_active_bwp = 1;
bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;},
{ scs = 1; bwpStart = 0; bwpSize = 51;},
{ scs = 1; bwpStart = 0; bwpSize = 24;});
```
This example configures 3 additional BWPs, with IDs from 1 to 3. Find these parameters in this configuration file: "ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf"
# Testing gNB and UE in RF simulator
## gNB command:
```
sudo ./nr-softmodem -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf --rfsim --rfsimulator.serveraddr server
```
## UE command:
```
sudo ./nr-uesoftmodem -C 3319680000 -r 106 --numerology 1 --ssb 516 --band 78 --rfsim --rfsimulator.serveraddr 127.0.0.1
```

View File

@@ -9,7 +9,8 @@ OAI uses/supports a number of environment variables, documented in the following
- `NVRAM_DIR`: directory to read/write NVRAM data in (5G) `nvram` tool; if not defined, will use `PWD` (working directory)
- `OAI_CONFIGMODULE`: can be used to pass the configuration file instead of `-O`
- `OAI_GDBSTACKS`: if defined when hitting an assertion (`DevAssert()`, `AssertFatal()`, ...), OAI will load `gdb` and provide a backtrace for every thread
- `OAI_RNGSEED`: overwrites any seed for random number generators (RNG) in simulators
- `OAI_RNGSEED`: provide a fixed seed for random number generators (RNG). If
this variable is absent, a random seed will be read (from `/dev/urandom`).
- `USIM_DIR`: directory to read/write USIM data in (4G) `usim` tool; if not defined, will use `PWD` (working directory)
Furthermore, these variables appear in code that is not maintained and maybe not even compiled anywhere:

View File

@@ -1,6 +1,15 @@
This tutorial explains how to perform handovers. It covers both F1 handovers
(intra-gNB, within a single gNB between DUs) and N2 handovers (inter-gNB).
This document assumes familiarity with the F1 split architecture and basic
OAI knowledge. Please refer to the prerequisite documentation listed below:
- To run the [Core Network](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_OAI_CN5G.md)
- To run [OAI full stack with COTS UE](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_COTS_UE.md)
- [F1 split design document](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/F1AP/F1-design.md?ref_type=heads)
for details on the F1 architecture and the networking relationships between
the CU and the associated DUs.
[[_TOC_]]
# Considered setup for F1 handover
@@ -13,22 +22,22 @@ same.
![F1 Handover setup](./RRC/ho.png)
# What is a gNB neighbor?
# gNB neighbour definition
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbors
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbours
play a central role in maintaining service continuity through mechanisms such
as handover and load balancing. By definition, a gNB neighbor is another gNB
as handover and load balancing. By definition, a gNB neighbour is another gNB
that can be measured and linked by the UE. If the current serving gNB is no
longer optimal, the UE may connect to a neighbor gNB.
longer optimal, the UE may connect to a neighbour gNB.
To support this behavior, the network configuration specifies additional frequencies
and cells that the UE should measure. The UE reports these measurements to the
network, which then decides whether or not to initiate a handover.
Neighbor types include:
- **Intra-gNB neighbors** - cells belonging to the same gNB
- **Inter-gNB neighbors** - cells belonging to different gNBs
- **Inter-RAT neighbors** - cells belonging to another RAT (e.g., LTE)
Neighbour types include:
- **Intra-gNB neighbours** - cells belonging to the same gNB
- **Inter-gNB neighbours** - cells belonging to different gNBs
- **Inter-RAT neighbours** - cells belonging to another RAT (e.g., LTE)
# Steps to run F1 handover with OAI UE
@@ -46,10 +55,6 @@ build both gNB and UE as well as activate the build of telnet to that purpose:
## Run the setup
This tutorial assumes you have a core network running; [refer to the
corresponding tutorial](./NR_SA_Tutorial_OAI_CN5G.md) if this is not the case
yet.
We will use the TDD configuration files in the repository for the
[CU](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf) as well for
[DU0](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf)
@@ -139,19 +144,23 @@ directory of the CU.
You can do handover across DUs with a COTS UE. Note that these DUs should be
separated by at least multiple meters to ensure that the UE will receive
different signal strengths when moving between cells.
In the CI setup we use a digital 4 channel attenuator that allows us to "control"
the transmitted signal from both RUs. This allows us to create a setup in
which the UE thinks it's changing positions between 2 cells, but in reality
it's not moving.
We support both intra-frequency and inter-frequency handovers. We have verified with USRPs
only, although other radios should work as well.
We support both intra-frequency and inter-frequency handovers. We have verified
with USRPs only, although other radios should work as well.
For UEs, we verified Quectel modules and iPhones. Note, though, that not all
phones might work; for instance, we did not achieve handovers with a OnePlus
Nord, yet.
For UEs, we verified Quectel modules, iPhones and Samsung S23 Ultra. Note,
though, that not all phones might work; for instance, we did not achieve
handovers with a OnePlus Nord, yet.
## Steps
First, make sure that you can run both DUs with the CU independently. Use the
same radio hardware for both radios to ensure that both cells can be received
equally good by the UE.
First, make sure that you can run both DUs with the CU independently.
Use the same radio hardware for both radios to ensure that both cells can be
received equally good by the UE.
In order to enable handovers (triggered by the UE), you have to configure the
neighbour relation of the DUs at the CU. To do so, proceed as follows:
@@ -163,11 +172,13 @@ neighbour relation of the DUs at the CU. To do so, proceed as follows:
```
cat nrRRC_stats.log
```
1. Fill in the [`neighbour-config.conf`](../ci-scripts/conf_files/neighbour-config.conf) configuration file as shown below, and
`@include` it in the CU file.
1. Start the CU and both DUs.
1. Fill in the [`neighbour-config.conf`](../ci-scripts/conf_files/neighbour-config.conf)
configuration file as shown below, and `@include` it in the CU file.
1. Start the CU and both DUs. If you are using an attenuator, make sure that
the signal on one DU is stronger than the other.
1. Bring the phone close to one cell, and leave flight mode. It should connect
to the DU to which it is closer.
to the DU to which it is closer/stronger signal.
1. Move the UE towards the other DU; it should trigger an "A3 event" (Neighbour
Becomes Better than Serving), and the CU will trigger the handover to the
other DU.
@@ -175,7 +186,14 @@ neighbour relation of the DUs at the CU. To do so, proceed as follows:
The output on the terminal should be the same as with RFsim. If no handover is
triggered:
- Make sure that both DUs use the same hardware.
- Make sure that both DUs use the same hardware. In case of USRPs, make sure that
they are synched:
- By connecting them to a GPS or an Octoclock to provide a common time and clock
reference.
- By synchronizing the RU hosts.
- By using Openairinterface starting tag [2025.w42](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tree/2025.w42?ref_type=tags)
(A fix was added to force the USRP to "use" the time/clock provided by the
external source instead to its own master clock. for more info see [MR](https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/3693)).
- Make sure that the UE sees both cells. For instance, you can switch to flight
mode, go closer to the other DU, and switch off flight mode -- the UE should
connect to that second DU.
@@ -187,6 +205,17 @@ decision about a handover is always at the network-side, the UE only "assists"
through measurements telling the CU that one DU is stronger than others.
Hence, "forcing" a handover just means that you manually trigger the handover,
instead of waiting for UE measurement report.)
Our CI setup consists of:
- 2 USRPs B210 that are synchronized by connecting them to an Octoclock over
10MHz refrence and a PPS signal. The RU hosts are synchronized via NTP.
- Mini-Circuits RC4DAT-6G-60 programmable attenuator. To control the digital attenuator,
a Python script was developed `ci-scripts/attenuatorctl.py`.
- Quectel RM520 as a UE.
- The setup is run using Docker `ci-scripts/yaml_files/5g_sa_f1_b210_ho`.
To run the setup using Docker:
- We consider 2 synchronized servers. One for each DU.
## Example neighbour configuration
@@ -209,70 +238,100 @@ Concretely, the first cell is `12345678` (on DU `[2]`), and it has `11111111`
The below configuration further enables periodic measurements, A2 event
("Serving becomes worse than threshold"), and A3 events ("Neighbour Becomes
Better than Serving"). The A2 event can be disabled by setting `enable = 0`. A3
events cannot be disabled as of now. Further, the A3 events can be made
specific to cells; `cell_id = -1` means "any cell".
Better than Serving").
The A2 event can be disabled by setting `enable = 0`.
The A3 event cannot be disabled as of now. It can be made
specific to cells or set to `cell_id = -1` which means "any cell".
`hysteresis` is a margin added to the serving cell measurements to
prevent unnecessary or frequent handovers. It ensures that the neighbouring
cell must show sufficiently better signal quality before a handover is
triggered. It is an integer between 0 and 30.
`timeToTrigger` the time during which specific criteria for the event
needs to be met in order to trigger a measurement report. It is an enumerated
parameter and in the configuration below it is set to 1 which corresponds to
`ms40` or 40 milliseconds.
*Note*: For more information please refer to 3GPP TS 38.331 specifications.
```
neighbour_list = (
{
nr_cellid = 12345678;
neighbour_cell_configuration = (
{
gNB_ID = 0xe01;
nr_cellid = 11111111;
physical_cellId = 1;
absoluteFrequencySSB = 643296;
subcarrierSpacing = 1; #30 KHz
band = 78;
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
tracking_area_code = 1;
}
)
},
{
nr_cellid = 11111111;
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 12345678;
physical_cellId = 0;
absoluteFrequencySSB = 643296;
subcarrierSpacing = 1; #30 KHz
band = 78;
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
tracking_area_code = 1;
}
)
}
);
############################################################
# gNB-to-gNB neighbour list + measurement configuration #
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
############################################################
neighbour_list = (
##########################################################
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) #
##########################################################
{
nr_cellid = 12345678; # Serving cell of gNB 0xe00
neighbour_cell_configuration = (
{
gNB_ID = 0xe01;
nr_cellid = 11111111; # Cell served by gNB 0xe01
physical_cellId = 1;
absoluteFrequencySSB = 643296;
subcarrierSpacing = 1; # 30 kHz
band = 77;
plmn = { mcc = 001; mnc = 01; mnc_length = 2 };
tracking_area_code = 1;
}
);
},
##########################################################
# Entry USED BY gNB_ID = 0xe01 (nr_cellid = 11111111) #
##########################################################
{
nr_cellid = 11111111; # Serving cell of gNB 0xe01
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 12345678L; # Cell served by gNB 0xe00
physical_cellId = 0;
absoluteFrequencySSB = 643296;
subcarrierSpacing = 1; # 30 kHz
band = 77;
plmn = { mcc = 001; mnc = 01; mnc_length = 2 };
tracking_area_code = 1;
}
);
}
);
############################################################
# Common NR measurement-event configuration #
############################################################
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 60;
enable = 1;
threshold = 60;
timeToTrigger = 1;
};
A3 = ({
cell_id = -1; #Default
offset = 10;
hysteresis = 0;
timeToTrigger = 1
})
A3 = (
{
cell_id = -1;
offset = 10;
hysteresis = 0;
timeToTrigger = 1;
}
)
};
```
`@include` this configuration file inside the gNB section of CU file as shown below.
```
plmn_list = ({ mcc = 222; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff })});
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff })});
@include "neighbour-config.conf"
@@ -364,30 +423,37 @@ done
## Run the setup
An N2 handover involves the transfer of a UE from one gNB to another via the 5G core network. Unlike F1 handover, where the CU handles the process internally between its DUs, N2 handover requires signaling through the AMF, making it a core-network-based handover.
An N2 handover involves the transfer of a UE from one gNB to another via the
5G core network. Unlike F1 handover, where the CU handles the process internally
between its DUs, N2 handover requires signaling through the AMF, making it
a core-network-based handover.
We assume:
* Two independent gNBs connected to the same 5GC via N2 interface.
* A UE initially connected to gNB-PCI0, which will be handed over to gNB-PCI1.
* Handover is triggered by either a decision based measurement event (e.g. A3) or telnet command.
* Handover is triggered by either a decision based measurement event (e.g. A3) or
telnet command.
## Steps to run N2 handover with OAI UE
**Note for same-machine setup:** When running both gNBs on the same machine, you need to assign a unique IP address to the second gNB to avoid network conflicts. For example:
**Note for same-machine setup:** When running both gNBs on the same machine,
you need to assign a unique IP address to the second gNB to avoid network conflicts.
For example:
```sh
sudo ip addr add 192.168.71.180/24 dev rfsim5g-public
```
1. Similarly to F1 handover, UE does not support any measurement reporting and handover is triggered by
telnet command. Therefore, ensure that both gNBs and UE are built with telnet support:
1. Similarly to F1 handover, UE does not support any measurement reporting and
handover is triggered by telnet command. Therefore, ensure that both gNBs and
UE are built with telnet support:
```sh
./build_oai --ninja --nrUE --gNB --build-lib telnetsrv
```
Run the 5G Core Network if not already running. See [OAI CN5G tutorial](./NR_SA_Tutorial_OAI_CN5G.md).
Run the 5G Core Network if not already running.
2. Start the source gNB (gNB-PCI0) e.g.
@@ -409,7 +475,8 @@ Ensure the UE successfully registers with the network.
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf --rfsim --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsimulator.serveraddr 127.0.0.1
```
**Note for same-machine setup:** When running both gNBs on the same machine, add the following network interface options to the target gNB command, e.g.:
**Note for same-machine setup:** When running both gNBs on the same machine,
add the following network interface options to the target gNB command, e.g.:
```sh
--gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 192.168.71.180
@@ -423,96 +490,15 @@ From gNB-PCI0, trigger handover on target gNB with PCI 1 for UE ID 1:
```sh
echo ci trigger_n2_ho 1,1 | nc 127.0.0.1 9090 && echo
```
where the input parameters correspond to the PCI of the neighbor cell and the RRC ID of the UE.
where the input parameters correspond to the PCI of the neighbour cell and the RRC ID of the UE.
This will initiate the N2 handover on the source gNB.
## Neighbour list and measurement configuration
Make sure the configuration file contains a neighbour list and measurement configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/neighbour-config.conf). This configuration can also be present in a different file and included in the gNB configuration file with `@include "neighbour-config-rfsim.conf"`.
Make sure the configuration file contains a neighbour list and measurement configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/neighbour-config.conf).
This configuration can also be present in a different file and included in the gNB configuration file with `@include "neighbour-config-rfsim.conf"`.
For each gNB there is a `neighbour_cell_configuration` linked to its serving cell ID.
The measurement configuration is based on A2 and A3 measurement events in 5G NR. These events are used by the UE to report radio conditions to the gNB. The A2 Measurement Event indicates that the serving cells signal quality has degraded below a defined threshold and the UE shall initiate measurement of neighboring cells. The A3 Measurement Event indicates that a neighboring cells signal quality is better than that of the serving cell by a certain offset and the UE shall trigger handover to a stronger neighboring cell
This is an example with comments on how to use the configuration file:
```
############################################################
# gNB-to-gNB neighbour list + measurement configuration #
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
############################################################
neighbour_list = (
##########################################################
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) #
##########################################################
{
nr_cellid = 12345678L; # Serving cell of gNB 0xe00
neighbour_cell_configuration = (
{
gNB_ID = 0xb00;
nr_cellid = 720898; # Cell served by gNB 0xb00
physical_cellId = 1;
absoluteFrequencySSB= 621312;
subcarrierSpacing = 1; # 30 kHz
band = 78;
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
tracking_area_code = 1;
}
);
},
##########################################################
# Entry USED BY gNB_ID = 0xb00 (nr_cellid = 720898) #
##########################################################
{
nr_cellid = 720898; # Serving cell of gNB 0xb00
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 12345678L; # Cell served by gNB 0xe00
physical_cellId = 0;
absoluteFrequencySSB= 641280;
subcarrierSpacing = 1; # 30 kHz
band = 78;
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
tracking_area_code = 1;
}
);
}
);
############################################################
# Common NR measurement-event configuration #
############################################################
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 60;
timeToTrigger = 1;
};
A3 = (
{
cell_id = 720898; # neighbour of gNB 0xe00
offset = 10;
hysteresis = 0;
timeToTrigger = 1;
},
{
cell_id = 12345678; # neighbour of gNB 0xb00
offset = 5;
hysteresis = 1;
timeToTrigger = 2;
}
);
};
```
See the example above for `neighbour-config-ho.conf`. The same configuration is for both F1 and N2 handover.

View File

@@ -1,3 +1,5 @@
# FAPI/nFAPI split in OAI
This document describes the SmallCellForum (SCF) (n)FAPI split in 5G, i.e.,
between the MAC/L2 and PHY/L1. It also describes how to make use of the
multiple transport mechanisms between the 2.
@@ -10,7 +12,7 @@ about nFAPI can be found in SCF 225.2.0.
[[_TOC_]]
# Quickstart
## Quickstart
Compile OAI as normal. Start the CN and make sure that the VNF configuration
matches the PLMN/IP addresses. Then, run the VNF
@@ -29,7 +31,7 @@ VNF!)
You should not observe a difference between nFAPI split and monolithic.
# Status
## Status
All FAPI message can be transferred between VNF and PNF. This is because OAI
uses FAPI with its corresponding messages internally, whether a split is in use
@@ -54,7 +56,7 @@ When using RFsim, the system might run slower than in monolithic. This is
because the PNF needs to slow down the execution time of a specific slot,
because it has to send a Slot.indication to the VNF for scheduling.
# Configuration
## Configuration
Both PNF and VNF are run through the `nr-softmodem` executable. The type of
mode is switched through the `--nfapi` switch, with options `MONOLITHIC`
@@ -173,6 +175,26 @@ After installing WLS, you can run the build command as shown below:
Refer to the above steps in [Quickstart](#quickstart), but run the PNF first as it is the WLS "master".
To optimize the performance of your setup, you can provide the option
`--thread-pool <list of allocated CPUs>` in the PNF command line. This allows
you to pin PNF processing threads to specific CPU cores, as they might
otherwise interfere with DPDK used by WLS.
Before selecting which CPU cores to allocate: run `nr-softmodem` without the
`--thread-pool` option and use a process monitoring tool such as htop to check
CPU availability. Check for lightly loaded cores, and use them in the
thread-pool for the PNF.
Example commands for running an OTA test with USRP B200 on 40MHz:
Run PNF
sudo NFAPI_TRACE_LEVEL=info ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.conf --nfapi PNF --continuous-tx -E --thread-pool 1,2,3,4,5
Run VNF
sudo NFAPI_TRACE_LEVEL=info ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.106prb.nfapi.conf --nfapi VNF
#### How to run OAI PNF with OSC/Radisys O-DU
Set up the hugepages for DPDK (1GB page size, 6 pages; this only needs to be
@@ -194,14 +216,19 @@ Clone the Radisys repository (We're currently using the `oai_integration` branch
git clone https://gerrit.o-ran-sc.org/r/o-du/l2 -b oai-integration
Build the O-DU
Build the O-DU (More details can be found in O-RAN's documentation page [here](https://docs.o-ran-sc.org/projects/o-ran-sc-o-du-l2/en/latest/user-guide.html#i-execution-on-locally-compiling-o-du-high-source-code))
cd ~/l2/build/odu
make clean_all;make odu PHY=INTEL_L1 MACHINE=BIT64 MODE=TDD;make cu_stub NODE=TEST_STUB MACHINE=BIT64 MODE=TDD;make ric_stub NODE=TEST_STUB MACHINE=BIT64 MODE=TDD
The O-DU requires some virtual interfaces to be setup in order to enable communication between the O-DU, CU_stub and RIC_stub
Setup local interfaces for the cu_stub, ric_stub and o_du
The IP addresses shown match the ones specified in OSC ODU configuration file, found in <o-du directory>/build/config/tdd_odu_config.xml
The parameters referenced are <DU_IP_V4_ADDR>, <CU_IP_V4_ADDR> and <RIC_IP_V4_ADDR>
sudo ifconfig enp7s0:ODU "192.168.130.81" && sudo ifconfig enp7s0:CU_STUB "192.168.130.82" && sudo ifconfig enp7s0:RIC_STUB "192.168.130.80"
sudo ifconfig <interface name>:ODU "192.168.130.81"
sudo ifconfig <interface name>:CU_STUB "192.168.130.82"
sudo ifconfig <interface name>:RIC_STUB "192.168.130.80"
Run cu_stu and ric_stub in separate terminals
@@ -231,7 +258,7 @@ Run the OAI-UE
sudo ./nr-uesoftmodem -r 273 --numerology 1 --band 78 -C 3400140000 --ssb 1518 --uicc0.imsi 001010000000001 --rfsim
# nFAPI logging system
## nFAPI logging system
nFAPI has its own logging system, independent of OAI's. It can be activated by
setting the `NFAPI_TRACE_LEVEL` environment variable to an appropriate value;
@@ -258,3 +285,26 @@ done over virtual time, i.e., frames/slots as executed by the 5G Systems. For
instance, these numbers might be slightly higher or slower in RFsim than in
wall-clock time, depending if the system advances faster or slower than
wall-clock time.
## Troubleshoot
When operating using the FAPI split, the PNF needs to give the VNF extra time
to schedule the next slot. Especially since the current nFAPI split still
relies on slot indications, extra time due to transport delays need to be
accounted for. Currently, this delay is set conservatively, meaning that it
should work for most systems, but can create problems during random access:
[NR_MAC] exceeded RA window: preamble at 411.19 now 413.0 (diff 21), ra_ResponseWindow 5/20 slots
[NR_MAC] sfn: 413.0 UE RA-RNTI 010b TC-RNTI 5d82: exceeded RA window, cannot schedule Msg2
means that the VNF received a preamble (411.19), but the current slot to be
scheduled (413.0) is beyond the random access response window (20 slots). In
this case, try one of the following:
- If the radio allows, reduce the L1 TX advance `RUs.[0].sl_ahead` by some
slots, but note that this could make the system less stable.
- Change the code to reduce `sl_ahead` inside function `handle_nr_slot_ind()`,
to reduce the FAPI scheduling slot time budget.
- Non-standard: You can manually increase the response window by setting
`gNBs.[0].servingCellConfigCommon.[0].ra_ResponseWindow` to, e.g., 6. Note
that the maximum allowed response window is 10ms.

View File

@@ -73,6 +73,10 @@ ENV TINI_VERSION=v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${TARGETARCH} /tini
RUN chmod +x /tini
ENV YQ_VERSION=v4.2.0
RUN wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${TARGETARCH} -O /usr/local/bin/yq &&\
chmod +x /usr/local/bin/yq
# In some network environments, GIT proxy is required
RUN /bin/bash -c "if [[ -v NEEDED_GIT_PROXY ]]; then git config --global http.proxy $NEEDED_GIT_PROXY; fi"

View File

@@ -66,6 +66,10 @@ ENV TINI_VERSION=v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${TARGETARCH} /tini
RUN chmod +x /tini
ENV YQ_VERSION=v4.2.0
RUN wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${TARGETARCH} -O /usr/local/bin/yq &&\
chmod +x /usr/local/bin/yq
# Copying only the needed files to create ran-base
WORKDIR /oai-ran/cmake_targets/tools
COPY cmake_targets/tools/build_helper \

View File

@@ -60,6 +60,10 @@ RUN apt-get update && \
ENV TINI_VERSION=v0.19.0
RUN wget https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${TARGETARCH} -O /tini && chmod +x /tini
ENV YQ_VERSION=v4.2.0
RUN wget https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${TARGETARCH} -O /usr/local/bin/yq &&\
chmod +x /usr/local/bin/yq
# In some network environments, GIT proxy is required
RUN /bin/bash -c "if [[ -v NEEDED_GIT_PROXY ]]; then git config --global http.proxy $NEEDED_GIT_PROXY; fi"

View File

@@ -110,6 +110,8 @@ RUN ldconfig && \
/usr/local/lib/libnvipc.so
WORKDIR /opt/oai-gnb
COPY --from=ran-build /usr/local/bin/yq /usr/local/bin/yq
COPY --from=ran-build /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -101,6 +101,7 @@ RUN ln -s /usr/local/lib/libaw2sori_transpro.so /usr/local/lib/libthirdparty_tra
WORKDIR /opt/oai-gnb-aw2s
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb-aw2s/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb-aw2s/bin/nr-softmodem"]

View File

@@ -51,7 +51,8 @@ RUN dnf update -y && \
lksctp-tools \
tzdata \
net-tools \
iputils && \
iputils \
yaml-cpp-devel && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf
@@ -95,6 +96,7 @@ RUN ln -s /usr/local/lib/libaw2sori_transpro.so /usr/local/lib/libthirdparty_tra
WORKDIR /opt/oai-gnb-aw2s
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb-aw2s/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb-aw2s/bin/nr-softmodem"]

View File

@@ -95,6 +95,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/libaw2sori_transpro.so /usr/local/lib/lib
WORKDIR /opt/oai-gnb-aw2s
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb-aw2s/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb-aw2s/bin/nr-softmodem"]

View File

@@ -126,6 +126,8 @@ RUN ldconfig && \
/opt/phy/fhi_lib/lib/build/libxran.so
WORKDIR /opt/oai-gnb
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -49,7 +49,8 @@ RUN dnf update -y && \
python3 \
python3-pip \
net-tools \
iputils && \
iputils \
yaml-cpp-devel && \
pip3 install six && \
pip3 install requests && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
@@ -114,6 +115,8 @@ RUN ldconfig && \
/opt/phy/fhi_lib/lib/build/libxran.so
WORKDIR /opt/oai-gnb
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -111,6 +111,8 @@ RUN ldconfig && \
/opt/phy/fhi_lib/lib/build/libxran.so
WORKDIR /opt/oai-gnb
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -130,6 +130,7 @@ WORKDIR /opt/oai-gnb
#EXPOSE 50000/udp # IF5 / ORI (control)
#EXPOSE 50001/udp # IF5 / ECPRI (data)
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -47,7 +47,8 @@ RUN dnf update -y && \
python3 \
python3-pip \
net-tools \
iputils && \
iputils \
yaml-cpp-devel && \
pip3 install six && \
pip3 install requests && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
@@ -124,6 +125,7 @@ WORKDIR /opt/oai-gnb
#EXPOSE 50000/udp # IF5 / ORI (control)
#EXPOSE 50001/udp # IF5 / ECPRI (data)
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -128,6 +128,7 @@ WORKDIR /opt/oai-gnb
#EXPOSE 50000/udp # IF5 / ORI (control)
#EXPOSE 50001/udp # IF5 / ECPRI (data)
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-softmodem"]

View File

@@ -35,6 +35,9 @@ RUN cp /oai-ran/docker/scripts/gnb_entrypoint.sh /oai-ran/docker/scripts/entrypo
FROM registry.access.redhat.com/ubi9/ubi:latest AS oai-nr-cuup
ENV TZ=Europe/Paris
# Install EPEL
RUN dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
RUN yum repolist --disablerepo=* && \
yum update -y && \
yum install -y \
@@ -42,7 +45,8 @@ RUN yum repolist --disablerepo=* && \
lksctp-tools \
tzdata \
net-tools \
iputils && \
iputils \
yaml-cpp-devel && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf
@@ -55,6 +59,7 @@ COPY --from=gnb-build \
COPY --from=gnb-build \
/oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so \
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
/usr/local/lib/
COPY --from=gnb-base \
@@ -73,6 +78,7 @@ WORKDIR /opt/oai-gnb/etc
WORKDIR /opt/oai-gnb
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-cuup", "-O", "/opt/oai-gnb/etc/gnb.conf"]

View File

@@ -43,7 +43,8 @@ RUN yum repolist --disablerepo=* && \
lksctp-tools \
tzdata \
net-tools \
iputils && \
iputils \
yaml-cpp-devel && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf
@@ -56,6 +57,7 @@ COPY --from=gnb-build \
COPY --from=gnb-build \
/oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so \
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
/usr/local/lib/
COPY --from=gnb-base \
@@ -71,6 +73,7 @@ WORKDIR /opt/oai-gnb/etc
WORKDIR /opt/oai-gnb
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-cuup", "-O", "/opt/oai-gnb/etc/gnb.conf"]

View File

@@ -42,7 +42,8 @@ RUN apt-get update && \
libconfig9 \
iproute2 \
net-tools \
openssl && \
openssl \
libyaml-cpp-dev && \
# if the --sanitize option was used to build, additional packages are required
/bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \
libasan8 \
@@ -61,6 +62,7 @@ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh
COPY --from=gnb-build \
/oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so \
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
/usr/local/lib/
RUN ldconfig && ldd /opt/oai-gnb/bin/nr-cuup
@@ -69,6 +71,8 @@ RUN ldconfig && ldd /opt/oai-gnb/bin/nr-cuup
WORKDIR /opt/oai-gnb/etc
WORKDIR /opt/oai-gnb
COPY --from=gnb-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=gnb-base /tini /tini
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"]
CMD ["/opt/oai-gnb/bin/nr-cuup", "-O", "/opt/oai-gnb/etc/gnb.conf"]

View File

@@ -122,6 +122,8 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai
/usr/local/lib64/libuhd.so.4.8.0
WORKDIR /opt/oai-nr-ue
COPY --from=nr-ue-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=nr-ue-base /tini /tini
CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem"]
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-nr-ue/bin/entrypoint.sh"]

View File

@@ -48,7 +48,8 @@ RUN dnf update -y && \
python3 \
python3-pip \
libXpm \
libX11 && \
libX11 \
yaml-cpp-devel && \
pip3 install six && \
pip3 install requests && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
@@ -119,6 +120,8 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai
/usr/local/lib64/libuhd.so.4.8.0
WORKDIR /opt/oai-nr-ue
COPY --from=nr-ue-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=nr-ue-base /tini /tini
CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem"]
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-nr-ue/bin/entrypoint.sh"]

View File

@@ -119,6 +119,8 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai
/usr/local/lib/libuhd.so.4.8.0
WORKDIR /opt/oai-nr-ue
COPY --from=nr-ue-base /usr/local/bin/yq /usr/local/bin/yq
COPY --from=nr-ue-base /tini /tini
CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem"]
ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-nr-ue/bin/entrypoint.sh"]

View File

@@ -405,7 +405,6 @@ int main ( int argc, char **argv )
#if T_TRACER
T_Config_Init();
#endif
//randominit (0);
set_taus_seed (0);
printf("configuring for RAU/RRU\n");

View File

@@ -492,7 +492,6 @@ int main( int argc, char **argv ) {
#if T_TRACER
T_Config_Init();
#endif
//randominit (0);
set_taus_seed (0);
cpuf=get_cpu_freq_GHz();
pthread_cond_init(&sync_cond,NULL);

View File

@@ -247,7 +247,7 @@ int connect_rau(RU_t *ru) {
void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
if (ru == RC.ru[0])
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx & 0xffffffff);
int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0);
int offset = get_samples_slot_timestamp(ru->nr_frame_parms, slot);
void *buffs[ru->nb_tx];
for (int aid = 0; aid < ru->nb_tx; aid++)
buffs[aid] = (void*)&ru->common.txdata[aid][offset];
@@ -260,15 +260,9 @@ void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
timestamp,
buffs[0],
buffs[1],
10 * log10((double)signal_energy(buffs[0], ru->nr_frame_parms->get_samples_per_slot(slot, ru->nr_frame_parms))),
10 * log10((double)signal_energy(buffs[0], get_samples_per_slot(slot, ru->nr_frame_parms))),
(int)txmeas.tv_nsec);
ru->ifdevice.trx_write_func2(&ru->ifdevice,
timestamp,
buffs,
0,
ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms),
0,
ru->nb_tx);
ru->ifdevice.trx_write_func2(&ru->ifdevice, timestamp, buffs, 0, get_samples_per_slot(slot, ru->nr_frame_parms), 0, ru->nb_tx);
}
// southbound IF4p5 fronthaul
@@ -295,11 +289,11 @@ void fh_if5_south_in(RU_t *ru,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 1 );
start_meas(&ru->rx_fhaul);
ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, fp->get_samples_per_slot(*tti, fp));
ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, get_samples_per_slot(*tti, fp));
if (proc->first_rx == 1)
ru->ts_offset = proc->timestamp_rx;
proc->frame_rx = ((proc->timestamp_rx - ru->ts_offset) / (fp->samples_per_subframe * 10)) & 1023;
proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp);
proc->tti_rx = get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp);
if (proc->first_rx == 0) {
if (proc->tti_rx != *tti) {
@@ -383,7 +377,7 @@ void fh_if4p5_south_in(RU_t *ru,
//caculate timestamp_rx, timestamp_tx based on frame and subframe
proc->tti_rx = sl;
proc->frame_rx = f;
proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0);
proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + get_samples_slot_timestamp(fp, proc->tti_rx);
// proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe);
proc->tti_tx = (sl+ru->sl_ahead)%fp->slots_per_frame;
proc->frame_tx = (sl > (fp->slots_per_frame - 1 - (ru->sl_ahead))) ? (f + 1) & 1023 : f;
@@ -528,7 +522,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
proc->frame_tx_unwrap += 1024;
proc->timestamp_tx =
((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + fp->get_samples_slot_timestamp(slot_tx, fp, 0);
((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, slot_tx);
LOG_D(PHY, "RU %d/%d TST %lu, frame %d, subframe %d\n", ru->idx, 0, proc->timestamp_tx, frame_tx, slot_tx);
// dump VCD output for first RU in list
@@ -566,14 +560,14 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
openair0_config_t *cfg = &ru->openair0_cfg;
uint32_t samples_per_slot = fp->get_samples_per_slot(*slot, fp);
uint32_t samples_per_slot = get_samples_per_slot(*slot, fp);
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][fp->get_samples_slot_timestamp(*slot, fp, 0)];
rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)];
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1);
openair0_timestamp old_ts = proc->timestamp_rx;
@@ -590,7 +584,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs);
if (proc->first_rx != 1) {
uint32_t samples_per_slot_prev = fp->get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp);
uint32_t samples_per_slot_prev = get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp);
if (proc->timestamp_rx - old_ts != samples_per_slot_prev) {
LOG_D(PHY,
@@ -609,7 +603,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
// in fact the following line is the same as long as the timestamp_rx is synchronized to GPS.
proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023;
proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx,fp);
proc->tti_rx = get_slot_from_timestamp(proc->timestamp_rx, fp);
// synchronize first reception to frame 0 subframe 0
LOG_D(PHY,
"RU %d/%d TS %ld, GPS %f, SR %f, frame %d, slot %d.%d / %d\n",
@@ -725,9 +719,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
T_INT(frame),
T_INT(slot),
T_INT(0),
T_BUFFER(&ru->common.txdata[0][fp->get_samples_slot_timestamp(slot, fp, 0)], fp->get_samples_per_slot(slot, fp) * 4));
T_BUFFER(&ru->common.txdata[0][get_samples_slot_timestamp(fp, slot)], get_samples_per_slot(slot, fp) * 4));
int sf_extension = 0;
int siglen=fp->get_samples_per_slot(slot,fp);
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;
@@ -786,7 +780,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
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][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t);
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1);
@@ -1176,7 +1170,7 @@ void *ru_thread(void *param)
}
proc->timestamp_tx = proc->timestamp_rx;
for (int i = proc->tti_rx; i < proc->tti_rx + ru->sl_ahead; i++)
proc->timestamp_tx += fp->get_samples_per_slot(i % fp->slots_per_frame, fp);
proc->timestamp_tx += get_samples_per_slot(i % fp->slots_per_frame, fp);
proc->tti_tx = (proc->tti_rx + ru->sl_ahead) % fp->slots_per_frame;
proc->frame_tx = proc->tti_rx > proc->tti_tx ? (proc->frame_rx + 1) & 1023 : proc->frame_rx;
LOG_D(PHY,

View File

@@ -546,7 +546,6 @@ int main( int argc, char **argv ) {
#if T_TRACER
T_Config_Init();
#endif
//randominit (0);
set_taus_seed (0);
cpuf=get_cpu_freq_GHz();
@@ -720,6 +719,8 @@ int main( int argc, char **argv ) {
itti_wait_tasks_end(NULL);
printf("Returned from ITTI signal handler\n");
nfapi_stop_l1();
if (RC.nb_nr_L1_inst > 0 || RC.nb_RU > 0)
stop_L1(0);

View File

@@ -19,6 +19,7 @@
* contact@openairinterface.org
*/
#include "PHY/defs_nr_common.h"
#define _GNU_SOURCE // For pthread_setname_np
#include <pthread.h>
#include <openair1/PHY/impl_defs_top.h>
@@ -383,7 +384,7 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx
openair0_timestamp writeTimestamp = proc->timestamp_tx;
int writeBlockSize = rxtxD->writeBlockSize;
// if writeBlockSize gets longer that slot size, fill with dummy
const int maxWriteBlockSize = fp->get_samples_per_slot(proc->nr_slot_tx, fp);
const int maxWriteBlockSize = get_samples_per_slot(proc->nr_slot_tx, fp);
while (writeBlockSize > maxWriteBlockSize) {
const int dummyBlockSize = min(writeBlockSize - maxWriteBlockSize, maxWriteBlockSize);
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, (void **)txp, dummyBlockSize, fp->nb_antennas_tx, flags);
@@ -423,7 +424,7 @@ void processSlotTX(void *arg)
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
c16_t *txp[fp->nb_antennas_tx];
for (int i = 0; i < fp->nb_antennas_tx; i++) {
txp[i] = UE->common_vars.txData[i] + fp->get_samples_slot_timestamp(proc->nr_slot_tx, fp, 0);
txp[i] = UE->common_vars.txData[i] + get_samples_slot_timestamp(fp, proc->nr_slot_tx);
}
if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT) {
@@ -434,8 +435,10 @@ void processSlotTX(void *arg)
nr_sidelink_indication_t sl_indication = {.module_id = UE->Mod_id,
.gNB_index = proc->gNB_id,
.cc_id = UE->CC_id,
.hfn_tx = proc->hfn_tx,
.frame_tx = proc->frame_tx,
.slot_tx = proc->nr_slot_tx,
.hfn_rx = proc->hfn_rx,
.frame_rx = proc->frame_rx,
.slot_rx = proc->nr_slot_rx,
.slot_type = SIDELINK_SLOT_TYPE_TX,
@@ -654,24 +657,25 @@ void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int duration_r
void *rxp[NB_ANTENNAS_RX];
if (toTrash)
for (int i = 0; i < fp->nb_antennas_rx; i++)
rxp[i] = malloc16(fp->get_samples_per_slot(0, fp) * 4);
rxp[i] = malloc16(get_samples_per_slot(0, fp) * 4);
for (int x = 0; x < num_frames * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; x++) { // two frames for initial sync
for (int slot = 0; slot < fp->slots_per_subframe; slot++) {
if (!toTrash)
for (int i = 0; i < fp->nb_antennas_rx; i++)
rxp[i] = ((void *)&UE->common_vars.rxdata[i][0])
+ 4 * ((x * fp->samples_per_subframe) + fp->get_samples_slot_timestamp(slot, fp, 0));
rxp[i] =
((void *)&UE->common_vars.rxdata[i][0]) + 4 * ((x * fp->samples_per_subframe) + get_samples_slot_timestamp(fp, slot));
int read_block_size = fp->get_samples_per_slot(slot, fp);
int read_block_size = get_samples_per_slot(slot, fp);
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, rxp, read_block_size, fp->nb_antennas_rx);
UEscopeCopy(UE, ueTimeDomainSamplesBeforeSync, rxp[0], sizeof(c16_t), 1, read_block_size, 0);
AssertFatal(read_block_size == tmp, "");
if (IS_SOFTMODEM_RFSIM) {
int ta = UE->timing_advance + UE->timing_advance_ntn;
const openair0_timestamp writeTimestamp =
*timestamp + fp->get_samples_slot_timestamp(slot, fp, duration_rx_to_tx) - UE->N_TA_offset - UE->timing_advance;
dummyWrite(UE, writeTimestamp, fp->get_samples_per_slot(slot, fp));
*timestamp + get_samples_slot_duration(fp, slot, duration_rx_to_tx) - UE->N_TA_offset - ta;
dummyWrite(UE, writeTimestamp, get_samples_per_slot(slot, fp));
}
}
}
@@ -692,12 +696,13 @@ static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int d
int slot = 0;
int size = rx_offset;
while (size > 0) {
const int unitTransfer = min(fp->get_samples_per_slot(slot, fp), size);
const int unitTransfer = min(get_samples_per_slot(slot, fp), size);
const int res = UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, fp->nb_antennas_rx);
DevAssert(unitTransfer == res);
if (IS_SOFTMODEM_RFSIM) {
int ta = UE->timing_advance + UE->timing_advance_ntn;
const openair0_timestamp writeTimestamp =
*timestamp + fp->get_samples_slot_timestamp(slot, fp, duration_rx_to_tx) - UE->N_TA_offset - UE->timing_advance;
*timestamp + get_samples_slot_duration(fp, slot, duration_rx_to_tx) - UE->N_TA_offset - ta;
dummyWrite(UE, writeTimestamp, unitTransfer);
}
slot = (slot + 1) % fp->slots_per_subframe;
@@ -706,23 +711,72 @@ static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int d
}
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
if (fp->numerology_index == 0)
return fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
int num_samples = (slot%(fp->slots_per_subframe/2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
num_samples += fp->ofdm_symbol_size;
return num_samples;
return get_samples_symbol_duration(fp, slot, 0, 1);
}
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
int rem_samples = fp->get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp);
int rem_samples = get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp);
int next_slot_first_symbol = 0;
if (slot < (fp->slots_per_frame-1))
next_slot_first_symbol = get_firstSymSamp(slot+1, fp);
return rem_samples + next_slot_first_symbol;
}
#define SPEED_OF_LIGHT 299792458
static inline void apply_ntn_timing_advance(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx)
{
const fapi_nr_dl_ntn_config_command_pdu *ntn_config_params = &UE->ntn_config_message->ntn_config_params;
const int abs_subframe_epoch = ntn_config_params->epoch_subframe
+ ntn_config_params->epoch_sfn * 10
+ ntn_config_params->epoch_hfn * 10240;
const int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch;
const double omega = ntn_config_params->omega;
const double cos_wt = cos(omega * ms_since_epoch);
const double sin_wt = sin(omega * ms_since_epoch);
const position_t pos_sat_0 = ntn_config_params->pos_sat_0;
const position_t pos_sat_90 = ntn_config_params->pos_sat_90;
const position_t pos_sat = {pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt,
pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt,
pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt};
position_t pos_ue = {0};
get_position_coordinates(UE->Mod_id, &pos_ue);
// calculate directional vector from SAT to UE
const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z};
// calculate distance between SAT and UE
const double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z);
// calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000)
const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT;
const double N_common_ta_adj = ntn_config_params->N_common_ta_adj;
const double N_common_ta_drift = ntn_config_params->N_common_ta_drift;
const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant;
UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj
+ N_common_ta_drift * ms_since_epoch / 1e6
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
* fp->samples_per_subframe;
LOG_D(PHY,
"N_UE_TA_adj = %f ms, N_common_ta_adj = %f ms, N_common_ta_drift = %f µs/s, N_common_ta_drift_variant = %f µs/s², ms_since_epoch = %d ms, "
"computed timing_advance_ntn = %d samples\n",
N_UE_TA_adj,
N_common_ta_adj,
N_common_ta_drift,
N_common_ta_drift_variant,
ms_since_epoch,
UE->timing_advance_ntn);
}
static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
NR_DL_FRAME_PARMS *fp,
int hfn_rx,
int frame_rx,
int slot_rx,
int *duration_rx_to_tx,
@@ -737,39 +791,13 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
if (koffset > *ntn_koffset)
*timing_advance += fp->get_samples_slot_timestamp(slot_rx, fp, (koffset - *ntn_koffset) << mu);
*timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu);
else if (koffset < *ntn_koffset)
*timing_advance -= fp->get_samples_slot_timestamp(slot_rx, fp, (*ntn_koffset - koffset) << mu);
*timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu);
*ntn_koffset = koffset;
const int abs_subframe_tx = 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
const int abs_subframe_epoch =
10 * UE->ntn_config_message->ntn_config_params.epoch_sfn + UE->ntn_config_message->ntn_config_params.epoch_subframe;
int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch;
// cope with sfn wrap-around
// this currently limits us to epoch times that are not more than 5.12 seconds in the future (allowed are up to 10.24 seconds)
// and ntn-UlSyncValidityDuration < 5.12 seconds (allowed are up to 900 seconds)
// TODO: fix this limitation by introducing the hyper frame number HFN
if (ms_since_epoch < -5120)
ms_since_epoch += 10240;
else if (ms_since_epoch > 5120)
ms_since_epoch -= 10240;
const double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
const double total_ta_drift = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift; // µs/s
const double total_ta_drift_variant = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant; // µs/s²
UE->timing_advance = fp->samples_per_subframe * (total_ta_ms + (total_ta_drift / 1000.0) * (ms_since_epoch / 1000.0) + (total_ta_drift_variant / 1000.0) * (ms_since_epoch / 1000.0) * (ms_since_epoch / 1000.0));
LOG_I(PHY,
"k_offset = %d ms (%d slots), total_ta_ms = %f ms, total_ta_drift = %f µs/s, total_ta_drift_variant = %f µs/s², ms_since_epoch = %d ms, computed "
"timing_advance = %d samples\n",
*ntn_koffset,
*ntn_koffset << mu,
total_ta_ms,
total_ta_drift,
total_ta_drift_variant,
ms_since_epoch,
UE->timing_advance);
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
apply_ntn_timing_advance(UE, fp, abs_subframe_tx);
}
}
@@ -809,7 +837,7 @@ void *UE_thread(void *arg)
int ntn_koffset = 0;
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
int timing_advance = UE->timing_advance;
int timing_advance = UE->timing_advance + UE->timing_advance_ntn;
UE->N_TA_offset = determine_N_TA_offset(UE);
NR_UE_MAC_INST_t *mac = get_mac_inst(UE->Mod_id);
@@ -968,6 +996,8 @@ void *UE_thread(void *arg)
curMsg.proc.nr_slot_tx = (absolute_slot + duration_rx_to_tx) % nb_slot_frame;
curMsg.proc.frame_rx = (absolute_slot / nb_slot_frame) % MAX_FRAME_NUMBER;
curMsg.proc.frame_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) % MAX_FRAME_NUMBER;
curMsg.proc.hfn_rx = (absolute_slot / nb_slot_frame) / MAX_FRAME_NUMBER;
curMsg.proc.hfn_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) / MAX_FRAME_NUMBER;
if (UE->received_config_request) {
if (UE->sl_mode) {
curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_rx, TDD);
@@ -984,18 +1014,24 @@ void *UE_thread(void *arg)
int firstSymSamp = get_firstSymSamp(slot_nr, fp);
for (int i = 0; i < fp->nb_antennas_rx; i++)
rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp + fp->get_samples_slot_timestamp(slot_nr, fp, 0)];
rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp + get_samples_slot_timestamp(fp, slot_nr)];
int iq_shift_to_apply = 0;
if (slot_nr == nb_slot_frame - 1) {
// we shift of half of measured drift, at each beginning of frame for both rx and tx
iq_shift_to_apply = shiftForNextFrame;
// TODO: remove this autonomous TA and use up-to-date values of ta-Common, ta-CommonDrift and ta-CommonDriftVariant from received SIB19 instead
if (get_nrUE_params()->autonomous_ta)
UE->timing_advance -= 2 * shiftForNextFrame;
// autonomous timing advance calculation, which does not use SIB19 information
if (ntn_koffset && get_nrUE_params()->autonomous_ta)
UE->timing_advance_ntn -= 2 * shiftForNextFrame;
shiftForNextFrame = -round(UE->max_pos_acc * get_nrUE_params()->time_sync_I);
}
// Calculate new TA based on SIB19 information for each subframe in NTN mode, if "autonomous_ta" is not enabled
if (ntn_koffset && !get_nrUE_params()->autonomous_ta && (absolute_slot + duration_rx_to_tx) % fp->slots_per_subframe == 0) {
const int abs_subframe_tx = (absolute_slot + duration_rx_to_tx) / fp->slots_per_subframe;
apply_ntn_timing_advance(UE, fp, abs_subframe_tx);
}
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
openair0_timestamp rx_timestamp;
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx);
@@ -1025,8 +1061,8 @@ void *UE_thread(void *arg)
}
// use previous timing_advance value to compute writeTimestamp
const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, duration_rx_to_tx)
- firstSymSamp - UE->N_TA_offset - timing_advance;
const openair0_timestamp writeTimestamp =
rx_timestamp + get_samples_slot_duration(fp, slot_nr, duration_rx_to_tx) - firstSymSamp - UE->N_TA_offset - timing_advance;
// Calculate TX deadline, approximately 1 symbol before the first sample should be written
const uint64_t samples_diff = writeTimestamp - rx_timestamp - fp->ofdm_symbol_size;
@@ -1034,8 +1070,8 @@ void *UE_thread(void *arg)
const uint64_t absolute_deadline_us = current_time.tv_sec * 1e6 + current_time.tv_nsec / 1e3 + deadline_us;
// but use current UE->timing_advance value to compute writeBlockSize
int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply;
int new_timing_advance = UE->timing_advance;
int writeBlockSize = get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply;
int new_timing_advance = UE->timing_advance + UE->timing_advance_ntn;
if (new_timing_advance != timing_advance) {
writeBlockSize -= new_timing_advance - timing_advance;
timing_advance = new_timing_advance;
@@ -1048,7 +1084,7 @@ void *UE_thread(void *arg)
}
if (curMsg.proc.nr_slot_rx == 0)
nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.frame_rx, curMsg.proc.gNB_id);
nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.hfn_rx, curMsg.proc.frame_rx, curMsg.proc.gNB_id);
// RX slot processing. We launch and forget.
notifiedFIFO_elt_t *newRx = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), curMsg.proc.nr_slot_tx, NULL, UE_dl_processing);
@@ -1064,7 +1100,7 @@ void *UE_thread(void *arg)
}
// apply new NTN timing information
apply_ntn_config(UE, fp, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
apply_ntn_config(UE, fp, curMsg.proc.hfn_rx, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
// Start TX slot processing here. It runs in parallel with RX slot processing
// in current code, DURATION_RX_TO_TX constant is the limit to get UL data to encode from a RX slot

View File

@@ -340,7 +340,6 @@ int main(int argc, char **argv)
T_Config_Init();
#endif
initTpool(get_softmodem_params()->threadPoolConfig, &(nrUE_params.Tpool), cpumeas(CPUMEAS_GETSTATE));
//randominit (0);
set_taus_seed (0);
if (!has_cap_sys_nice())

View File

@@ -20,6 +20,7 @@
*/
#include "position_interface.h"
#include "executables/nr-uesoftmodem.h"
static void read_position_coordinates(char *sectionName, position_t *position)
{

View File

@@ -22,11 +22,6 @@
#ifndef __POSITION_INTERFACE__H__
#define __POSITION_INTERFACE__H__
#include <executables/nr-softmodem-common.h>
#include <executables/softmodem-common.h>
#include "PHY/defs_nr_UE.h"
#include "executables/nr-uesoftmodem.h"
/* position configuration parameters name */
#define CONFIG_STRING_POSITION_X "x"
#define CONFIG_STRING_POSITION_Y "y"

View File

@@ -63,12 +63,20 @@ char cpu_buf_recv[RECV_BUF_LEN];
uint16_t sfn = 0, slot = 0;
nv_ipc_t *ipc;
nfapi_vnf_config_t *vnf_config = 0;
void set_config(nfapi_vnf_config_t *conf)
void nvIPC_Stop()
{
vnf_config = conf;
LOG_I(NR_MAC, "Received STOP.indication\n");
((vnf_t *)get_config())->terminate = true;
}
void nvIPC_send_stop_request()
{
nfapi_nr_stop_request_scf_t req = {.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST, .header.phy_id = 0};
LOG_I(NR_MAC, "Sending NFAPI STOP.request\n");
nfapi_nr_vnf_stop_req(get_config(), get_config()->pnf_list->p5_idx, &req);
}
static uint16_t old_sfn = 0;
static uint16_t old_slot = 0;
////////////////////////////////////////////////////////////////////////
@@ -84,6 +92,7 @@ static int ipc_handle_rx_msg(nv_ipc_t *ipc, nv_ipc_msg_t *msg)
uint8_t *end = msg->msg_buf + msg->msg_len;
// unpack FAPI messages and handle them
nfapi_vnf_config_t * vnf_config = get_config();
if (vnf_config != 0) {
// first, unpack the header
fapi_phy_api_msg fapi_msg;
@@ -479,7 +488,6 @@ static int aerial_recv_msg(nv_ipc_t *ipc, nv_ipc_msg_t *recv_msg)
return 0;
}
bool recv_task_running = false;
void *epoll_recv_task(void *arg)
{
struct epoll_event ev, events[MAX_EVENTS];
@@ -497,11 +505,12 @@ void *epoll_recv_task(void *arg)
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
LOG_E(NFAPI_VNF, "%s epoll_ctl failed\n", __func__);
}
while (1) {
if (!recv_task_running) {
recv_task_running = true;
}
// From here on out the thread is ready to receive data, simulate the reception
// of a PARAM.response to get the VNF to send a CONFIG.request
nfapi_nr_param_response_scf_t resp_msg = {.header.message_id = NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE};
nfapi_vnf_config_t * vnf_config = get_config();
vnf_config->nr_param_resp(vnf_config, 1, &resp_msg);
while (((vnf_t *)vnf_config)->terminate == false) {
LOG_D(NFAPI_VNF, "%s: epoll_wait fd_rx=%d ...\n", __func__, ipc_rx_event_fd);
int nfds;
@@ -524,6 +533,7 @@ void *epoll_recv_task(void *arg)
}
}
close(epoll_fd);
ipc->ipc_destroy(ipc);
return NULL;
}
@@ -568,21 +578,18 @@ int nvIPC_Init(nvipc_params_t nvipc_params_s)
LOG_I(NFAPI_VNF, "%s: create IPC interface successful\n", __func__);
sleep(1);
create_recv_thread(nvipc_params_s.nvipc_poll_core);
while(!recv_task_running){usleep(100000);}
nfapi_nr_param_response_scf_t resp_msg;
vnf_config->nr_param_resp(vnf_config, 1, &resp_msg);
return 0;
}
int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req)
{
nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config);
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
ul_tti_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST;
// int retval = nfapi_vnf_p7_ul_tti_req(p7_config, ul_tti_req);
int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &ul_tti_req->header);
int retval = p7_config->send_p7_msg(get_p7_vnf(), &ul_tti_req->header);
if (retval != 0) {
LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval);
@@ -598,11 +605,11 @@ int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req)
int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req)
{
nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config);
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
ul_dci_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST;
// int retval = nfapi_vnf_p7_ul_dci_req(p7_config, ul_dci_req);
int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &ul_dci_req->header);
int retval = p7_config->send_p7_msg(get_p7_vnf(), &ul_dci_req->header);
if (retval != 0) {
LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval);
} else {
@@ -613,12 +620,12 @@ int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req)
int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req)
{
nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config);
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
tx_data_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST;
// LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_data_req->SFN),
// tx_data_req->Number_of_PDUs); int retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req);
int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &tx_data_req->header);
int retval = p7_config->send_p7_msg(get_p7_vnf(), &tx_data_req->header);
if (retval != 0) {
LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval);
} else {
@@ -630,10 +637,10 @@ int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req)
int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req)
{
nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config);
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
dl_config_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST;
dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &dl_config_req->header);
int retval = p7_config->send_p7_msg(get_p7_vnf(), &dl_config_req->header);
dl_config_req->dl_tti_request_body.nPDUs = 0;
dl_config_req->dl_tti_request_body.nGroup = 0;
@@ -644,9 +651,9 @@ int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req)
}
int oai_fapi_send_end_request(int cell, uint32_t frame, uint32_t slot){
nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config);
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
nfapi_nr_slot_indication_scf_t nr_slot_resp = {.header.message_id = 0x8F, .sfn = frame, .slot = slot};
int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &nr_slot_resp.header);
int retval = p7_config->send_p7_msg(get_p7_vnf(), &nr_slot_resp.header);
if (retval != 0) {
LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval);
}

View File

@@ -56,11 +56,13 @@ bool aerial_send_P7_msg_with_data(void *packedBuf,
void *dataBuf,
uint32_t dataLength,
nfapi_nr_p7_message_header_t *header);
void set_config(nfapi_vnf_config_t *conf);
int nvIPC_Init(nvipc_params_t nvipc_params_s);
int oai_fapi_send_end_request(int cell_id, uint32_t frame, uint32_t slot);
int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req);
int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req);
int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req);
int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req);
void nvIPC_Stop();
void nvIPC_send_stop_request();
#endif // OPENAIRINTERFACE_FAPI_NVIPC_H

View File

@@ -1780,6 +1780,35 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf
return 0;
}
void stop_nr_nfapi_pnf()
{
#ifdef ENABLE_WLS
wls_fapi_nr_pnf_stop();
#endif
#ifdef ENABLE_SOCKET
socket_nfapi_nr_pnf_stop();
#endif
}
static bool has_sent_stop_ind = false;
int nr_stop_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nfapi_nr_stop_request_scf_t *req)
{
if (has_sent_stop_ind) {
// STOP.indication already sent, nothing to do
return 0;
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "Send STOP.indication\n");
nfapi_nr_stop_indication_scf_t resp = {.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION,
.header.phy_id = req->header.phy_id};
nfapi_nr_stop_indication(config, &resp);
has_sent_stop_ind = true;
#ifdef ENABLE_WLS
wls_pnf_close(pnf_p5_init_and_receive_pthread);
#endif
// raise the SIGTERM to simulate CTRL+C
raise(SIGTERM);
return 0;
}
int measurement_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nfapi_measurement_request_t *req) {
nfapi_measurement_response_t resp;
memset(&resp, 0, sizeof(resp));
@@ -2135,6 +2164,7 @@ void configure_nr_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_add
config->nr_param_req = &nr_param_request;
config->nr_config_req = &nr_config_request;
config->nr_start_req = &nr_start_request;
config->nr_stop_req = &nr_stop_request;
config->rssi_req = &rssi_request;
config->broadcast_detect_req = &broadcast_detect_request;
config->system_information_schedule_req = &system_information_schedule_request;
@@ -2285,7 +2315,7 @@ void handle_nr_slot_ind(uint16_t sfn, uint16_t slot, NR_Sched_Rsp_t *sched_resp)
#ifndef ENABLE_WLS
int slot_ahead = 2 << mu;
#else
int slot_ahead = 1;
int slot_ahead = 1 << mu;
#endif
uint16_t sfn_tx = sfn;
uint16_t slot_tx = slot;

View File

@@ -38,5 +38,5 @@ int oai_nfapi_nr_crc_indication(nfapi_nr_crc_indication_t *ind);
int oai_nfapi_nr_srs_indication(nfapi_nr_srs_indication_t *ind);
int oai_nfapi_nr_uci_indication(nfapi_nr_uci_indication_t *ind);
int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind);
void stop_nr_nfapi_pnf();
#endif /* NFAPI_PNF_H_ */

View File

@@ -70,10 +70,25 @@
#endif
#define TEST
static nfapi_vnf_config_t *config;
extern RAN_CONTEXT_t RC;
extern UL_RCC_IND_t UL_RCC_INFO;
nfapi_vnf_config_t * get_config()
{
return config;
}
vnf_p7_t *get_p7_vnf()
{
vnf_info *vnf = config->user_data;
return (vnf_p7_t *)vnf->p7_vnfs->config;
}
nfapi_vnf_p7_config_t *get_p7_vnf_config()
{
return &get_p7_vnf()->_public;
}
int vnf_pack_vendor_extension_tlv(void *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *codec) {
//NFAPI_TRACE(NFAPI_TRACE_INFO, "vnf_pack_vendor_extension_tlv\n");
nfapi_tl_t *tlv = (nfapi_tl_t *)ve;
@@ -1251,7 +1266,6 @@ void *configure_nr_p7_vnf(void *ptr)
p7_vnf->config->hdr_unpack_func = &fapi_nr_p7_message_header_unpack;
p7_vnf->config->pack_func = &fapi_nr_p7_message_pack;
p7_vnf->config->send_p7_msg = &wls_vnf_nr_send_p7_message;
wls_vnf_set_p7_config(p7_vnf->config);
#endif
#ifdef ENABLE_SOCKET
@@ -1645,32 +1659,86 @@ void vnf_start_thread(void *ptr) {
nfapi_vnf_start((nfapi_vnf_config_t *)ptr);
}
static vnf_info vnf;
static bool has_stop_ind = false;
static bool waiting_stop_ind = false;
int nr_stop_ind_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_stop_indication_scf_t *resp)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_STOP_IND idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id);
has_stop_ind = true;
#ifdef ENABLE_AERIAL
nvIPC_Stop();
#endif
#ifdef ENABLE_SOCKET
nfapi_vnf_p7_stop(get_p7_vnf_config());
#endif
#ifdef ENABLE_WLS
wls_vnf_stop();
#endif
if (!waiting_stop_ind) {
// hasn't been initialized yet, means the PNF stopped before the VNF did
// raise a SIGINT to stop the VNF
raise(SIGINT);
}
return 0;
}
void stop_nr_nfapi_vnf()
{
if (has_stop_ind) {
// If it got here with the STOP.indication flag already set, it means it was triggered by the PNF,
// no need to send a STOP.request
return;
}
#ifdef ENABLE_WLS
wls_vnf_send_stop_request();
#endif
#ifdef ENABLE_AERIAL
nvIPC_send_stop_request();
#endif
#ifdef ENABLE_SOCKET
socket_nfapi_send_stop_request((vnf_t *)config);
#endif
waiting_stop_ind = true;
uint64_t counter = 0;
vnf_p7_t *p7_vnf = get_p7_vnf();
while (p7_vnf->terminate == 0 && counter < 50) {
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Not terminated yet, counter %ld\n", counter);
usleep(1000);
counter++;
}
if (p7_vnf->terminate == 0) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "STOP.indication timed out, exiting\n");
nfapi_nr_stop_indication_scf_t msg = {.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION, .header.phy_id = 0};
config->nr_stop_ind(config, 0, &msg);
} else {
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Terminated, exiting\n");
}
}
void configure_nr_nfapi_vnf(eth_params_t params)
{
#ifndef ENABLE_AERIAL
nfapi_setmode(NFAPI_MODE_VNF);
#endif
memset(&vnf, 0, sizeof(vnf));
memset(vnf.p7_vnfs, 0, sizeof(vnf.p7_vnfs));
vnf.p7_vnfs[0].timing_window = 30;
vnf.p7_vnfs[0].periodic_timing_enabled = 0;
vnf.p7_vnfs[0].aperiodic_timing_enabled = 0;
vnf.p7_vnfs[0].periodic_timing_period = 1;
vnf.p7_vnfs[0].config = nfapi_vnf_p7_config_create();
vnf_info *vnf = calloc(1, sizeof(vnf_info));
memset(vnf->p7_vnfs, 0, sizeof(vnf->p7_vnfs));
vnf->p7_vnfs[0].timing_window = 30;
vnf->p7_vnfs[0].periodic_timing_enabled = 0;
vnf->p7_vnfs[0].aperiodic_timing_enabled = 0;
vnf->p7_vnfs[0].periodic_timing_period = 1;
vnf->p7_vnfs[0].config = nfapi_vnf_p7_config_create();
#ifndef ENABLE_AERIAL
NFAPI_TRACE(NFAPI_TRACE_INFO,
"[VNF] %s() vnf.p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n",
"[VNF] %s() vnf->p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n",
__FUNCTION__,
vnf.p7_vnfs[0].config,
vnf->p7_vnfs[0].config,
params.my_addr,
params.my_portc);
strcpy(vnf.p7_vnfs[0].local_addr, params.my_addr);
vnf.p7_vnfs[0].local_port = params.my_portd;
strcpy(vnf->p7_vnfs[0].local_addr, params.my_addr);
vnf->p7_vnfs[0].local_port = params.my_portd;
#endif
vnf.p7_vnfs[0].mac = (mac_t *)malloc(sizeof(mac_t));
nfapi_vnf_config_t *config = nfapi_vnf_config_create();
vnf->p7_vnfs[0].mac = malloc(sizeof(mac_t));
config = nfapi_vnf_config_create();
config->malloc = malloc;
config->free = free;
config->vnf_p5_port = params.my_portc;
@@ -1688,9 +1756,10 @@ void configure_nr_nfapi_vnf(eth_params_t params)
config->nr_param_resp = &nr_param_resp_cb;
config->nr_config_resp = &nr_config_resp_cb;
config->nr_start_resp = &nr_start_resp_cb;
config->nr_stop_ind = &nr_stop_ind_cb;
config->nr_error_ind = &nr_error_ind_cb;
config->vendor_ext = &vendor_nr_ext_cb;
config->user_data = &vnf;
config->user_data = vnf;
// To allow custom vendor extentions to be added to nfapi
config->codec_config.unpack_vendor_extension_tlv = &vnf_nr_unpack_vendor_extension_tlv;
config->codec_config.pack_vendor_extension_tlv = &vnf_nr_pack_vendor_extension_tlv;
@@ -1727,7 +1796,6 @@ void configure_nr_nfapi_vnf(eth_params_t params)
config->hdr_unpack_func = &fapi_nr_message_header_unpack;
config->pack_func = &fapi_nr_p5_message_pack;
config->send_p5_msg = &aerial_nr_send_p5_message;
set_config(config);
NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__);
nfapi_vnf_pnf_info_t *pnf = (nfapi_vnf_pnf_info_t *)malloc(sizeof(nfapi_vnf_pnf_info_t));
NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf);
@@ -1736,7 +1804,6 @@ void configure_nr_nfapi_vnf(eth_params_t params)
pnf->connected = 1;
// Add needed parameters
vnf_info *vnf = (vnf_info *)(config->user_data);
pnf_info *pnf_info = vnf->pnfs;
for (int i = 0; i < 1; ++i) {
@@ -1773,18 +1840,23 @@ void configure_nr_nfapi_vnf(eth_params_t params)
void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) {
nfapi_setmode(NFAPI_MODE_VNF);
memset(&vnf, 0, sizeof(vnf));
memset(vnf.p7_vnfs, 0, sizeof(vnf.p7_vnfs));
vnf.p7_vnfs[0].timing_window = 32;
vnf.p7_vnfs[0].periodic_timing_enabled = 1;
vnf.p7_vnfs[0].aperiodic_timing_enabled = 0;
vnf.p7_vnfs[0].periodic_timing_period = 10;
vnf.p7_vnfs[0].config = nfapi_vnf_p7_config_create();
NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s() vnf.p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n", __FUNCTION__, vnf.p7_vnfs[0].config, vnf_addr, vnf_p5_port);
strcpy(vnf.p7_vnfs[0].local_addr, vnf_addr);
vnf.p7_vnfs[0].local_port = vnf_p7_port;
vnf.p7_vnfs[0].mac = (mac_t *)malloc(sizeof(mac_t));
nfapi_vnf_config_t *config = nfapi_vnf_config_create();
vnf_info *vnf = calloc(1, sizeof(vnf_info));
memset(vnf->p7_vnfs, 0, sizeof(vnf->p7_vnfs));
vnf->p7_vnfs[0].timing_window = 32;
vnf->p7_vnfs[0].periodic_timing_enabled = 1;
vnf->p7_vnfs[0].aperiodic_timing_enabled = 0;
vnf->p7_vnfs[0].periodic_timing_period = 10;
vnf->p7_vnfs[0].config = nfapi_vnf_p7_config_create();
NFAPI_TRACE(NFAPI_TRACE_INFO,
"[VNF] %s() vnf.p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n",
__FUNCTION__,
vnf->p7_vnfs[0].config,
vnf_addr,
vnf_p5_port);
strcpy(vnf->p7_vnfs[0].local_addr, vnf_addr);
vnf->p7_vnfs[0].local_port = vnf_p7_port;
vnf->p7_vnfs[0].mac = malloc(sizeof(mac_t));
config = nfapi_vnf_config_create();
config->malloc = malloc;
config->free = free;
config->vnf_p5_port = vnf_p5_port;
@@ -1803,7 +1875,7 @@ void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int
config->config_resp = &config_resp_cb;
config->start_resp = &start_resp_cb;
config->vendor_ext = &vendor_ext_cb;
config->user_data = &vnf;
config->user_data = vnf;
// To allow custom vendor extentions to be added to nfapi
config->codec_config.unpack_vendor_extension_tlv = &vnf_unpack_vendor_extension_tlv;
config->codec_config.pack_vendor_extension_tlv = &vnf_pack_vendor_extension_tlv;
@@ -1820,7 +1892,7 @@ void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int
}
int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) {
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
dl_config_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
dl_config_req->header.message_id = NFAPI_DL_CONFIG_REQUEST;
LOG_D(PHY, "[VNF] %s() DL_CONFIG_REQ sfn_sf:%d_%d number_of_pdus:%d\n", __FUNCTION__,
@@ -1856,7 +1928,7 @@ int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) {
int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req)
{
LOG_D(NR_PHY, "Entering oai_nfapi_nr_dl_config_req sfn:%d,slot:%d\n", dl_config_req->SFN, dl_config_req->Slot);
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
dl_config_req->header.message_id= NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST;
dl_config_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
@@ -1875,7 +1947,7 @@ int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req)
int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req)
{
LOG_D(NR_PHY, "Entering oai_nfapi_nr_tx_data_req sfn:%d,slot:%d\n", tx_data_req->SFN, tx_data_req->Slot);
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
tx_data_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST;
//LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_req->sfn_sf), tx_req->tx_request_body.number_of_pdus);
@@ -1892,7 +1964,7 @@ int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req)
int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req)
{
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
tx_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
tx_req->header.message_id = NFAPI_TX_REQUEST;
//LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_req->sfn_sf), tx_req->tx_request_body.number_of_pdus);
@@ -1908,7 +1980,7 @@ int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req)
}
int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) {
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
ul_dci_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST;
//LOG_D(PHY, "[VNF] %s() HI_DCI0_REQ sfn_sf:%d dci:%d hi:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(hi_dci0_req->sfn_sf), hi_dci0_req->hi_dci0_request_body.number_of_dci, hi_dci0_req->hi_dci0_request_body.number_of_hi);
@@ -1924,7 +1996,7 @@ int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) {
}
int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) {
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
hi_dci0_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST;
//LOG_D(PHY, "[VNF] %s() HI_DCI0_REQ sfn_sf:%d dci:%d hi:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(hi_dci0_req->sfn_sf), hi_dci0_req->hi_dci0_request_body.number_of_dci, hi_dci0_req->hi_dci0_request_body.number_of_hi);
@@ -1960,7 +2032,7 @@ static void remove_ul_config_req_pdu(int index, nfapi_ul_config_request_t *ul_co
}
int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) {
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
ul_tti_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST;
@@ -1980,7 +2052,7 @@ int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) {
}
int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) {
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
ul_config_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
ul_config_req->header.message_id = NFAPI_UL_CONFIG_REQUEST;
//LOG_D(PHY, "[VNF] %s() header message_id:%02x\n", __FUNCTION__, ul_config_req->header.message_id);
@@ -2040,7 +2112,7 @@ int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) {
int oai_nfapi_ue_release_req(nfapi_ue_release_request_t *release_req){
if(release_req->ue_release_request_body.number_of_TLVs <= 0)
return 0;
nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
release_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!!
release_req->header.message_id = NFAPI_UE_RELEASE_REQUEST;

View File

@@ -148,5 +148,8 @@ typedef struct {
void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port);
void configure_nr_nfapi_vnf(eth_params_t params);
void stop_nr_nfapi_vnf();
nfapi_vnf_config_t *get_config();
vnf_p7_t *get_p7_vnf();
nfapi_vnf_p7_config_t *get_p7_vnf_config();
#endif /* NFAPI_VNF_H_ */

View File

@@ -36,4 +36,5 @@ bool pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, ui
bool pnf_nr_send_p7_message(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_header_t* header, uint32_t msg_len);
void *pnf_start_p5_thread(void *ptr);
void *pnf_nr_p7_thread_start(void *ptr);
void socket_nfapi_nr_pnf_stop();
#endif // SOCKET_PNF_H

View File

@@ -31,4 +31,5 @@ bool vnf_nr_send_p5_msg(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_head
bool vnf_nr_send_p7_msg(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t* header);
void vnf_start_p5_thread(void* ptr);
void* vnf_nr_start_p7_thread(void* ptr);
void socket_nfapi_send_stop_request(vnf_t *vnf);
#endif // SOCKET_VNF_H

View File

@@ -20,6 +20,15 @@
*/
#include "socket_pnf.h"
#include "nfapi.h"
static nfapi_pnf_config_t *config;
void socket_nfapi_nr_pnf_stop()
{
AssertFatal(config->nr_stop_req, "STOP.request Handler should be set!");
nfapi_nr_stop_request_scf_t req = {0};
req.header.phy_id = 0;
req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_PNF_STOP_REQUEST;
config->nr_stop_req(config, 0, &req);
}
bool pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len)
{
@@ -148,7 +157,7 @@ bool pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *head
void *pnf_start_p5_thread(void *ptr)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN PNF NFAPI start thread %s\n", __FUNCTION__);
nfapi_pnf_config_t *config = (nfapi_pnf_config_t *)ptr;
config = (nfapi_pnf_config_t *)ptr;
struct sched_param sp;
sp.sched_priority = 20;
pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp);

View File

@@ -20,9 +20,26 @@
*/
#include "socket_vnf.h"
#include "common/utils/LOG/log.h"
#include "nfapi.h"
#include "nfapi_vnf.h"
#include <common/platform_constants.h>
#include "nfapi/oai_integration/vendor_ext.h" //TODO: Remove this include when removing the Aerial transport stuff
void socket_stop_nfapi_p5_p7()
{
get_p7_vnf()->terminate = 1;
get_config()->pnf_disconnect_indication = NULL;
}
void socket_nfapi_send_stop_request(vnf_t *vnf)
{
nfapi_nr_stop_request_scf_t req = {.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST, .header.phy_id = 0};
nfapi_nr_vnf_stop_req(&vnf->_public, 0, &req);
NFAPI_TRACE(NFAPI_TRACE_INFO, "Sent NFAPI STOP.request\n");
}
static bool send_p5_msg(vnf_t *vnf, nfapi_vnf_pnf_info_t *pnf, const void *msg, int len, uint8_t stream)
{
int result = socket_send_p5_msg(vnf->sctp, pnf->p5_sock, &pnf->p5_pnf_sockaddr, msg, len, stream);
@@ -279,7 +296,6 @@ static int nfapi_nr_vnf_p5_start(nfapi_vnf_config_t *config)
// Verify that config is not null
if (config == 0)
return -1;
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__);
int p5ListenSock, p5Sock;
@@ -293,7 +309,7 @@ static int nfapi_nr_vnf_p5_start(nfapi_vnf_config_t *config)
struct sctp_initmsg initMsg = {0};
int noDelay;
vnf_t *vnf = (vnf_t *)(config);
vnf_t *vnf = (vnf_t *)(get_config());
NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 VNF connection on port %u\n", config->vnf_p5_port);
@@ -747,8 +763,8 @@ static int nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t *config)
return -1;
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__);
vnf_p7_t *vnf_p7 = (vnf_p7_t *)config;
vnf_p7_t *vnf_p7 = get_p7_vnf();
vnf_p7 = (vnf_p7_t *)config;
// Create p7 receive udp port
// todo : this needs updating for Ipv6

View File

@@ -25,7 +25,6 @@
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "wls_lib.h"
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h"
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h"

View File

@@ -30,4 +30,6 @@ bool wls_pnf_nr_send_p7_message(pnf_p7_t* pnf_p7,nfapi_nr_p7_message_header_t *m
void *wls_fapi_pnf_nr_start_thread(void *ptr);
int wls_fapi_nr_pnf_start();
void wls_pnf_set_p7_config(void *p7_config);
void wls_fapi_nr_pnf_stop();
void wls_pnf_close(pthread_t p5_thread);
#endif // OPENAIRINTERFACE_WLS_PNF_H

View File

@@ -27,7 +27,8 @@
void *wls_fapi_vnf_nr_start_thread(void *ptr);
int wls_fapi_nr_vnf_start();
void wls_vnf_set_p7_config(void *p7_config);
bool wls_vnf_nr_send_p5_message(vnf_t *vnf,uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len);
bool wls_vnf_nr_send_p7_message(vnf_p7_t* vnf_p7,nfapi_nr_p7_message_header_t* msg);
void wls_vnf_send_stop_request();
void wls_vnf_stop();
#endif //OPENAIRINTERFACE_WLS_VNF_H

View File

@@ -20,7 +20,7 @@
*/
#include "wls_common.h"
#include "wls_lib.h"
void fill_fapi_list_elem(p_fapi_api_queue_elem_t currElem, p_fapi_api_queue_elem_t nextElem, const uint8_t msgType, const uint8_t numMsgInBlock, const uint32_t alignOffset)
{
currElem->msg_type = msgType;
@@ -90,9 +90,19 @@ uint8_t wls_send_fapi_msg(PWLS_MAC_CTX pWls, const uint16_t message_id, const in
{
int num_avail_blocks = WLS_NumBlocks(pWls->hWls);
NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks);
int counter = 0;
while (num_avail_blocks < 2) {
num_avail_blocks = WLS_NumBlocks(pWls->hWls);
NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks);
if (message_id == NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION) {
// In the case of the STOP.indication, it can happen that this is called after the VNF stopped
// For example, if it crashed for some reason, in that case, implement a timeout and return
usleep(10 * 1000);
counter++;
if (counter == 10) {
return true;
}
}
}
/* get PA blocks for header and msg */
uint64_t pa_hdr = dequeueBlock(pWls);

View File

@@ -29,9 +29,10 @@
#include <pnf_p7.h>
#include <sys/time.h>
#include "wls_lib.h"
#include "pnf.h"
#include "nr_nfapi_p7.h"
#include "nr_fapi_p5.h"
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h"
// A copy of the PNF P7 config is needed for the message processing thread, in other transport mechanisms where P7 is handled in a
// different thread, the config is passed to it upon the thread creation
@@ -65,6 +66,28 @@ void *wls_fapi_pnf_nr_start_thread(void *ptr)
return (void *)0;
}
void wls_pnf_close(pthread_t p5_thread)
{
_this->terminate = 1;
WLS_WakeUp(wls_mac_get_ctx()->hWls);
pthread_join(p5_thread, NULL);
if (WLS_Close(wls_mac_get_ctx()->hWls) != 0) {
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] WLS_CLose call failed...\n");
} else {
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] WLS_CLose called successfully...\n");
}
rte_eal_cleanup();
}
void wls_fapi_nr_pnf_stop()
{
AssertFatal(cfg->nr_stop_req, "STOP.request Handler should be set!");
nfapi_nr_stop_request_scf_t req = {0};
req.header.phy_id = 0;
req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST;
cfg->nr_stop_req(cfg, 0, &req);
}
int wls_fapi_nr_pnf_start()
{
int64_t ret;
@@ -194,6 +217,9 @@ bool wls_pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks);
while (num_avail_blocks < 2) {
num_avail_blocks = WLS_NumBlocks(pWls->hWls);
if (_this->terminate) {
return false;
}
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks);
}
/* get PA blocks for header and msg */
@@ -254,7 +280,7 @@ void phy_mac_recv()
bool to_return = false;
while (_this->terminate == 0) {
int numMsgToGet = WLS_Wait(pWls->hWls);
if (numMsgToGet == 0) {
if (numMsgToGet == 0 || _this->terminate) {
continue;
}
uint64_t PAs[numMsgToGet];
@@ -279,6 +305,11 @@ void phy_mac_recv()
}
}
}
// A STOP.indication might have been processed, which set's terminate to 1
// don't return pages in that case
if (_this->terminate) {
break;
}
if (to_return) {
// We only return the pages to be enqueued in case we're using the OAI VNF,
// The Radisys O-DU handles enqueueing the blocks differently, and also doesn't handle receiving a single block

View File

@@ -21,26 +21,23 @@
#include "wls_vnf.h"
#include "vnf_p7.h"
#include "common/utils/LOG/log.h"
#include "wls_lib.h"
#include <rte_eal.h>
#include <rte_string_fns.h>
#include <rte_common.h>
#include <rte_lcore.h>
#include <rte_debug.h>
#include <nr_fapi_p5.h>
#include "common/utils/LOG/log.h"
#include <rte_errno.h>
#include <unistd.h>
#include <common/platform_constants.h>
#include <sys/wait.h>
#include "nfapi_vnf.h"
static nfapi_vnf_config_t *config;
static WLS_MAC_CTX wls_mac_iface;
vnf_t *_vnf = NULL;
// A copy of the VNF P7 config is needed for the message processing thread, in other transport mechanisms where P7 is handled in a
// different thread, the config is passed to it upon the thread creation
nfapi_vnf_p7_config_t *wls_vnf_p7_config = NULL;
void wls_vnf_set_p7_config(void *p7_config)
{
wls_vnf_p7_config = (nfapi_vnf_p7_config_t *)p7_config;
}
static PWLS_MAC_CTX wls_mac_get_ctx(void)
{
@@ -99,17 +96,54 @@ static bool wls_mac_create_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void *pMemArr
return true;
}
void mac_dpdk_init()
bool primary_process_running(int argc, char *argv[])
{
char *my_argv[] = {"OAI_VNF", "-c3", "--proc-type=auto", "--file-prefix", WLS_DEV_NAME, "--iova-mode=pa"};
printf("\nCalling rte_eal_init: ");
for (unsigned long i = 0; i < RTE_DIM(my_argv); i++) {
printf("%s ", my_argv[i]);
}
printf("\n");
// If the PNF was stopped normally, this is enough, as the mp_socket file does not exist
if (access("/var/run/dpdk/" WLS_DEV_NAME "/mp_socket", W_OK | R_OK) != 0)
return false;
if (rte_eal_init(RTE_DIM(my_argv), my_argv) < 0)
rte_panic("\nCannot init EAL\n");
// If we run rte_eal_init before the primary process is running, it will result in a 'Connection Refused' error in the logs, but
// the call itself will succeed ( retval not -1 )
//
// We can use rte_eal_primary_proc_alive to determine if the primary process is running, the issue is that since the init had a
// refused connection, if we try to open WLS after rte_eal_primary_proc_alive reports that the primary is running, it will fail,
// since rte_eal_init failed to connect to the primary process, and we can't call rte_eal_init in the same process more than once,
// or it will result in an EALREADY error
//
// Given this, a new process is created that calls rte_eal_init and checks whether the primary process is running, exiting
// right after and reporting to our VNF the primary status
//
// When the VNF receives the status from the forked process that the
// primary process is running, it then calls rte_eal_init, which at this point we know will be successful, and continue to open
// the WLS instance
pid_t pid = fork();
if (pid == 0) {
// We set the log level to emergency , effectively disabling logs in the child process
// This prevents too many logs being printed out to the terminal while we wait for the primary process to be available
rte_log_set_global_level(RTE_LOG_EMERG);
AssertFatal(rte_eal_init(argc, argv) != -1, "rte_eal_init() failed\n");
int status = rte_eal_primary_proc_alive(NULL) == 0;
rte_eal_cleanup();
_exit(status);
}
int status;
waitpid(pid, &status, 0);
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
}
bool mac_dpdk_init()
{
char *my_argv[] = {"OAI_VNF", "-c3", "--proc-type=secondary", "--file-prefix", WLS_DEV_NAME, "--iova-mode=pa"};
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "\nCalling rte_eal_init: ");
for (int i = 0; i < RTE_DIM(my_argv); i++) {
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "%s ", my_argv[i]);
}
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "\n");
while (!primary_process_running(RTE_DIM(my_argv), my_argv)) {
NFAPI_TRACE(NFAPI_TRACE_INFO, "DPDK primary process not available yet, retrying in 1 second...\n");
sleep(1);
}
return rte_eal_init(RTE_DIM(my_argv), my_argv) >= 0;
}
static uint32_t wls_mac_alloc_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void **ppBlock)
@@ -258,7 +292,7 @@ for(int i = 0 ; i< pWls->nTotalBlocks; i++){
void* pMsg = wls_mac_alloc_buffer(pWls, 0, i);
/* Enqueue all blocks */
nBlocks += WLS_EnqueueBlock(pWls->hWls, WLS_VA2PA(pWls->hWls, pMsg));
}
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "\nAllocated %d Blocks \n", nBlocks);
return true;
}
@@ -274,6 +308,33 @@ static int vnf_wls_init()
return 1;
}
void wls_vnf_stop()
{
vnf_p7_t *p7_vnf = get_p7_vnf();
_vnf->terminate = 1;
p7_vnf->terminate = 1;
rte_eal_cleanup();
}
void wls_vnf_send_stop_request()
{
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
nfapi_nr_stop_request_scf_t req = {.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST, .header.phy_id = 0};
vnf_p7_t *p7_vnf = get_p7_vnf();
nfapi_vnf_config_t * config = get_config();
if (p7_vnf == NULL || pWls->hWls == NULL) {
nfapi_nr_stop_indication_scf_t msg;
msg.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION;
msg.header.phy_id = 0;
config->nr_stop_ind(config, 0, &msg);
return;
}
if (pWls->hWls != NULL) {
nfapi_nr_vnf_stop_req(config, 0, &req);
}
}
void *wls_fapi_vnf_nr_start_thread(void *ptr)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] IN WLS PNF NFAPI start thread %s\n", __FUNCTION__);
@@ -294,11 +355,11 @@ static void procPhyMessages(uint32_t msg_size, void *msg_buf, uint16_t msg_id)
case NFAPI_NR_PHY_MSG_TYPE_CONFIG_RESPONSE:
case NFAPI_NR_PHY_MSG_TYPE_START_RESPONSE:
case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION:
vnf_nr_handle_p4_p5_message(msg_buf, msg_size, 0, config);
vnf_nr_handle_p4_p5_message(msg_buf, msg_size, 0, get_config());
break;
case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: {
vnf_nr_handle_p7_message(msg_buf, msg_size + NFAPI_NR_P7_HEADER_LENGTH, (vnf_p7_t *)wls_vnf_p7_config);
vnf_nr_handle_p7_message(msg_buf, msg_size + NFAPI_NR_P7_HEADER_LENGTH, get_p7_vnf());
break;
}
default:
@@ -308,6 +369,7 @@ static void procPhyMessages(uint32_t msg_size, void *msg_buf, uint16_t msg_id)
int wls_fapi_nr_vnf_start(nfapi_vnf_config_t *cfg)
{
nfapi_vnf_config_t * config = get_config();
config = cfg;
if (config == 0) {
@@ -333,7 +395,7 @@ int wls_fapi_nr_vnf_start(nfapi_vnf_config_t *cfg)
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
while (_vnf->terminate == 0) {
int numMsgToGet = WLS_Wait(pWls->hWls);
if (numMsgToGet == 0) {
if (numMsgToGet == 0 || _vnf->terminate) {
continue;
}
@@ -351,6 +413,9 @@ int wls_fapi_nr_vnf_start(nfapi_vnf_config_t *cfg)
procPhyMessages(len, (void *)(msg + 1), msg->msg_type);
}
}
if (_vnf->terminate) {
break;
}
for (int i = 0; i < pa_idx; i++) {
if (WLS_EnqueueBlock(pWls->hWls, PAs[i]) == -1) {
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Error in WLS_EnqueueBlock for block %lu\n", PAs[i]);
@@ -403,7 +468,7 @@ bool wls_vnf_nr_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *
AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n");
//memcpy((uint8_t *)(fapiMsgElem + 1), message, packed_len + NFAPI_HEADER_LENGTH);
const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle
fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2);
memcpy((uint8_t *)(headerElem + 1), wls_header, 2);
int packed_len = ((nfapi_vnf_p7_config_t *)vnf_p7)->pack_func(msg, (fapiMsgElem + 1), NFAPI_MAX_PACKED_MESSAGE_SIZE, NULL);

View File

@@ -24,6 +24,7 @@
#include "PHY/impl_defs_top.h"
#include "PHY/impl_defs_nr.h"
#include "common/utils/nr/nr_common.h"
#include "executables/position_interface.h"
#define NFAPI_UE_MAX_NUM_CB 8
#define NFAPI_MAX_NUM_UL_PDU 255
@@ -562,18 +563,26 @@ typedef struct {
} fapi_nr_ta_command_pdu;
typedef struct {
int epoch_hfn;
int epoch_sfn;
int epoch_subframe;
// orbital angular velocity in rad/ms
double omega;
// satellite position at epoch time
position_t pos_sat_0;
// satellite position at 90° orbit
position_t pos_sat_90;
// N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms)
double N_common_ta_adj;
// drift rate of common ta in µs/s
double N_common_ta_drift;
// change rate of common ta drift in µs/s²
double N_common_ta_drift_variant;
// cell scheduling offset expressed in terms of 15kHz SCS
long cell_specific_k_offset;
// ntn_total_time_advance_ms represents the complete round-trip-time between gNB and UE via SAT
double ntn_total_time_advance_ms;
// drift rate of ntn_total_time_advance_ms in µs/s
double ntn_total_time_advance_drift;
// change rate of ntn_total_time_advance_ms drift in µs/s²
double ntn_total_time_advance_drift_variant;
} fapi_nr_dl_ntn_config_command_pdu;
typedef struct {
@@ -697,7 +706,6 @@ typedef struct
uint8_t restricted_set_config;//PRACH restricted set config Value: 0: unrestricted 1: restricted set type A 2: restricted set type B
uint8_t num_prach_fd_occasions;//Corresponds to the parameter 𝑀 in [38.211, sec 6.3.3.2] which equals the higher layer parameter msg1FDM Value: 1,2,4,8
fapi_nr_num_prach_fd_occasions_t* num_prach_fd_occasions_list;
uint8_t ssb_per_rach;//SSB-per-RACH-occasion Value: 0: 1/8 1:1/4, 2:1/2 3:1 4:2 5:4, 6:8 7:16
uint8_t prach_multiple_carriers_in_a_band;//0 = disabled 1 = enabled
uint8_t root_seq_computed; // flag set and used only in PHY to indicate if table is computed with this config

View File

@@ -1254,6 +1254,10 @@ uint8_t pack_nr_p5_message_body(nfapi_nr_p4_p5_message_header_t *header,
result = pack_stop_request(header, ppWritePackedMsg, end, config);
break;
case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION:
result = pack_nr_stop_indication(header, ppWritePackedMsg, end, config);
break;
case NFAPI_NR_PHY_MSG_TYPE_STOP_RESPONSE:
result = pack_stop_response(header, ppWritePackedMsg, end, config);
break;
@@ -2447,6 +2451,10 @@ bool nfapi_nr_p5_message_unpack(void *pMessageBuf,
result = unpack_stop_request(&pReadPackedMessage, end, pMessageHeader, config);
break;
case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION:
result = unpack_nr_stop_indication(&pReadPackedMessage, end, pMessageHeader, config);
break;
case NFAPI_NR_PHY_MSG_TYPE_STOP_RESPONSE:
result = unpack_stop_response(&pReadPackedMessage, end, pMessageHeader, config);
break;

View File

@@ -497,6 +497,14 @@ int nfapi_nr_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_nr_start_response_
*/
int nfapi_pnf_stop_resp(nfapi_pnf_config_t* config, nfapi_stop_response_t* resp);
/*! Send the STOP.indication
* \param config A pointer to a pnf configuration
* \param resp A pointer to the message structure
* \return 0 for success, -1 for failure
*
*/
int nfapi_nr_stop_indication(nfapi_pnf_config_t* config, nfapi_nr_stop_indication_scf_t* resp);
/*! Send the MEASUREMENT.response
* \param config A pointer to a pnf configuraiton
* \param resp A pointer to the message structure

View File

@@ -387,6 +387,18 @@ int nfapi_pnf_stop_resp(nfapi_pnf_config_t* config, nfapi_stop_response_t* resp)
return pnf_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_stop_response_t));
}
int nfapi_nr_stop_indication(nfapi_pnf_config_t* config, nfapi_nr_stop_indication_scf_t* resp)
{
if (config == NULL || resp == NULL) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__);
return -1;
}
pnf_t* _this = (pnf_t*)(config);
AssertFatal(config->send_p5_msg, "Function pointer must be configured|");
return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_stop_indication_scf_t));
}
int nfapi_pnf_measurement_resp(nfapi_pnf_config_t* config, nfapi_measurement_response_t* resp)
{
if (config == NULL || resp == NULL)

View File

@@ -728,34 +728,19 @@ int nr_pnf_p7_get_msgs(pnf_p7_t* pnf_p7,
ret_dl_tti->SFN = sfn;
ret_dl_tti->Slot = slot;
ret_dl_tti->dl_tti_request_body.nPDUs = 0;
nfapi_nr_dl_tti_request_t* dl_tti_req = &tx_slot_buffer->dl_tti_req;
if (dl_tti_req->SFN == sfn && dl_tti_req->Slot == slot) {
copy_dl_tti_request(dl_tti_req, ret_dl_tti);
tx_slot_buffer->dl_tti_req.SFN = -1;
tx_slot_buffer->dl_tti_req.Slot = -1;
}
ret_tx_data->SFN = sfn;
ret_tx_data->Slot = slot;
ret_tx_data->Number_of_PDUs = 0;
nfapi_nr_dl_tti_request_t* dl_tti_req = &tx_slot_buffer->dl_tti_req;
nfapi_nr_tx_data_request_t* txd = &tx_slot_buffer->tx_data_req;
if (dl_tti_req->SFN == sfn && dl_tti_req->Slot == slot && txd->SFN == sfn && txd->Slot == slot) {
nfapi_nr_dl_tti_request_body_t* p_tti = &dl_tti_req->dl_tti_request_body;
int ret_idx = 0;
for (int i = 0; i < p_tti->nPDUs; ++i) {
int tx_index = p_tti->dl_tti_pdu_list[i].pdsch_pdu.pdsch_pdu_rel15.pduIndex - 1;
if (tx_index >= txd->Number_of_PDUs) {
NFAPI_TRACE(NFAPI_TRACE_ERROR,
"%4d.%2d no corresponding tx_data.request for dl_tti.request index %d, dropping\n",
sfn,
slot,
tx_index);
continue;
}
ret_dl_tti->dl_tti_request_body.dl_tti_pdu_list[ret_idx] = p_tti->dl_tti_pdu_list[i];
// TODO avoid huge copy
ret_tx_data->pdu_list[ret_idx] = txd->pdu_list[i];
ret_idx++;
}
ret_dl_tti->dl_tti_request_body.nPDUs = ret_idx;
ret_tx_data->Number_of_PDUs = ret_idx;
tx_slot_buffer->dl_tti_req.SFN = -1;
tx_slot_buffer->dl_tti_req.Slot = -1;
if (txd->SFN == sfn && txd->Slot == slot) {
copy_tx_data_request(txd, ret_tx_data);
tx_slot_buffer->tx_data_req.SFN = -1;
tx_slot_buffer->tx_data_req.Slot = -1;
}
@@ -764,10 +749,7 @@ int nr_pnf_p7_get_msgs(pnf_p7_t* pnf_p7,
ret_ul_tti->Slot = slot;
ret_ul_tti->n_pdus = 0;
if (tx_slot_buffer->ul_tti_req.SFN == sfn && tx_slot_buffer->ul_tti_req.Slot == slot) {
nfapi_nr_ul_tti_request_t* p = &tx_slot_buffer->ul_tti_req;
ret_ul_tti->n_pdus = p->n_pdus;
for (int i = 0; i < p->n_pdus; ++i)
ret_ul_tti->pdus_list[i] = p->pdus_list[i];
copy_ul_tti_request(&tx_slot_buffer->ul_tti_req, ret_ul_tti);
tx_slot_buffer->ul_tti_req.SFN = -1;
tx_slot_buffer->ul_tti_req.Slot = -1;
}
@@ -776,10 +758,7 @@ int nr_pnf_p7_get_msgs(pnf_p7_t* pnf_p7,
ret_ul_dci->Slot = slot;
ret_ul_dci->numPdus = 0;
if (tx_slot_buffer->ul_dci_req.SFN == sfn && tx_slot_buffer->ul_dci_req.Slot == slot) {
nfapi_nr_ul_dci_request_t* p = &tx_slot_buffer->ul_dci_req;
ret_ul_dci->numPdus = p->numPdus;
for (int i = 0; i < p->numPdus; ++i)
ret_ul_dci->ul_dci_pdu_list[i] = p->ul_dci_pdu_list[i];
copy_ul_dci_request(&tx_slot_buffer->ul_dci_req, ret_ul_dci);
tx_slot_buffer->ul_dci_req.SFN = -1;
tx_slot_buffer->ul_dci_req.Slot = -1;
}

View File

@@ -268,8 +268,8 @@ int nfapi_pnf_p7_nr_rx_data_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rx_data_
pnf_p7_t* _this = (pnf_p7_t*)(config);
AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|");
int ret = _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rx_data_indication_t));
if (ret == 0) {
bool ret = _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rx_data_indication_t));
if (ret) {
for (int i = 0; i < ind->number_of_pdus; ++i)
_this->nr_stats.ul.bytes += ind->pdu_list[i].pdu_length;
}

View File

@@ -210,6 +210,24 @@ typedef struct nfapi_vnf_config
int (*pnf_start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_start_response_t* resp);
int (*pnf_nr_start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_pnf_start_response_t* resp);
/*! A callback for the STOP.indication
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
* \param ind A data structure for the decoded STOP.indication This will
* have been allocated on the stack.
* \return not currently used.
*
* The STOP.indication contains the result of the STOP.request
*
*
* ind may contain pointers to dynamically allocated sub structures
* such as the vendor_extention. The dynamically allocated structure will
* be deallocated on return. If the client wishes to 'keep' the structures
* then the substructure pointers should be set to 0 and then the client should
* use the codec_config.deallocate function to release it at a future point
*/
int (*nr_stop_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_stop_indication_scf_t* ind);
/*! A callback for the PNF_STOP.resp
* \param config A pointer to the vnf configuration
* \param p5_idx The p5 index used to indicate a particular pnf p5 connection
@@ -640,6 +658,7 @@ int nfapi_nr_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_star
* \return 0 means success, -1 failure
*/
int nfapi_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_request_t* req);
int nfapi_nr_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_stop_request_scf_t* req);
/*! Send the MEASUREMENT.request
* \param config A pointer to a vnf config

View File

@@ -665,6 +665,30 @@ void vnf_nr_handle_error_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_co
}
}
void vnf_nr_handle_stop_indication(void* pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx)
{
// ensure it's valid
if (pRecvMsg == NULL || config == NULL) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__);
} else {
NFAPI_TRACE(NFAPI_TRACE_INFO, "Received STOP.indication\n");
nfapi_nr_stop_indication_scf_t msg;
// unpack the message
if (config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config)) {
if (config->nr_stop_ind) {
(config->nr_stop_ind)(config, p5_idx, &msg);
}
} else {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__);
}
// make sure to release any dynamic part of the message
if (msg.vendor_extension)
config->codec_config.deallocate(msg.vendor_extension);
}
}
void vnf_handle_stop_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx)
{
@@ -1172,6 +1196,10 @@ void vnf_nr_handle_p4_p5_message(void *pRecvMsg, int recvMsgLen, int p5_idx, nfa
vnf_handle_stop_response(pRecvMsg, recvMsgLen, config, p5_idx);
break;
case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION:
vnf_nr_handle_stop_indication(pRecvMsg, recvMsgLen, config, p5_idx);
break;
default:
{
if(messageHeader.message_id >= NFAPI_VENDOR_EXT_MSG_MIN &&

View File

@@ -665,6 +665,18 @@ int nfapi_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_stop_reques
return vnf_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_stop_request_t));
}
int nfapi_nr_vnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_stop_request_scf_t* req)
{
if (config == 0 || req == 0)
return -1;
vnf_t* _this = (vnf_t*)(config);
AssertFatal(config->send_p5_msg, "Function pointer must be configured\n");
NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Sending NFAPI STOP.request\n");
return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_stop_request_scf_t));
}
int nfapi_vnf_measurement_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_measurement_request_t* req)
{
if(config == 0 || req == 0)

View File

@@ -3,3 +3,6 @@ add_subdirectory(TOOLS)
add_subdirectory(NR_TRANSPORT)
add_subdirectory(CODING)
add_subdirectory(MODULATION)
if (ENABLE_TESTS)
add_subdirectory(INIT/tests)
endif()

View File

@@ -438,7 +438,7 @@ int main(int argc, char *argv[])
int n_trials = 1;
double SNR_step = 0.1;
randominit(0);
randominit();
int test_uncoded = 0;
n_iter_stats_t dec_iter[400] = {0};

View File

@@ -72,7 +72,7 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi
PHY_vars_UE = malloc(sizeof(PHY_VARS_UE));
mac_xface = malloc(sizeof(MAC_xface));
randominit(0);
randominit();
set_taus_seed(0);
lte_frame_parms = &(PHY_vars_eNB->lte_frame_parms);
@@ -367,7 +367,7 @@ int main(int argc, char *argv[])
int num_pdcch_symbols = 1;
int subframe = 6;
randominit(0);
randominit();
logInit();
lte_param_init(1,1,1,0,0,3);

View File

@@ -47,7 +47,7 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx)
PHY_config = malloc(sizeof(PHY_CONFIG));
mac_xface = malloc(sizeof(MAC_xface));
randominit(0);
randominit();
set_taus_seed(0);
lte_frame_parms = &(PHY_config->lte_frame_parms);
@@ -241,8 +241,7 @@ int main(int argc, char *argv[])
PHY_vars = malloc(sizeof(PHY_VARS));
mac_xface = malloc(sizeof(MAC_xface));
randominit(0);
randominit();
set_taus_seed(0);
ccodelte_init();

View File

@@ -125,7 +125,7 @@ int main(int argc, char *argv[])
cpu_meas_enabled = 1;
reset_meas(&timeEncoder);
reset_meas(&timeDecoder);
randominit(0);
randominit();
crcTableInit();
if (polarMessageType == 0) { // PBCH

View File

@@ -13,7 +13,7 @@ int main(int argc, char *argv[])
cpu_meas_enabled = 1;
reset_meas(&timeEncoder);
reset_meas(&timeDecoder);
randominit(0);
randominit();
int ret = 1;
int arguments, iterations = 1000, messageLength = 11;

View File

@@ -77,7 +77,7 @@ void lte_param_init(PHY_VARS_eNB **eNBp,
eNB->RU_list[0] = ru;
ru->num_eNB=1;
srand(0);
randominit(0);
randominit();
set_taus_seed(0);
frame_parms = &(eNB->frame_parms);
frame_parms->N_RB_DL = N_RB_DL; //50 for 10MHz and 25 for 5 MHz

View File

@@ -259,33 +259,116 @@ uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp)
return samp_count;
}
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp)
uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols)
{
uint32_t slot_idx = 0;
int samples_till_the_slot = fp->get_samples_per_slot(slot_idx,fp)-1;
timestamp_rx = timestamp_rx%fp->samples_per_frame;
int end_symbol = start_symbol + num_symbols - 1;
AssertFatal(start_symbol <= end_symbol && start_symbol >= 0 && end_symbol < fp->symbols_per_slot,
"Symbol range is invalid start_symbol %d, num_symbols %d symbols_per_slot %d\n",
start_symbol,
num_symbols,
fp->symbols_per_slot);
if (num_symbols == fp->symbols_per_slot) {
return get_samples_per_slot(slot, fp);
}
uint32_t num_samples = 0;
int num_symbols_added = 0;
while (timestamp_rx > samples_till_the_slot) {
slot_idx++;
samples_till_the_slot += fp->get_samples_per_slot(slot_idx,fp);
}
return slot_idx;
// Handle symbols with different nb_prefix_samples0
if (fp->numerology_index == 0) {
// Add symbol 0
if (start_symbol == 0) {
num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
num_symbols_added++;
}
// Add symbol 7
if (start_symbol <= 7 && end_symbol >= 7) {
num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
num_symbols_added++;
}
} else {
// Add first symbol
if (start_symbol == 0) {
num_samples += (slot % (fp->slots_per_subframe / 2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
num_samples += fp->ofdm_symbol_size;
num_symbols_added++;
}
}
int num_symbols_left = max(0, num_symbols - num_symbols_added);
num_samples += num_symbols_left * (fp->nb_prefix_samples + fp->ofdm_symbol_size);
return num_samples;
}
uint32_t get_samples_slot_timestamp(int slot, const NR_DL_FRAME_PARMS *fp, unsigned int sl_ahead)
uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol)
{
uint32_t samp_count = 0;
if(!sl_ahead) {
for(unsigned int idx_slot = 0; idx_slot < slot; idx_slot++)
samp_count += fp->get_samples_per_slot(idx_slot, fp);
} else {
for (unsigned int idx_slot = slot; idx_slot < slot + sl_ahead; idx_slot++)
samp_count += fp->get_samples_per_slot(idx_slot, fp);
if (symbol == 0) {
return 0;
}
return get_samples_symbol_duration(fp, slot, 0, symbol);
}
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp)
{
timestamp_rx = timestamp_rx % fp->samples_per_frame;
if (timestamp_rx < fp->samples_per_slot0)
return 0;
if (fp->numerology_index == 0)
return timestamp_rx / fp->samples_per_subframe;
const unsigned int num_half_sf = timestamp_rx / (fp->samples_per_subframe / 2);
const unsigned int slot_per_half_sf = fp->slots_per_subframe / 2;
uint32_t slot_count = num_half_sf * slot_per_half_sf;
int samp_idx = num_half_sf * (fp->samples_per_subframe / 2) - 1;
// Remaining samples
if (samp_idx < timestamp_rx) {
slot_count++;
samp_idx += fp->samples_per_slot0; // First slot of half subframe
}
if (samp_idx < timestamp_rx) {
const unsigned int rem_samples = timestamp_rx - samp_idx;
const unsigned int num_slots = ceil((double)rem_samples / fp->samples_per_slotN0);
slot_count += num_slots;
}
return slot_count - 1;
}
uint32_t get_samples_slot_timestamp(const NR_DL_FRAME_PARMS *fp, unsigned int slot)
{
if (slot == 0)
return 0;
if (fp->numerology_index == 0)
return slot * fp->samples_per_subframe;
uint32_t samp_count = 0;
// Number of half subframes
const unsigned int num_half_sf = slot / (fp->slots_per_subframe / 2);
samp_count += num_half_sf * fp->samples_per_subframe / 2;
// Remaining slots
unsigned int rem_slots = slot % (fp->slots_per_subframe / 2);
if (rem_slots > 0) {
samp_count += fp->samples_per_slot0; // First slot of the last half subframe
rem_slots--;
}
samp_count += rem_slots * fp->samples_per_slotN0; // Remaining slots of the last half subframe
return samp_count;
}
uint32_t get_samples_slot_duration(const NR_DL_FRAME_PARMS *fp, unsigned int start_slot, unsigned int num_slots)
{
if (start_slot == 0 && num_slots == 0)
return 0;
return (get_samples_slot_timestamp(fp, start_slot + num_slots) - get_samples_slot_timestamp(fp, start_slot));
}
void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *fp)
{
@@ -319,12 +402,11 @@ void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->get_samples_per_slot = &get_samples_per_slot;
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
fp->get_slot_from_timestamp = &get_slot_from_timestamp;
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->samples_per_slot0 = fp->numerology_index == 0 ? fp->samples_per_subframe
: fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples)
+ (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = get_freq_range_from_freq(fp->dl_CarrierFreq);
@@ -402,11 +484,11 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->get_samples_per_slot = &get_samples_per_slot;
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->samples_per_slot0 = fp->numerology_index == 0 ? fp->samples_per_subframe
: fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples)
+ (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = get_freq_range_from_freq(fp->dl_CarrierFreq);
@@ -460,11 +542,14 @@ void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink
frame_parms->samples_per_frame_wCP = 10 * frame_parms->samples_per_subframe_wCP;
frame_parms->samples_per_slot_wCP = frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size;
frame_parms->samples_per_slotN0 = (frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * frame_parms->symbols_per_slot;
frame_parms->samples_per_slot0 = frame_parms->nb_prefix_samples0 + ((frame_parms->symbols_per_slot-1)*frame_parms->nb_prefix_samples) + (frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size);
frame_parms->samples_per_subframe = (frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size) * 2 +
(frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * (frame_parms->symbols_per_slot * frame_parms->slots_per_subframe - 2);
frame_parms->get_samples_per_slot = &get_samples_per_slot;
frame_parms->get_samples_slot_timestamp = &get_samples_slot_timestamp;
frame_parms->samples_per_subframe = (frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size) * 2
+ (frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size)
* (frame_parms->symbols_per_slot * frame_parms->slots_per_subframe - 2);
frame_parms->samples_per_slot0 = frame_parms->numerology_index == 0
? frame_parms->samples_per_subframe
: frame_parms->nb_prefix_samples0
+ ((frame_parms->symbols_per_slot - 1) * frame_parms->nb_prefix_samples)
+ (frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size);
frame_parms->samples_per_frame = 10 * frame_parms->samples_per_subframe;
LOG_W(PHY, "samples_per_subframe %d/per second %d, wCP %d\n", frame_parms->samples_per_subframe, 1000*frame_parms->samples_per_subframe, frame_parms->samples_per_subframe_wCP);
@@ -560,12 +645,11 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot * fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 =
fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples) + (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->get_samples_per_slot = &get_samples_per_slot;
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
fp->samples_per_slot0 = fp->numerology_index == 0 ? fp->samples_per_subframe
: fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples)
+ (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = get_freq_range_from_freq(fp->sl_CarrierFreq);

View File

@@ -55,10 +55,11 @@ void free_nr_ue_ul_harq(NR_UL_UE_HARQ_t harq_list[NR_MAX_ULSCH_HARQ_PROCESSES],
void phy_init_nr_top(PHY_VARS_NR_UE *ue);
void phy_term_nr_top(void);
#ifndef __cplusplus
void init_delay_table(uint16_t ofdm_symbol_size,
int max_delay_comp,
int max_ofdm_symbol_size,
c16_t delay_table[][max_ofdm_symbol_size]);
#endif
void sl_ue_phy_init(PHY_VARS_NR_UE *UE);
#endif

View File

@@ -0,0 +1,2 @@
add_executable(test_nr_frame_params test_nr_frame_params.cpp)
target_link_libraries(test_nr_frame_params PRIVATE LOG minimal_lib PHY_NR -lm GTest::gtest)

View File

@@ -0,0 +1,177 @@
/*
* 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 "gtest/gtest.h"
extern "C" {
#include <stdlib.h>
#include "openair1/PHY/defs_nr_common.h"
#include "openair1/PHY/INIT/nr_phy_init.h"
static softmodem_params_t softmodem_params;
softmodem_params_t *get_softmodem_params(void)
{
return &softmodem_params;
}
}
uint32_t ref_get_samples_slot_timestamp(NR_DL_FRAME_PARMS *fp, unsigned int slot)
{
uint32_t samp_count = 0;
for (unsigned int i = 0; i < slot; i++) {
samp_count += get_samples_per_slot(i, fp);
}
return samp_count;
}
uint32_t ref_get_slot_from_timestamp(openair0_timestamp ts, NR_DL_FRAME_PARMS *fp)
{
uint32_t slot_idx = 0;
int samples_till_the_slot = get_samples_per_slot(slot_idx, fp) - 1;
ts = ts % fp->samples_per_frame;
while (ts > samples_till_the_slot) {
slot_idx++;
samples_till_the_slot += get_samples_per_slot(slot_idx, fp);
}
return slot_idx;
}
void test_coherence_symbol_api(NR_DL_FRAME_PARMS *fp)
{
EXPECT_EQ(get_samples_symbol_timestamp(fp, 0, 0), get_samples_slot_timestamp(fp, 0));
for (int slot = 0; slot < 4; slot++) {
EXPECT_EQ(get_samples_symbol_duration(fp, slot, 0, fp->symbols_per_slot) + get_samples_slot_timestamp(fp, slot),
get_samples_slot_timestamp(fp, slot + 1));
}
for (int symbol = 0; symbol < fp->symbols_per_slot - 1; symbol++) {
EXPECT_EQ(get_samples_symbol_timestamp(fp, 0, symbol + 1) - get_samples_symbol_timestamp(fp, 0, symbol),
get_samples_symbol_duration(fp, 0, symbol, 1));
}
}
void test_coherence_slot_api(NR_DL_FRAME_PARMS *fp)
{
for (unsigned int slot = 0; slot < fp->slots_per_frame; slot++) {
EXPECT_EQ(get_samples_slot_timestamp(fp, slot), ref_get_samples_slot_timestamp(fp, slot));
}
openair0_timestamp ts = get_samples_per_slot(0, fp);
// When timestamp is the last sample of the slot
EXPECT_EQ(get_slot_from_timestamp(ts - 1, fp), 0);
for (unsigned int slot = 0; slot < fp->slots_per_frame; slot++) {
// When timestamp is the first sample of the slot
ts = ref_get_samples_slot_timestamp(fp, slot);
EXPECT_EQ(get_slot_from_timestamp(ts, fp), slot);
// When timestamp is anywhere in the slot
ts += (rand() % fp->samples_per_slotN0);
EXPECT_EQ(get_slot_from_timestamp(ts, fp), slot);
}
}
TEST(nr_frame_params, test_mu_3)
{
NR_DL_FRAME_PARMS fp;
int mu = NR_MU_3;
memset(&fp, 0, sizeof(fp));
nfapi_nr_config_request_scf_t cfg;
cfg.carrier_config.num_rx_ant.value = 4;
cfg.carrier_config.num_tx_ant.value = 4;
cfg.carrier_config.dl_grid_size[mu].value = 66;
cfg.carrier_config.ul_grid_size[mu].value = 66;
cfg.cell_config.frame_duplex_type.value = TDD;
cfg.ssb_config.scs_common.value = mu;
fp.dl_CarrierFreq = 27524520000;
fp.nr_band = 261;
nr_init_frame_parms(&cfg, &fp);
nr_dump_frame_parms(&fp);
test_coherence_symbol_api(&fp);
test_coherence_slot_api(&fp);
}
TEST(nr_frame_params, test_mu_2)
{
NR_DL_FRAME_PARMS fp;
int mu = NR_MU_2;
memset(&fp, 0, sizeof(fp));
nfapi_nr_config_request_scf_t cfg;
cfg.carrier_config.num_rx_ant.value = 4;
cfg.carrier_config.num_tx_ant.value = 4;
cfg.carrier_config.dl_grid_size[mu].value = 51;
cfg.carrier_config.ul_grid_size[mu].value = 51;
cfg.cell_config.frame_duplex_type.value = TDD;
cfg.ssb_config.scs_common.value = mu;
fp.dl_CarrierFreq = 27524520000;
fp.nr_band = 261;
nr_init_frame_parms(&cfg, &fp);
nr_dump_frame_parms(&fp);
test_coherence_symbol_api(&fp);
test_coherence_slot_api(&fp);
}
TEST(nr_frame_params, test_mu_1)
{
NR_DL_FRAME_PARMS fp;
int mu = NR_MU_1;
memset(&fp, 0, sizeof(fp));
nfapi_nr_config_request_scf_t cfg;
cfg.carrier_config.num_rx_ant.value = 4;
cfg.carrier_config.num_tx_ant.value = 4;
cfg.carrier_config.dl_grid_size[mu].value = 106;
cfg.carrier_config.ul_grid_size[mu].value = 106;
cfg.cell_config.frame_duplex_type.value = TDD;
cfg.ssb_config.scs_common.value = mu;
fp.dl_CarrierFreq = 3600000000;
fp.nr_band = 78;
nr_init_frame_parms(&cfg, &fp);
nr_dump_frame_parms(&fp);
test_coherence_symbol_api(&fp);
test_coherence_slot_api(&fp);
}
TEST(nr_frame_params, test_mu_0)
{
int mu = NR_MU_0;
NR_DL_FRAME_PARMS fp;
memset(&fp, 0, sizeof(fp));
nfapi_nr_config_request_scf_t cfg;
cfg.carrier_config.num_rx_ant.value = 4;
cfg.carrier_config.num_tx_ant.value = 4;
cfg.carrier_config.dl_grid_size[mu].value = 216;
cfg.carrier_config.ul_grid_size[mu].value = 216;
cfg.cell_config.frame_duplex_type.value = TDD;
cfg.ssb_config.scs_common.value = mu;
fp.dl_CarrierFreq = 2600000000;
fp.nr_band = 38;
nr_init_frame_parms(&cfg, &fp);
nr_dump_frame_parms(&fp);
test_coherence_symbol_api(&fp);
test_coherence_slot_api(&fp);
}
int main(int argc, char **argv)
{
uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY);
logInit();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -80,7 +80,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
// For Sidelink 16 frames worth of samples is processed to find SSB, for 5G-NR 2.
const unsigned int total_samples = (is_sl) ? 16 * frame_parms->samples_per_frame : 2 * frame_parms->samples_per_frame;
unsigned int rx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
unsigned int rx_offset = get_samples_slot_timestamp(frame_parms, slot);
const unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol;
for (int idx_symb = slot * frame_parms->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
rx_offset += (idx_symb % (0x7 << frame_parms->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;
@@ -150,7 +150,7 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
int32_t tmp_dft_in[8192] __attribute__ ((aligned (32)));
// offset of first OFDM symbol
unsigned int rxdata_offset = frame_parms->get_samples_slot_timestamp(Ns,frame_parms,0);
unsigned int rxdata_offset = get_samples_slot_timestamp(frame_parms, Ns);
unsigned int abs_symbol = Ns * frame_parms->symbols_per_slot + symbol;
for (int idx_symb = Ns*frame_parms->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
rxdata_offset += (idx_symb%(0x7<<frame_parms->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;

View File

@@ -362,7 +362,7 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
// Fixme: slot or slot makes no sense ???
int slot2 = p->prach_sequence_length ? p->slot : p->slot;
int idx = aa + beam_id * p->nb_rx;
c16_t *prach = (c16_t *)&rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - N_TA_offset];
c16_t *prach = (c16_t *)&rxdata[idx][get_samples_slot_timestamp(fp, slot2) + sample_offset_slot - N_TA_offset];
// do DFT
c16_t *prach2 = prach + Ncp;

View File

@@ -324,7 +324,7 @@ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc,
int32_t sync_pos = -1; // sync_pos_frame = -1;
int32_t metric_tdd_ncp = 0;
uint8_t phase_tdd_ncp;
uint8_t phase_tdd_ncp = 0;
double im, re;
int ret = -1;
uint16_t rx_slss_id = 65535;

View File

@@ -70,6 +70,7 @@ void math_dft(cd_t *in, cd_t *out, int len)
int main(void)
{
int ret = 0;
randominit();
load_dftslib();
c16_t *d16 = malloc16(12 * dftFtab[sizeofArray(dftFtab) - 1].size * sizeof(*d16));
c16_t *o16 = malloc16(12 * dftFtab[sizeofArray(dftFtab) - 1].size * sizeof(*d16));

View File

@@ -467,7 +467,8 @@ typedef struct PHY_VARS_NR_UE_s {
/// Timing Advance updates variables
/// Timing advance update computed from the TA command signalled from gNB
int timing_advance;
int timing_advance; /// corresponds to N_TA
int timing_advance_ntn; /// corresponds to N_common_TA_adj + N_UE_TA_adj
int N_TA_offset; ///timing offset used in TDD
int ta_frame;
int ta_slot;
@@ -538,11 +539,14 @@ typedef struct {
/// NR slot index within frame_rx [0 .. slots_per_frame - 1] to act upon for transmission
int nr_slot_rx;
int tx_slot_type;
//#endif
/// frame to act upon for transmission
int frame_tx;
/// frame to act upon for reception
int frame_rx;
/// hyper frame number to act upon for transmission
int hfn_tx;
/// hyper frame number to act upon for reception
int hfn_rx;
} UE_nr_rxtx_proc_t;
typedef struct {

View File

@@ -165,11 +165,6 @@ void init_prach_list(prach_list_t *);
typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS;
typedef uint32_t (*get_samples_per_slot_t)(int slot, const NR_DL_FRAME_PARMS *fp);
typedef uint32_t (*get_slot_from_timestamp_t)(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp);
typedef uint32_t (*get_samples_slot_timestamp_t)(int slot, const NR_DL_FRAME_PARMS *fp, unsigned int sl_ahead);
struct NR_DL_FRAME_PARMS {
/// frequency range
frequency_range_t freq_range;
@@ -225,12 +220,6 @@ struct NR_DL_FRAME_PARMS {
uint16_t slots_per_frame;
/// Number of samples in a subframe
uint32_t samples_per_subframe;
/// Number of samples in current slot
get_samples_per_slot_t get_samples_per_slot;
/// slot calculation from timestamp
get_slot_from_timestamp_t get_slot_from_timestamp;
/// Number of samples before slot
get_samples_slot_timestamp_t get_samples_slot_timestamp;
/// Number of samples in 0th and center slot of a subframe
uint32_t samples_per_slot0;
/// Number of samples in other slots of the subframe
@@ -336,4 +325,17 @@ typedef struct {
#define KHz (1000UL)
#define MHz (1000*KHz)
// Get symbol duration within slot in samples
uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols);
// Get timestamp of symbol within slot in samples
uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol);
// Get slot duration between two slot
uint32_t get_samples_slot_duration(const NR_DL_FRAME_PARMS *fp, unsigned int start_slot, unsigned int num_slots);
// Get timestamp of slot from start of frame
uint32_t get_samples_slot_timestamp(const NR_DL_FRAME_PARMS *fp, unsigned int slot);
// Get slot from timestamp
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp);
// Get number of samples in the slot
uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp);
#endif

Some files were not shown because too many files have changed in this diff Show More