Compare commits

...

7 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
cb71140665 Add ENABLE_RESTAPI cmake option
This option guards against downloading REST API related packages in case
they are not needed.
2024-12-05 16:58:04 +01:00
Bartosz Podrygajlo
d8d2832141 Use compact pointer names in simulator_rest_api.cpp 2024-12-05 16:58:04 +01:00
Bartosz Podrygajlo
36b0f09652 Replace the usage of crow::json with nlohmann::json
Use nlohmann::json instead of crow::json, this allows a more clear separation between
the json serialization library and the REST API library.
2024-12-05 16:58:04 +01:00
Bartosz Podrygajlo
2b3d555059 UE REST API as a shared object library
REST API for the UE can be enabled using --rest-api flag
2024-12-05 16:57:57 +01:00
Bartosz Podrygajlo
0a0a784afb Fix phy rest api for cpumeas stats 2024-12-05 16:30:43 +01:00
Bartosz Podrygajlo
7ee1647e2f Add rest api to rfsim
Add simple rest api to rfsimulator that allows changing of pathloss during runtime.
Fix an error in nrue.uicc.yaml config for rfsimulator
Add rfsimulator config to gnb.sa.band78.fr1.106PRB.usrpb210.yaml
2024-12-05 16:30:43 +01:00
Bartosz Podrygajlo
071d084e9d Crow-based REST API 2024-12-05 16:30:39 +01:00
17 changed files with 481 additions and 104 deletions

View File

@@ -299,6 +299,7 @@ message(STATUS "Selected KPM Version: ${KPM_VERSION}")
add_boolean_option(ENABLE_IMSCOPE OFF "Enable phy scope based on imgui" OFF)
add_boolean_option(ENABLE_RESTAPI OFF "Build the REST API modules" OFF)
##################################################
# ASN.1 grammar C code generation & dependencies #
@@ -2371,6 +2372,24 @@ if(ENABLE_TESTS)
endif()
endif()
if (ENABLE_RESTAPI)
# Find package defined here as the order of execution of cmake commands matters: this needs to happen before any
find_package(nlohmann_json)
if (NOT nlohmann_json_FOUND)
message(STATUS "nlohmann_json is not found, will be downloaded automatically. To prevent that install nlohmann_json on your system (nlohmann-json3-dev)")
CPMAddPackage("gh:nlohmann/json@3.11.3")
else()
if (NOT TARGET nlohmann_json::nlohmann_json)
if (TARGET nlohman_json)
add_library(nlohmann_json::nlohmann_json ALIAS nlohmann_json)
else()
message(FATAL_ERROR "Your nlohmann_json installation is faulty as it doesn't define any of the expected targets")
endif()
endif()
endif()
endif()
add_subdirectory(common)
add_subdirectory(doc)
add_subdirectory(nfapi)
@@ -2378,3 +2397,4 @@ add_subdirectory(openair1)
add_subdirectory(openair2)
add_subdirectory(openair3)
add_subdirectory(radio)

View File

@@ -21,3 +21,6 @@ if (ENABLE_TESTS)
endif()
add_subdirectory(barrier)
add_subdirectory(actor)
if (ENABLE_RESTAPI)
add_subdirectory(rest_api)
endif()

View File

@@ -0,0 +1,21 @@
CPMAddPackage("gh:chriskohlhoff/asio#asio-1-18-1@1.18.1")
if (asio_ADDED)
# asio has no CMake support, so we create our own target
add_library(asio INTERFACE)
add_library(asio::asio ALIAS asio)
target_include_directories(asio SYSTEM INTERFACE ${asio_SOURCE_DIR}/asio/include)
target_compile_definitions(asio INTERFACE ASIO_STANDALONE)
endif()
CPMAddPackage(
NAME Crow
GIT_REPOSITORY https://github.com/CrowCpp/Crow.git
GIT_TAG v1.2.0
OPTIONS
"CROW_INSTALL OFF"
)
add_library(nr_ue_rest_api MODULE nr_ue_rest_api.cpp)
target_include_directories(nr_ue_rest_api PUBLIC ./)
target_link_libraries(nr_ue_rest_api PUBLIC Crow::Crow nr_ue_phy_rest_api_module shlib_loader nlohmann_json::nlohmann_json)
set_target_properties(nr_ue_rest_api PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

View File

@@ -0,0 +1,63 @@
/*
* 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 <crow.h>
#include "nr_ue_phy_rest_api_module.h"
#include "system.h"
#define PORT 11101
void* api_run(void*);
extern "C" {
#include "common/utils/load_module_shlib.h"
void nr_ue_rest_api_autoinit(void* arg)
{
char thread_name[] = "nr_ue_rest_api";
pthread_t rest_api_thread;
threadCreate(&rest_api_thread, api_run, arg, thread_name, -1, OAI_PRIORITY_RT_LOW);
}
}
typedef void (*regsiter_routes_ftype)(crow::Blueprint* bp);
void* api_run(void*)
{
crow::SimpleApp ue_rest_api;
ue_rest_api.loglevel(crow::LogLevel::Warning);
CROW_ROUTE(ue_rest_api, "/healthcheck")([]() { return "OK"; });
crow::Blueprint phy_bp("phy");
nr_ue::rest_api::phy::register_routes(&phy_bp);
ue_rest_api.register_blueprint(phy_bp);
char rfsim[] = "rfsimulator";
char register_routes[] = "register_routes";
regsiter_routes_ftype rfsim_register_routes = (regsiter_routes_ftype)get_shlibmodule_fptr(rfsim, register_routes);
crow::Blueprint rfsim_bp("rfsimulator");
if (rfsim_register_routes) {
rfsim_register_routes(&rfsim_bp);
ue_rest_api.register_blueprint(rfsim_bp);
}
ue_rest_api.port(PORT).run();
return NULL;
}

View File

@@ -539,6 +539,10 @@ int main(int argc, char **argv)
printf("UE threads created by %ld\n", gettid());
}
if (IS_SOFTMODEM_RESTAPI_ENABLED) {
load_module_shlib("nr_ue_rest_api",NULL,0,NULL);
}
// wait for end of program
printf("TYPE <CTRL-C> TO TERMINATE\n");

View File

@@ -39,6 +39,7 @@
#define BIT_23 (1 << 23)
#define BIT_24 (1 << 24)
#define BIT_25 (1 << 25)
#define BIT_26 (1 << 26)
#define SOFTMODEM_NOS1_BIT BIT_0
#define SOFTMODEM_NOKRNMOD_BIT BIT_1
@@ -56,6 +57,7 @@
#define SOFTMODEM_5GUE_BIT BIT_23
#define SOFTMODEM_NOSTATS_BIT BIT_24
#define SOFTMODEM_IMSCOPE_BIT BIT_25
#define SOFTMODEM_RESTAPI_BIT BIT_26
// clang-format on
#endif // SOFTMODEM_BITS_H

View File

@@ -100,6 +100,7 @@ void get_common_options(configmodule_interface_t *cfg, uint32_t execmask)
uint32_t noS1 = 0, nonbiot = 0;
uint32_t rfsim = 0, do_forms = 0;
uint32_t enable_imscope = 0;
uint32_t enable_rest_api = 0;
int nfapi_index = 0;
char *logmem_filename = NULL;
check_execmask(execmask);
@@ -163,6 +164,10 @@ void get_common_options(configmodule_interface_t *cfg, uint32_t execmask)
set_softmodem_optmask(SOFTMODEM_IMSCOPE_BIT);
}
if (enable_rest_api) {
set_softmodem_optmask(SOFTMODEM_RESTAPI_BIT);
}
if (start_websrv) {
load_module_shlib("websrv", NULL, 0, NULL);
}

View File

@@ -78,6 +78,7 @@ extern "C"
#define CONFIG_HLP_CHESTFREQ "Set channel estimation type in frequency domain. 0-Linear interpolation (default). 1-PRB based averaging of channel estimates in frequency. \n"
#define CONFIG_HLP_CHESTTIME "Set channel estimation type in time domain. 0-Symbols take estimates of the last preceding DMRS symbol (default). 1-Symbol based averaging of channel estimates in time. \n"
#define CONFIG_HLP_IMSCOPE "Enable phy scope based on imgui and implot"
#define CONFIG_HLP_RESTAPI "Enable REST API"
#define CONFIG_HLP_NONSTOP "Go back to frame sync mode after 100 consecutive PBCH failures\n"
//#define CONFIG_HLP_NUMUES "Set the number of UEs for the emulation"
@@ -187,6 +188,7 @@ extern int usrp_tx_thread;
{"A" , CONFIG_HLP_TADV, 0, .iptr=&softmodem_params.command_line_sample_advance,.defintval=0, TYPE_INT, 0}, \
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
{"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \
{"rest-api" , CONFIG_HLP_RESTAPI, PARAMFLAG_BOOL, .uptr=&enable_rest_api, .defintval=0, TYPE_UINT, 0}, \
}
// clang-format on
@@ -233,6 +235,7 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
// clang-format on
@@ -291,6 +294,7 @@ extern int usrp_tx_thread;
#define IS_SOFTMODEM_5GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_5GUE_BIT)
#define IS_SOFTMODEM_NOSTATS_BIT ( get_softmodem_optmask() & SOFTMODEM_NOSTATS_BIT)
#define IS_SOFTMODEM_IMSCOPE_ENABLED ( get_softmodem_optmask() & SOFTMODEM_IMSCOPE_BIT)
#define IS_SOFTMODEM_RESTAPI_ENABLED ( get_softmodem_optmask() & SOFTMODEM_RESTAPI_BIT)
typedef struct {
uint64_t optmask;

View File

@@ -5,3 +5,9 @@ target_include_directories(nr_phy_common PUBLIC inc/)
add_library(nr_ue_phy_meas src/nr_ue_phy_meas.c)
target_include_directories(nr_ue_phy_meas PUBLIC inc/)
target_link_libraries(nr_ue_phy_meas PUBLIC utils)
if (ENABLE_RESTAPI)
add_library(nr_ue_phy_rest_api_module src/nr_ue_phy_rest_api_module.cpp)
target_include_directories(nr_ue_phy_rest_api_module PUBLIC ./)
target_link_libraries(nr_ue_phy_rest_api_module PUBLIC Crow::Crow nr_ue_phy_meas UTIL nlohmann_json::nlohmann_json)
endif()

View File

@@ -0,0 +1,33 @@
/*
* 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 NR_UE_PHY_REST_API_MODULE_H
#define NR_UE_PHY_REST_API_MODULE_H
#include <crow.h>
#include <string>
namespace nr_ue::rest_api::phy
{
void register_routes(crow::Blueprint* bp);
}
#endif

View File

@@ -0,0 +1,80 @@
/*
* 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 "nlohmann/json.hpp"
#include <crow.h>
#include <vector>
#include "nr_ue_phy_rest_api_module.h"
#include "nr_ue_phy_meas.h"
#include "PHY/defs_nr_UE.h"
#include "time_meas.h"
extern "C" {
extern PHY_VARS_NR_UE ***PHY_vars_UE_g;
}
namespace nr_ue::rest_api::phy {
nlohmann::json generate_meas_json(time_stats_t *stat)
{
return nlohmann::json({{"name", std::string(stat->meas_name)},
{"count", std::uint64_t(stat->trials)},
{"uS", (float)(stat->diff / (cpu_freq_GHz * 1000))}});
}
void register_routes(crow::Blueprint *bp)
{
bp->new_rule_dynamic("/healthcheck")([]() { return crow::response(crow::status::OK, std::string("OK")); });
bp->new_rule_dynamic("/cpumeas/<int>")([](int ue_index) {
if (ue_index != 0) {
return crow::response(crow::status::BAD_REQUEST);
}
nlohmann::json response_data = nlohmann::json::array();
PHY_VARS_NR_UE *phy_vars_nr_ue = PHY_vars_UE_g[ue_index][0];
nr_ue_phy_cpu_stat_t *phy_cpu_stats = &phy_vars_nr_ue->phy_cpu_stats;
for (auto meas_index = 0; meas_index < MAX_CPU_STAT_TYPE; meas_index++) {
response_data.push_back(generate_meas_json(&phy_cpu_stats->cpu_time_stats[meas_index]));
}
return crow::response(crow::status::OK, response_data.dump());
});
bp->new_rule_dynamic("/cpumeas/<int>/<int>")([](int ue_index, int meas_index) {
if (ue_index != 0) {
return crow::response(crow::status::BAD_REQUEST);
}
if (meas_index < 0 || meas_index >= MAX_CPU_STAT_TYPE) {
return crow::response(crow::status::BAD_REQUEST);
}
PHY_VARS_NR_UE *phy_vars_nr_ue = PHY_vars_UE_g[ue_index][0];
nr_ue_phy_cpu_stat_t *phy_cpu_stats = &phy_vars_nr_ue->phy_cpu_stats;
return crow::response(generate_meas_json(&phy_cpu_stats->cpu_time_stats[meas_index]).dump());
});
bp->new_rule_dynamic("/cpumeas/enable")([]() {
cpumeas(CPUMEAS_ENABLE);
return crow::response(crow::status::OK, std::string("OK"));
});
bp->new_rule_dynamic("/cpumeas/disable")([]() {
cpumeas(CPUMEAS_DISABLE);
return crow::response(crow::status::OK, std::string("OK"));
});
}
} // namespace nr_ue::rest_api::phy

View File

@@ -94,12 +94,12 @@ int load_lib(openair0_device *device,
eth_params_t *cfg,
uint8_t flag)
{
loader_shlibfunc_t shlib_fdesc[1];
loader_shlibfunc_t shlib_fdesc[2];
int num_fdesc = 1;
int ret=0;
char *deflibname=OAI_RF_LIBNAME;
openair0_cfg->command_line_sample_advance = get_softmodem_params()->command_line_sample_advance;
openair0_cfg->recplay_mode = read_recplayconfig(&(openair0_cfg->recplay_conf),&(device->recplay_state));
if (openair0_cfg->recplay_mode == RECPLAY_RECORDMODE) {
set_softmodem_optmask(SOFTMODEM_RECRECORD_BIT); // softmodem has to know we use the iqrecorder to workaround randomized algorithms
}
@@ -110,6 +110,8 @@ int load_lib(openair0_device *device,
} else if (IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) {
deflibname=OAI_RFSIM_LIBNAME;
shlib_fdesc[0].fname="device_init";
shlib_fdesc[1].fname = "register_routes";
num_fdesc = 2;
} else if (flag == RAU_LOCAL_RADIO_HEAD) {
if (IS_SOFTMODEM_RFSIM)
deflibname="rfsimulator";
@@ -132,7 +134,7 @@ int load_lib(openair0_device *device,
config_get(config_get_if(), device_params, numparams, DEVICE_SECTION);
ret=load_module_shlib(devname,shlib_fdesc,1,NULL);
ret=load_module_shlib(devname,shlib_fdesc,num_fdesc,NULL);
AssertFatal( (ret >= 0),
"Library %s couldn't be loaded\n",devname);

View File

@@ -1,9 +1,17 @@
add_library(rfsimulator MODULE
simulator.c
apply_channelmod.c
../../openair1/PHY/TOOLS/signal_energy.c
set(rfsimulator_sources
simulator.c
apply_channelmod.c
../../openair1/PHY/TOOLS/signal_energy.c
)
if (ENABLE_RESTAPI)
list(APPEND rfsimulator_sources simulator_rest_api.cpp)
endif()
add_library(rfsimulator MODULE ${rfsimulator_sources})
target_link_libraries(rfsimulator PRIVATE SIMU HASHTABLE)
if (ENABLE_RESTAPI)
target_link_libraries(rfsimulator PRIVATE Crow::Crow nlohmann_json::nlohmann_json)
endif()
set_target_properties(rfsimulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_executable(replay_node stored_node.c)

View File

@@ -1,35 +1,114 @@
/*
* 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* 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
*/
* 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* 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 __RFSIMULATOR_H
#define __RFSIMULATOR_H
void rxAddInput( const c16_t *input_sig,
c16_t *after_channel_sig,
int rxAnt,
channel_desc_t *channelDesc,
int nbSamples,
uint64_t TS,
uint32_t CirSize
);
#ifndef RFSIMULATOR_H
#define RFSIMULATOR_H
#include <common/utils/telnetsrv/telnetsrv.h>
#include <openair1/SIMULATION/TOOLS/sim.h>
#include "hashtable.h"
// This needs to be re-architected in the future
//
// File Descriptors management in rfsimulator is not optimized
// Relying on FD_SETSIZE (actually 1024) is not appropriated
// Also the use of fd value as returned by Linux as an index for buf[] structure is not appropriated
// especially for client (UE) side since only 1 fd per connection to a gNB is needed. On the server
// side the value should be tuned to the maximum number of connections with UE's which corresponds
// to the maximum number of UEs hosted by a gNB which is unlikely to be in the order of thousands
// since all I/Q's would flow through the same TCP transport.
// Until a convenient management is implemented, the MAX_FD_RFSIMU is used everywhere (instead of
// FD_SETSIE) and reduced to 125. This should allow for around 20 simultaeous UEs.
//
// #define MAX_FD_RFSIMU FD_SETSIZE
#define MAX_FD_RFSIMU 250
typedef c16_t sample_t; // 2*16 bits complex number
// Simulator role
typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
typedef struct buffer_s {
int conn_sock;
openair0_timestamp lastReceivedTS;
bool headerMode;
bool trashingPacket;
samplesBlockHeader_t th;
char *transferPtr;
uint64_t remainToTransfer;
char *circularBufEnd;
sample_t *circularBuf;
channel_desc_t *channel_model;
} buffer_t;
typedef struct {
int listen_sock, epollfd;
openair0_timestamp nextRxTstamp;
openair0_timestamp lastWroteTS;
simuRole role;
char *ip;
uint16_t port;
int saveIQfile;
buffer_t buf[MAX_FD_RFSIMU];
int next_buf;
// Hashtable used as an indirection level between file descriptor and the buf array
hash_table_t *fd_to_buf_map;
int rx_num_channels;
int tx_num_channels;
double sample_rate;
double rx_freq;
double tx_bw;
int channelmod;
double chan_pathloss;
double chan_forgetfact;
uint64_t chan_offset;
float noise_power_dB;
void *telnetcmd_qid;
poll_telnetcmdq_func_t poll_telnetcmdq;
int wait_timeout;
double prop_delay_ms;
} rfsimulator_state_t;
//
// CirSize defines the number of samples inquired for a read cycle
// It is bounded by a slot read capability (which depends on bandwidth and numerology)
// up to multiple slots read to allow I/Q buffering of the I/Q TCP stream
//
// As a rule of thumb:
// -it can't be less than the number of samples for a slot
// -it can range up to multiple slots
//
// The default value is chosen for 10ms buffering which makes 23040*20 = 460800 samples
// The previous value is kept below in comment it was computed for 100ms 1x 20MHz
// #define CirSize 6144000 // 100ms SiSo 20MHz LTE
#define minCirSize 460800 // 10ms SiSo 40Mhz 3/4 sampling NR78 FR1
void rxAddInput(const c16_t *input_sig,
c16_t *after_channel_sig,
int rxAnt,
channel_desc_t *channelDesc,
int nbSamples,
uint64_t TS,
uint32_t CirSize);
#endif

View File

@@ -44,28 +44,12 @@
#include <common/utils/assertions.h>
#include <common/utils/LOG/log.h>
#include <common/utils/load_module_shlib.h>
#include <common/utils/telnetsrv/telnetsrv.h>
#include <common/config/config_userapi.h>
#include "common_lib.h"
#define CHANNELMOD_DYNAMICLOAD
#include <openair1/SIMULATION/TOOLS/sim.h>
#include "rfsimulator.h"
#include "hashtable.h"
#define PORT 4043 //default TCP port for this simulator
//
// CirSize defines the number of samples inquired for a read cycle
// It is bounded by a slot read capability (which depends on bandwidth and numerology)
// up to multiple slots read to allow I/Q buffering of the I/Q TCP stream
//
// As a rule of thumb:
// -it can't be less than the number of samples for a slot
// -it can range up to multiple slots
//
// The default value is chosen for 10ms buffering which makes 23040*20 = 460800 samples
// The previous value is kept below in comment it was computed for 100ms 1x 20MHz
// #define CirSize 6144000 // 100ms SiSo 20MHz LTE
#define minCirSize 460800 // 10ms SiSo 40Mhz 3/4 sampling NR78 FR1
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
@@ -89,11 +73,6 @@
#define MAX_FD_RFSIMU 250
#define SEND_BUFF_SIZE 100000000 // Socket buffer size
// Simulator role
typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
//
#define RFSIMU_SECTION "rfsimulator"
#define RFSIMU_OPTIONS_PARAMNAME "options"
@@ -138,51 +117,8 @@ static telnetshell_cmddef_t *setmodel_cmddef = &(rfsimu_cmdarray[1]);
static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}};
pthread_mutex_t Sockmutex;
unsigned int nb_ue = 0;
static uint64_t CirSize = minCirSize;
typedef c16_t sample_t; // 2*16 bits complex number
typedef struct buffer_s {
int conn_sock;
openair0_timestamp lastReceivedTS;
bool headerMode;
bool trashingPacket;
samplesBlockHeader_t th;
char *transferPtr;
uint64_t remainToTransfer;
char *circularBufEnd;
sample_t *circularBuf;
channel_desc_t *channel_model;
} buffer_t;
typedef struct {
int listen_sock, epollfd;
openair0_timestamp nextRxTstamp;
openair0_timestamp lastWroteTS;
simuRole role;
char *ip;
uint16_t port;
int saveIQfile;
buffer_t buf[MAX_FD_RFSIMU];
int next_buf;
// Hashtable used as an indirection level between file descriptor and the buf array
hash_table_t *fd_to_buf_map;
int rx_num_channels;
int tx_num_channels;
double sample_rate;
double rx_freq;
double tx_bw;
int channelmod;
double chan_pathloss;
double chan_forgetfact;
uint64_t chan_offset;
float noise_power_dB;
void *telnetcmd_qid;
poll_telnetcmdq_func_t poll_telnetcmdq;
int wait_timeout;
double prop_delay_ms;
} rfsimulator_state_t;
rfsimulator_state_t *rfsimulator_state = NULL;
static buffer_t *get_buff_from_socket(rfsimulator_state_t *simulator_state, int socket)
@@ -1179,5 +1115,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
exit(1);
}
rfsimulator_state = rfsimulator;
return 0;
}

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 <crow.h>
#include <vector>
#include <nlohmann/json.hpp>
extern "C" {
#include "rfsimulator.h"
extern rfsimulator_state_t *rfsimulator_state;
}
namespace rfsimulator::rest_api {
nlohmann::json generate_channel_json(channel_desc_t *channel_model, int conn_sock)
{
return nlohmann::json({{"name", std::string(channel_model->model_name)},
{"conn_sock", conn_sock},
{"path_loss_dB", channel_model->path_loss_dB},
{"noise_power_dB", channel_model->noise_power_dB},
{"nb_tx", channel_model->nb_tx},
{"nb_rx", channel_model->nb_rx}});
}
extern "C" void register_routes(crow::Blueprint *bp)
{
bp->new_rule_dynamic("/healthcheck/")([]() { return crow::response(crow::status::OK, std::string("OK")); });
bp->new_rule_dynamic("/channel/")([]() {
nlohmann::json response_data = nlohmann::json::array();
for (auto buffer_index = 0; buffer_index < MAX_FD_RFSIMU; buffer_index++) {
auto buf = &rfsimulator_state->buf[buffer_index];
if (buf->conn_sock != -1 && buf->channel_model != nullptr) {
response_data.push_back(generate_channel_json(buf->channel_model, buffer_index));
}
}
return crow::response(crow::status::OK, response_data.dump());
});
bp->new_rule_dynamic("/channel/<string>/")
.methods(crow::HTTPMethod::POST, crow::HTTPMethod::GET)([](const crow::request &req, std::string channel_name) {
nlohmann::json req_json;
try {
req_json = nlohmann::json::parse(req.body);
} catch (const nlohmann::json::exception &e) {
std::cerr << "Exception: " << e.what() << std::endl;
return crow::response(crow::status::BAD_REQUEST, std::string(e.what()));
}
for (auto buffer_index = 0; buffer_index < MAX_FD_RFSIMU; buffer_index++) {
auto buf = &rfsimulator_state->buf[buffer_index];
if (buf->conn_sock != -1 && buf->channel_model != nullptr) {
if (channel_name.compare(buf->channel_model->model_name) == 0) {
if (req.method == crow::HTTPMethod::GET) {
return crow::response(generate_channel_json(buf->channel_model, buf->conn_sock).dump());
} else {
const char path_loss_db[] = "path_loss_dB";
if (req_json.contains(path_loss_db)) {
buf->channel_model->path_loss_dB = req_json[path_loss_db];
}
return crow::response(crow::status::OK, std::string("OK"));
}
}
}
}
return crow::response(crow::status::BAD_REQUEST, std::string("Channel not found"));
});
}
} // namespace rfsimulator::rest_api

View File

@@ -215,3 +215,26 @@ e2_agent:
near_ric_ip_addr: 127.0.0.1
#sm_dir = /path/where/the/SMs/are/located/
sm_dir: /usr/local/lib/flexric/
#/* configuration for channel modelisation */
#/* To be included in main config file when */
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
channelmod:
max_chan: 10
modellist: modellist_rfsimu_1
modellist_rfsimu_1:
- model_name: rfsimu_channel_enB0
type: AWGN
ploss_dB: 20
noise_power_dB: -4
forgetfact: 0
offset: 0
ds_tdl: 0
- model_name: rfsimu_channel_ue0
type: AWGN
ploss_dB: 20
nose_power_dB: -2
forgetfact: 0
offset: 0
ds_tdl: 0