T tracer: add gnb tracer
Minimalist gnb tracer to trace (for the moment) rxdataF when some decoding for PUCCH or PUSCH has been done. Important: T_BUFFER_MAX and T_CACHE_SIZE have been changed. T_BUFFER_MAX is twice as big as before. T_CACHE_SIZE has been devided by two. Globally, the memory usage of the T tracer is the same, but since we divided by two the number of buffers in the cache, we may hit some realtime problems if all the buffers are busy at some point. The simple solution would be to use 8192*2 for T_CACHE_SIZE as it was, but then we double the memory usage of the T tracer. This, or another solution, to be defined.
This commit is contained in:
@@ -4,6 +4,7 @@ T_IDs.h
|
||||
T_messages.txt.h
|
||||
genids
|
||||
tracer/enb
|
||||
tracer/gnb
|
||||
tracer/extract_config
|
||||
tracer/record
|
||||
tracer/replay
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
ID = BENETEL
|
||||
GROUP = ALL
|
||||
FORMAT = int,frame : int,slot : buffer,rxdataF
|
||||
|
||||
#general logs
|
||||
ID = ENB_MASTER_TICK
|
||||
DESC = eNodeB master tick - one tick per ms, to be used as "reference clock", mostly for ticktime view
|
||||
@@ -93,6 +89,10 @@ ID = GNB_PHY_MIB
|
||||
DESC = NR MIB data
|
||||
GROUP = ALL:PHY:GNB:WIRESHARK
|
||||
FORMAT = int,gNB_ID : int,frame : int,slot : buffer,data
|
||||
ID = GNB_PHY_PUCCH_PUSCH_IQ
|
||||
DESC = gNodeB input data in the frequency domain for a slot where some PUCCH or PUSCH detection was done
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,frame : int,slot : buffer,rxdataF
|
||||
|
||||
#MAC logs
|
||||
ID = ENB_MAC_UE_DL_SDU
|
||||
|
||||
@@ -7,7 +7,8 @@ LIBS=-lm
|
||||
XLIBS=-lX11 -lpng -lXft
|
||||
|
||||
all: record replay extract_config textlog enb ue vcd macpdu2wireshark \
|
||||
extract_input_subframe extract_output_subframe to_vcd extract multi
|
||||
extract_input_subframe extract_output_subframe to_vcd extract multi \
|
||||
gnb
|
||||
|
||||
record: utils.o record.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o record $^ $(LIBS)
|
||||
@@ -60,6 +61,11 @@ macpdu2wireshark: macpdu2wireshark.o database.o utils.o handler.o event.o \
|
||||
multi: multi.o utils.o database.o config.o
|
||||
$(CC) $(CFLAGS) -o multi $^ $(LIBS)
|
||||
|
||||
gnb: utils.o gnb.o database.o event.o handler.o config.o \
|
||||
view/view.a gui/gui.a logger/logger.a \
|
||||
filter/filter.a
|
||||
$(CC) $(CFLAGS) -o gnb $^ $(LIBS) $(XLIBS)
|
||||
|
||||
multi.o: ../T_IDs.h
|
||||
|
||||
../T_IDs.h:
|
||||
@@ -85,7 +91,7 @@ filter/filter.a:
|
||||
clean:
|
||||
rm -f *.o core tracer_remote textlog enb ue vcd record replay
|
||||
rm -f extract_config macpdu2wireshark extract_input_subframe
|
||||
rm -f extract_output_subframe to_vcd extract multi
|
||||
rm -f extract_output_subframe to_vcd extract multi gnb
|
||||
cd gui && $(MAKE) clean
|
||||
cd view && $(MAKE) clean
|
||||
cd logger && $(MAKE) clean
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "database.h"
|
||||
#include "handler.h"
|
||||
#include "config.h"
|
||||
#include "logger/logger.h"
|
||||
#include "view/view.h"
|
||||
#include "gui/gui.h"
|
||||
|
||||
typedef struct {
|
||||
widget *pucch_pusch_iq_plot;
|
||||
logger *pucch_pusch_iq_logger;
|
||||
} gnb_gui;
|
||||
|
||||
typedef struct {
|
||||
int socket;
|
||||
int *is_on;
|
||||
int nevents;
|
||||
pthread_mutex_t lock;
|
||||
gnb_gui *e;
|
||||
void *database;
|
||||
} gnb_data;
|
||||
|
||||
void is_on_changed(void *_d)
|
||||
{
|
||||
gnb_data *d = _d;
|
||||
char t;
|
||||
|
||||
if (pthread_mutex_lock(&d->lock)) abort();
|
||||
|
||||
if (d->socket == -1) goto no_connection;
|
||||
|
||||
t = 1;
|
||||
if (socket_send(d->socket, &t, 1) == -1 ||
|
||||
socket_send(d->socket, &d->nevents, sizeof(int)) == -1 ||
|
||||
socket_send(d->socket, d->is_on, d->nevents * sizeof(int)) == -1)
|
||||
goto connection_dies;
|
||||
|
||||
no_connection:
|
||||
if (pthread_mutex_unlock(&d->lock)) abort();
|
||||
return;
|
||||
|
||||
connection_dies:
|
||||
close(d->socket);
|
||||
d->socket = -1;
|
||||
if (pthread_mutex_unlock(&d->lock)) abort();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void *gui_thread(void *_g)
|
||||
{
|
||||
gui *g = _g;
|
||||
gui_loop(g);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void gnb_main_gui(gnb_gui *e, gui *g, event_handler *h, void *database,
|
||||
gnb_data *ed)
|
||||
{
|
||||
widget *main_window;
|
||||
widget *top_container;
|
||||
widget *line;
|
||||
widget *w;
|
||||
logger *l;
|
||||
view *v;
|
||||
|
||||
main_window = new_toplevel_window(g, 500, 300, "gNB tracer");
|
||||
|
||||
top_container = new_container(g, VERTICAL);
|
||||
widget_add_child(g, main_window, top_container, -1);
|
||||
|
||||
line = new_container(g, HORIZONTAL);
|
||||
widget_add_child(g, top_container, line, -1);
|
||||
|
||||
/* PUCCH/PUSCH IQ data */
|
||||
w = new_xy_plot(g, 55, 55, "", 50);
|
||||
e->pucch_pusch_iq_plot = w;
|
||||
widget_add_child(g, line, w, -1);
|
||||
xy_plot_set_range(g, w, -1000, 1000, -1000, 1000);
|
||||
xy_plot_set_title(g, w, "rxdataF");
|
||||
l = new_iqlog_full(h, database, "GNB_PHY_PUCCH_PUSCH_IQ", "rxdataF");
|
||||
v = new_view_xy(300*12*14,10,g,w,new_color(g,"#000"),XY_FORCED_MODE);
|
||||
logger_add_view(l, v);
|
||||
e->pucch_pusch_iq_logger = l;
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
int port = DEFAULT_REMOTE_PORT;
|
||||
int *is_on;
|
||||
int number_of_events;
|
||||
int i;
|
||||
event_handler *h;
|
||||
gnb_data gnb_data;
|
||||
gui *g;
|
||||
gnb_gui eg;
|
||||
|
||||
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; }
|
||||
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();
|
||||
|
||||
h = new_handler(database);
|
||||
|
||||
on_off(database, "GNB_PHY_PUCCH_PUSCH_IQ", is_on, 1);
|
||||
|
||||
gnb_data.database = database;
|
||||
gnb_data.socket = -1;
|
||||
gnb_data.is_on = is_on;
|
||||
gnb_data.nevents = number_of_events;
|
||||
if (pthread_mutex_init(&gnb_data.lock, NULL)) abort();
|
||||
|
||||
g = gui_init();
|
||||
new_thread(gui_thread, g);
|
||||
|
||||
gnb_main_gui(&eg, g, h, database, &gnb_data);
|
||||
|
||||
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
||||
|
||||
restart:
|
||||
clear_remote_config();
|
||||
if (gnb_data.socket != -1) close(gnb_data.socket);
|
||||
gnb_data.socket = connect_to(ip, port);
|
||||
|
||||
/* send the first message - activate selected traces */
|
||||
is_on_changed(&gnb_data);
|
||||
|
||||
/* read messages */
|
||||
while (1) {
|
||||
event e;
|
||||
e = get_event(gnb_data.socket, &ebuf, database);
|
||||
if (e.type == -1) goto restart;
|
||||
if (pthread_mutex_lock(&gnb_data.lock)) abort();
|
||||
handle_event(h, e);
|
||||
if (pthread_mutex_unlock(&gnb_data.lock)) abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -74,6 +74,44 @@ static void _event(void *p, event e)
|
||||
l->common.v[i]->append(l->common.v[i], l->i, l->q, count);
|
||||
}
|
||||
|
||||
static void _event_full(void *p, event e)
|
||||
{
|
||||
struct iqlog *l = p;
|
||||
int i;
|
||||
void *buffer;
|
||||
int bsize;
|
||||
int nsamples;
|
||||
float *idst, *qdst;
|
||||
|
||||
if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0)
|
||||
return;
|
||||
|
||||
buffer = e.e[l->buffer_arg].b;
|
||||
bsize = e.e[l->buffer_arg].bsize;
|
||||
|
||||
nsamples = bsize / 4;
|
||||
|
||||
if (nsamples > l->max_length) {
|
||||
l->i = realloc(l->i, nsamples * sizeof(float));
|
||||
if (l->i == NULL) abort();
|
||||
l->q = realloc(l->q, nsamples * sizeof(float));
|
||||
if (l->q == NULL) abort();
|
||||
l->max_length = nsamples;
|
||||
}
|
||||
|
||||
idst = l->i;
|
||||
qdst = l->q;
|
||||
for (i = 0; i < nsamples; i++) {
|
||||
*idst = ((int16_t *)buffer)[i * 2];
|
||||
*qdst = ((int16_t *)buffer)[i * 2 + 1];
|
||||
idst++;
|
||||
qdst++;
|
||||
}
|
||||
|
||||
for (i = 0; i < l->common.vsize; i++)
|
||||
l->common.v[i]->append(l->common.v[i], l->i, l->q, nsamples);
|
||||
}
|
||||
|
||||
logger *new_iqlog(event_handler *h, void *database,
|
||||
char *event_name, char *nb_rb, char *N_RB_UL, char *symbols_per_tti,
|
||||
char *buffer_varname)
|
||||
@@ -149,3 +187,43 @@ logger *new_iqlog(event_handler *h, void *database,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
logger *new_iqlog_full(event_handler *h, void *database, char *event_name,
|
||||
char *buffer_varname)
|
||||
{
|
||||
struct iqlog *ret;
|
||||
int event_id;
|
||||
database_event_format f;
|
||||
int i;
|
||||
|
||||
ret = calloc(1, sizeof(struct iqlog)); if (ret == NULL) abort();
|
||||
|
||||
ret->common.event_name = strdup(event_name);
|
||||
if (ret->common.event_name == NULL) abort();
|
||||
ret->database = database;
|
||||
|
||||
event_id = event_id_from_name(database, event_name);
|
||||
|
||||
ret->common.handler_id = register_handler_function(h, event_id, _event_full,
|
||||
ret);
|
||||
|
||||
f = get_format(database, event_id);
|
||||
|
||||
/* look for args */
|
||||
ret->buffer_arg = -1;
|
||||
for (i = 0; i < f.count; i++) {
|
||||
if (!strcmp(f.name[i], buffer_varname)) ret->buffer_arg = i;
|
||||
}
|
||||
if (ret->buffer_arg == -1) {
|
||||
printf("%s:%d: buffer argument '%s' not found in event '%s'\n",
|
||||
__FILE__, __LINE__, buffer_varname, event_name);
|
||||
abort();
|
||||
}
|
||||
if (strcmp(f.type[ret->buffer_arg], "buffer") != 0) {
|
||||
printf("%s:%d: argument '%s' has wrong type (should be 'buffer')\n",
|
||||
__FILE__, __LINE__, buffer_varname);
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ logger *new_ticklog(void *event_handler, void *database,
|
||||
logger *new_iqlog(void *event_handler, void *database,
|
||||
char *event_name, char *nb_rb, char *N_RB_UL, char *symbols_per_tti,
|
||||
char *buffer_varname);
|
||||
logger *new_iqlog_full(void *event_handler, void *database, char *event_name,
|
||||
char *buffer_varname);
|
||||
logger *new_iqdotlog(void *event_handler, void *database,
|
||||
char *event_name, char *I, char *Q);
|
||||
|
||||
|
||||
@@ -542,6 +542,9 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
|
||||
}
|
||||
|
||||
void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
|
||||
/* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */
|
||||
int pucch_decode_done = 0;
|
||||
int pusch_decode_done = 0;
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1);
|
||||
LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx);
|
||||
@@ -563,6 +566,8 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
|
||||
(pucch->frame == frame_rx) &&
|
||||
(pucch->slot == slot_rx) ) {
|
||||
|
||||
pucch_decode_done = 1;
|
||||
|
||||
nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu;
|
||||
uint16_t num_ucis;
|
||||
switch (pucch_pdu->format_type) {
|
||||
@@ -651,7 +656,7 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
|
||||
}
|
||||
#endif
|
||||
|
||||
T(T_BENETEL, T_INT(frame_rx), T_INT(slot_rx), T_BUFFER(&gNB->common_vars.rxdataF[0][0], 2048*4*14));
|
||||
pusch_decode_done = 1;
|
||||
|
||||
uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index;
|
||||
uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols;
|
||||
@@ -680,5 +685,9 @@ T(T_BENETEL, T_INT(frame_rx), T_INT(slot_rx), T_BUFFER(&gNB->common_vars.rxdataF
|
||||
// figure out a better way to choose slot_rx, 19 is ok for a particular TDD configuration with 30kHz SCS
|
||||
if ((frame_rx&127) == 0 && slot_rx==19) dump_pusch_stats(gNB);
|
||||
|
||||
if (pucch_decode_done || pusch_decode_done) {
|
||||
T(T_GNB_PHY_PUCCH_PUSCH_IQ, T_INT(frame_rx), T_INT(slot_rx), T_BUFFER(&gNB->common_vars.rxdataF[0][0], gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size * 4));
|
||||
}
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user