This commit is contained in:
2026-01-14 04:27:37 +00:00
parent cf4ca86169
commit c28054a285
13 changed files with 294 additions and 281 deletions
@@ -12,17 +12,17 @@ gNBs =
gNB_name = "cu-rfsim"; gNB_name = "cu-rfsim";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1; tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) });
@include "neighbour-config.conf" # @include "neighbour-config.conf"
nr_cellid = 12345678L; nr_cellid = 12345678L;
tr_s_preference = "f1"; tr_s_preference = "f1";
local_s_address = "192.168.71.150"; local_s_address = "192.168.71.140";
remote_s_address = "192.168.71.171"; remote_s_address = "192.168.71.141";
local_s_portd = 2153; local_s_portd = 2153;
remote_s_portd = 2153; remote_s_portd = 2153;
@@ -40,8 +40,8 @@ gNBs =
NETWORK_INTERFACES : NETWORK_INTERFACES :
{ {
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.150"; GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.140";
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.71.150"; GNB_IPV4_ADDRESS_FOR_NGU = "192.168.71.140";
GNB_PORT_FOR_S1U = 2152; # Spec 2152 GNB_PORT_FOR_S1U = 2152; # Spec 2152
}; };
} }
@@ -25,10 +25,11 @@ gNBs =
////////// Physical parameters: ////////// Physical parameters:
pdsch_AntennaPorts_XP = 4; pdsch_AntennaPorts_XP = 2;
pusch_AntennaPorts = 4; pusch_AntennaPorts = 4;
do_CSIRS = 0; # used to be 1 pdsch_AntennaPorts_N1 = 2;
do_SRS = 1; do_CSIRS = 1; # used to be 1
do_SRS = 0;
min_rxtxtime = 6; min_rxtxtime = 6;
pdcch_ConfigSIB1 = ( pdcch_ConfigSIB1 = (
@@ -256,7 +257,6 @@ MACRLCs = (
#pucch_TargetSNRx10 = 200; #pucch_TargetSNRx10 = 200;
ulsch_max_frame_inactivity = 0; ulsch_max_frame_inactivity = 0;
dl_max_mcs = 30; dl_max_mcs = 30;
min_grant_prb = 10;
} }
); );
@@ -264,8 +264,9 @@ L1s = (
{ {
num_cc = 1; num_cc = 1;
tr_n_preference = "local_mac"; tr_n_preference = "local_mac";
pusch_proc_threads = 8;
prach_dtx_threshold = 120; prach_dtx_threshold = 120;
#pucch0_dtx_threshold = 120; pucch0_dtx_threshold = 120;
} }
); );
@@ -281,17 +282,19 @@ RUs = (
max_rxgain = 75; max_rxgain = 75;
eNB_instances = [0]; eNB_instances = [0];
##beamforming 1x4 matrix: 1 layer x 4 antennas ##beamforming 1x4 matrix: 1 layer x 4 antennas
bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; # bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
#clock_src = "internal"; #clock_src = "internal";
# sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal" # sdr_addrs = "mgmt_addr=192.168.10.2,addr=192.168.10.2,clock_source=internal,time_source=internal"
bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff];
sdr_addrs = "serial=XXXXXXX"; sdr_addrs = "serial=XXXXXXX";
clock_src = "internal";
} }
); );
THREAD_STRUCT = ( THREAD_STRUCT = (
{ {
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD"; parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE"; worker_config = "WORKER_ENABLE";
} }
@@ -300,6 +303,8 @@ THREAD_STRUCT = (
rfsimulator : rfsimulator :
{ {
serveraddr = "server"; serveraddr = "server";
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs";
}; };
security = { security = {
@@ -328,114 +333,54 @@ log_config :
rlc_log_level ="info"; rlc_log_level ="info";
pdcp_log_level ="info"; pdcp_log_level ="info";
rrc_log_level ="info"; rrc_log_level ="info";
ngap_log_level ="debug"; ngap_log_level ="info";
f1ap_log_level ="debug"; f1ap_log_level ="info";
}; };
# Channel model - minimal noise for antenna muting tests
# channelmod = { # channelmod = {
# max_chan = 10; # // 2 descriptors per UE (DL+UL). 10 UEs => 20. Keep margin.
# max_chan = 32;
# modellist = "modellist_antenna_muting"; # modellist = "modellist_antenna_muting";
# modellist_antenna_muting = ( # modellist_antenna_muting = (
# { # // UE0
# model_name = "rfsimu_channel_enB0" # { model_name="rfsimu_dl_ue0"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# type = "AWGN"; # { model_name="rfsimu_ul_ue0"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# ploss_dB = 0;
# noise_power_dB = -50; # // UE1
# forgetfact = 0; # { model_name="rfsimu_dl_ue1"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# offset = 0; # { model_name="rfsimu_ul_ue1"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# ds_tdl = 0;
# }, # // UE2
# { # { model_name="rfsimu_dl_ue2"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# model_name = "rfsimu_channel_ue0" # { model_name="rfsimu_ul_ue2"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# type = "AWGN";
# ploss_dB = 0; # // UE3
# noise_power_dB = -50; # { model_name="rfsimu_dl_ue3"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# forgetfact = 0; # { model_name="rfsimu_ul_ue3"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# offset = 0;
# ds_tdl = 0; # // UE4
# }, # { model_name="rfsimu_dl_ue4"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# { # { model_name="rfsimu_ul_ue4"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# model_name = "rfsimu_channel_ue1"
# type = "AWGN"; # // UE5
# ploss_dB = 0; # { model_name="rfsimu_dl_ue5"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# noise_power_dB = -50; # { model_name="rfsimu_ul_ue5"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# forgetfact = 0;
# offset = 0; # // UE6
# ds_tdl = 0; # { model_name="rfsimu_dl_ue6"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# }, # { model_name="rfsimu_ul_ue6"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# {
# model_name = "rfsimu_channel_ue2" # // UE7
# type = "AWGN"; # { model_name="rfsimu_dl_ue7"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# ploss_dB = 0; # { model_name="rfsimu_ul_ue7"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# noise_power_dB = -50;
# forgetfact = 0; # // UE8
# offset = 0; # { model_name="rfsimu_dl_ue8"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# ds_tdl = 0; # { model_name="rfsimu_ul_ue8"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# },
# { # // UE9
# model_name = "rfsimu_channel_ue3" # { model_name="rfsimu_dl_ue9"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; },
# type = "AWGN"; # { model_name="rfsimu_ul_ue9"; type="AWGN"; ploss_dB=20; noise_power_dB=-10; forgetfact=0; offset=0; ds_tdl=0; }
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# },
# {
# model_name = "rfsimu_channel_ue4"
# type = "AWGN";
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# },
# {
# model_name = "rfsimu_channel_ue5"
# type = "AWGN";
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# },
# {
# model_name = "rfsimu_channel_ue6"
# type = "AWGN";
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# },
# {
# model_name = "rfsimu_channel_ue7"
# type = "AWGN";
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# },
# {
# model_name = "rfsimu_channel_ue8"
# type = "AWGN";
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# },
# {
# model_name = "rfsimu_channel_ue9"
# type = "AWGN";
# ploss_dB = 0;
# noise_power_dB = -50;
# forgetfact = 0;
# offset = 0;
# ds_tdl = 0;
# }
# ); # );
# }; # };
+33 -5
View File
@@ -9,23 +9,51 @@ uicc0:
thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
#/* configuration for channel modelisation */ #/* configuration for channel modelisation */
#/* To be included in main config file when */ #/* Realistic channel model for antenna muting tests */
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */ #/* With realistic noise/path loss, antenna muting will show throughput reduction */
channelmod: channelmod:
max_chan: 10 max_chan: 10
modellist: modellist_rfsimu_1 modellist: modellist_rfsimu_1
modellist_rfsimu_1: modellist_rfsimu_1:
- model_name: rfsimu_channel_enB0 - model_name: rfsimu_channel_enB0
type: AWGN type: AWGN
ploss_dB: 20 ploss_dB: 20 # Realistic path loss
noise_power_dB: -4 noise_power_dB: -10 # Moderate noise to show antenna muting impact
forgetfact: 0 forgetfact: 0
offset: 0 offset: 0
ds_tdl: 0 ds_tdl: 0
- model_name: rfsimu_channel_ue0 - model_name: rfsimu_channel_ue0
type: AWGN type: AWGN
ploss_dB: 20 # Realistic path loss
noise_power_dB: -10 # Moderate noise
forgetfact: 0
offset: 0
ds_tdl: 0
- model_name: rfsimu_channel_ue1
type: AWGN
ploss_dB: 20 ploss_dB: 20
noise_power_dB: -2 noise_power_dB: -10
forgetfact: 0
offset: 0
ds_tdl: 0
- model_name: rfsimu_channel_ue2
type: AWGN
ploss_dB: 20
noise_power_dB: -10
forgetfact: 0
offset: 0
ds_tdl: 0
- model_name: rfsimu_channel_ue3
type: AWGN
ploss_dB: 20
noise_power_dB: -10
forgetfact: 0
offset: 0
ds_tdl: 0
- model_name: rfsimu_channel_ue4
type: AWGN
ploss_dB: 20
noise_power_dB: -10
forgetfact: 0 forgetfact: 0
offset: 0 offset: 0
ds_tdl: 0 ds_tdl: 0
+1
View File
@@ -47,3 +47,4 @@ RUN /bin/sh oaienv && \
cd cmake_targets && \ cd cmake_targets && \
mkdir -p log && \ mkdir -p log && \
./build_oai -I -w USRP --install-optional-packages ./build_oai -I -w USRP --install-optional-packages
-111
View File
@@ -1,111 +0,0 @@
#
# Dockerfile to rebuild nakaolab image with O-RAN antenna muting support
#
# Usage:
# cd /home/maki/openairinterface5g
# docker build -f docker/Dockerfile.nakaolab.rebuild -t nakaolab:latest .
#
FROM ubuntu:noble AS builder
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
# Install build dependencies
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
ninja-build \
ccache \
git \
libsctp-dev \
libconfig-dev \
libboost-all-dev \
libblas-dev \
liblapack-dev \
liblapacke-dev \
libyaml-cpp-dev \
libusb-1.0-0-dev \
python3 \
python3-pip \
python3-dev \
xxd \
libpcre2-dev \
bison \
flex \
libssl-dev \
libatlas-base-dev \
&& pip3 install pyyaml --break-system-packages \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Copy source code
WORKDIR /oai-ran
COPY . .
# Build gNB and UE with rfsimulator
RUN cd cmake_targets && \
./build_oai --ninja --gNB --nrUE -w SIMU -c && \
echo "Build complete"
# Build FlexRIC if exists
RUN if [ -d "openair2/E2AP/flexric" ]; then \
cd openair2/E2AP/flexric && \
mkdir -p build && cd build && \
cmake .. && make -j$(nproc) && \
make install; \
fi
#
# Final image
#
FROM ubuntu:noble
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
libsctp1 \
libconfig9 \
libboost-chrono1.83.0 \
libboost-date-time1.83.0 \
libboost-filesystem1.83.0 \
libboost-regex1.83.0 \
libboost-serialization1.83.0 \
libboost-thread1.83.0 \
libboost-system1.83.0 \
libboost-program-options1.83.0 \
libblas3 \
liblapack3 \
libyaml-cpp0.8 \
libusb-1.0-0 \
net-tools \
iputils-ping \
iproute2 \
iperf \
iperf3 \
netcat-openbsd \
procps \
gdb \
python3 \
python3-six \
python3-requests \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Copy built binaries and libraries
WORKDIR /oai-ran
COPY --from=builder /oai-ran/cmake_targets/ran_build /oai-ran/cmake_targets/ran_build
COPY --from=builder /oai-ran/targets /oai-ran/targets
COPY --from=builder /oai-ran/ci-scripts/conf_files /oai-ran/ci-scripts/conf_files
# Copy FlexRIC if built
COPY --from=builder /usr/local/lib/flexric /usr/local/lib/flexric
COPY --from=builder /usr/local/etc/flexric /usr/local/etc/flexric
RUN echo "/usr/local/lib/flexric" >> /etc/ld.so.conf.d/flexric.conf && ldconfig || true
# Copy FlexRIC binaries
RUN mkdir -p /oai-ran/openair2/E2AP/flexric/build/examples
COPY --from=builder /oai-ran/openair2/E2AP/flexric/build/examples /oai-ran/openair2/E2AP/flexric/build/examples
ENTRYPOINT ["/bin/bash"]
+29 -28
View File
@@ -122,23 +122,28 @@ static void process_command(const char *cmd, char *response, size_t resp_size)
} }
} }
else if (strcmp(p, "STATUS") == 0) { else if (strcmp(p, "STATUS") == 0) {
bool in_recovery = nr_is_in_recovery_mode(g_ctrl.ant_state);
snprintf(response, resp_size, snprintf(response, resp_size,
"=== Antenna Status ===\n" "=== Antenna Status ===\n"
"TX Array: %s\n" "TX Array: %s\n"
" Antennas: %d configured, %d active\n" " Antennas: %d configured, %d active\n"
" Bitmask: 0x%02X\n" " Bitmask: 0x%02X\n"
" Antenna 0 protected: %s\n"
"RX Array: %s\n" "RX Array: %s\n"
" Antennas: %d configured, %d active\n" " Antennas: %d configured, %d active\n"
" Bitmask: 0x%02X\n" " Bitmask: 0x%02X\n"
"Recovery Mode: %s\n"
"Backend: %s\n", "Backend: %s\n",
g_ctrl.ant_state->tx_array_name, g_ctrl.ant_state->tx_array_name,
g_ctrl.ant_state->num_tx_antennas, g_ctrl.ant_state->num_tx_antennas,
nr_get_active_tx_antenna_count(g_ctrl.ant_state), nr_get_active_tx_antenna_count(g_ctrl.ant_state),
nr_get_tx_antenna_bitmask(g_ctrl.ant_state), nr_get_tx_antenna_bitmask(g_ctrl.ant_state),
g_ctrl.ant_state->config.protect_antenna0 ? "YES" : "NO",
g_ctrl.ant_state->rx_array_name, g_ctrl.ant_state->rx_array_name,
g_ctrl.ant_state->num_rx_antennas, g_ctrl.ant_state->num_rx_antennas,
nr_get_active_rx_antenna_count(g_ctrl.ant_state), nr_get_active_rx_antenna_count(g_ctrl.ant_state),
nr_get_rx_antenna_bitmask(g_ctrl.ant_state), nr_get_rx_antenna_bitmask(g_ctrl.ant_state),
in_recovery ? "ACTIVE (use identity matrix)" : "OFF",
g_ctrl.backend == ANTENNA_CTRL_BACKEND_MPLANE ? "O-RAN M-Plane NETCONF" : g_ctrl.backend == ANTENNA_CTRL_BACKEND_MPLANE ? "O-RAN M-Plane NETCONF" :
g_ctrl.backend == ANTENNA_CTRL_BACKEND_TEST_SOCKET ? "Test Socket (NOT O-RAN)" : g_ctrl.backend == ANTENNA_CTRL_BACKEND_TEST_SOCKET ? "Test Socket (NOT O-RAN)" :
"None"); "None");
@@ -158,17 +163,24 @@ static void process_command(const char *cmd, char *response, size_t resp_size)
snprintf(response, resp_size, "OK: Statistics reset\n"); snprintf(response, resp_size, "OK: Statistics reset\n");
} }
else if (strcmp(p, "RESET") == 0 || strcmp(p, "UNMUTE ALL") == 0) { else if (strcmp(p, "RESET") == 0 || strcmp(p, "UNMUTE ALL") == 0) {
// Reset all antennas to active state // Reset all antennas to active state with recovery mode
uint8_t all_tx = (1 << g_ctrl.ant_state->num_tx_antennas) - 1; nr_unmute_all_tx_antennas(g_ctrl.ant_state);
uint8_t all_rx = (1 << g_ctrl.ant_state->num_rx_antennas) - 1; nr_unmute_all_rx_antennas(g_ctrl.ant_state);
nr_set_tx_antenna_bitmask(g_ctrl.ant_state, all_tx);
nr_set_rx_antenna_bitmask(g_ctrl.ant_state, all_rx);
snprintf(response, resp_size, snprintf(response, resp_size,
"OK: All antennas unmuted\n" "OK: All antennas unmuted (recovery mode: %u ms)\n"
" TX mask: 0x%02X (%d antennas)\n" " TX mask: 0x%02X (%d antennas)\n"
" RX mask: 0x%02X (%d antennas)\n", " RX mask: 0x%02X (%d antennas)\n",
all_tx, g_ctrl.ant_state->num_tx_antennas, g_ctrl.ant_state->recovery.recovery_duration_ms,
all_rx, g_ctrl.ant_state->num_rx_antennas); nr_get_tx_antenna_bitmask(g_ctrl.ant_state), g_ctrl.ant_state->num_tx_antennas,
nr_get_rx_antenna_bitmask(g_ctrl.ant_state), g_ctrl.ant_state->num_rx_antennas);
}
else if (strcmp(p, "PROTECT ANT0 ON") == 0) {
nr_set_antenna0_protection(g_ctrl.ant_state, true);
snprintf(response, resp_size, "OK: Antenna 0 protection enabled (SSB)\n");
}
else if (strcmp(p, "PROTECT ANT0 OFF") == 0) {
nr_set_antenna0_protection(g_ctrl.ant_state, false);
snprintf(response, resp_size, "OK: Antenna 0 protection disabled (WARNING: may cause UE sync loss)\n");
} }
else if (strcmp(p, "SYNC") == 0) { else if (strcmp(p, "SYNC") == 0) {
// Synchronize to RU (only works with M-Plane backend) // Synchronize to RU (only works with M-Plane backend)
@@ -180,26 +192,15 @@ static void process_command(const char *cmd, char *response, size_t resp_size)
} }
else if (strcmp(p, "HELP") == 0) { else if (strcmp(p, "HELP") == 0) {
snprintf(response, resp_size, snprintf(response, resp_size,
"=== O-RAN Antenna Control Interface ===\n" "=== Antenna Control ===\n"
"Commands:\n" "MUTE TX/RX <id> - Mute antenna\n"
" MUTE TX <ant_id> - Mute TX antenna (0-based)\n" "UNMUTE TX/RX <id> - Unmute antenna\n"
" UNMUTE TX <ant_id> - Unmute TX antenna\n" "SET TX/RX MASK <hex> - Set bitmask\n"
" MUTE RX <ant_id> - Mute RX antenna\n" "STATUS - Show state\n"
" UNMUTE RX <ant_id> - Unmute RX antenna\n" "STATS - Show statistics\n"
" SET TX MASK <hex> - Set TX bitmask (O-RAN compliant)\n" "RESET - Unmute all\n"
" SET RX MASK <hex> - Set RX bitmask (O-RAN compliant)\n" "PROTECT ANT0 ON/OFF\n"
" STATUS - Show current antenna state\n" "HELP/QUIT\n");
" STATS - Show energy saving statistics\n"
" RESET STATS - Reset statistics\n"
" RESET / UNMUTE ALL - Unmute all antennas (restore default)\n"
" SYNC - Sync state to RU (M-Plane only)\n"
" HELP - Show this help\n"
" QUIT - Close connection\n"
"\n"
"Example: SET TX MASK 03 (enables antennas 0,1; mutes 2,3)\n"
"\n"
"NOTE: This test socket interface is NOT O-RAN compliant.\n"
" For production, use NETCONF via radio/fhi_72/mplane/\n");
} }
else if (strcmp(p, "QUIT") == 0 || strcmp(p, "EXIT") == 0) { else if (strcmp(p, "QUIT") == 0 || strcmp(p, "EXIT") == 0) {
snprintf(response, resp_size, "BYE\n"); snprintf(response, resp_size, "BYE\n");
+104 -4
View File
@@ -84,10 +84,19 @@ void nr_init_antenna_state(nr_antenna_state_t *state,
state->stats.last_update_timestamp = get_timestamp_us(); state->stats.last_update_timestamp = get_timestamp_us();
// Initialize recovery mode
state->recovery.in_recovery = false;
state->recovery.recovery_start_ts = 0;
state->recovery.recovery_duration_ms = 500; // 500ms default recovery time
// Protect antenna 0 by default (needed for SSB/PSS/SSS)
state->config.protect_antenna0 = true;
LOG_I(PHY, "[ANTENNA_STATE] Initialized: TX antennas=%d (mask=0x%02X, array=%s), " LOG_I(PHY, "[ANTENNA_STATE] Initialized: TX antennas=%d (mask=0x%02X, array=%s), "
"RX antennas=%d (mask=0x%02X, array=%s)\n", "RX antennas=%d (mask=0x%02X, array=%s), antenna0_protected=%d\n",
state->num_tx_antennas, state->tx_antenna_bitmask, state->tx_array_name, state->num_tx_antennas, state->tx_antenna_bitmask, state->tx_array_name,
state->num_rx_antennas, state->rx_antenna_bitmask, state->rx_array_name); state->num_rx_antennas, state->rx_antenna_bitmask, state->rx_array_name,
state->config.protect_antenna0);
} }
void nr_free_antenna_state(nr_antenna_state_t *state) void nr_free_antenna_state(nr_antenna_state_t *state)
@@ -153,13 +162,19 @@ uint8_t nr_set_rx_antenna_bitmask(nr_antenna_state_t *state, uint8_t bitmask)
uint8_t nr_get_tx_antenna_bitmask(const nr_antenna_state_t *state) uint8_t nr_get_tx_antenna_bitmask(const nr_antenna_state_t *state)
{ {
if (state == NULL) return 0xFF; if (state == NULL) return 0xFF;
return state->tx_antenna_bitmask; pthread_mutex_lock((pthread_mutex_t*)&state->lock);
uint8_t m = state->tx_antenna_bitmask;
pthread_mutex_unlock((pthread_mutex_t*)&state->lock);
return m;
} }
uint8_t nr_get_rx_antenna_bitmask(const nr_antenna_state_t *state) uint8_t nr_get_rx_antenna_bitmask(const nr_antenna_state_t *state)
{ {
if (state == NULL) return 0xFF; if (state == NULL) return 0xFF;
return state->rx_antenna_bitmask; pthread_mutex_lock((pthread_mutex_t*)&state->lock);
uint8_t m = state->rx_antenna_bitmask;
pthread_mutex_unlock((pthread_mutex_t*)&state->lock);
return m;
} }
bool nr_is_tx_antenna_active(const nr_antenna_state_t *state, uint8_t ant_id) bool nr_is_tx_antenna_active(const nr_antenna_state_t *state, uint8_t ant_id)
@@ -190,6 +205,13 @@ void nr_mute_tx_antenna(nr_antenna_state_t *state, uint8_t ant_id)
{ {
if (state == NULL || ant_id >= state->num_tx_antennas) return; if (state == NULL || ant_id >= state->num_tx_antennas) return;
// Protect antenna 0 if configured (needed for SSB/PSS/SSS transmission)
if (ant_id == 0 && state->config.protect_antenna0) {
LOG_W(PHY, "[ANTENNA_STATE] Cannot mute TX antenna 0: protected for SSB transmission\n");
LOG_W(PHY, "[ANTENNA_STATE] Use 'SET TX MASK' to override protection if needed\n");
return;
}
uint8_t new_mask = state->tx_antenna_bitmask & ~(1 << ant_id); uint8_t new_mask = state->tx_antenna_bitmask & ~(1 << ant_id);
nr_set_tx_antenna_bitmask(state, new_mask); nr_set_tx_antenna_bitmask(state, new_mask);
} }
@@ -294,3 +316,81 @@ void nr_reset_antenna_stats(nr_antenna_state_t *state)
pthread_mutex_unlock(&state->lock); pthread_mutex_unlock(&state->lock);
} }
void nr_unmute_all_tx_antennas(nr_antenna_state_t *state)
{
if (state == NULL) return;
pthread_mutex_lock(&state->lock);
uint8_t old_mask = state->tx_antenna_bitmask;
uint8_t all_on = (1 << state->num_tx_antennas) - 1;
state->tx_antenna_bitmask = all_on;
// Enter recovery mode if we were muted
if (old_mask != all_on) {
state->recovery.in_recovery = true;
state->recovery.recovery_start_ts = get_timestamp_us();
LOG_I(PHY, "[ANTENNA_STATE] Entering recovery mode for %u ms after unmuting TX antennas\n",
state->recovery.recovery_duration_ms);
}
state->stats.tx_mute_events++;
state->stats.last_update_timestamp = get_timestamp_us();
LOG_I(PHY, "[ANTENNA_STATE] All TX antennas unmuted: 0x%02X -> 0x%02X (array=%s)\n",
old_mask, all_on, state->tx_array_name);
pthread_mutex_unlock(&state->lock);
}
void nr_unmute_all_rx_antennas(nr_antenna_state_t *state)
{
if (state == NULL) return;
pthread_mutex_lock(&state->lock);
uint8_t old_mask = state->rx_antenna_bitmask;
uint8_t all_on = (1 << state->num_rx_antennas) - 1;
state->rx_antenna_bitmask = all_on;
state->stats.rx_mute_events++;
state->stats.last_update_timestamp = get_timestamp_us();
LOG_I(PHY, "[ANTENNA_STATE] All RX antennas unmuted: 0x%02X -> 0x%02X (array=%s)\n",
old_mask, all_on, state->rx_array_name);
pthread_mutex_unlock(&state->lock);
}
bool nr_is_in_recovery_mode(const nr_antenna_state_t *state)
{
if (state == NULL) return false;
if (!state->recovery.in_recovery) return false;
// Check if recovery period has elapsed
uint64_t now = get_timestamp_us();
uint64_t elapsed_us = now - state->recovery.recovery_start_ts;
uint64_t duration_us = (uint64_t)state->recovery.recovery_duration_ms * 1000ULL;
if (elapsed_us >= duration_us) {
// Recovery complete - cast away const for state update
nr_antenna_state_t *s = (nr_antenna_state_t *)state;
s->recovery.in_recovery = false;
LOG_I(PHY, "[ANTENNA_STATE] Recovery mode complete after %lu ms\n", elapsed_us / 1000);
return false;
}
return true;
}
void nr_set_antenna0_protection(nr_antenna_state_t *state, bool protect)
{
if (state == NULL) return;
pthread_mutex_lock(&state->lock);
state->config.protect_antenna0 = protect;
LOG_I(PHY, "[ANTENNA_STATE] Antenna 0 protection %s\n", protect ? "enabled" : "disabled");
pthread_mutex_unlock(&state->lock);
}
@@ -72,6 +72,18 @@ typedef struct {
char tx_array_name[64]; char tx_array_name[64];
char rx_array_name[64]; char rx_array_name[64];
/// Recovery mode: after unmuting, allow CSI to update before using full capacity
struct {
bool in_recovery; ///< Currently in recovery mode
uint64_t recovery_start_ts; ///< Timestamp when recovery started (us)
uint32_t recovery_duration_ms; ///< Recovery duration in milliseconds (default 500ms)
} recovery;
/// Configuration flags
struct {
bool protect_antenna0; ///< Never mute antenna 0 (needed for SSB)
} config;
} nr_antenna_state_t; } nr_antenna_state_t;
/** /**
@@ -222,6 +234,35 @@ void nr_get_antenna_stats(const nr_antenna_state_t *state,
*/ */
void nr_reset_antenna_stats(nr_antenna_state_t *state); void nr_reset_antenna_stats(nr_antenna_state_t *state);
/**
* @brief Unmute all TX antennas and enter recovery mode
* @param state Pointer to antenna state structure
*
* This initiates a recovery period during which the scheduler
* uses conservative settings to allow UE CSI reports to update.
*/
void nr_unmute_all_tx_antennas(nr_antenna_state_t *state);
/**
* @brief Unmute all RX antennas
* @param state Pointer to antenna state structure
*/
void nr_unmute_all_rx_antennas(nr_antenna_state_t *state);
/**
* @brief Check if system is in recovery mode after unmuting
* @param state Pointer to antenna state structure
* @return true if in recovery mode
*/
bool nr_is_in_recovery_mode(const nr_antenna_state_t *state);
/**
* @brief Set antenna 0 protection (SSB antenna)
* @param state Pointer to antenna state structure
* @param protect true to prevent muting antenna 0
*/
void nr_set_antenna0_protection(nr_antenna_state_t *state, bool protect);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -793,10 +793,10 @@ static void pf_dl(gNB_MAC_INST *mac,
while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap)) while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap))
rbStart++; rbStart++;
uint16_t max_rbSize = 10; uint16_t max_rbSize = 1;
/* while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap)) */ while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap))
/* max_rbSize++; */ max_rbSize++;
if (max_rbSize < min_rbSize) { if (max_rbSize < min_rbSize) {
LOG_D(NR_MAC, LOG_D(NR_MAC,
@@ -223,15 +223,23 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
return 0; return 0;
} }
// O-RAN MPLANE-TRX-CONTROL: When antennas are muted, the UE's PMI report // O-RAN MPLANE-TRX-CONTROL: Handle antenna muting and recovery mode
// is based on the full antenna array and may be invalid. Use identity matrix.
if (nrmac->antenna_state) { if (nrmac->antenna_state) {
int active_tx = nr_get_active_tx_antenna_count(nrmac->antenna_state); int active_tx = nr_get_active_tx_antenna_count(nrmac->antenna_state);
int configured_tx = nrmac->antenna_state->num_tx_antennas; int configured_tx = nrmac->antenna_state->num_tx_antennas;
if (active_tx < configured_tx) {
LOG_D(NR_MAC, "[ANTENNA_MUTE] Using identity matrix: %d/%d TX antennas active\n", // During recovery mode after unmuting, use identity matrix to allow CSI update
active_tx, configured_tx); if (nr_is_in_recovery_mode(nrmac->antenna_state)) {
return 0; // Use identity matrix when any antennas are muted LOG_D(NR_MAC, "[ANTENNA_MUTE] Recovery mode active, using identity matrix\n");
return 0;
}
// When antennas are muted and we're using fewer layers than configured,
// use identity matrix for robustness (UE's PMI based on old config)
if (active_tx < configured_tx && layers < configured_tx) {
LOG_D(NR_MAC, "[ANTENNA_MUTE] Using identity matrix: %d/%d TX antennas active, %d layers\n",
active_tx, configured_tx, layers);
return 0;
} }
} }
const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id; const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id;
@@ -2176,8 +2176,8 @@ static int pf_ul(gNB_MAC_INST *nrmac,
/* if it's for inactivity, min_grant_prb is enough, otherwise check what /* if it's for inactivity, min_grant_prb is enough, otherwise check what
* would be the maximum */ * would be the maximum */
/* uint16_t max_rbSize = iterator->sched_inactive ? min_rb : bi.bwpSize; */ uint16_t max_rbSize = iterator->sched_inactive ? min_rb : bi.bwpSize;
uint16_t max_rbSize = min_rb; /* uint16_t max_rbSize = min_rb; */
uint16_t available_rb = 1; uint16_t available_rb = 1;
while (rbStart + available_rb < bi.bwpSize && !(rballoc_mask[rbStart + bi.bwpStart + available_rb] & slbitmap) && available_rb < max_rbSize) while (rbStart + available_rb < bi.bwpSize && !(rballoc_mask[rbStart + bi.bwpStart + available_rb] & slbitmap) && available_rb < max_rbSize)
available_rb++; available_rb++;
@@ -250,11 +250,11 @@ log_config :
}; };
fhi_72 = { fhi_72 = {
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well dpdk_devices = ("0000:01:02.0", "0000:01:02.1"); # one VF can be used as well
system_core = 0; system_core = 0;
io_core = 1; io_core = 1;
worker_cores = (2); worker_cores = (2);
ru_addr = ("e8:c7:4f:25:81:b3", "e8:c7:4f:25:81:b3"); ru_addr = ("e8:c7:4f:25:7f:f6", "e8:c7:4f:25:81:b3");
mtu = 9600; # note: 1500 works as well, with both E and F releases mtu = 9600; # note: 1500 works as well, with both E and F releases
fh_config = ({ fh_config = ({
T1a_cp_dl = (285, 429); T1a_cp_dl = (285, 429);
+2 -2
View File
@@ -41,9 +41,9 @@ iperf_udp_ul_forever() { ( iperf -u -c "$IPERF_HOST_UDP" -B "$OAITUN_IP" -p "$IP
# ---------------- profiles ---------------- # ---------------- profiles ----------------
do_boring() { do_boring() {
iperf_udp_dl_forever 15M iperf_udp_dl_forever 3M
wait wait
# iperf -c "$IPERF_HOST" -p "$IPERF_PORT" -B "$OAITUN_IP" -u -b 25M -t "$LONG_T" # iperf -c "$IPERF_HOST" -p "$IPERF_PORT" -B "$OAITUN_IP" -u -b 25M -t "$LONG_T"
} }
do_browsing() { do_browsing() {