333 lines
9.5 KiB
C
333 lines
9.5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "utils.h"
|
|
#include "gui/gui.h"
|
|
#include "view/view.h"
|
|
#include "logger/logger.h"
|
|
#include "filter/filter.h"
|
|
#include "database.h"
|
|
#include "configuration.h"
|
|
#include "handler.h"
|
|
|
|
typedef struct {
|
|
int used;
|
|
} ue_list_item;
|
|
|
|
typedef struct {
|
|
widget *container;
|
|
} gnb_gui;
|
|
|
|
typedef struct {
|
|
int socket;
|
|
gui *g;
|
|
gnb_gui *gg;
|
|
event_handler *h;
|
|
void *database;
|
|
ue_list_item ues[65536];
|
|
int rnti_arg;
|
|
} gnb_data;
|
|
|
|
void *gui_thread(void *_g)
|
|
{
|
|
gui *g = _g;
|
|
gui_loop(g);
|
|
return 0;
|
|
}
|
|
|
|
void add_ue(gnb_data *gd, int rnti, int lcid)
|
|
{
|
|
event_handler *h = gd->h;
|
|
void *database = gd->database;
|
|
gnb_gui *gg = gd->gg;
|
|
gui *g = gd->g;
|
|
widget *line;
|
|
widget *w, *w2, *col;
|
|
view *v;
|
|
logger *l;
|
|
|
|
gd->ues[rnti].used = 1;
|
|
|
|
line = new_container(g, HORIZONTAL);
|
|
widget_add_child(g, gg->container, line, -1);
|
|
|
|
/* label */
|
|
char s[512];
|
|
sprintf(s, "UE %d", rnti);
|
|
widget *label = new_label(g, s);
|
|
widget_add_child(g, line, label, -1);
|
|
|
|
/* DL MCS */
|
|
w = new_xy_plot(g, 128, 55, "DL mcs", 20);
|
|
xy_plot_set_range(g, w, 0, 1024*20, -2, 30);
|
|
widget_add_child(g, line, w, -1);
|
|
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
|
|
"GNB_MAC_DL", "mcs", 0, -1);
|
|
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_DL", "rnti"),
|
|
filter_int(rnti)));
|
|
|
|
/* DL TBS */
|
|
col = new_container(g, VERTICAL);
|
|
widget_add_child(g, line, col, -1);
|
|
w = new_xy_plot(g, 70, 10, "DL tbs", 35);
|
|
w2 = new_textarea(g, 70, 11, 64);
|
|
xy_plot_set_range(g, w, 0, 1024*20, 0, 1000);
|
|
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
|
|
widget_add_child(g, col, w2, -1);
|
|
widget_add_child(g, col, w, -1);
|
|
container_set_child_growable(g, col, w, 1);
|
|
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
|
|
"GNB_MAC_DL", "tbs", 0, -1);
|
|
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
|
|
view_tti_enable_automax(v, w2);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_DL", "rnti"),
|
|
filter_int(rnti)));
|
|
|
|
/* DL lcid throughput */
|
|
col = new_container(g, VERTICAL);
|
|
widget_add_child(g, line, col, -1);
|
|
sprintf(s, "DL lcid %d", lcid);
|
|
w = new_xy_plot(g, 70, 10, s, 35);
|
|
w2 = new_textarea(g, 70, 11, 64);
|
|
xy_plot_set_range(g, w, 0, 1000, 0, 100000);
|
|
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
|
|
widget_add_child(g, col, w2, -1);
|
|
widget_add_child(g, col, w, -1);
|
|
container_set_child_growable(g, col, w, 1);
|
|
l = new_throughputlog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
|
|
"GNB_MAC_LCID_DL", "data_size", 20);
|
|
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 20);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_and(
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_LCID_DL", "rnti"),
|
|
filter_int(rnti)),
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_LCID_DL", "lcid"),
|
|
filter_int(lcid))));
|
|
|
|
/* UL MCS */
|
|
w = new_xy_plot(g, 128, 55, "UL mcs", 20);
|
|
xy_plot_set_range(g, w, 0, 1024*20, -2, 30);
|
|
widget_add_child(g, line, w, -1);
|
|
/* GNB_PHY_DL_TICK (and not UL) because GNB_MAC_UL is from DCI */
|
|
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
|
|
"GNB_MAC_UL", "mcs", 0, -1);
|
|
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_UL", "rnti"),
|
|
filter_int(rnti)));
|
|
|
|
/* UL TBS */
|
|
col = new_container(g, VERTICAL);
|
|
widget_add_child(g, line, col, -1);
|
|
w = new_xy_plot(g, 70, 10, "UL tbs", 35);
|
|
w2 = new_textarea(g, 70, 11, 64);
|
|
xy_plot_set_range(g, w, 0, 1024*20, 0, 1000);
|
|
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
|
|
widget_add_child(g, col, w2, -1);
|
|
widget_add_child(g, col, w, -1);
|
|
container_set_child_growable(g, col, w, 1);
|
|
/* GNB_PHY_DL_TICK (and not UL) because GNB_MAC_UL is from DCI */
|
|
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
|
|
"GNB_MAC_UL", "tbs", 0, -1);
|
|
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
|
|
view_tti_enable_automax(v, w2);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_UL", "rnti"),
|
|
filter_int(rnti)));
|
|
|
|
/* UL lcid throughput */
|
|
col = new_container(g, VERTICAL);
|
|
widget_add_child(g, line, col, -1);
|
|
sprintf(s, "UL lcid %d", lcid);
|
|
w = new_xy_plot(g, 70, 10, s, 35);
|
|
w2 = new_textarea(g, 70, 11, 64);
|
|
xy_plot_set_range(g, w, 0, 1000, 0, 100000);
|
|
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
|
|
widget_add_child(g, col, w2, -1);
|
|
widget_add_child(g, col, w, -1);
|
|
container_set_child_growable(g, col, w, 1);
|
|
l = new_throughputlog(h, database, "GNB_PHY_UL_TICK", "frame", "slot",
|
|
"GNB_MAC_LCID_UL", "data_size", 20);
|
|
v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 20);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_and(
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_LCID_UL", "rnti"),
|
|
filter_int(rnti)),
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_LCID_UL", "lcid"),
|
|
filter_int(lcid))));
|
|
|
|
/* lcid RLC tx buffer occupancy */
|
|
col = new_container(g, VERTICAL);
|
|
widget_add_child(g, line, col, -1);
|
|
sprintf(s, "rlc tx %d", lcid);
|
|
w = new_xy_plot(g, 70, 10, s, 35);
|
|
w2 = new_textarea(g, 70, 11, 64);
|
|
xy_plot_set_range(g, w, 0, 1024*20, 0, 1000);
|
|
xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK);
|
|
widget_add_child(g, col, w2, -1);
|
|
widget_add_child(g, col, w, -1);
|
|
container_set_child_growable(g, col, w, 1);
|
|
l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot",
|
|
"GNB_MAC_LCID_DL", "tx_list_occupancy", 0, -1);
|
|
v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20);
|
|
view_tti_enable_automax(v, w2);
|
|
logger_add_view(l, v);
|
|
logger_set_filter(l,
|
|
filter_and(
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_LCID_DL", "rnti"),
|
|
filter_int(rnti)),
|
|
filter_eq(
|
|
filter_evarg(database, "GNB_MAC_LCID_DL", "lcid"),
|
|
filter_int(lcid))));
|
|
}
|
|
|
|
void build_gui(gnb_gui *gg, gui *g)
|
|
{
|
|
widget *main_window;
|
|
|
|
main_window = new_toplevel_window(g, 900, 1000, "gNB MAC tracer");
|
|
gg->container = new_container(g, VERTICAL);
|
|
widget_add_child(g, main_window, gg->container, -1);
|
|
}
|
|
|
|
void usage(void)
|
|
{
|
|
printf(
|
|
"options:\n"
|
|
" -d <database file> this option is mandatory\n"
|
|
" -ip <host> connect to given IP address (default %s)\n"
|
|
" -p <port> connect to given port (default %d)\n",
|
|
DEFAULT_REMOTE_IP,
|
|
DEFAULT_REMOTE_PORT
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
void check_new_ue(void *_gd, event e)
|
|
{
|
|
gnb_data *gd = _gd;
|
|
int rnti = e.e[gd->rnti_arg].i;
|
|
if (!gd->ues[rnti].used)
|
|
add_ue(gd, rnti, 4);
|
|
}
|
|
|
|
int main(int n, char **v)
|
|
{
|
|
gui *g;
|
|
gnb_gui gg;
|
|
gnb_data *gd;
|
|
char *database_filename = NULL;
|
|
void *database;
|
|
char *ip = DEFAULT_REMOTE_IP;
|
|
int port = DEFAULT_REMOTE_PORT;
|
|
event_handler *h;
|
|
int *is_on;
|
|
int number_of_events;
|
|
int i;
|
|
|
|
for (i = 1; i < n; i++) {
|
|
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
|
if (!strcmp(v[i], "-d")) { if (i > n-2) usage(); database_filename = v[++i]; continue; }
|
|
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
|
|
if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
|
|
usage();
|
|
}
|
|
|
|
if (database_filename == NULL) {
|
|
printf("ERROR: provide a database file (-d)\n");
|
|
exit(1);
|
|
}
|
|
|
|
database = parse_database(database_filename);
|
|
|
|
load_config_file(database_filename);
|
|
|
|
number_of_events = number_of_ids(database);
|
|
is_on = calloc(number_of_events, sizeof(int));
|
|
if (is_on == NULL) abort();
|
|
|
|
on_off(database, "GNB_PHY_DL_TICK", is_on, 1);
|
|
on_off(database, "GNB_MAC_DL", is_on, 1);
|
|
on_off(database, "GNB_MAC_LCID_DL", is_on, 1);
|
|
on_off(database, "GNB_PHY_UL_TICK", is_on, 1);
|
|
on_off(database, "GNB_MAC_UL", is_on, 1);
|
|
on_off(database, "GNB_MAC_LCID_UL", is_on, 1);
|
|
|
|
gd = calloc(1, sizeof(*gd)); if (!gd) abort();
|
|
|
|
h = new_handler(database);
|
|
|
|
g = gui_init();
|
|
new_thread(gui_thread, g);
|
|
|
|
build_gui(&gg, g);
|
|
|
|
gd->g = g;
|
|
gd->gg = ≫
|
|
gd->h = h;
|
|
gd->database = database;
|
|
|
|
/* get rnti_arg from event GNB_MAC_DL */
|
|
int event_id = event_id_from_name(database, "GNB_MAC_DL");
|
|
database_event_format f = get_format(database, event_id);
|
|
gd->rnti_arg = -1;
|
|
for (i = 0; i < f.count; i++) {
|
|
if (!strcmp(f.name[i], "rnti")) gd->rnti_arg = i;
|
|
}
|
|
if (gd->rnti_arg == -1) {
|
|
printf("fatal: event 'GNB_MAC_DL' does not have argument 'rnti'\n");
|
|
exit(1);
|
|
}
|
|
if (strcmp(f.type[gd->rnti_arg], "int") != 0) {
|
|
printf("fatal: argument 'rnti' of event 'GNB_MAC_DL' is not 'int'\n");
|
|
exit(1);
|
|
}
|
|
|
|
register_handler_function(h, event_id, check_new_ue, gd);
|
|
|
|
OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL};
|
|
|
|
gd->socket = -1;
|
|
|
|
restart:
|
|
clear_remote_config();
|
|
if (gd->socket != -1) close(gd->socket);
|
|
gd->socket = connect_to(ip, port);
|
|
|
|
/* send the first message - activate selected traces */
|
|
int t = 1;
|
|
if (socket_send(gd->socket, &t, 1) == -1 ||
|
|
socket_send(gd->socket, &number_of_events, sizeof(int)) == -1 ||
|
|
socket_send(gd->socket, is_on, number_of_events * sizeof(int)) == -1)
|
|
goto restart;
|
|
|
|
while (1) {
|
|
event e;
|
|
e = get_event(gd->socket, &ebuf, database);
|
|
if (e.type == -1) goto restart;
|
|
handle_event(h, e);
|
|
}
|
|
|
|
return 0;
|
|
}
|