Commit dbe5d2ed authored by Yan Kuo's avatar Yan Kuo

get CSI-RS

parent 2c4dac7b
......@@ -1898,6 +1898,8 @@ add_executable(nr-uesoftmodem
${rrc_h}
${s1ap_h}
${OPENAIR_DIR}/executables/nr-uesoftmodem.c
${OPENAIR_DIR}/executables/extract_csi_rs.c
${OPENAIR_DIR}/executables/cJSON.c
${OPENAIR_DIR}/executables/position_interface.c
${OPENAIR_DIR}/executables/nr-ue.c
${OPENAIR_DIR}/executables/nr-ue-ru.c
......@@ -1912,6 +1914,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB
ITTI SIMU radio_common
time_management softmodem_common
microhttpd # apt install libmicrohttpd-dev
-Wl,--end-group z dl)
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas)
......
......@@ -467,7 +467,8 @@ check_install_oai_software() {
openssl \
zlib1g-dev \
xxd \
libyaml-cpp-dev
libyaml-cpp-dev \
libmicrohttpd-dev
elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]] || [[ "$OS_DISTRO" == "rocky" ]]; then
......
#include "data_transfer.h"
#include <microhttpd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>
#include "cJSON.h"
// 宏定义,用于控制台颜色(如果终端支持)
#define COLOR_GREEN "\033[1;32m"
#define COLOR_RED "\033[1;31m"
#define COLOR_YELLOW "\033[1;33m"
#define COLOR_RESET "\033[0m"
// 醒目打印宏,自动添加时间戳和分隔线
#define CSI_LOG_START() \
do { \
time_t now = time(NULL); \
printf(COLOR_GREEN "[CSI-RS] %s", ctime(&now)); \
printf("============================================\n" COLOR_RESET); \
} while(0)
#define CSI_LOG_STOP() \
do { \
time_t now = time(NULL); \
printf(COLOR_RED "[CSI-RS] %s", ctime(&now)); \
printf("============================================\n" COLOR_RESET); \
} while(0)
#define CSI_LOG_MSG(color, fmt, ...) \
printf(color "[CSI-RS] " fmt "\n" COLOR_RESET, ##__VA_ARGS__)
#define PORT 8889
static int g_csi_recording_enabled = 0;
static char g_csi_save_path[256] = {0};
static pthread_mutex_t csi_mutex = PTHREAD_MUTEX_INITIALIZER;
static void set_start_csi(const char *save_path)
{
__atomic_store_n(&g_csi_recording_enabled, 1, __ATOMIC_SEQ_CST);
pthread_mutex_lock(&csi_mutex);
if (save_path != NULL) {
memset(g_csi_save_path,0,sizeof(g_csi_save_path));
strncpy(g_csi_save_path, save_path, sizeof(g_csi_save_path) - 1);
g_csi_save_path[sizeof(g_csi_save_path) - 1] = '\0';
} else {
g_csi_save_path[0] = '\0';
}
pthread_mutex_unlock(&csi_mutex);
CSI_LOG_START();
CSI_LOG_MSG(COLOR_GREEN, ">>> CSI RECORDING STARTED <<<");
CSI_LOG_MSG(COLOR_GREEN, "Save path: %s", g_csi_save_path[0] ? g_csi_save_path : "(default)");
CSI_LOG_MSG(COLOR_GREEN, "Recording enabled: 1");
CSI_LOG_MSG(COLOR_GREEN, "============================================");
}
static void set_stop_csi()
{
__atomic_store_n(&g_csi_recording_enabled, 0, __ATOMIC_SEQ_CST);
CSI_LOG_STOP();
CSI_LOG_MSG(COLOR_RED, ">>> CSI RECORDING STOPPED <<<");
CSI_LOG_MSG(COLOR_RED, "Recording enabled: 0");
CSI_LOG_MSG(COLOR_RED, "Last save path: %s", g_csi_save_path[0] ? g_csi_save_path : "(none)");
CSI_LOG_MSG(COLOR_RED, "============================================");
}
void get_csi_save_path(char *out, int len)
{
if (out == NULL || len == 0)
return;
pthread_mutex_lock(&csi_mutex);
strncpy(out, g_csi_save_path, len - 1);
out[len - 1] = '\0';
pthread_mutex_unlock(&csi_mutex);
}
int get_csi_recording_enabled()
{
return __atomic_load_n(&g_csi_recording_enabled, __ATOMIC_SEQ_CST);
}
// 构造 HTTP 响应的函数
int send_json_response(struct MHD_Connection *connection, const char *json_str)
{
struct MHD_Response *response;
int ret;
response = MHD_create_response_from_buffer(strlen(json_str),
(void*)json_str,
MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(response, "Content-Type", "application/json");
ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
MHD_destroy_response(response);
return ret;
}
struct request_context {
char *body_data;
size_t body_len;
size_t body_capacity;
};
// 请求处理函数
enum MHD_Result answer_to_connection(void *cls, struct MHD_Connection *connection,
const char *url, const char *method,
const char *version, const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
(void)cls; (void)version;
if (strcmp(url, "/csi_rs") != 0) {
const char *json = "{\"error\":\"Not Found\"}";
struct MHD_Response *resp = MHD_create_response_from_buffer(strlen(json), (void*)json, MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(resp, "Content-Type", "application/json");
int ret = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, resp);
MHD_destroy_response(resp);
return ret;
}
if (strcmp(method, "POST") != 0) {
const char *err = "{\"error\":\"Only POST allowed\"}";
struct MHD_Response *resp = MHD_create_response_from_buffer(strlen(err), (void*)err, MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(resp, "Content-Type", "application/json");
int ret = MHD_queue_response(connection, MHD_HTTP_METHOD_NOT_ALLOWED, resp);
MHD_destroy_response(resp);
return ret;
}
struct request_context **ctx_ptr = (struct request_context**)con_cls;
struct request_context *ctx = *ctx_ptr;
if (ctx == NULL) {
// 第一次调用,分配上下文
ctx = calloc(1, sizeof(struct request_context));
if (ctx == NULL)
return MHD_NO;
*ctx_ptr = ctx;
// 如果没有数据块(例如空 body),则后续会立即进入 *upload_data_size == 0 的分支
// 但正常 POST 会在后续调用中传递数据,因此这里直接返回等待数据
if (*upload_data_size == 0)
return MHD_YES;
}
if (*upload_data_size != 0) {
// 有数据块到达,追加到缓冲区
size_t new_len = ctx->body_len + *upload_data_size;
if (new_len > ctx->body_capacity) {
size_t new_cap = ctx->body_capacity == 0 ? 4096 : ctx->body_capacity * 2;
while (new_cap < new_len) new_cap *= 2;
char *new_buf = realloc(ctx->body_data, new_cap);
if (new_buf == NULL) {
free(ctx->body_data);
free(ctx);
*ctx_ptr = NULL;
return MHD_NO;
}
ctx->body_data = new_buf;
ctx->body_capacity = new_cap;
}
memcpy(ctx->body_data + ctx->body_len, upload_data, *upload_data_size);
ctx->body_len += *upload_data_size;
*upload_data_size = 0; // 告知库已消费
return MHD_YES; // 继续等待更多数据
} else {
// *upload_data_size == 0:数据传输完毕,处理完整 body
const char *response_json = NULL;
int http_status = MHD_HTTP_OK;
int is_free_response_json = 0;
if (ctx->body_len == 0) {
response_json = "{\"error\":\"Empty body\"}";
http_status = MHD_HTTP_BAD_REQUEST;
} else {
char *body_str = malloc(ctx->body_len + 1);
if (body_str == NULL) {
response_json = "{\"error\":\"Internal memory error\"}";
http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
} else {
memcpy(body_str, ctx->body_data, ctx->body_len);
body_str[ctx->body_len] = '\0';
cJSON *root = cJSON_Parse(body_str);
free(body_str);
if (root == NULL) {
response_json = "{\"error\":\"Invalid JSON\"}";
http_status = MHD_HTTP_BAD_REQUEST;
} else {
cJSON *action_obj = cJSON_GetObjectItem(root, "action");
if (!cJSON_IsString(action_obj) || action_obj->valuestring == NULL) {
response_json = "{\"error\":\"Missing or invalid 'action' field\"}";
http_status = MHD_HTTP_BAD_REQUEST;
} else {
const char *action = action_obj->valuestring;
if (strcmp(action, "start") == 0) {
cJSON *path_obj = cJSON_GetObjectItem(root, "save_path");
if (!cJSON_IsString(path_obj) || path_obj->valuestring == NULL) {
response_json = "{\"error\":\"Missing or invalid 'save_path' for start action\"}";
http_status = MHD_HTTP_BAD_REQUEST;
} else {
const char *save_path = path_obj->valuestring;
set_start_csi(save_path);
const char *fmt = "{\"status\":\"started\", \"save_path\":\"%s\"}";
char *tmp = malloc(strlen(fmt) + strlen(save_path) + 1);
if (tmp) {
is_free_response_json = 1;
sprintf(tmp, fmt, save_path);
response_json = tmp;
} else {
response_json = "{\"error\":\"Out of memory\"}";
http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
}
}
} else if (strcmp(action, "stop") == 0) {
set_stop_csi();
response_json = "{\"status\":\"stopped\"}";
} else {
response_json = "{\"error\":\"Unknown action, must be 'start' or 'stop'\"}";
http_status = MHD_HTTP_BAD_REQUEST;
}
}
cJSON_Delete(root);
}
}
}
struct MHD_Response *resp = MHD_create_response_from_buffer(strlen(response_json), (void*)response_json, MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(resp, "Content-Type", "application/json");
int ret = MHD_queue_response(connection, http_status, resp);
MHD_destroy_response(resp);
if (is_free_response_json)
free((void*)response_json);
// 清理上下文
free(ctx->body_data);
free(ctx);
*ctx_ptr = NULL;
return ret;
}
}
struct MHD_Daemon *httpdaemon;
int start_csi_http_server()
{
httpdaemon = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD,
PORT,
NULL, NULL,
&answer_to_connection, NULL,
MHD_OPTION_END);
if (httpdaemon == NULL) {
fprintf(stderr, "Failed to start HTTP server\n");
return 1;
}
return 0;
}
void stop_csi_http_server()
{
MHD_stop_daemon(httpdaemon);
}
\ No newline at end of file
#ifndef HTTP_SERVER_H_
#define HTTP_SERVER_H_
int start_csi_http_server();
void stop_csi_http_server();
void get_csi_save_path(char *out, int len);
int get_csi_recording_enabled();
#endif /* HTTP_SERVER_H_ */
......@@ -29,6 +29,7 @@
#include "NR_IF_Module.h"
#include "openair1/SIMULATION/TOOLS/sim.h"
#include "openair2/RRC/NR_UE/L2_interface_ue.h"
#include "executables/extract_csi_rs.h"
#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
......@@ -442,6 +443,8 @@ int main(int argc, char **argv)
init_NR_UE_threads(PHY_vars_UE_g[inst][0]);
}
start_csi_http_server();
// wait for end of program
printf("TYPE <CTRL-C> TO TERMINATE\n");
......@@ -457,6 +460,8 @@ int main(int argc, char **argv)
LOG_W(NR_PHY, "Returned from ITTI signal handler\n");
oai_exit = 1;
stop_csi_http_server();
if (PHY_vars_UE_g && PHY_vars_UE_g[0]) {
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
PHY_VARS_NR_UE *phy_vars = PHY_vars_UE_g[0][CC_id];
......
......@@ -15,12 +15,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "executables/nr-softmodem-common.h"
#include "nr_transport_proto_ue.h"
#include "PHY/NR_REFSIG/nr_refsig.h"
#include "common/utils/nr/nr_common.h"
#include "PHY/NR_UE_ESTIMATION/filt16a_32.h"
#include "executables/extract_csi_rs.h"
// Additional memory allocation, because of applying the filter and the memory offset to ensure memory alignment
#define FILTER_MARGIN 32
......@@ -943,6 +945,46 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
nr_csi_rs_cqi_estimation(precoded_sinr_dB, &cqi);
}
if(get_csi_recording_enabled()) {
if (csirs_config_pdu->measurement_bitmap > 0) {
char file_name_path[64] = {0};
get_csi_save_path(file_name_path,64);
char buf[64];
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm tm;
localtime_r(&tv.tv_sec, &tm);
snprintf(buf, sizeof(buf),
"%04d%02d%02d_%02d%02d%02d_%03ld",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
tv.tv_usec / 1000);
char file_name_generate[256] = {0};
sprintf(file_name_generate,"%scsi_rs_generate_%s.bin",file_name_path,buf);
FILE *file_generate;
file_generate = fopen(file_name_generate, "wb");
for (int m = 0; m < frame_parms->nb_antennas_rx; m++) {
fwrite(csi_info->csi_rs_generated_signal[m], sizeof(c16_t), frame_parms->samples_per_slot_wCP, file_generate);
}
fclose(file_generate);
char file_name_get[256] = {0};
sprintf(file_name_get,"%scsi_rs_get_%s.bin",file_name_path,buf);
FILE *file_get;
file_get = fopen(file_name_get, "wb");
for (int m = 0; m < frame_parms->nb_antennas_rx; m++) {
fwrite(csi_rs_received_signal[m],sizeof(c16_t), frame_parms->samples_per_slot_wCP, file_get);
}
fclose(file_get);
// LOG_I(NR_PHY, "************ [frame_parms->nb_antennas_rx %d] [frame_parms->samples_per_slot_wCP %d]\n", frame_parms->nb_antennas_rx, frame_parms->samples_per_slot_wCP);
// LOG_I(NR_PHY, "CSI-RS measurement_bitmap %d\n",csirs_config_pdu->measurement_bitmap);
}
}
switch (csirs_config_pdu->measurement_bitmap) {
case 1 :
LOG_I(NR_PHY, "[UE %d] RSRP = %i dBm\n", ue->Mod_id, rsrp_dBm);
......
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
uicc0 = {
imsi = "2089900007487";
key = "fec86ba6eb707ed08905757b1bb44b8f";
opc= "C42449363BBAD02B66D16BC975D77CC1";
pdu_sessions = ({ dnn = "oai"; nssai_sst = 1; });
}
position0 = {
x = 0.0;
y = 0.0;
z = 6377900.0;
imsi = "466920000000001";
key = "00112233445566778899AABBCCDDEEFF";
opc= "000102030405060708090A0B0C0D0E0F";
pdu_sessions = ({ dnn = "internet"; nssai_sst = 1; nssai_sd=0xFFFFFF;});
#dnn= "internet";
#nssai_sst=1;
#nssai_sd=0xFFFFFF;
}
@include "channelmod_rfsimu_LEO_satellite.conf"
#position0 = {
# x = 0.0;
# y = 0.0;
# z = 6377900.0;
#}
#
#@include "channelmod_rfsimu_LEO_satellite.conf"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment