Compare commits

...

13 Commits

Author SHA1 Message Date
rajchdav
662a1bd2db Work on the testbench, currently there is an issue with jupyter notebook kernel crashes on code, that is functional in python scripts. The issue is being investigated, but there is a posibility its caused by the oaipylib 2026-04-08 15:47:49 +02:00
Nada Bouknana
da8ecda3d0 minor cleanup in python polar encoder 2026-03-20 12:56:47 +01:00
Nada Bouknana
fa739441af modify the python polar encoder function to use the buffer protocol in order to work with arrays as input 2026-03-20 11:46:58 +01:00
Raymond Knopp
b5f0853bfa fixed segfault in C->Python output conversion (missing PyLong_FromUnsignedLongLong) 2026-03-18 14:01:21 +01:00
Raymond Knopp
919ef73a54 added full example of encoder/channel/decoder 2026-03-18 11:44:15 +01:00
Raymond Knopp
3d794f9ba7 updates to README.md 2026-03-13 15:02:38 +01:00
Raymond Knopp
e081e3a827 bug fixing on encoder. It runs and produces plausible output 2026-03-13 14:47:39 +01:00
Nada Bouknana
24c893840e add initial version of polar encoder functions, to be tested 2026-03-12 11:00:07 +01:00
Raymond Knopp
86e4d93684 logging for oaipylib 2026-03-11 21:53:20 +01:00
Raymond Knopp
49cd0bcb05 fixed some issues with linking of shared lib (CMakeLists.txt and setup.py) 2026-03-11 21:39:13 +01:00
Raymond Knopp
71f5b18bb3 added init from nr_dlsim to oai_lib_init 2026-03-11 10:28:29 +01:00
Raymond Knopp
d573653fe4 added initial functions for init/shutdown/polar encode 2026-03-11 09:59:16 +01:00
Raymond Knopp
a8bcd1070f initial python bindings for OAI shared library 2026-03-11 09:16:45 +01:00
21 changed files with 1793 additions and 3 deletions

9
.gitignore vendored
View File

@@ -33,3 +33,12 @@ nfapi_nr_interface_scf
*.log
*.out
CMakeUserPresets.json
oaipylib.egg-info
#docker build
build
#other gitignores
private_folder
tmp_comp_results
__pycache__

View File

@@ -2148,7 +2148,7 @@ if (${T_TRACER})
PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU
L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_UE_NR ngap
GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE SIMU
dfts config_internals nr_common crc_byte)
liboaipy dfts config_internals nr_common crc_byte)
if (TARGET ${i})
add_dependencies(${i} generate_T)
endif()
@@ -2202,6 +2202,7 @@ add_subdirectory(openair2)
add_subdirectory(openair3)
add_subdirectory(radio)
add_subdirectory(tests)
add_subdirectory(python)
if(TARGET oai_cuda_lib)
message(STATUS "CUDA library 'oai_cuda_lib' found, linking to targets...")
@@ -2212,3 +2213,4 @@ endif()
if(PACKAGING_LTE OR PACKAGING_NR OR PACKAGING_COMMON OR PACKAGING_USRP OR PACKAGING_PHYSIM)
include("tools/packages/packages.cmake")
endif()

View File

@@ -121,8 +121,7 @@ t_nrPolar_params *nr_polar_params(int8_t messageType, uint16_t messageLength, ui
newPolarInitNode->encoderLength = NR_POLAR_PBCH_E;
newPolarInitNode->crcCorrectionBits = NR_POLAR_PBCH_CRC_ERROR_CORRECTION_BITS;
newPolarInitNode->crc_generator_matrix = crc24c_generator_matrix(newPolarInitNode->payloadBits); // G_P
// printf("Initializing polar parameters for PBCH (K %d, E
// %d)\n",newPolarInitNode->payloadBits,newPolarInitNode->encoderLength);
//printf("Initializing polar parameters for PBCH (K %d, E %d)\n",newPolarInitNode->payloadBits,newPolarInitNode->encoderLength);
} else if (messageType == NR_POLAR_DCI_MESSAGE_TYPE) {
newPolarInitNode->n_max = NR_POLAR_DCI_N_MAX;

View File

@@ -126,6 +126,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
while(gNB->configured == 0)
usleep(10000);
LOG_I(PHY,"Loading dfts shared lib\n");
load_dftslib();
crcTableInit();

53
python/CMakeLists.txt Normal file
View File

@@ -0,0 +1,53 @@
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
# * this work for additional information regarding copyright ownership.
# * The OpenAirInterface Software Alliance licenses this file to You under
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
# * except in compliance with the License.
# * You may obtain a copy of the License at
# *
# * http://www.openairinterface.org/?page_id=698
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# * See the License for the specific language governing permissions and
# * limitations under the License.
# *-------------------------------------------------------------------------------
# * For more information about the OpenAirInterface (OAI) Software Alliance:
# * contact@openairinterface.org
# */
cmake_minimum_required (VERSION 3.19)
project (OpenAirInterface LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(OAI_VERSION 2.4.0)
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
add_library(liboaipy MODULE
src/oaipylib_module.c
src/oaipylib_wrappers.c
src/oaipylib_top.c
${NFAPI_USER_DIR}/nfapi.c
${NFAPI_USER_DIR}/gnb_ind_vars.c
${PHY_INTERFACE_DIR}/queue_t.c
)
target_include_directories(liboaipy PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_include_directories(liboaipy PRIVATE ${Python3_INCLUDE_DIRS})
target_link_libraries(liboaipy PRIVATE
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group
m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common
softmodem_common
Python3::Module
)
set_target_properties(liboaipy PROPERTIES
PREFIX ""
OUTPUT_NAME "liboaipy"
)

View File

@@ -0,0 +1,123 @@
import math
import random
import os
import sys
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
import oaipylib as oai
import numpy as np
def nr_bit2byte_uint32_8(inp, array_size):
array_ind = (array_size + 31) // 32
out = [0] * array_size
for i in range(array_ind - 1):
for j in range(32):
out[i * 32 + j] = (inp[i] >> j) & 1
start = (array_ind - 1) * 32
for j in range(array_size - start):
out[start + j] = (inp[array_ind - 1] >> j) & 1
return out
def nr_byte2bit_uint8_32(inp, array_size):
array_ind = (array_size + 31) // 32
out = [0] * array_ind
for i in range(array_ind):
val = 0
for j in range(31, 0, -1):
idx = i * 32 + j
bit = inp[idx] if idx < array_size else 0
val |= bit
val <<= 1
bit0 = inp[i * 32] if i * 32 < array_size else 0
val |= bit0
out[i] = val & 0xFFFFFFFF
return out
def nr_bit2byte_uint32_8(inp, array_size):
array_ind = (array_size + 31) // 32
out = [0] * array_size
for i in range(array_ind - 1):
for j in range(32):
out[i * 32 + j] = (inp[i] >> j) & 1
start = (array_ind - 1) * 32
for j in range(array_size - start):
out[start + j] = (inp[array_ind - 1] >> j) & 1
return out
def bpsk_from_uint32_words(inp, array_size):
bits = nr_bit2byte_uint32_8(inp, array_size)
scale = 1.0 / math.sqrt(2.0)
return [scale if b == 0 else -scale for b in bits]
def add_awgn_and_convert_q15(samples, SNRdB):
"""
Add zero-mean Gaussian noise and convert to signed Q15.
Parameters
----------
samples : sequence of float
Input real-valued samples, e.g. BPSK symbols.
noise_variance : float
Variance of the Gaussian noise.
Returns
-------
list[int]
Noisy samples quantized to Q15 int16 values.
"""
SNR_lin = 10**(SNRdB / 10.0)
noise_variance = (1 / (2.0 * SNR_lin))
if noise_variance < 0:
raise ValueError("noise_variance must be non-negative")
sigma = math.sqrt(noise_variance)
out = []
for x in samples:
noisy = x + random.gauss(0.0, sigma)
# Q15 scaling: float in approximately [-1, 1) -> int8_t range coded in int16_t
q15 = int(round(noisy * 8.0))
# Saturate to int16 range
if q15 > 127:
q15 = 127
elif q15 < -128:
q15 = -128
out.append(q15)
return out
## Testing
oai.init()
# this is a 32-bit input with format 0 (PBCH) which has 864 encoded bits
encoder_input = np.array([0x12345678],dtype='Q') #dtype=np.ulonglong)
mv = memoryview(encoder_input)
print(f"Python array format is: {mv.format}")
encoded_output = oai.nr_polar_encoder(encoder_input,0,0,0,32,0)
bpsk_out = bpsk_from_uint32_words(encoded_output,864)
#print(bpsk_out)
SNRdB = 0;
decoder_input = add_awgn_and_convert_q15(bpsk_out, SNRdB)
#print(decoder_input)
# here we pass the parameters to the OAI polar decoder, decoder_input (Q15 input), ones_flag = 0, messageType=0, messageLength = 864, aggregation_level = 0
decoder_output = oai.nr_polar_decoder(decoder_input,0,0,864,0)
#print(len(decoder_output))
print(hex(decoder_output[0]))
oai.shutdown()

42
python/README.md Normal file
View File

@@ -0,0 +1,42 @@
# oaipylib
Minimal CPython extension skeleton in C for wrapping the OAI C library.
## Layout
- `src/oai_lib_api.h`: placeholder header for API into OAI functions
- `src/oaipylib_wrappers.h`: Python wrapper declarations
- `src/oaipylib_wrappers.c`: Python/C wrapper implementations
- `src/oaipylib_module.c`: Python module definition
- `setup.py`: setuptools build script
- `pyproject.toml`: build-system config
## Building liboai
From OAI top-level
```bash
mkdir build
cd build
cmake .. -GNinja
ninja liboaipy dfts ldpc
cp libdfts.so python
cp libldpc.so python
export LD_LIBRARY_PATH="path to openairinterface5g/build/python":$LD_LIBRARY_PATH
```
## Build
```bash
python -m pip install -U pip setuptools wheel
python -m pip install .
```
## To test
```bash
python Examples/polartest.py
```
You should see that the output matches the input (0x12345678) at SNR=0dB. Debugging traces will be removed
## Docker test enviroment
There is a work in progress doocker test enviroment located in the dokcer_testenv folder. Currently there is an issue with kernel crashes of jupyter notebooks when running any testing scripts for the OAIPYLIB, these issues could be caused by the docker enviroment, thus it is not recemended to use this envroment for work on the library or any adjacent script. Until the cause of the kernel crashes is confirmed to be unrelated to the docker container setup

View File

@@ -0,0 +1,59 @@
FROM ubuntu:24.04
# Avoid interactive prompts during apt installations
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
software-properties-common \
automake \
build-essential \
cmake \
ninja-build \
pkg-config \
git \
libreadline-dev \
libconfig-dev \
libsctp-dev \
libssl-dev \
libtool \
patch \
openssl \
zlib1g-dev \
xxd \
libyaml-cpp-dev \
python3-dev \
python-is-python3 \
python3-pip \
python3-venv \
python3-numpy \
python3-matplotlib \
python3-seaborn \
python3-pandas \
python3-ipykernel \
jupyter \
bison \
flex \
&& rm -rf /var/lib/apt/lists/*
# Install asn1c from source (as OAI requires a specific version)
RUN cd /tmp && \
git clone https://github.com/mouse07410/asn1c && \
cd asn1c && \
git checkout 940dd5fa9f3917913fd487b13dfddfacd0ded06e && \
autoreconf -iv && \
CFLAGS="-O2 -fno-strict-aliasing" ./configure --prefix /opt/asn1c/ && \
make -j$(nproc) && \
make install && \
ldconfig && \
cd / && rm -rf /tmp/asn1c
# Install simde from source
RUN cd /tmp && \
git clone https://github.com/simd-everywhere/simde-no-tests.git simde && \
cd simde && \
git checkout c7f26b73ba8e874b95c2cec2b497826ad2188f68 && \
cp -rv ../simde /usr/include && \
cd / && rm -rf /tmp/simde
# Run bash to allow interactive access or sleep
CMD ["sleep", "infinity"]

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
rm -rf build
mkdir -p build
cd build
cmake .. -GNinja
ninja liboaipy dfts ldpc
install -m 755 libdfts.so python/libdfts.so
install -m 755 libldpc.so python/libldpc.so
# Make liboaipy discoverable without requiring manual LD_LIBRARY_PATH exports.
install -m 755 python/liboaipy.so /usr/local/lib/liboaipy.so
ldconfig
# Remove any stale local symlink that can shadow the real Python extension module.
rm -f python/oaipylib.so
cd ../python
python3 -m pip install --force-reinstall . --break-system-packages

View File

@@ -0,0 +1,9 @@
services:
oai-dev:
build: .
container_name: oai-dev-ubuntu24
volumes:
- .:/opt/oai
working_dir: /opt/oai
command: sleep infinity
restart: unless-stopped

View File

@@ -0,0 +1,56 @@
#!/bin/bash
# A wrapper script to execute a command inside the OAI development container.
set -e # Exit immediately if a command exits with a non-zero status.
# 1. Define Container and Project Paths
CONTAINER_NAME="oai-dev-ubuntu24"
PROJECT_ROOT_IN_CONTAINER="/opt/oai"
# 2. Check for Script Argument
if [ -z "$1" ]; then
echo "Error: No script path provided."
echo "Usage: $0 <path/to/script_to_execute.py>"
echo "Example: $0 python/Examples/polartest.py"
exit 1
fi
SCRIPT_PATH_ON_HOST=$1
# 2b. Ensure computation results are written to a dedicated folder in the
# directory where this wrapper is executed.
RESULTS_DIR_ON_HOST="${PWD}/tmp_comp_results"
mkdir -p "${RESULTS_DIR_ON_HOST}"
# 3. Check if Container is Running
# The `docker ps -q` command returns the container ID if it's running, otherwise it's empty.
if ! docker ps -q -f "name=${CONTAINER_NAME}" | grep -q .; then
echo "Error: Container '${CONTAINER_NAME}' is not running."
echo "Please ensure the container is up with: docker-compose up -d"
exit 1
fi
# 4. Construct the Full Path to the Script inside the Container
# The volume mounts the project root to /opt/oai, so we prepend that.
SCRIPT_PATH_IN_CONTAINER="${PROJECT_ROOT_IN_CONTAINER}/${SCRIPT_PATH_ON_HOST}"
RESULTS_DIR_IN_CONTAINER="${PROJECT_ROOT_IN_CONTAINER}/tmp_comp_results"
# 5. Execute the Script
echo "--- Executing '${SCRIPT_PATH_IN_CONTAINER}' in container '${CONTAINER_NAME}' ---"
echo "--- Writing computation results to '${RESULTS_DIR_ON_HOST}' ---"
echo ""
# The `docker exec` command runs the python3 interpreter on the script path inside the container.
# We set LD_LIBRARY_PATH to make sure the oaipylib shared object is found.
OAI_LIB_PATH="${PROJECT_ROOT_IN_CONTAINER}/build/python"
PYTHON_SRC_PATH="${PROJECT_ROOT_IN_CONTAINER}/python"
docker exec \
--workdir "${RESULTS_DIR_IN_CONTAINER}" \
--env PYTHONPATH=${OAI_LIB_PATH}:${PYTHON_SRC_PATH} \
--env LD_LIBRARY_PATH=${OAI_LIB_PATH} \
"${CONTAINER_NAME}" \
python3 "${SCRIPT_PATH_IN_CONTAINER}"
echo ""
echo "--- Execution finished ---"

View File

@@ -0,0 +1,110 @@
import math
import os
import sys
import random
import json
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
import oaipylib as oai
import numpy as np
# --- Test Configuration ---
SNR_START = -10.0
SNR_END = 5.0
SNR_STEP = 0.5
SNR_RANGE = np.arange(SNR_START, SNR_END + SNR_STEP, SNR_STEP)
NUM_RUNS_PER_SNR = 5000
ORIGINAL_INPUT = 0x12345678
MESSAGE_LENGTH = 32
AGGREGATION_LEVELS = [1, 2, 4, 8, 16]
MESSAGE_TYPE = 1 # DCI
# --- Helper Functions ---
def bpsk(inp, array_size):
np_input = np.array(inp, dtype=np.uint32)
bits = ((np_input[:, None] >> np.arange(32, dtype=np.uint32)) & 1).flatten()[:array_size]
return (1 - 2 * bits.astype(np.int8)) / np.sqrt(2.0)
def add_awgn_and_quantize(samples, SNRdB):
SNR_lin = 10**(SNRdB / 10.0)
noise_variance = (1 / (2.0 * SNR_lin))
sigma = math.sqrt(noise_variance)
decoder_input = []
for x in samples:
noisy = x + random.gauss(0.0, sigma)
q15 = int(round(noisy * 8.0))
if q15 > 127: q15 = 127
elif q15 < -128: q15 = -128
decoder_input.append(q15)
return decoder_input
# --- Main script ---
oai.init()
global_results = {}
try:
for agg_level in AGGREGATION_LEVELS:
encoded_len = 108 * agg_level
#print(f"\n>> Aggregation Level: {agg_level} (E={encoded_len})")
encoder_input = np.array([ORIGINAL_INPUT], dtype='Q')
encoded_output = oai.nr_polar_encoder(encoder_input, 0, 0, MESSAGE_TYPE, MESSAGE_LENGTH, agg_level)
bpsk_symbols = bpsk(encoded_output, encoded_len)
results = {}
for snr in SNR_RANGE:
num_failures = 0
for _ in range(NUM_RUNS_PER_SNR):
decoder_input = add_awgn_and_quantize(bpsk_symbols, snr)
decoder_output = oai.nr_polar_decoder(decoder_input, 0, MESSAGE_TYPE, MESSAGE_LENGTH, agg_level)
if decoder_output[0] != ORIGINAL_INPUT:
num_failures += 1
bler = num_failures / NUM_RUNS_PER_SNR
# Use string key for SNR to make it JSON serializable
results[f"{snr:.2f}"] = bler
#print(f" SNR: {snr:5.2f} dB | BLER: {bler:.4f}")
global_results[str(agg_level)] = results
output_file = "polar_results.json"
with open(output_file, 'w') as f:
json.dump(global_results, f, indent=4)
print(f"\nResults saved to {output_file}")
# --- Plotting ---
try:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# Convert results to a DataFrame for easy plotting
df = pd.DataFrame(global_results).transpose()
df.index.name = 'Aggregation Level'
df.columns.name = 'SNR (dB)'
# Sort index and columns to ensure correct order
df.index = df.index.astype(int)
df = df.sort_index()
df.columns = df.columns.astype(float)
df = df.reindex(sorted(df.columns), axis=1)
plt.figure(figsize=(12, 8))
sns.heatmap(df, annot=False, cmap='plasma', cbar_kws={'label': 'BLER'})
plt.title(f"Polar Decoder BLER Heatmap (K={MESSAGE_LENGTH})")
plt.ylabel("Aggregation Level (E = 108 * Agg)")
plt.xlabel("SNR (dB)")
plot_file = "polar_bler_heatmap.png"
plt.savefig(plot_file)
print(f"Heatmap saved to {plot_file}")
except ImportError:
print("\nMatplotlib/Seaborn not found. Skipping plotting.")
except Exception as e:
print(f"\nPlotting failed: {e}")
finally:
oai.shutdown()

View File

@@ -0,0 +1,187 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "343fd19f",
"metadata": {},
"source": [
"# Testbench notebook work in progress.\n",
"\n",
"Currently it will **crash the kernel** after second run, when started in the test enviroment docker\n",
"\n",
"Code in here is the same as other python scripts in this python folder. Until the kernel crashing behavior is fixed, no new code will be writen in the form of a jupyter notebook"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "20c62db9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pre-allocating padded host memory for the CPU channel pipeline...\n",
"Original input: 0x12345678\n",
"Decoded output: 0x12345678\n",
"SUCCESS: Decoded output matches original input.\n",
"[NR_MAC] TDD period index = 6, based on the sum of dl_UL_TransmissionPeriodicity from Pattern1 (5.000000 ms) and Pattern2 (0.000000 ms): Total = 5.000000 ms\n",
"\u001b[0m[NR_MAC] Set TDD configuration period to: 8 DL slots, 3 UL slots, 10 slots per period (NR_TDD_UL_DL_Pattern is 7 DL slots, 2 UL slots, 6 DL symbols, 4 UL symbols)\n",
"\u001b[0m[NR_MAC] Configured 1 TDD patterns (total slots: pattern1 = 10, pattern2 = 0)\n",
"\u001b[0m[UTIL] threadCreate() for MAC_STATS: creating thread (no affinity, default priority)\n",
"\u001b[0m[NR_MAC] Set TX antenna number to 1, Set RX antenna number to 1 (num ssb 8: ff000000,0)\n",
"\u001b[0m[NR_MAC] TDD period index = 6, based on the sum of dl_UL_TransmissionPeriodicity from Pattern1 (5.000000 ms) and Pattern2 (0.000000 ms): Total = 5.000000 ms\n",
"\u001b[0m[NR_MAC] Set TDD configuration period to: 8 DL slots, 3 UL slots, 10 slots per period (NR_TDD_UL_DL_Pattern is 7 DL slots, 2 UL slots, 6 DL symbols, 4 UL symbols)\n",
"\u001b[0m[NR_MAC] Configured 1 TDD patterns (total slots: pattern1 = 10, pattern2 = 0)\n",
"\u001b"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[LOG] init aborted, configuration couldn't be performed\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0m[NR_PHY] Set TDD Period Configuration: 2 periods per frame, 20 slots to be configured (8 DL, 3 UL)\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 0 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 1 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 2 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 3 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 4 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 5 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 6 is DOWNLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 7 is FLEXIBLE: DDDDDDFFFFUUUU\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 8 is UPLINK\n",
"\u001b[0m[NR_PHY] TDD period configuration: slot 9 is UPLINK\n",
"\u001b[0m[PHY] DL frequency 3619080000 Hz, UL frequency 3619080000 Hz: uldl offset 0 Hz\n",
"\u001b[0m[PHY] Initializing frame parms for mu 1, N_RB 106, Ncp 0\n",
"\u001b[0m[PHY] Init: N_RB_DL 106, first_carrier_offset 1412, nb_prefix_samples 144,nb_prefix_samples0 176, ofdm_symbol_size 2048\n",
"\u001b[0m[NR_MAC] TDA index 0: start 0 length 12 k2 6\n",
"\u001b[0m[NR_MAC] TDA index 1: start 10 length 3 k2 6\n",
"\u001b[0m[NR_MAC] Adding new UE context with RNTI 0x1234\n",
"\u001b[0m[NR_MAC] Switching to DL-BWP 1\n",
"\u001b[0m[NR_MAC] Switching to UL-BWP 1\n",
"\u001b[0m[NR_MAC] Added new UE 1234 with initial CellGroup\n",
"\u001b[0m[PHY] L1 configured without analog beamforming\n",
"\u001b[0m[PHY] Loading dfts shared lib\n",
"\u001b[0mCMDLINE: \"phytest\" \"-O\" \"cmdlineonly::dbgl0\" \n",
"[OCM] Channel Model (inside of new_channel_desc_scm)=23\n",
"\n",
"\u001b[0m[OCM] [CHANNEL] Getting new channel descriptor, nb_tx 1, nb_rx 1, nb_taps 1, channel_length 1\n",
"\u001b[0mAWGN: ricean_factor 0.000000\n",
"Allocating 614400 samples for txdata\n",
"[PHY] Initializing UE vars for gNB TXant 1, UE RXant 1\n",
"\u001b[0m[PHY] prs_config configuration NOT found..!! Skipped configuring UE for the PRS reception\n",
"\u001b[0m[NR_MAC] [UE0] Initializing MAC\n",
"\u001b[0m[RLC] Activated srb0 for UE 0\n",
"\u001b[0m[NR_MAC] Initializing dl and ul config_request. num_slots = 20\n",
"\u001b[0m[MAC] [UE 0] Applying CellGroupConfig from gNodeB\n",
"\u001b[0m\u001b[32m[NR_MAC] Received reconfigurationWithSync\n",
"\u001b[0m[NR_MAC] Configuring CRNTI 1234\n",
"\u001b[0m[NR_MAC] [UE 0] Set dl_frequency=3600000 kHz (from absoluteFrequencyPointA=640000, band=78, scs=1)\n",
"\u001b[0m[NR_MAC] TDD period index = 6, based on the sum of dl_UL_TransmissionPeriodicity from Pattern1 (5.000000 ms) and Pattern2 (0.000000 ms): Total = 5.000000 ms\n",
"\u001b[0m[NR_MAC] Set TDD configuration period to: 8 DL slots, 3 UL slots, 10 slots per period (NR_TDD_UL_DL_Pattern is 7 DL slots, 2 UL slots, 6 DL symbols, 4 UL symbols)\n",
"\u001b[0m[NR_MAC] Configured 1 TDD patterns (total slots: pattern1 = 10, pattern2 = 0)\n",
"\u001b[0mParsing input for py_oaipylib_nr_polar_encoder\n",
"Calling oai_lib_nr_polar_encoder(0x2d9f7c00,0,0,0,32,0)\n",
"encoded Length 864 (uint32 list size 27), encoded output 303946609(0x121ddb71) (first 32 bits)\n",
"Allocating x for input of size 864\n",
"Calling oai_lib_nr_polar_decoder with ones_flag 0, messageType 0, messageLength 864, aggregation_level 0\n"
]
}
],
"source": [
"import math\n",
"import os\n",
"import sys\n",
"import random\n",
"sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)\n",
"import oaipylib as oai\n",
"import numpy as np\n",
"\n",
"\n",
"def bpsk(inp, array_size):\n",
" np_input = np.array(inp, dtype=np.uint32)\n",
" # Create an array of shape (num_integers, 32)\n",
" # Each row contains the bits of the corresponding integer\n",
" bits = ((np_input[:, None] >> np.arange(32, dtype=np.uint32)) & 1).flatten()[:array_size]\n",
" return (1 - 2 * bits.astype(np.int8)) / np.sqrt(2.0)\n",
"\n",
"def awgn(samples, SNRdB):\n",
" SNR_lin = 10**(SNRdB / 10.0)\n",
" noise_variance = (1 / (2.0 * SNR_lin))\n",
" sigma = np.sqrt(noise_variance)\n",
" # Use a fixed seed for reproducible results\n",
" random.seed(0)\n",
" out = []\n",
" for x in samples:\n",
" noisy = x + random.gauss(0.0, sigma)\n",
" q15 = int(round(noisy * 8.0))\n",
" if q15 > 127:\n",
" q15 = 127\n",
" elif q15 < -128:\n",
" q15 = -128\n",
" out.append(q15)\n",
" return np.array(out, dtype=np.int16)\n",
"\n",
"# --- Test Script ---\n",
"\n",
"oai.init()\n",
"\n",
"# 1. Define input data\n",
"encoder_input = np.array([0x12345678], dtype='Q')\n",
"\n",
"# 2. Call the OAI Polar Encoder\n",
"encoded_output = oai.nr_polar_encoder(encoder_input, 0, 0, 0, 32, 0)\n",
"encoded_len = 864\n",
"\n",
"# 3. Modulate using BPSK\n",
"bpsk_symbols = bpsk(encoded_output, encoded_len)\n",
"\n",
"# 4. Add AWGN and Quantize\n",
"SNRdB = 0\n",
"decoder_input = awgn(bpsk_symbols, SNRdB)\n",
"\n",
"# 5. Call the OAI Polar Decoder\n",
"decoder_output = oai.nr_polar_decoder(decoder_input, 0, 0, encoded_len, 0)\n",
"\n",
"# 6. Print result and shutdown\n",
"print(f\"Original input: {hex(encoder_input[0])}\")\n",
"print(f\"Decoded output: {hex(decoder_output[0])}\")\n",
"if encoder_input[0] == decoder_output[0]:\n",
" print(\"SUCCESS: Decoded output matches original input.\")\n",
"else:\n",
" print(\"FAILURE: Decoded output does not match original input.\")\n",
"\n",
"oai.shutdown()\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

3
python/pyproject.toml Normal file
View File

@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=61", "wheel"]
build-backend = "setuptools.build_meta"

20
python/setup.py Normal file
View File

@@ -0,0 +1,20 @@
from setuptools import Extension, setup
ext = Extension(
"oaipylib",
sources=[
"src/oaipylib_module.c",
"src/oaipylib_wrappers.c",
],
include_dirs=["src"],
libraries=["oaipy"],
library_dirs=["../build/python"],
runtime_library_dirs=["../build/python"],
extra_compile_args=["-O2"],
)
setup(
name="oaipylib",
version="0.1.0",
ext_modules=[ext],
)

33
python/src/oai_lib_api.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef OAI_LIB_API_H
#define OAI_LIB_API_H
#ifdef __cplusplus
extern "C" {
#endif
int oai_lib_init(void);
void oai_lib_shutdown(void);
int oai_lib_nr_polar_encoder(uint64_t *A,
void **out,
int32_t crcmask,
uint8_t ones_flag,
int8_t messageType,
uint16_t messageLength,
uint8_t aggregation_level);
int oai_lib_nr_polar_decoder(int16_t *x,
uint64_t *out,
uint8_t ones_flag,
int8_t messageType,
uint16_t messageLength,
uint8_t aggregation_level);
const char *oai_lib_last_error(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,43 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "oaipylib_wrappers.h"
static PyMethodDef oaipylib_methods[] = {
{"init", py_oaipylib_init, METH_NOARGS, "Initialize the underlying C library."},
{"shutdown", py_oaipylib_shutdown, METH_NOARGS, "Shutdown the underlying C library."},
{"nr_polar_encoder", py_oaipylib_nr_polar_encoder, METH_VARARGS, "3GPP NR Polar Encoder"},
{"nr_polar_decoder", py_oaipylib_nr_polar_decoder, METH_VARARGS, "16-bit LLR 3GPP NR Polar Decoder"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef oaipylib_module = {
PyModuleDef_HEAD_INIT,
"oaipylib",
"Python bindings for the OAI C library.",
-1,
oaipylib_methods
};
PyMODINIT_FUNC PyInit_oaipylib(void) {
PyObject *module = PyModule_Create(&oaipylib_module);
if (!module) {
return NULL;
}
PyObject *error = PyErr_NewException("oaipylib.Error", NULL, NULL);
if (!error) {
Py_DECREF(module);
return NULL;
}
if (PyModule_AddObject(module, "Error", error) < 0) {
Py_DECREF(error);
Py_DECREF(module);
return NULL;
}
oaipylib_set_exception_object(error);
return module;
}

798
python/src/oaipylib_top.c Normal file
View File

@@ -0,0 +1,798 @@
/*
* 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 <errno.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/utils/assertions.h"
#include "common/utils/nr/nr_common.h"
#include "common/utils/var_array.h"
#include "executables/nr-uesoftmodem.h"
#include "executables/softmodem-common.h"
#include "LAYER2/NR_MAC_UE/mac_defs.h"
#include "LAYER2/NR_MAC_UE/mac_proto.h"
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
#include "LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
#include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "LAYER2/NR_MAC_gNB/nr_radio_config.h"
#include "NR_BCCH-BCH-Message.h"
#include "NR_BWP-Downlink.h"
#include "NR_CellGroupConfig.h"
#include "NR_MAC_COMMON/nr_mac.h"
#include "NR_MAC_COMMON/nr_mac_common.h"
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
#include "NR_ReconfigurationWithSync.h"
#include "NR_ServingCellConfig.h"
#include "NR_SetupRelease.h"
#include "NR_UE_PHY_INTERFACE/NR_IF_Module.h"
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
#include "PHY/INIT/nr_phy_init.h"
#include "PHY/MODULATION/modulation_common.h"
#include "PHY/NR_REFSIG/ptrs_nr.h"
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/defs_RU.h"
#include "PHY/defs_gNB.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/defs_nr_common.h"
#include "PHY/impl_defs_nr.h"
#include "PHY/phy_vars_nr_ue.h"
#include "SCHED_NR/sched_nr.h"
#include "SCHED_NR_UE/defs.h"
#include "SCHED_NR_UE/fapi_nr_ue_l1.h"
#include "T.h"
#include "asn_internal.h"
#include "assertions.h"
#include "common/config/config_load_configmodule.h"
#include "common/ngran_types.h"
#include "common/ran_context.h"
#include "common/utils/T/T.h"
#include "common/utils/nr/nr_common.h"
#include "common/utils/var_array.h"
#include "common_lib.h"
#include "e1ap_messages_types.h"
#include "fapi_nr_ue_interface.h"
#include "nfapi_interface.h"
#include "nfapi_nr_interface.h"
#include "nfapi_nr_interface_scf.h"
#include "nr_ue_phy_meas.h"
#include "oai_asn1.h"
#include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h"
#include "openair1/SIMULATION/TOOLS/sim.h"
#include "thread-pool.h"
#include "time_meas.h"
#include "utils.h"
#define inMicroS(a) (((double)(a))/(get_cpu_freq_GHz()*1000.0))
#include "SIMULATION/LTE_PHY/common_sim.h"
#ifdef __cplusplus
extern "C" {
#endif
PHY_VARS_gNB *gNB;
PHY_VARS_NR_UE *UE;
RAN_CONTEXT_t RC;
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
double cpuf;
char *uecap_file;
//uint8_t nfapi_mode = 0;
uint64_t downlink_frequency[MAX_NUM_CCs][4];
THREAD_STRUCT thread_struct;
nfapi_ue_release_request_body_t release_rntis;
//Fixme: Uniq dirty DU instance, by global var, datamodel need better management
instance_t DUuniqInstance=0;
instance_t CUuniqInstance=0;
// needed for some functions
openair0_config_t openair0_cfg[MAX_CARDS];
configmodule_interface_t *uniqCfg = NULL;
int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); }
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); }
void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); }
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); }
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) {
return 0;
}
void processSlotTX(void *arg) {}
// needed for some functions
openair0_config_t openair0_cfg[MAX_CARDS];
void update_ptrs_config(NR_CellGroupConfig_t *secondaryCellGroup, uint16_t *rbSize, uint8_t *mcsIndex,int8_t *ptrs_arg);
void update_dmrs_config(NR_CellGroupConfig_t *scg, int8_t* dmrs_arg);
extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration
/* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs/nrOfLayers from command line of dlsim */
int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLayers = 1, g_pmi = 0;
void nr_dlsim_preprocessor(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch)
{
NR_UE_info_t *UE_info = nr_mac->UE_info.connected_ue_list[0];
AssertFatal(nr_mac->UE_info.connected_ue_list[1] == NULL, "Only single UE allowed in dlsim\n");
NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl;
NR_UE_DL_BWP_t *current_BWP = &UE_info->current_DL_BWP;
NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon;
int nr_of_candidates = 0;
if (g_mcsIndex < 4) {
find_aggregation_candidates(&sched_ctrl->aggregation_level, &nr_of_candidates, sched_ctrl->search_space, 8);
}
if (nr_of_candidates == 0) {
find_aggregation_candidates(&sched_ctrl->aggregation_level, &nr_of_candidates, sched_ctrl->search_space, 4);
}
uint32_t Y = get_Y(sched_ctrl->search_space, pp_pdsch->slot, UE_info->rnti);
int CCEIndex = find_pdcch_candidate(nr_mac,
/* CC_id = */ 0,
sched_ctrl->aggregation_level,
nr_of_candidates,
0,
&sched_ctrl->sched_pdcch,
sched_ctrl->coreset,
Y);
AssertFatal(CCEIndex >= 0,
"%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n",
pp_pdsch->frame,
pp_pdsch->slot,
0,
UE_info->rnti);
sched_ctrl->cce_index = CCEIndex;
NR_sched_pdsch_t sched_pdsch = {
.rbStart = g_rbStart,
.rbSize = g_rbSize,
.bwp_info = get_pdsch_bwp_start_size(nr_mac, UE_info),
.mcs = g_mcsIndex,
.nrOfLayers = g_nrOfLayers,
.pm_index = g_pmi,
};
/* the following might override the table that is mandated by RRC
* configuration */
current_BWP->mcsTableIdx = g_mcsTableIdx;
sched_pdsch.time_domain_allocation = get_dl_tda(nr_mac, pp_pdsch->slot);
AssertFatal(sched_pdsch.time_domain_allocation >= 0,"Unable to find PDSCH time domain allocation in list\n");
sched_pdsch.tda_info = get_dl_tda_info(current_BWP,
sched_ctrl->search_space->searchSpaceType->present,
sched_pdsch.time_domain_allocation,
NR_MIB__dmrs_TypeA_Position_pos2,
1,
TYPE_C_RNTI_,
sched_ctrl->coreset->controlResourceSetId,
false);
sched_pdsch.dmrs_parms = get_dl_dmrs_params(scc,
current_BWP,
&sched_pdsch.tda_info,
sched_pdsch.nrOfLayers);
sched_pdsch.Qm = nr_get_Qm_dl(sched_pdsch.mcs, current_BWP->mcsTableIdx);
sched_pdsch.R = nr_get_code_rate_dl(sched_pdsch.mcs, current_BWP->mcsTableIdx);
sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm,
sched_pdsch.R,
sched_pdsch.rbSize,
sched_pdsch.tda_info.nrOfSymbols,
sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT,
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
sched_pdsch.nrOfLayers) >> 3;
/* the simulator assumes the HARQ PID is equal to the slot number */
sched_pdsch.dl_harq_pid = pp_pdsch->slot;
/* The scheduler uses lists to track whether a HARQ process is
* free/busy/awaiting retransmission, and updates the HARQ process states.
* However, in the simulation, we never get ack or nack for any HARQ process,
* thus the list and HARQ states don't match what the scheduler expects.
* Therefore, below lines just "repair" everything so that the scheduler
* won't remark that there is no HARQ feedback */
sched_ctrl->feedback_dl_harq.head = -1; // always overwrite feedback HARQ process
if (sched_ctrl->harq_processes[pp_pdsch->slot].round == 0) // depending on round set in simulation ...
add_front_nr_list(&sched_ctrl->available_dl_harq, pp_pdsch->slot); // ... make PID available
else
add_front_nr_list(&sched_ctrl->retrans_dl_harq, pp_pdsch->slot); // ... make PID retransmission
sched_ctrl->harq_processes[pp_pdsch->slot].is_waiting = false;
AssertFatal(sched_pdsch.rbStart >= 0, "invalid rbStart %d\n", sched_pdsch.rbStart);
AssertFatal(sched_pdsch.rbSize > 0, "invalid rbSize %d\n", sched_pdsch.rbSize);
AssertFatal(sched_pdsch.mcs >= 0, "invalid mcs %d\n", sched_pdsch.mcs);
AssertFatal(current_BWP->mcsTableIdx >= 0 && current_BWP->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", current_BWP->mcsTableIdx);
post_process_dlsch(nr_mac, pp_pdsch, UE_info, &sched_pdsch);
}
nrUE_params_t nrUE_params;
nrUE_params_t *get_nrUE_params(void) {
return &nrUE_params;
}
void validate_input_pmi(nfapi_nr_config_request_scf_t *gNB_config,
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts,
int nrOfLayers,
int pmi)
{
if (pmi == 0)
return;
nfapi_nr_pm_pdu_t *pmi_pdu = &gNB_config->pmi_list.pmi_pdu[pmi - 1]; // pmi 0 is identity matrix
AssertFatal(pmi == pmi_pdu->pm_idx, "PMI %d doesn't match to the one in precoding matrix %d\n", pmi, pmi_pdu->pm_idx);
AssertFatal(nrOfLayers == pmi_pdu->numLayers, "Number of layers %d doesn't match to the one in precoding matrix %d for PMI %d\n",
nrOfLayers, pmi_pdu->numLayers, pmi);
int num_antenna_ports = pdsch_AntennaPorts.N1 * pdsch_AntennaPorts.N2 * pdsch_AntennaPorts.XP;
AssertFatal(num_antenna_ports == pmi_pdu->num_ant_ports, "Configured antenna ports %d does not match precoding matrix AP size %d for PMI %d\n",
num_antenna_ports, pmi_pdu->num_ant_ports, pmi);
}
float **s_interleaved, **r_re, **r_im;
uint8_t n_tx=1,n_rx=1;
channel_desc_t *gNB2UE;
channel_desc_t *UE2gNB;
NR_Sched_Rsp_t *Sched_INFO;
c16_t **txdata;
int oai_lib_init() {
stop = false;
__attribute__((unused)) struct sigaction oldaction;
sigaction(SIGINT, &sigint_action, &oldaction);
FILE *csv_file = NULL;
char *filename_csv = NULL;
setbuf(stdout, NULL);
int c;
int i,aa;//,l;
double SNR, snr0 = -2.0, snr1 = 2.0;
uint8_t snr1set=0;
double effRate;
//float psnr;
double eff_tp_check = 0.7;
uint32_t TBS = 0;
//double iqim = 0.0;
//unsigned char pbch_pdu[6];
// int sync_pos, sync_pos_slot;
// FILE *rx_frame_file;
FILE *output_fd = NULL;
//uint8_t write_output_file=0;
//int result;
//int freq_offset;
// int subframe_offset;
// char fname[40], vname[40];
int trial, n_trials = 1, n_false_positive = 0;
//int n_errors2, n_alamouti;
uint8_t round;
uint8_t num_rounds = 4;
char gNBthreads[128]="n";
//uint32_t nsymb,tx_lev,tx_lev1 = 0,tx_lev2 = 0;
//uint8_t extended_prefix_flag=0;
//int8_t interf1=-21,interf2=-21;
FILE *input_fd=NULL,*pbch_file_fd=NULL;
//char input_val_str[50],input_val_str2[50];
//uint8_t frame_mod4,num_pdcch_symbols = 0;
SCM_t channel_model = AWGN; // AWGN Rayleigh1 Rayleigh1_anticorr;
double DS_TDL = .03;
int delay = 0;
//double pbch_sinr;
//int pbch_tx_ant;
int N_RB_DL=106,mu=1;
//unsigned char frame_type = 0;
int frame=1,slot=1;
int frame_length_complex_samples;
//int frame_length_complex_samples_no_prefix;
NR_DL_FRAME_PARMS *frame_parms;
UE_nr_rxtx_proc_t UE_proc;
gNB_MAC_INST *gNB_mac;
NR_UE_MAC_INST_t *UE_mac;
int cyclic_prefix_type = NFAPI_CP_NORMAL;
int loglvl=OAILOG_INFO;
//float target_error_rate = 0.01;
cpuf = get_cpu_freq_GHz();
int8_t enable_ptrs = 0;
int8_t modify_dmrs = 0;
int8_t dmrs_arg[3] = {-1,-1,-1};// Invalid values
/* L_PTRS = ptrs_arg[0], K_PTRS = ptrs_arg[1] */
int8_t ptrs_arg[2] = {-1,-1};// Invalid values
uint16_t ptrsRePerSymb = 0;
uint16_t pdu_bit_map = 0x0;
uint16_t dlPtrsSymPos = 0;
uint16_t ptrsSymbPerSlot = 0;
uint16_t rbSize = 106;
uint8_t mcsIndex = 9;
uint8_t dlsch_threads = 0;
int chest_type[2] = {0};
uint8_t max_ldpc_iterations = 5;
int print_perf = 0;
int use_cuda = 0;
void *h_tx_sig_pinned = NULL;
#ifdef ENABLE_CUDA
void *d_tx_sig = NULL, *d_intermediate_sig = NULL, *d_final_output = NULL;
void *d_curand_states = NULL;
void *h_final_output_pinned = NULL;
void *d_channel_coeffs_gpu = NULL;
#endif
logInit();
set_glog(loglvl);
/* initialize the sin table */
InitSinLUT();
#ifdef ENABLE_CUDA
init_cuda_chsim_buffers(use_cuda,
n_tx,
n_rx,
&d_tx_sig,
&d_intermediate_sig,
&d_final_output,
&d_curand_states,
&h_tx_sig_pinned,
&h_final_output_pinned,
&d_channel_coeffs_gpu);
#endif
#if !defined(ENABLE_CUDA) || !use_cuda
printf("Pre-allocating padded host memory for the CPU channel pipeline...\n");
int num_samples_alloc = 153600;
const int max_padding_alloc = 256 - 1;
size_t padded_tx_alloc_bytes = n_tx * (num_samples_alloc + max_padding_alloc) * 2 * sizeof(float);
h_tx_sig_pinned = malloc(padded_tx_alloc_bytes);
if (h_tx_sig_pinned == NULL) {
printf("Error: Failed to allocate host buffer for CPU path\n");
exit(-1);
}
#endif
get_softmodem_params()->phy_test = 1;
get_softmodem_params()->do_ra = 0;
IS_SOFTMODEM_DLSIM = true;
RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *));
RC.gNB[0] = (PHY_VARS_gNB*) malloc(sizeof(PHY_VARS_gNB ));
memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB));
gNB = RC.gNB[0];
gNB->ofdm_offset_divisor = UINT_MAX;
gNB->phase_comp = true; // we need to perform phase compensation, otherwise everything will fail
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
frame_parms->nb_antennas_tx = n_tx;
frame_parms->nb_antennas_rx = n_rx;
frame_parms->N_RB_DL = N_RB_DL;
frame_parms->N_RB_UL = N_RB_DL;
AssertFatal((gNB->if_inst = NR_IF_Module_init(0)) != NULL, "Cannot register interface");
gNB->if_inst->NR_PHY_config_req = nr_phy_config_request;
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));;
prepare_scc(scc);
uint64_t ssb_bitmap = 1; // Enable only first SSB with index ssb_indx=0
fill_scc_sim(scc, &ssb_bitmap, N_RB_DL, N_RB_DL, mu, mu);
fix_scc(scc, ssb_bitmap);
frame_structure_t frame_structure = {0};
frame_type_t frame_type = TDD;
config_frame_structure(mu,
scc->tdd_UL_DL_ConfigurationCommon,
get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon),
frame_type,
&frame_structure);
AssertFatal(is_dl_slot(slot, &frame_structure), "The slot selected is not DL. Can't run DLSIM\n");
// TODO do a UECAP for phy-sim
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts = {0};
pdsch_AntennaPorts.N1 = n_tx > 1 ? n_tx >> 1 : 1;
pdsch_AntennaPorts.N2 = 1;
pdsch_AntennaPorts.XP = n_tx > 1 ? 2 : 1;
const nr_mac_config_t conf = {.pdsch_AntennaPorts = pdsch_AntennaPorts,
.pusch_AntennaPorts = n_tx,
.minRXTXTIME = 6,
.do_CSIRS = 0,
.do_SRS = 0,
.num_dlharq = 16,
.num_ulharq = 16,
.maxMIMO_layers = g_nrOfLayers,
.force_256qam_off = false,
.timer_config.sr_ProhibitTimer = 0,
.timer_config.sr_TransMax = 64,
.timer_config.sr_ProhibitTimer_v1700 = 0,
.timer_config.t300 = 400,
.timer_config.t301 = 400,
.timer_config.t310 = 2000,
.timer_config.n310 = 10,
.timer_config.t311 = 3000,
.timer_config.n311 = 1,
.timer_config.t319 = 400,
.num_agg_level_candidates = {0, 0, 1, 1, 0}};
const nr_rlc_configuration_t rlc_config = {
.srb = {
.t_poll_retransmit = 45,
.t_reassembly = 35,
.t_status_prohibit = 0,
.poll_pdu = -1,
.poll_byte = -1,
.max_retx_threshold = 8,
.sn_field_length = 12,
},
.drb_am = {
.t_poll_retransmit = 45,
.t_reassembly = 15,
.t_status_prohibit = 15,
.poll_pdu = 64,
.poll_byte = 1024 * 500,
.max_retx_threshold = 32,
.sn_field_length = 18,
},
.drb_um = {
.t_reassembly = 15,
.sn_field_length = 12,
}
};
RC.nb_nr_macrlc_inst = 1;
RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int));
for (i = 0; i < RC.nb_nr_macrlc_inst; i++)
RC.nb_nr_mac_CC[i] = 1;
mac_top_init_gNB(ngran_gNB, scc, &conf, &rlc_config);
gNB_mac = RC.nrmac[0];
nr_mac_config_scc(RC.nrmac[0], scc, &conf);
gNB_mac->dl_bler.harq_round_max = num_rounds;
gNB->ap_N1 = pdsch_AntennaPorts.N1;
gNB->ap_N2 = pdsch_AntennaPorts.N2;
gNB->ap_XP = pdsch_AntennaPorts.XP;
validate_input_pmi(&gNB_mac->config[0], pdsch_AntennaPorts, g_nrOfLayers, g_pmi);
NR_UE_NR_Capability_t *UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_DL, g_mcsTableIdx, 0);
rnti_t rnti = 0x1234;
int uid = 0;
int ssb_index = 0;
NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, UE_Capability_nr, 0, 1, &conf, uid, ssb_index);
secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc, frame);
/* -U option modify DMRS */
if(modify_dmrs) {
update_dmrs_config(secondaryCellGroup, dmrs_arg);
}
/* -T option enable PTRS */
if(enable_ptrs) {
update_ptrs_config(secondaryCellGroup, &rbSize, &mcsIndex, ptrs_arg);
}
//xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
// UE dedicated configuration
nr_mac_add_test_ue(RC.nrmac[0], rnti, secondaryCellGroup);
// reset preprocessor to the one of DLSIM after it has been set during
// nr_mac_config_scc()
gNB_mac->pre_processor_dl = nr_dlsim_preprocessor;
phy_init_nr_gNB(gNB);
N_RB_DL = gNB->frame_parms.N_RB_DL;
NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.connected_ue_list[0];
configure_UE_BWP(RC.nrmac[0], scc, UE_info, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1);
// stub to configure frame_parms
// nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions);
// call MAC to configure common parameters
/* nr_mac_add_test_ue() has created one user, so set the scheduling
* parameters from command line in global variables that will be picked up by
* scheduling preprocessor */
if (g_mcsIndex < 0) g_mcsIndex = 9;
if (g_rbStart < 0) g_rbStart=0;
if (g_rbSize < 0) g_rbSize = N_RB_DL - g_rbStart;
double fs,txbw,rxbw;
get_samplerate_and_bw(mu,
N_RB_DL,
frame_parms->threequarter_fs,
&fs,
&txbw,
&rxbw);
gNB2UE = new_channel_desc_scm(n_tx,
n_rx,
channel_model,
fs/1e6,//sampling frequency in MHz
0,
txbw,
DS_TDL,
0.0,
CORR_LEVEL_LOW,
0,
delay,
0,
0);
#ifdef ENABLE_CUDA
float *h_channel_coeffs = NULL;
if (use_cuda) {
int num_links = n_tx * n_rx;
h_channel_coeffs = (float *)malloc(num_links * gNB2UE->channel_length * sizeof(float) * 2);
}
#endif
if (gNB2UE==NULL) {
printf("Problem generating channel model. Exiting.\n");
exit(-1);
}
frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
//frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
int slot_offset = get_samples_slot_timestamp(frame_parms, slot);
int slot_length = slot_offset - get_samples_slot_timestamp(frame_parms, slot - 1);
s_interleaved = malloc(n_tx * sizeof(float *));
r_re = malloc(n_rx * sizeof(float *));
r_im = malloc(n_rx * sizeof(float *));
txdata = malloc(n_tx * sizeof(int *));
for (i = 0; i < n_tx; i++) {
s_interleaved[i] = malloc(slot_length * 2 * sizeof(float));
printf("Allocating %d samples for txdata\n", frame_length_complex_samples);
txdata[i] = calloc(1, frame_length_complex_samples * sizeof(int));
}
for (i = 0; i < n_rx; i++) {
r_re[i] = calloc(1, slot_length * sizeof(float));
r_im[i] = calloc(1, slot_length * sizeof(float));
}
//configure UE
UE = malloc(sizeof(PHY_VARS_NR_UE));
memset((void*)UE,0,sizeof(PHY_VARS_NR_UE));
PHY_vars_UE_g = malloc(sizeof(PHY_VARS_NR_UE**));
PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE*));
PHY_vars_UE_g[0][0] = UE;
memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
UE->frame_parms.nb_antennas_rx = n_rx;
UE->frame_parms.nb_antenna_ports_gNB = n_tx;
UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface;
UE->max_ldpc_iterations = max_ldpc_iterations;
init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats);
UE->is_synchronized = 1;
if (init_nr_ue_signal(UE, 1) != 0)
{
printf("Error at UE NR initialisation\n");
exit(-1);
}
init_nr_ue_transport(UE);
UE_mac = nr_l2_init_ue(0, mu);
ue_init_config_request(UE_mac, get_slots_per_frame_from_scs(mu));
UE->if_inst = nr_ue_if_module_init(0);
UE->if_inst->scheduled_response = nr_ue_scheduled_response;
UE->if_inst->phy_config_request = nr_ue_phy_config_request;
UE->if_inst->dl_indication = nr_ue_dl_indication;
UE->if_inst->ul_indication = dummy_nr_ue_ul_indication;
UE->chest_freq = chest_type[0];
UE->chest_time = chest_type[1];
UE_mac->if_module = nr_ue_if_module_init(0);
initFloatingCoresTpool(dlsch_threads, &nrUE_params.Tpool, false, "UE-tpool");
// generate signal
AssertFatal(input_fd==NULL,"Not ready for input signal file\n");
// clone CellGroup to have a separate copy at UE
NR_CellGroupConfig_t *UE_CellGroup = clone_CellGroupConfig(secondaryCellGroup);
//Configure UE
NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc);
nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false);
nr_rrc_mac_config_req_cg(0, 0, 0, 0, UE_CellGroup, UE_Capability_nr);
asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, UE_CellGroup);
UE_mac->state = UE_CONNECTED;
UE_mac->ra.ra_state = nrRA_SUCCEEDED;
nr_phy_data_t phy_data = {0};
fapi_nr_dl_config_request_t dl_config = {.sfn = frame, .slot = slot};
nr_scheduled_response_t scheduled_response = {.dl_config = &dl_config, .phy_data = &phy_data, .mac = UE_mac};
nr_ue_phy_config_request(&UE_mac->phy_config);
//NR_COMMON_channels_t *cc = RC.nrmac[0]->common_channels;
int ret = 1;
initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool");
initNotifiedFIFO(&gNB->L1_tx_out);
// Buffers to store internal memory of slot process
int rx_size = (((14 * UE->frame_parms.N_RB_DL * 12 * sizeof(int32_t)) + 15) >> 4) << 4;
UE->phy_sim_rxdataF = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers,
UE->frame_parms.samples_per_slot_wCP * sizeof(int32_t));
UE->phy_sim_pdsch_llr = calloc(1, (8 * (3 * 8 * 8448)) * sizeof(int16_t)); // Max length
UE->phy_sim_pdsch_rxdataF_ext = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
UE->phy_sim_pdsch_rxdataF_comp = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
UE->phy_sim_pdsch_dl_ch_estimates = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
UE->phy_sim_pdsch_dl_ch_estimates_ext = calloc(sizeof(int32_t *) * UE->frame_parms.nb_antennas_rx * g_nrOfLayers, rx_size);
int a_segments = MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*NR_MAX_NB_LAYERS; //number of segments to be allocated
if (g_rbSize != 273) {
a_segments = a_segments*g_rbSize;
a_segments = (a_segments/273)+1;
}
uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
UE->phy_sim_dlsch_b = calloc(1, dlsch_bytes);
// csv file
if (filename_csv != NULL) {
csv_file = fopen(filename_csv, "a");
if (csv_file == NULL) {
printf("Can't open file \"%s\", errno %d\n", filename_csv, errno);
free(s_interleaved);
free(r_re);
free(r_im);
free(txdata);
return 1;
}
// adding name of parameters into file
fprintf(csv_file,"SNR,false_positive,");
for (int r = 0; r < num_rounds; r++)
fprintf(csv_file,"n_errors_%d,errors_scrambling_%d,channel_bler_%d,channel_ber_%d,",r,r,r,r);
fprintf(csv_file,"avg_round,eff_rate,eff_throughput,TBS\n");
}
//---------------
Sched_INFO = memalign(32, sizeof(*Sched_INFO));
if (Sched_INFO == NULL) {
LOG_E(PHY, "out of memory\n");
exit(1);
}
return 0;
}
void oai_lib_shutdown(void) {
free(Sched_INFO);
if (gNB2UE) free_channel_desc_scm(gNB2UE);
if (UE2gNB) free_channel_desc_scm(UE2gNB);
for (int i = 0; i < n_tx; i++) {
free(s_interleaved[i]);
free(txdata[i]);
}
for (int i = 0; i < n_rx; i++) {
free(r_re[i]);
free(r_im[i]);
}
#ifdef ENABLE_CUDA
free_cuda_chsim_buffers(use_cuda,
&d_tx_sig,
&d_intermediate_sig,
&d_final_output,
&d_curand_states,
&h_tx_sig_pinned,
&h_final_output_pinned,
&h_channel_coeffs,
&d_channel_coeffs_gpu);
#endif
free(s_interleaved);
free(r_re);
free(r_im);
free(txdata);
free(UE->phy_sim_rxdataF);
free(UE->phy_sim_pdsch_llr);
free(UE->phy_sim_pdsch_rxdataF_ext);
free(UE->phy_sim_pdsch_rxdataF_comp);
free(UE->phy_sim_pdsch_dl_ch_estimates);
free(UE->phy_sim_pdsch_dl_ch_estimates_ext);
free(UE->phy_sim_dlsch_b);
free_nrLDPC_coding_interface(&gNB->nrLDPC_coding_interface);
}
int oai_lib_nr_polar_decoder(int16_t *x,
uint64_t *out,
uint8_t ones_flag,
int8_t messageType,
uint16_t messageLength,
uint8_t aggregation_level) {
polar_decoder_int16(x, out, ones_flag, messageType, messageLength,aggregation_level);
return 0;
}
int oai_lib_nr_polar_encoder(uint64_t *A,
void **out,
int32_t crcmask,
uint8_t ones_flag,
int8_t messageType,
uint16_t messageLength,
uint8_t aggregation_level) {
// A is the input which is at most 64 bits
// out is the rate-matched output, encoded as a bit-packed 32-bit element array. The expected length in bits depends on the messageType:
// messageType = 0 => PBCH => output length (bits) = 864 bits (27 32-bit words)
// messageType = 1 => DCI => output length (bits) = 108 * aggregation_level
// messageType = 2 => PUCCH => output length (bits) = 16 * aggregation_level
// messageType = 3 => PSBCH =? output length (bits) = 1792 bits (56 32-bit words))
// crc is automatically computed based on the messageLength and messageType and crcmask is applied to the resultant CRC if required. Set to 0 if not required
// ones_flag is used to append 24 1's at the beginning of a DCI message prior to computing the CRC parity
// aggregation_level is 1,2,4,8,16
int encodedLength=0;
switch(messageType) {
case 0: //PBCH
default:
encodedLength = 864;
break;
case 1: //DCI
encodedLength = (108*aggregation_level);
break;
case 2: //UCI/PUCCH
encodedLength = (16*aggregation_level);
break;
case 3: //PSBCH
encodedLength = 1792;
}
*out = malloc(1+(encodedLength>>3));
polar_encoder_fast(A,*out,crcmask,ones_flag,messageType,messageLength,aggregation_level);
return(encodedLength);
}
const char *oai_lib_last_error(void) {
}
#ifdef __cplusplus
}
#endif

21
python/src/oaipylib_top.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* 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
*/

View File

@@ -0,0 +1,185 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdlib.h>
#include <limits.h>
#include "oaipylib_wrappers.h"
#include "oai_lib_api.h"
#define ARRAY_LENGTH 27
static PyObject *OaipylibError = NULL;
void oaipylib_set_exception_object(PyObject *exc) {
OaipylibError = exc;
}
PyObject *oaipylib_raise_error(const char *context) {
const char *msg = oai_lib_last_error();
if (msg == NULL) {
msg = "unknown library error";
}
if (OaipylibError) {
PyErr_Format(OaipylibError, "%s: %s", context, msg);
} else {
PyErr_Format(PyExc_RuntimeError, "%s: %s", context, msg);
}
return NULL;
}
PyObject *py_oaipylib_init(PyObject *self, PyObject *args) {
(void)self;
(void)args;
if (oai_lib_init() != 0) {
return oaipylib_raise_error("oai_lib_init failed");
}
Py_RETURN_NONE;
}
PyObject *py_oaipylib_shutdown(PyObject *self, PyObject *args) {
(void)self;
(void)args;
oai_lib_shutdown();
Py_RETURN_NONE;
}
PyObject *py_oaipylib_nr_polar_encoder(PyObject *self, PyObject *args) {
(void)self;
uint32_t **out; // output is allocated in OAI API function
PyObject *out_obj = NULL;
PyObject *buffer_obj;
Py_buffer py_A;
int32_t crcmask;
uint8_t ones_flag;
uint8_t messageType;
uint16_t messageLength;
uint8_t aggregation_level;
printf("Parsing input for py_oaipylib_nr_polar_encoder\n");
// parse the buffer object instead
if (!PyArg_ParseTuple(args, "OibbHb", &buffer_obj, &crcmask, &ones_flag,&messageType,&messageLength,&aggregation_level)) {
return NULL;
}
// extracting information from the buffer
if (PyObject_GetBuffer(buffer_obj, &py_A, PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT)==-1){
return NULL;
}
// check the array dimension
if(py_A.ndim != 1) {
PyErr_SetString(PyExc_TypeError, "Encoder input is expected to be 1-D array");
PyBuffer_Release(&py_A);
return NULL;
}
// check types of the items in the array
// add also 'L' ?
if (strcmp(py_A.format,"Q") != 0) {
PyErr_SetString(PyExc_TypeError, "Expected an array of uint64_t");
PyBuffer_Release(&py_A);
return NULL;
}
// pass the raw buffer to the C function
out = malloc(sizeof(uint32_t*));
printf("Calling oai_lib_nr_polar_encoder(%p,%x,%d,%d,%d,%d)\n", out, crcmask, ones_flag, (int8_t)messageType, messageLength,aggregation_level);
int encodedLength = oai_lib_nr_polar_encoder(py_A.buf, (void**)out, crcmask, ones_flag, (int8_t)messageType, messageLength,aggregation_level);
if (encodedLength <= 0) return oaipylib_raise_error("oai_lib_nr_polar_encoder failed");
int encodedLength_u32 = (encodedLength>>5) + ((encodedLength&31) > 0 ? 1 : 0);
printf("encoded Length %d (uint32 list size %d), encoded output %d(0x%x) (first 32 bits)\n",encodedLength,encodedLength_u32,(*out)[0],(*out)[0]);
// once done working with the buffer, release it
PyBuffer_Release(&py_A);
PyObject *result = PyList_New(encodedLength_u32);
if (!result) {
free(out);
free(*out);
return NULL;
}
for (Py_ssize_t i = 0; i < encodedLength_u32; ++i) {
PyObject *value = PyLong_FromUnsignedLong((unsigned long)((*out)[i]));
if (!value) {
Py_DECREF(result);
free(*out);
free(out);
return NULL;
}
PyList_SET_ITEM(result, i, value);
}
free(*out);
free(out);
return result;
}
PyObject *py_oaipylib_nr_polar_decoder(PyObject *self, PyObject *args) {
(void)self;
PyObject *input_obj = NULL;
uint64_t out; // output stored
uint8_t ones_flag;
int8_t messageType;
uint16_t messageLength;
uint8_t aggregation_level;
if (!PyArg_ParseTuple(args, "ObbHb", &input_obj, &ones_flag,&messageType,&messageLength,&aggregation_level)) {
return NULL;
}
PyObject *seq = PySequence_Fast(input_obj, "input must be a sequence");
if (!seq) {
return NULL;
}
Py_ssize_t n = PySequence_Fast_GET_SIZE(seq);
if (n <= 0) {
Py_DECREF(seq);
PyErr_SetString(PyExc_ValueError, "input sequence must not be empty");
return NULL;
}
printf("Allocating x for input of size %d\n",n);
int16_t *x = (int16_t *)malloc((size_t)n * sizeof(int16_t));
if (!x) {
Py_DECREF(seq);
PyErr_NoMemory();
return NULL;
}
PyObject **items = PySequence_Fast_ITEMS(seq);
for (Py_ssize_t i = 0; i < n; ++i) {
x[i] = (int16_t)(PyLong_AsLong(items[i]));
if (PyErr_Occurred()) {
Py_DECREF(seq);
free(x);
return NULL;
}
}
printf("Calling oai_lib_nr_polar_decoder with ones_flag %d, messageType %d, messageLength %d, aggregation_level %d\n",
ones_flag,messageType,messageLength,aggregation_level);
int rc = oai_lib_nr_polar_decoder(x, &out, ones_flag, messageType, messageLength,aggregation_level);
Py_DECREF(seq);
free(x);
if (rc != 0) {
return oaipylib_raise_error("oai_lib_run_algorithm failed");
}
// printf("output : %x\n",out);
PyObject *result = PyList_New(1);
if (!result) {
return NULL;
}
PyList_SET_ITEM(result, 0, PyLong_FromUnsignedLongLong((unsigned long long)out));
return result;
}

View File

@@ -0,0 +1,14 @@
#ifndef OAIPYLIB_WRAPPERS_H
#define OAIPYLIB_WRAPPERS_H
#include <Python.h>
PyObject *py_oaipylib_init(PyObject *self, PyObject *args);
PyObject *py_oaipylib_shutdown(PyObject *self, PyObject *args);
PyObject *py_oaipylib_nr_polar_encoder(PyObject *self, PyObject *args);
PyObject *py_oaipylib_nr_polar_decoder(PyObject *self, PyObject *args);
PyObject *oaipylib_raise_error(const char *context);
void oaipylib_set_exception_object(PyObject *exc);
#endif