nr_phy_scope.c 33.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * 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
 *
laurent's avatar
laurent committed
12 13
 * Author and copyright: Laurent Thomas, open-cells.com
 *
14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * 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
 */

/* Form definition file generated by fdesign */

#include <stdlib.h>
#include "nr_phy_scope.h"
28
#include "executables/softmodem-common.h"
29
#include "executables/nr-softmodem-common.h"
laurent's avatar
laurent committed
30
#include <forms.h>
31 32

#define TPUT_WINDOW_LENGTH 100
33
#define ScaleZone 4
laurent's avatar
laurent committed
34
#define localBuff(NaMe,SiZe) float NaMe[SiZe]; memset(NaMe,0,sizeof(NaMe));
35

Laurent's avatar
Laurent committed
36
int otg_enabled;
37

Laurent's avatar
Laurent committed
38 39
const FL_COLOR rx_antenna_colors[4] = {FL_RED,FL_BLUE,FL_GREEN,FL_YELLOW};
const FL_COLOR water_colors[4] = {FL_BLUE,FL_GREEN,FL_YELLOW,FL_RED};
40

41
typedef struct complex16 scopeSample_t;
laurent's avatar
laurent committed
42 43 44 45
#define SquaredNorm(VaR) ((VaR).r*(VaR).r+(VaR).i*(VaR).i)

typedef struct OAIgraph {
  FL_OBJECT *graph;
Laurent's avatar
Laurent committed
46
  FL_OBJECT *text;
laurent's avatar
laurent committed
47 48 49 50
  float maxX;
  float maxY;
  float minX;
  float minY;
Laurent's avatar
Laurent committed
51 52 53 54 55 56
  int x;
  int y;
  int w;
  int h;
  int waterFallh;
  double *waterFallAvg;
57
  boolean_t initDone;
laurent's avatar
laurent committed
58
  int iteration;
59
  void (*gNBfunct) (struct OAIgraph *graph, scopeData_t *p, int UE_id);
laurent's avatar
laurent committed
60
  void (*nrUEfunct)(struct OAIgraph *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id);
laurent's avatar
laurent committed
61 62 63 64 65 66 67
} OAIgraph_t;

/* Forms and Objects */
typedef struct {
  FL_FORM    *phy_scope;
  OAIgraph_t graph[20];
  FL_OBJECT *button_0;
laurent's avatar
laurent committed
68
} OAI_phy_scope_t;
69

laurent's avatar
laurent committed
70 71 72 73 74 75 76 77 78 79 80 81 82
typedef struct {
  FL_FORM    *stats_form;
  void       *vdata;
  char       *cdata;
  long        ldata;
  FL_OBJECT *stats_text;
  FL_OBJECT *stats_button;
} FD_stats_form;

static void drawsymbol(FL_OBJECT *obj, int id,
                       FL_POINT *p, int n, int w, int h) {
  fl_points( p, n, FL_YELLOW);
}
83

laurent's avatar
laurent committed
84 85
// button callback example
#if 0
laurent's avatar
laurent committed
86
static void dl_traffic_on_off( FL_OBJECT *button, long arg) {
87 88 89 90 91 92 93 94 95 96
  if (fl_get_button(button)) {
    fl_set_object_label(button, "DL Traffic ON");
    otg_enabled = 1;
    fl_set_object_color(button, FL_GREEN, FL_GREEN);
  } else {
    fl_set_object_label(button, "DL Traffic OFF");
    otg_enabled = 0;
    fl_set_object_color(button, FL_RED, FL_RED);
  }
}
laurent's avatar
laurent committed
97
#endif
98

Laurent's avatar
Laurent committed
99 100 101 102 103 104
#define WATERFALL 10000

static void commonGraph(OAIgraph_t *graph, int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, FL_COLOR pointColor) {
  if (type==WATERFALL) {
    graph->waterFallh=h-15;
    graph->waterFallAvg=malloc(sizeof(*graph->waterFallAvg) * graph->waterFallh);
105 106 107

    for (int i=0; i< graph->waterFallh; i++)
      graph->waterFallAvg[i]=0;
Laurent's avatar
Laurent committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

    graph->graph=fl_add_canvas(FL_NORMAL_CANVAS, x, y, w, graph->waterFallh, label);
    graph->text=fl_add_text(FL_NORMAL_TEXT, x, y+graph->waterFallh, w, 15, label);
    fl_set_object_lcolor(graph->text,FL_WHITE);
    fl_set_object_color(graph->text, FL_BLACK, FL_BLACK);
    fl_set_object_lalign(graph->text, FL_ALIGN_CENTER );
  } else {
    graph->graph=fl_add_xyplot(type, x, y, w, h, label);
    fl_set_object_lcolor(graph->graph, FL_WHITE ); // Label color
    fl_set_object_color(graph->graph, FL_BLACK, pointColor);

    for (int i=0; i< FL_MAX_XYPLOTOVERLAY; i++)
      fl_set_xyplot_symbol(graph->graph, i, drawsymbol);
  }

  graph->x=x;
  graph->y=y;
  graph->w=w;
  graph->h=h;
  graph->maxX=0;
  graph->maxY=0;
  graph->minX=0;
  graph->minY=0;
131
  graph->initDone=false;
Laurent's avatar
Laurent committed
132
  graph->iteration=0;
laurent's avatar
laurent committed
133
}
134

135
static OAIgraph_t gNBcommonGraph( void (*funct) (OAIgraph_t *graph, scopeData_t *p, int UE_id),
laurent's avatar
laurent committed
136 137
                                  int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, FL_COLOR pointColor) {
  OAIgraph_t graph;
Laurent's avatar
Laurent committed
138
  commonGraph(&graph, type, x, y, w, h, label, pointColor);
laurent's avatar
laurent committed
139 140 141 142
  graph.gNBfunct=funct;
  graph.nrUEfunct=NULL;
  return graph;
}
143

laurent's avatar
laurent committed
144
static OAIgraph_t nrUEcommonGraph( void (*funct) (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id),
laurent's avatar
laurent committed
145 146
                                   int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, FL_COLOR pointColor) {
  OAIgraph_t graph;
Laurent's avatar
Laurent committed
147
  commonGraph(&graph, type, x, y, w, h, label, pointColor);
laurent's avatar
laurent committed
148 149 150 151
  graph.gNBfunct=NULL;
  graph.nrUEfunct=funct;
  return graph;
}
152

laurent's avatar
laurent committed
153
static void setRange(OAIgraph_t *graph, float minX, float maxX, float minY, float maxY) {
154 155 156 157 158
  if ( maxX > graph->maxX ||  minX < graph->minX ||
       abs(maxX-graph->maxX)>abs(graph->maxX)/2 ||
       abs(maxX-graph->maxX)>abs(graph->maxX)/2 ) {
    graph->maxX/=2;
    graph->minX/=2;
laurent's avatar
laurent committed
159 160
    graph->maxX=max(graph->maxX,maxX);
    graph->minX=min(graph->minX,minX);
161 162 163 164 165 166 167 168
    fl_set_xyplot_xbounds(graph->graph, graph->minX*1.2, graph->maxX*1.2);
  }

  if ( maxY > graph->maxY || minY < graph->minY ||
       abs(maxY-graph->maxY)>abs(graph->maxY)/2 ||
       abs(maxY-graph->maxY)>abs(graph->maxY)/2 ) {
    graph->maxY/=2;
    graph->minY/=2;
laurent's avatar
laurent committed
169 170
    graph->maxY=max(graph->maxY,maxY);
    graph->minY=min(graph->minY,minY);
171
    fl_set_xyplot_ybounds(graph->graph, graph->minY*1.2, graph->maxY*1.2);
laurent's avatar
laurent committed
172 173
  }
}
174

Laurent's avatar
Laurent committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
static void oai_xygraph_getbuff(OAIgraph_t *graph, float **x, float **y, int len, int layer) {
  float *old_x;
  float *old_y;
  int old_len=-1;

  if (graph->iteration >1)
    fl_get_xyplot_data_pointer(graph->graph, layer, &old_x, &old_y, &old_len);

  if (old_len != len) {
    LOG_W(HW,"allocating graph of %d scope\n", len);
    float values[len];
    float time[len];

    // make time in case we will use it
    for (int i=0; i<len; i++)
      time[i] = values[i] = i;

    if (layer==0)
      fl_set_xyplot_data(graph->graph,time,values,len,"","","");
    else
      fl_add_xyplot_overlay(graph->graph,layer,time,values,len,rx_antenna_colors[layer]);

    fl_get_xyplot_data_pointer(graph->graph, layer, &old_x, &old_y, &old_len);
    AssertFatal(old_len==len,"");
  }

  *x=old_x;
  *y=old_y;
}

static void oai_xygraph(OAIgraph_t *graph, float *x, float *y, int len, int layer, boolean_t NoAutoScale) {
  fl_redraw_object(graph->graph);
207

laurent's avatar
laurent committed
208 209
  if ( NoAutoScale && graph->iteration%NoAutoScale == 0) {
    float maxX=0, maxY=0, minX=0, minY=0;
210

laurent's avatar
laurent committed
211 212 213 214 215 216
    for (int k=0; k<len; k++) {
      maxX=max(maxX,x[k]);
      minX=min(minX,x[k]);
      maxY=max(maxY,y[k]);
      minY=min(minY,y[k]);
    }
217

Laurent's avatar
Laurent committed
218
    setRange(graph, minX-5, maxX+5, minY-5, maxY+5);
laurent's avatar
laurent committed
219
  }
220

laurent's avatar
laurent committed
221
  graph->iteration++;
222 223
}

224
static void genericWaterFall (OAIgraph_t *graph, scopeSample_t *values, const int datasize, const int divisions, const char *label) {
225
  if ( values == NULL )
226 227
    return;

Laurent's avatar
Laurent committed
228 229
  fl_winset(FL_ObjWin(graph->graph));
  const int samplesPerPixel=datasize/graph->w;
230 231
  int displayPart=graph->waterFallh-ScaleZone;
  int row=graph->iteration%displayPart;
Laurent's avatar
Laurent committed
232 233
  double avg=0;

234
  for (int i=0; i < displayPart; i++)
Laurent's avatar
Laurent committed
235 236
    avg+=graph->waterFallAvg[i];

237
  avg/=displayPart;
Laurent's avatar
Laurent committed
238 239 240 241 242
  graph->waterFallAvg[row]=0;

  for (int pix=0; pix<graph->w; pix++) {
    scopeSample_t *end=values+(pix+1)*samplesPerPixel;
    end-=2;
243
    AssertFatal(end <= values+datasize,"diff : %ld", end-values+datasize);
Laurent's avatar
Laurent committed
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    double val=0;

    for (scopeSample_t *s=values+(pix)*samplesPerPixel;
         s <end;
         s++)
      val += SquaredNorm(*s);

    val/=samplesPerPixel;
    graph->waterFallAvg[row]+=val/graph->w;
    int col=0;

    if (val > avg*2 )
      col=1;

    if (val > avg*10 )
      col=2;

    if (val > avg*100 )
      col=3;

264
    fl_point(pix, graph->iteration%displayPart, water_colors[col]);
laurent's avatar
laurent committed
265
  }
266

267 268 269 270 271 272 273 274 275 276 277 278
  if (graph->initDone==false) {
    for ( int i=0; i < graph->waterFallh; i++ )
      for ( int j = 0 ; j < graph->w ; j++ )
        fl_point(j, i, FL_BLACK);

    for ( int i=1; i<divisions; i++)
      for (int j= displayPart; j<graph->waterFallh; j++)
        fl_point(i*(graph->w/divisions),j, FL_WHITE);

    graph->initDone=true;
  }

279
  fl_set_object_label_f(graph->text, "%s, avg I/Q pow: %4.1f", label, 0/*sqrt(avg)*/);
laurent's avatar
laurent committed
280
  graph->iteration++;
281 282
}

laurent's avatar
laurent committed
283
static void genericPowerPerAntena(OAIgraph_t  *graph, const int nb_ant, const scopeSample_t **data, const int len) {
Laurent's avatar
Laurent committed
284 285
  float *values, *time;
  oai_xygraph_getbuff(graph, &time, &values, len, 0);
laurent's avatar
laurent committed
286

laurent's avatar
laurent committed
287 288 289 290
  for (int ant=0; ant<nb_ant; ant++) {
    if (data[ant] != NULL) {
      for (int i=0; i<len; i++) {
        values[i] = SquaredNorm(data[ant][i]);
291 292
      }

laurent's avatar
laurent committed
293
      oai_xygraph(graph,time,values, len, ant, 10);
294
    }
laurent's avatar
laurent committed
295 296
  }
}
297

298 299
static void gNBWaterFall (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
  NR_DL_FRAME_PARMS *frame_parms=&p->gNB->frame_parms;
Laurent's avatar
Laurent committed
300
  //use 1st antenna
301
  genericWaterFall(graph, (scopeSample_t *)p->ru->common.rxdata[0],
302 303
                   frame_parms->samples_per_frame,  frame_parms->slots_per_frame,
                   "X axis:one frame in time");
Laurent's avatar
Laurent committed
304 305 306
}

/* replaced by waterfall
laurent's avatar
laurent committed
307 308 309
static void timeSignal (OAIgraph_t *graph, PHY_VARS_gNB *phy_vars_gnb, RU_t *phy_vars_ru, const int nb_UEs) {
  // Received signal in time domain of receive antenna 0
  if (!phy_vars_ru->common.rxdata)
laurent's avatar
laurent committed
310
    return;
311

laurent's avatar
laurent committed
312
  NR_DL_FRAME_PARMS *frame_parms=&phy_vars_gnb->frame_parms;
laurent's avatar
laurent committed
313 314 315 316
  genericLogPowerPerAntena(graph, frame_parms->nb_antennas_rx,
                           (const scopeSample_t **)phy_vars_ru->common.rxdata,
                           frame_parms->samples_per_frame);
}
Laurent's avatar
Laurent committed
317
*/
318

319 320
static void timeResponse (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
  const int len=2*p->gNB->frame_parms.ofdm_symbol_size;
Laurent's avatar
Laurent committed
321 322
  float *values, *time;
  oai_xygraph_getbuff(graph, &time, &values, len, 0);
laurent's avatar
laurent committed
323
  const int ant=0; // display antenna 0 for each UE
324

laurent's avatar
laurent committed
325
  for (int ue=0; ue<nb_UEs; ue++) {
326 327 328 329 330 331 332 333 334
    if ( p->gNB->pusch_vars && p->gNB->pusch_vars[ue] &&
         p->gNB->pusch_vars[ue]->ul_ch_estimates_time &&
         p->gNB->pusch_vars[ue]->ul_ch_estimates_time[ant] ) {
      scopeSample_t *data= (scopeSample_t *)p->gNB->pusch_vars[ue]->ul_ch_estimates_time[ant];

      if (data != NULL) {
        for (int i=0; i<len; i++) {
          values[i] = SquaredNorm(data[i]);
        }
laurent's avatar
laurent committed
335

336
        oai_xygraph(graph,time,values, len, ue, 10);
337 338
      }
    }
laurent's avatar
laurent committed
339 340
  }
}
341

342 343
static void gNBfreqWaterFall (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
  NR_DL_FRAME_PARMS *frame_parms=&p->gNB->frame_parms;
Laurent's avatar
Laurent committed
344
  //use 1st antenna
345
  genericWaterFall(graph, (scopeSample_t *)p->rxdataF, frame_parms->samples_per_frame_wCP,
346
                   frame_parms->slots_per_frame,
347
                   "X axis: Frequency domain, one subframe");
Laurent's avatar
Laurent committed
348 349 350
}

/*
laurent's avatar
laurent committed
351 352 353 354 355 356
static void frequencyResponse (OAIgraph_t *graph, PHY_VARS_gNB *phy_vars_gnb, RU_t *phy_vars_ru, int nb_UEs) {
  NR_DL_FRAME_PARMS *frame_parms=&phy_vars_gnb->frame_parms;
  genericLogPowerPerAntena(graph, frame_parms->nb_antennas_rx,
                           (const scopeSample_t **)phy_vars_ru->common.rxdataF,
                           frame_parms->samples_per_slot_wCP);
}
Laurent's avatar
Laurent committed
357
*/
358

359
static void puschLLR (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
laurent's avatar
laurent committed
360 361 362
  //int Qm = 2;
  int coded_bits_per_codeword =3*8*6144+12; // (8*((3*8*6144)+12)); // frame_parms->N_RB_UL*12*Qm*frame_parms->symbols_per_tti;

laurent's avatar
laurent committed
363
  for (int ue=0; ue<nb_UEs; ue++) {
364 365 366 367 368 369
    if ( p->gNB->pusch_vars &&
         p->gNB->pusch_vars[ue] &&
         p->gNB->pusch_vars[ue]->llr ) {
      int16_t *pusch_llr = (int16_t *)p->gNB->pusch_vars[ue]->llr;
      float *llr, *bit;
      oai_xygraph_getbuff(graph, &bit, &llr, coded_bits_per_codeword, ue);
370

laurent's avatar
laurent committed
371 372 373
      for (int i=0; i<coded_bits_per_codeword; i++) {
        llr[i] = (float) pusch_llr[i];
      }
laurent's avatar
laurent committed
374

laurent's avatar
laurent committed
375 376 377 378
      oai_xygraph(graph,bit,llr,coded_bits_per_codeword,ue,10);
    }
  }
}
379

380 381
static void puschIQ (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
  NR_DL_FRAME_PARMS *frame_parms=&p->gNB->frame_parms;
laurent's avatar
laurent committed
382 383
  int sz=frame_parms->N_RB_UL*12*frame_parms->symbols_per_slot;

laurent's avatar
laurent committed
384
  for (int ue=0; ue<nb_UEs; ue++) {
385 386 387 388 389 390 391
    if ( p->gNB->pusch_vars &&
         p->gNB->pusch_vars[ue] &&
         p->gNB->pusch_vars[ue]->rxdataF_comp &&
         p->gNB->pusch_vars[ue]->rxdataF_comp[0] ) {
      scopeSample_t *pusch_comp = (scopeSample_t *) p->gNB->pusch_vars[ue]->rxdataF_comp[0];
      float *I, *Q;
      oai_xygraph_getbuff(graph, &I, &Q, sz, ue);
392

laurent's avatar
laurent committed
393 394 395 396
      for (int k=0; k<sz; k++ ) {
        I[k] = pusch_comp[k].r;
        Q[k] = pusch_comp[k].i;
      }
laurent's avatar
laurent committed
397

laurent's avatar
laurent committed
398 399 400 401 402
      oai_xygraph(graph,I,Q,sz,ue,10);
    }
  }
}

403
static void pucchEnergy (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
404
  // PUSCH I/Q of MF Output
laurent's avatar
laurent committed
405
  /*
laurent's avatar
laurent committed
406 407 408
    int32_t *pucch1ab_comp = (int32_t *) NULL; //phy_vars_gnb->pucch1ab_stats[UE_id];
    int32_t *pucch1_comp = (int32_t *) NULL; //phy_vars_gnb->pucch1_stats[UE_id];
    float I_pucch[10240],Q_pucch[10240],A_pucch[10240],B_pucch[10240],C_pucch[10240];
409

laurent's avatar
laurent committed
410
    for (int ind=0; ind<10240; ind++) {
411 412
      I_pucch[ind] = (float)pucch1ab_comp[2*(ind)];
      Q_pucch[ind] = (float)pucch1ab_comp[2*(ind)+1];
413
      A_pucch[ind] = pucch1_comp?(10*log10(pucch1_comp[ind])):0;
414
      B_pucch[ind] = ind;
laurent's avatar
laurent committed
415
      int32_t *pucch1_thres = (int32_t *) NULL; // phy_vars_gnb->pucch1_stats_thres[UE_id];
416
      C_pucch[ind] = pucch1_thres?(float)pucch1_thres[ind]:0;
417 418
    }

laurent's avatar
laurent committed
419 420 421 422 423 424
    fl_set_xyplot_data(graph,I_pucch,Q_pucch,10240,"","","");
    fl_set_xyplot_data(graph,B_pucch,A_pucch,1024,"","","");
    fl_add_xyplot_overlay(graph,1,B_pucch,C_pucch,1024,FL_RED);
    fl_set_xyplot_ybounds(graph,-5000,5000);
    fl_set_xyplot_xbounds(graph,-5000,5000);
    fl_set_xyplot_ybounds(graph,0,80);
425
  }
laurent's avatar
laurent committed
426
  */
laurent's avatar
laurent committed
427 428
}

429
static void pucchIQ (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
laurent's avatar
laurent committed
430
}
431

432
static void puschThroughtput (OAIgraph_t *graph, scopeData_t *p, int nb_UEs) {
433
  // PUSCH Throughput
laurent's avatar
laurent committed
434
  /*
Laurent's avatar
Laurent committed
435 436 437
  float tput_time_enb[NUMBER_OF_UE_MAX][TPUT_WINDOW_LENGTH] = {{0}};
  float tput_enb[NUMBER_OF_UE_MAX][TPUT_WINDOW_LENGTH] = {{0}};

438 439
  memmove( tput_time_enb[UE_id], &tput_time_enb[UE_id][1], (TPUT_WINDOW_LENGTH-1)*sizeof(float) );
  memmove( tput_enb[UE_id], &tput_enb[UE_id][1], (TPUT_WINDOW_LENGTH-1)*sizeof(float) );
440
  tput_time_enb[UE_id][TPUT_WINDOW_LENGTH-1]  = (float) 0;
laurent's avatar
laurent committed
441 442
  //  tput_enb[UE_id][TPUT_WINDOW_LENGTH-1] = ((float) total_dlsch_bitrate)/1000.0;
  fl_set_xyplot_data(graph,tput_time_enb[UE_id],tput_enb[UE_id],TPUT_WINDOW_LENGTH,"","","");
443 444
  //    fl_get_xyplot_ybounds(form->pusch_tput,&ymin,&ymax);
  //    fl_set_xyplot_ybounds(form->pusch_tput,0,ymax);
laurent's avatar
laurent committed
445
  */
446
}
laurent's avatar
laurent committed
447
static OAI_phy_scope_t *create_phy_scope_gnb(void) {
448
  FL_OBJECT *obj;
laurent's avatar
laurent committed
449
  OAI_phy_scope_t *fdui = calloc(( sizeof *fdui ),1);
450
  // Define form
laurent's avatar
laurent committed
451
  fdui->phy_scope = fl_bgn_form( FL_NO_BOX, 800, 800 );
452
  // This the whole UI box
laurent's avatar
laurent committed
453
  obj = fl_add_box( FL_BORDER_BOX, 0, 0, 800, 800, "" );
laurent's avatar
laurent committed
454 455
  fl_set_object_color( obj, FL_BLACK, FL_WHITE );
  int curY=0,x,y,w,h;
456
  // Received signal
Laurent's avatar
Laurent committed
457 458
  fdui->graph[0] = gNBcommonGraph( gNBWaterFall, WATERFALL, 0, curY, 400, 100,
                                   "Received Signal (Time-Domain, one frame)", FL_RED );
459
  // Time-domain channel response
laurent's avatar
laurent committed
460
  fdui->graph[1] = gNBcommonGraph( timeResponse, FL_NORMAL_XYPLOT, 410, curY, 400, 100,
laurent's avatar
laurent committed
461
                                   "SRS Frequency Response (samples, abs)", FL_RED );
Laurent's avatar
Laurent committed
462
  fl_get_object_bbox(fdui->graph[1].graph,&x, &y,&w, &h);
laurent's avatar
laurent committed
463
  curY+=h;
464
  // Frequency-domain channel response
Laurent's avatar
Laurent committed
465 466
  fdui->graph[2] = gNBcommonGraph( gNBfreqWaterFall, WATERFALL, 0, curY, 800, 100,
                                   "Channel Frequency domain (RE, one frame)", FL_RED );
laurent's avatar
laurent committed
467
  fl_get_object_bbox(fdui->graph[2].graph,&x, &y,&w, &h);
468
  curY+=h+20;
laurent's avatar
laurent committed
469
  // LLR of PUSCH
laurent's avatar
laurent committed
470
  fdui->graph[3] = gNBcommonGraph( puschLLR, FL_POINTS_XYPLOT, 0, curY, 500, 200,
laurent's avatar
laurent committed
471 472
                                   "PUSCH Log-Likelihood Ratios (LLR, mag)", FL_YELLOW );
  // I/Q PUSCH comp
laurent's avatar
laurent committed
473
  fdui->graph[4] = gNBcommonGraph( puschIQ, FL_POINTS_XYPLOT, 500, curY, 300, 200,
laurent's avatar
laurent committed
474
                                   "PUSCH I/Q of MF Output", FL_YELLOW );
laurent's avatar
laurent committed
475 476
  fl_get_object_bbox(fdui->graph[3].graph,&x, &y,&w, &h);
  curY+=h;
laurent's avatar
laurent committed
477
  // I/Q PUCCH comp (format 1)
laurent's avatar
laurent committed
478
  fdui->graph[5] = gNBcommonGraph( pucchEnergy, FL_POINTS_XYPLOT, 0, curY, 300, 100,
laurent's avatar
laurent committed
479 480 481
                                   "PUCCH1 Energy (SR)", FL_YELLOW );
  //  fl_set_xyplot_xgrid( fdui->pusch_llr,FL_GRID_MAJOR);
  // I/Q PUCCH comp (fromat 1a/b)
laurent's avatar
laurent committed
482
  fdui->graph[6] = gNBcommonGraph( pucchIQ, FL_POINTS_XYPLOT, 500, curY, 300, 100,
laurent's avatar
laurent committed
483
                                   "PUCCH I/Q of MF Output", FL_YELLOW );
laurent's avatar
laurent committed
484 485
  fl_get_object_bbox(fdui->graph[6].graph,&x, &y,&w, &h);
  curY+=h;
laurent's avatar
laurent committed
486
  // Throughput on PUSCH
laurent's avatar
laurent committed
487
  fdui->graph[7] = gNBcommonGraph( puschThroughtput, FL_NORMAL_XYPLOT, 0, curY, 500, 100,
laurent's avatar
laurent committed
488 489
                                   "PUSCH Throughput [frame]/[kbit/s]", FL_WHITE );
  fdui->graph[8].graph=NULL;
490
  fl_end_form( );
laurent's avatar
laurent committed
491
  fdui->phy_scope->fdui = fdui;
laurent's avatar
laurent committed
492
  fl_show_form (fdui->phy_scope, FL_PLACE_HOTSPOT, FL_FULLBORDER, "LTE UL SCOPE gNB");
493 494
  return fdui;
}
laurent's avatar
laurent committed
495 496
static const int scope_enb_num_ue = 1;
void phy_scope_gNB(OAI_phy_scope_t *form,
497
                   scopeData_t *p,
laurent's avatar
laurent committed
498
                   int UE_id) {
Laurent's avatar
Laurent committed
499
  static OAI_phy_scope_t *rememberForm=NULL;
laurent's avatar
laurent committed
500 501

  if (form==NULL)
Laurent's avatar
Laurent committed
502
    form=rememberForm;
laurent's avatar
laurent committed
503
  else
Laurent's avatar
Laurent committed
504
    rememberForm=form;
laurent's avatar
laurent committed
505

Laurent's avatar
Laurent committed
506 507
  if (form==NULL)
    return;
laurent's avatar
laurent committed
508 509 510 511

  int i=0;

  while (form->graph[i].graph) {
512
    form->graph[i].gNBfunct(form->graph+i, p, UE_id);
laurent's avatar
laurent committed
513 514 515
    i++;
  }

Laurent's avatar
Laurent committed
516
  //fl_check_forms();
laurent's avatar
laurent committed
517
}
laurent's avatar
laurent committed
518
static void *scope_thread_gNB(void *arg) {
519
  scopeData_t *p=(scopeData_t *) arg;
laurent's avatar
laurent committed
520 521 522
  //# ifdef ENABLE_XFORMS_WRITE_STATS
  //  FILE *gNB_stats = fopen("gNB_stats.txt", "w");
  //#endif
laurent's avatar
laurent committed
523
  size_t stksize=0;
Thomas Schlichter's avatar
Thomas Schlichter committed
524 525
  pthread_attr_t atr;
  pthread_attr_init(&atr);
laurent's avatar
laurent committed
526 527 528
  pthread_attr_getstacksize(&atr, &stksize);
  pthread_attr_setstacksize(&atr,32*1024*1024 );
  sleep(3); // no clean interthread barriers
Laurent's avatar
Laurent committed
529 530 531
  int fl_argc=1;
  char *name="5G-gNB-scope";
  fl_initialize (&fl_argc, &name, NULL, 0, 0);
laurent's avatar
laurent committed
532 533
  int nb_ue=min(NUMBER_OF_UE_MAX, scope_enb_num_ue);
  OAI_phy_scope_t  *form_gnb = create_phy_scope_gnb();
534

laurent's avatar
laurent committed
535
  while (!oai_exit) {
536
    phy_scope_gNB(form_gnb, p, nb_ue);
laurent's avatar
laurent committed
537
    usleep(99*1000);
538 539
  }

laurent's avatar
laurent committed
540 541
  return NULL;
}
542 543 544 545 546 547
static void copyRxdataF(int32_t *data, int slot,  void *scopeData) {
  scopeData_t *scope=(scopeData_t *)scopeData;
  memcpy(scope->rxdataF + slot*scope->gNB->frame_parms.samples_per_slot_wCP,
         data,
         scope->gNB->frame_parms.samples_per_slot_wCP);
}
548

549
void gNBinitScope(scopeParms_t *p) {
550
  AssertFatal(p->gNB->scopeData=malloc(sizeof(scopeData_t)),"");
551 552 553 554 555 556
  scopeData_t *scope=(scopeData_t *) p->gNB->scopeData;
  scope->argc=p->argc;
  scope->argv=p->argv;
  scope->ru=p->ru;
  scope->gNB=p->gNB;
  scope->slotFunc=copyRxdataF;
557
  AssertFatal(scope->rxdataF=(int32_t *) calloc(p->gNB->frame_parms.samples_per_frame_wCP*sizeof(int32_t),1),"");
laurent's avatar
laurent committed
558
  pthread_t forms_thread;
559
  threadCreate(&forms_thread, scope_thread_gNB, p->gNB->scopeData, "scope", -1, OAI_PRIORITY_RT_LOW);
laurent's avatar
laurent committed
560
}
Laurent's avatar
Laurent committed
561 562 563 564
static void ueWaterFall  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
  // Received signal in time domain of receive antenna 0
  genericWaterFall(graph,
                   (scopeSample_t *) phy_vars_ue->common_vars.rxdata[0],
565 566 567
                   phy_vars_ue->frame_parms.samples_per_frame,
                   phy_vars_ue->frame_parms.slots_per_frame,
                   "X axis: one frame time");
Laurent's avatar
Laurent committed
568 569
}
/* replaced by waterfall
laurent's avatar
laurent committed
570
static void ueTimeResponse  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
571
  // Received signal in time domain of receive antenna 0
laurent's avatar
laurent committed
572 573 574
  genericLogPowerPerAntena(graph, phy_vars_ue->frame_parms.nb_antennas_rx,
                           (const scopeSample_t **) phy_vars_ue->common_vars.rxdata,
                           phy_vars_ue->frame_parms.samples_per_frame);
laurent's avatar
laurent committed
575
}
Laurent's avatar
Laurent committed
576
*/
laurent's avatar
laurent committed
577
static void ueChannelResponse  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
578
  // Channel Impulse Response
laurent's avatar
laurent committed
579 580 581
  genericPowerPerAntena(graph, phy_vars_ue->frame_parms.nb_antennas_rx,
                        (const scopeSample_t **) phy_vars_ue->pbch_vars[eNB_id]->dl_ch_estimates_time,
                        phy_vars_ue->frame_parms.ofdm_symbol_size>>3);
laurent's avatar
laurent committed
582
}
Laurent's avatar
Laurent committed
583 584 585 586 587
static void ueFreqWaterFall (OAIgraph_t *graph,PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id ) {
  NR_DL_FRAME_PARMS *frame_parms=&phy_vars_ue->frame_parms;
  //use 1st antenna
  genericWaterFall(graph,
                   (scopeSample_t *)phy_vars_ue->common_vars.common_vars_rx_data_per_thread[0].rxdataF[0],
588 589 590
                   frame_parms->samples_per_slot_wCP,
                   phy_vars_ue->frame_parms.slots_per_frame,
                   "X axis: one frame frequency" );
Laurent's avatar
Laurent committed
591 592
}
/*
laurent's avatar
laurent committed
593
static void uePbchFrequencyResp  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
laurent's avatar
laurent committed
594 595 596
  // Channel Frequency Response (includes 5 complex sample for filter)
  if (!phy_vars_ue->pbch_vars[eNB_id]->dl_ch_estimates)
    return;
597

laurent's avatar
laurent committed
598 599 600 601 602
  NR_DL_FRAME_PARMS *frame_parms = &phy_vars_ue->frame_parms;
  uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx;
  uint8_t nb_antennas_tx = frame_parms->nb_antenna_ports_gNB;
  scopeSample_t   **chest_f = (scopeSample_t **) phy_vars_ue->pbch_vars[eNB_id]->dl_ch_estimates;
  int ind = 0;
Laurent's avatar
Laurent committed
603 604
  float *freq, *chest_f_abs;
  oai_xygraph_getbuff(graph, &freq, &chest_f_abs, frame_parms->ofdm_symbol_size, 0);
laurent's avatar
laurent committed
605 606 607 608

  for (int atx=0; atx<nb_antennas_tx; atx++) {
    for (int arx=0; arx<nb_antennas_rx; arx++) {
      if (chest_f[(atx<<1)+arx] != NULL) {
Laurent's avatar
Laurent committed
609

laurent's avatar
laurent committed
610 611 612 613
        for (int k=0; k<frame_parms->ofdm_symbol_size; k++) {
          freq[ind] = (float)ind;
          chest_f_abs[ind] = (short)10*log10(1.0+SquaredNorm(chest_f[(atx<<1)+arx][6144+k]));
          ind++;
614 615 616 617
        }
      }
    }
  }
laurent's avatar
laurent committed
618 619 620 621 622 623

  // tx antenna 0
  //fl_set_xyplot_xbounds(form->chest_f,0,nb_antennas_rx*nb_antennas_tx*nsymb_ce);
  //fl_set_xyplot_xtics(form->chest_f,nb_antennas_rx*nb_antennas_tx*frame_parms->symbols_per_tti,2);
  //        fl_set_xyplot_xtics(form->chest_f,nb_antennas_rx*nb_antennas_tx*2,2);
  //fl_set_xyplot_xgrid(form->chest_f,FL_GRID_MAJOR);
laurent's avatar
laurent committed
624
  oai_xygraph(graph,freq,chest_f_abs,frame_parms->ofdm_symbol_size,0,10);
laurent's avatar
laurent committed
625
}
Laurent's avatar
Laurent committed
626
*/
laurent's avatar
laurent committed
627
static void uePbchLLR  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
628
  // PBCH LLRs
laurent's avatar
laurent committed
629 630 631 632
  if ( !phy_vars_ue->pbch_vars[eNB_id]->llr)
    return;

  int16_t *pbch_llr = (int16_t *) phy_vars_ue->pbch_vars[eNB_id]->llr;
Laurent's avatar
Laurent committed
633 634
  float *llr_pbch, *bit_pbch;
  oai_xygraph_getbuff(graph, &bit_pbch, &llr_pbch, 864, 0);
635

laurent's avatar
laurent committed
636 637
  for (int i=0; i<864; i++) {
    llr_pbch[i] = (float) pbch_llr[i];
638 639
  }

laurent's avatar
laurent committed
640
  oai_xygraph(graph,bit_pbch,llr_pbch,864,0,10);
laurent's avatar
laurent committed
641
}
laurent's avatar
laurent committed
642
static void uePbchIQ  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
643
  // PBCH I/Q of MF Output
laurent's avatar
laurent committed
644 645 646
  if (!phy_vars_ue->pbch_vars[eNB_id]->rxdataF_comp[0])
    return;

laurent's avatar
laurent committed
647
  scopeSample_t *pbch_comp = (scopeSample_t *) phy_vars_ue->pbch_vars[eNB_id]->rxdataF_comp[0];
Laurent's avatar
Laurent committed
648 649
  float *I, *Q;
  oai_xygraph_getbuff(graph, &I, &Q, 180*3, 0);
650 651
  memset(I,0,180*3*sizeof(*I));
  memset(Q,0,180*3*sizeof(*Q));
laurent's avatar
laurent committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665
  int first_symbol=1;
  int base=0;

  for (int symbol=first_symbol; symbol<(first_symbol+3); symbol++) {
    int nb_re;

    if (symbol == 2 || symbol == 6)
      nb_re = 72;
    else
      nb_re = 180;

    AssertFatal(base+nb_re<180*3,"");

    for (int i=0; i<nb_re; i++) {
laurent's avatar
laurent committed
666 667
      I[base+i] = pbch_comp[symbol*20*12+i].r;
      Q[base+i] = pbch_comp[symbol*20*12+i].i;
668
    }
laurent's avatar
laurent committed
669 670

    base+=nb_re;
671 672
  }

Laurent's avatar
Laurent committed
673
  AssertFatal(base <= 180*3,"");
674
  oai_xygraph(graph,I,Q,base,0, 10);
laurent's avatar
laurent committed
675
}
laurent's avatar
laurent committed
676
static void uePcchLLR  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
677
  // PDCCH LLRs
laurent's avatar
laurent committed
678 679
  if (!phy_vars_ue->pdcch_vars[0][eNB_id]->llr)
    return;
680

681 682 683
  //int num_re = 4*273*12; // 12*frame_parms->N_RB_DL*num_pdcch_symbols
  //int Qm = 2;
  int coded_bits_per_codeword = 2*4*100*12; //num_re*Qm;
Laurent's avatar
Laurent committed
684 685
  float *llr, *bit;
  oai_xygraph_getbuff(graph, &bit, &llr, coded_bits_per_codeword*RX_NB_TH_MAX, 0);
686
  int base=0;
laurent's avatar
laurent committed
687

688 689 690 691 692
  for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
    int16_t *pdcch_llr = (int16_t *) phy_vars_ue->pdcch_vars[thr][eNB_id]->llr;

    for (int i=0; i<coded_bits_per_codeword; i++) {
      llr[base+i] = (float) pdcch_llr[i];
laurent's avatar
laurent committed
693
    }
694 695

    base+=coded_bits_per_codeword;
696 697
  }

Laurent's avatar
Laurent committed
698
  AssertFatal(base <= coded_bits_per_codeword*RX_NB_TH_MAX, "");
699
  oai_xygraph(graph,bit,llr,base,0,10);
laurent's avatar
laurent committed
700
}
laurent's avatar
laurent committed
701
static void uePcchIQ  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
702
  // PDCCH I/Q of MF Output
laurent's avatar
laurent committed
703 704 705
  if (!phy_vars_ue->pdcch_vars[0][eNB_id]->rxdataF_comp[0])
    return;

laurent's avatar
laurent committed
706
  int nb=4*273*12; // 12*frame_parms->N_RB_DL*num_pdcch_symbols
Laurent's avatar
Laurent committed
707 708
  float *I, *Q;
  oai_xygraph_getbuff(graph, &I, &Q, nb*RX_NB_TH_MAX, 0);
laurent's avatar
laurent committed
709 710 711
  int base=0;

  for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
laurent's avatar
laurent committed
712
    scopeSample_t *pdcch_comp = (scopeSample_t *) phy_vars_ue->pdcch_vars[thr][eNB_id]->rxdataF_comp[0];
laurent's avatar
laurent committed
713 714

    for (int i=0; i< nb; i++) {
laurent's avatar
laurent committed
715 716
      I[base+i] = pdcch_comp[i].r;
      Q[base+i] = pdcch_comp[i].i;
717
    }
laurent's avatar
laurent committed
718 719

    base+=nb;
720 721
  }

Laurent's avatar
Laurent committed
722
  AssertFatal(base <= nb*RX_NB_TH_MAX, "");
laurent's avatar
laurent committed
723
  oai_xygraph(graph,I,Q,base,0,10);
laurent's avatar
laurent committed
724
}
laurent's avatar
laurent committed
725
static void uePdschLLR  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
726
  // PDSCH LLRs
laurent's avatar
laurent committed
727 728 729 730 731 732
  if (!phy_vars_ue->pdsch_vars[0][eNB_id]->llr[0])
    return;

  int num_re = 4500;
  int Qm = 2;
  int coded_bits_per_codeword = num_re*Qm;
Laurent's avatar
Laurent committed
733 734
  float *llr, *bit;
  oai_xygraph_getbuff(graph, &bit, &llr, coded_bits_per_codeword*RX_NB_TH_MAX, 0);
laurent's avatar
laurent committed
735 736 737 738 739 740 741 742
  int base=0;

  for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
    int16_t *pdsch_llr = (int16_t *) phy_vars_ue->pdsch_vars[thr][eNB_id]->llr[0]; // stream 0

    for (int i=0; i<coded_bits_per_codeword; i++) {
      llr[base+i] = (float) pdsch_llr[i];
      bit[base+i] = (float) base+i;
743 744
    }

laurent's avatar
laurent committed
745
    base+=coded_bits_per_codeword;
746 747
  }

Laurent's avatar
Laurent committed
748
  AssertFatal(base <= coded_bits_per_codeword*RX_NB_TH_MAX, "");
laurent's avatar
laurent committed
749
  //fl_set_xyplot_xbounds(form->pdsch_llr,0,coded_bits_per_codeword);
laurent's avatar
laurent committed
750
  oai_xygraph(graph,bit,llr,base,0,10);
laurent's avatar
laurent committed
751
}
laurent's avatar
laurent committed
752
static void uePdschIQ  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
753
  // PDSCH I/Q of MF Output
laurent's avatar
laurent committed
754 755 756 757 758
  if (!phy_vars_ue->pdsch_vars[0][eNB_id]->rxdataF_comp0[0])
    return;

  NR_DL_FRAME_PARMS *frame_parms = &phy_vars_ue->frame_parms;
  int sz=7*2*frame_parms->N_RB_DL*12; // size of the malloced buffer
Laurent's avatar
Laurent committed
759 760
  float *I, *Q;
  oai_xygraph_getbuff(graph, &I, &Q, sz*RX_NB_TH_MAX, 0);
laurent's avatar
laurent committed
761
  int base=0;
Laurent's avatar
Laurent committed
762 763
  memset(I+base, 0, sz*RX_NB_TH_MAX * sizeof(*I));
  memset(Q+base, 0, sz*RX_NB_TH_MAX * sizeof(*Q));
laurent's avatar
laurent committed
764 765

  for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
laurent's avatar
laurent committed
766
    scopeSample_t *pdsch_comp = (scopeSample_t *) phy_vars_ue->pdsch_vars[thr][eNB_id]->rxdataF_comp0[0];
laurent's avatar
laurent committed
767 768

    for (int s=0; s<sz; s++) {
laurent's avatar
laurent committed
769 770
      I[s+base] += pdsch_comp[s].r;
      Q[s+base] += pdsch_comp[s].i;
771
    }
laurent's avatar
laurent committed
772 773

    base+=sz;
774
  }
laurent's avatar
laurent committed
775

Laurent's avatar
Laurent committed
776 777
  AssertFatal(base <= sz*RX_NB_TH_MAX, "");
  oai_xygraph(graph,I,Q,sz*RX_NB_TH_MAX,0,10);
laurent's avatar
laurent committed
778 779
}
static void uePdschThroughput  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
780
  /*
Laurent's avatar
Laurent committed
781 782 783 784
  float tput_time_ue[NUMBER_OF_UE_MAX][TPUT_WINDOW_LENGTH] = {{0}};
  float tput_ue[NUMBER_OF_UE_MAX][TPUT_WINDOW_LENGTH] = {{0}};
  float tput_ue_max[NUMBER_OF_UE_MAX] = {0};

785 786 787 788 789 790 791 792 793

  // PDSCH Throughput
  memmove( tput_time_ue[UE_id], &tput_time_ue[UE_id][1], (TPUT_WINDOW_LENGTH-1)*sizeof(float) );
  memmove( tput_ue[UE_id],      &tput_ue[UE_id][1],      (TPUT_WINDOW_LENGTH-1)*sizeof(float) );

  tput_time_ue[UE_id][TPUT_WINDOW_LENGTH-1]  = (float) frame;
  tput_ue[UE_id][TPUT_WINDOW_LENGTH-1] = ((float) total_dlsch_bitrate)/1000.0;

  if (tput_ue[UE_id][TPUT_WINDOW_LENGTH-1] > tput_ue_max[UE_id]) {
laurent's avatar
laurent committed
794
  tput_ue_max[UE_id] = tput_ue[UE_id][TPUT_WINDOW_LENGTH-1];
795 796 797 798 799 800
  }

  fl_set_xyplot_data(form->pdsch_tput,tput_time_ue[UE_id],tput_ue[UE_id],TPUT_WINDOW_LENGTH,"","","");

  fl_set_xyplot_ybounds(form->pdsch_tput,0,tput_ue_max[UE_id]);
  */
laurent's avatar
laurent committed
801
}
laurent's avatar
laurent committed
802
static OAI_phy_scope_t *create_phy_scope_nrue( int ID ) {
laurent's avatar
laurent committed
803
  FL_OBJECT *obj;
laurent's avatar
laurent committed
804
  OAI_phy_scope_t *fdui = calloc(( sizeof *fdui ),1);
laurent's avatar
laurent committed
805 806 807 808 809
  // Define form
  fdui->phy_scope = fl_bgn_form( FL_NO_BOX, 800, 900 );
  // This the whole UI box
  obj = fl_add_box( FL_BORDER_BOX, 0, 0, 800, 900, "" );
  fl_set_object_color( obj, FL_BLACK, FL_BLACK );
laurent's avatar
laurent committed
810
  int curY=0,x,y,w,h;
laurent's avatar
laurent committed
811
  // Received signal
Laurent's avatar
Laurent committed
812 813
  fdui->graph[0] = nrUEcommonGraph(ueWaterFall,
                                   WATERFALL, 0, curY, 400, 100, "Received Signal (Time-Domain, one frame)", FL_RED );
laurent's avatar
laurent committed
814 815
  // Time-domain channel response
  fdui->graph[1] = nrUEcommonGraph(ueChannelResponse,
laurent's avatar
laurent committed
816
                                   FL_NORMAL_XYPLOT, 400, curY, 400, 100, "Channel Impulse Response (samples, abs)", FL_RED );
Laurent's avatar
Laurent committed
817
  fl_get_object_bbox(fdui->graph[1].graph,&x, &y,&w, &h);
laurent's avatar
laurent committed
818
  curY+=h;
laurent's avatar
laurent committed
819
  // Frequency-domain channel response
Laurent's avatar
Laurent committed
820 821
  fdui->graph[2] = nrUEcommonGraph(ueFreqWaterFall,
                                   WATERFALL, 0, curY, 800, 100, "Channel Frequency (RE, one slot)", FL_RED );
laurent's avatar
laurent committed
822
  fl_get_object_bbox(fdui->graph[2].graph,&x, &y,&w, &h);
823
  curY+=h+20;
laurent's avatar
laurent committed
824 825
  // LLR of PBCH
  fdui->graph[3] = nrUEcommonGraph(uePbchLLR,
laurent's avatar
laurent committed
826
                                   FL_POINTS_XYPLOT, 0, curY, 500, 100, "PBCH Log-Likelihood Ratios (LLR, mag)", FL_GREEN );
laurent's avatar
laurent committed
827 828 829
  fl_set_xyplot_xgrid(fdui->graph[3].graph,FL_GRID_MAJOR);
  // I/Q PBCH comp
  fdui->graph[4] = nrUEcommonGraph(uePbchIQ,
laurent's avatar
laurent committed
830 831 832
                                   FL_POINTS_XYPLOT, 500, curY, 300, 100, "PBCH I/Q of MF Output", FL_GREEN );
  fl_get_object_bbox(fdui->graph[3].graph,&x, &y,&w, &h);
  curY+=h;
laurent's avatar
laurent committed
833 834
  // LLR of PDCCH
  fdui->graph[5] = nrUEcommonGraph(uePcchLLR,
laurent's avatar
laurent committed
835
                                   FL_POINTS_XYPLOT, 0, curY, 500, 100, "PDCCH Log-Likelihood Ratios (LLR, mag)", FL_CYAN );
laurent's avatar
laurent committed
836 837
  // I/Q PDCCH comp
  fdui->graph[6] = nrUEcommonGraph(uePcchIQ,
laurent's avatar
laurent committed
838 839 840
                                   FL_POINTS_XYPLOT, 500, curY, 300, 100, "PDCCH I/Q of MF Output", FL_CYAN );
  fl_get_object_bbox(fdui->graph[5].graph,&x, &y,&w, &h);
  curY+=h;
laurent's avatar
laurent committed
841 842
  // LLR of PDSCH
  fdui->graph[7] = nrUEcommonGraph(uePdschLLR,
laurent's avatar
laurent committed
843
                                   FL_POINTS_XYPLOT, 0, curY, 500, 200, "PDSCH Log-Likelihood Ratios (LLR, mag)", FL_YELLOW );
laurent's avatar
laurent committed
844 845
  // I/Q PDSCH comp
  fdui->graph[8] = nrUEcommonGraph(uePdschIQ,
laurent's avatar
laurent committed
846 847 848
                                   FL_POINTS_XYPLOT, 500, curY, 300, 200, "PDSCH I/Q of MF Output", FL_YELLOW );
  fl_get_object_bbox(fdui->graph[8].graph,&x, &y,&w, &h);
  curY+=h;
laurent's avatar
laurent committed
849 850
  // Throughput on PDSCH
  fdui->graph[9] = nrUEcommonGraph(uePdschThroughput,
laurent's avatar
laurent committed
851
                                   FL_NORMAL_XYPLOT, 0, curY, 500, 100, "PDSCH Throughput [frame]/[kbit/s]", FL_WHITE );
laurent's avatar
laurent committed
852 853
  fdui->graph[10].graph=NULL;
  // Generic UE Button
laurent's avatar
laurent committed
854
#if 0
laurent's avatar
laurent committed
855 856 857 858 859 860 861 862
  fdui->button_0 = fl_add_button( FL_PUSH_BUTTON, 540, 720, 240, 40, "" );
  fl_set_object_lalign(fdui->button_0, FL_ALIGN_CENTER );
  //openair_daq_vars.use_ia_receiver = 0;
  fl_set_button(fdui->button_0,0);
  fl_set_object_label(fdui->button_0, "IA Receiver OFF");
  fl_set_object_color(fdui->button_0, FL_RED, FL_RED);
  fl_set_object_callback(fdui->button_0, ia_receiver_on_off, 0 );
  fl_hide_object(fdui->button_0);
laurent's avatar
laurent committed
863
#endif
laurent's avatar
laurent committed
864 865 866 867 868 869 870
  fl_end_form( );
  fdui->phy_scope->fdui = fdui;
  char buf[100];
  sprintf(buf,"NR DL SCOPE UE %d", ID);
  fl_show_form (fdui->phy_scope, FL_PLACE_HOTSPOT, FL_FULLBORDER, buf);
  return fdui;
}
laurent's avatar
laurent committed
871
void phy_scope_nrUE(OAI_phy_scope_t *form,
laurent's avatar
laurent committed
872 873 874
                    PHY_VARS_NR_UE *phy_vars_ue,
                    int eNB_id,
                    int UE_id) {
laurent's avatar
laurent committed
875
  static OAI_phy_scope_t *remeberForm=NULL;
laurent's avatar
laurent committed
876 877 878 879 880 881 882 883 884 885 886 887

  if (form==NULL)
    form=remeberForm;
  else
    remeberForm=form;

  if (form==NULL)
    return;

  int i=0;

  while (form->graph[i].graph) {
laurent's avatar
laurent committed
888
    form->graph[i].nrUEfunct(form->graph+i, phy_vars_ue, eNB_id, UE_id);
laurent's avatar
laurent committed
889
    i++;
890
  }
laurent's avatar
laurent committed
891

Laurent's avatar
Laurent committed
892
  //fl_check_forms();
893
}
laurent's avatar
laurent committed
894 895 896
static void *nrUEscopeThread(void *arg) {
  PHY_VARS_NR_UE *ue=(PHY_VARS_NR_UE *)arg;
  size_t stksize;
897
  pthread_attr_t atr={0};
laurent's avatar
laurent committed
898 899
  pthread_attr_getstacksize(&atr, &stksize);
  pthread_attr_setstacksize(&atr,32*1024*1024 );
laurent's avatar
laurent committed
900 901 902 903
  int fl_argc=1;
  char *name="5G-UE-scope";
  fl_initialize (&fl_argc, &name, NULL, 0, 0);
  OAI_phy_scope_t  *form_nrue=create_phy_scope_nrue(0);
laurent's avatar
laurent committed
904 905

  while (!oai_exit) {
906
    fl_freeze_form(form_nrue->phy_scope);
laurent's avatar
laurent committed
907
    phy_scope_nrUE(form_nrue,
laurent's avatar
laurent committed
908 909
                   ue,
                   0,0);
910 911
    fl_unfreeze_form(form_nrue->phy_scope);
    fl_redraw_form(form_nrue->phy_scope);
laurent's avatar
laurent committed
912 913 914 915 916
    usleep(99*1000);
  }

  pthread_exit((void *)arg);
}
917
void nrUEinitScope(PHY_VARS_NR_UE *ue) {
laurent's avatar
laurent committed
918
  pthread_t forms_thread;
laurent's avatar
laurent committed
919 920
  threadCreate(&forms_thread, nrUEscopeThread, ue, "scope", -1, OAI_PRIORITY_RT_LOW);
}
921 922
void nrscope_autoinit(void *dataptr) {
  AssertFatal( (IS_SOFTMODEM_GNB_BIT||IS_SOFTMODEM_5GUE_BIT),"Scope cannot find NRUE or GNB context");
Laurent's avatar
Laurent committed
923

924
  if (IS_SOFTMODEM_GNB_BIT)
Laurent's avatar
Laurent committed
925
    gNBinitScope(dataptr);
926
  else
Laurent's avatar
Laurent committed
927
    nrUEinitScope(dataptr);
928
}
laurent's avatar
laurent committed
929 930
// Kept to put back the functionality soon
#if 0
931 932 933
//FD_stats_form                  *form_stats=NULL,*form_stats_l2=NULL;
//char                            title[255];
//static pthread_t                forms_thread; //xforms
laurent's avatar
laurent committed
934 935
static void reset_stats_gNB(FL_OBJECT *button,
                            long arg) {
936 937 938 939 940
  int i,k;
  //PHY_VARS_gNB *phy_vars_gNB = RC.gNB[0][0];

  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
    for (k=0; k<8; k++) { //harq_processes
941
      /*      for (j=0; j<phy_vars_gNB->dlsch[i][0]->Mlimit; j++) {
laurent's avatar
laurent committed
942 943 944
              phy_vars_gNB->UE_stats[i].dlsch_NAK[k][j]=0;
              phy_vars_gNB->UE_stats[i].dlsch_ACK[k][j]=0;
              phy_vars_gNB->UE_stats[i].dlsch_trials[k][j]=0;
945
        }
laurent's avatar
laurent committed
946 947 948 949 950 951
        phy_vars_gNB->UE_stats[i].dlsch_l2_errors[k]=0;
        phy_vars_gNB->UE_stats[i].ulsch_errors[k]=0;
        phy_vars_gNB->UE_stats[i].ulsch_consecutive_errors=0;
        phy_vars_gNB->UE_stats[i].dlsch_sliding_cnt=0;
        phy_vars_gNB->UE_stats[i].dlsch_NAK_round0=0;
        phy_vars_gNB->UE_stats[i].dlsch_mcs_offset=0;*/
952
    }
953
  }
954
}
laurent's avatar
laurent committed
955
static FD_stats_form *create_form_stats_form(int ID) {
956
  FL_OBJECT *obj;
laurent's avatar
laurent committed
957
  FD_stats_form *fdui = calloc(( sizeof *fdui ),1);
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
  fdui->vdata = fdui->cdata = NULL;
  fdui->ldata = 0;
  fdui->stats_form = fl_bgn_form( FL_NO_BOX, 1115, 900 );
  obj = fl_add_box( FL_UP_BOX, 0, 0, 1115, 900, "" );
  //fdui->stats_text = obj = fl_add_text( FL_NORMAL_TEXT, 60, 50, 1000, 810, "test" );
  //fl_set_object_lsize( obj, FL_TINY_SIZE );
  fdui->stats_text = obj = fl_add_browser( FL_NORMAL_BROWSER, 60, 50, 1000, 810, "test" );
  fl_set_browser_fontsize(obj,FL_TINY_SIZE);
  fdui->stats_button = obj = fl_add_button( FL_PUSH_BUTTON, 60, 10, 130, 30, "Reset Stats" );
  fl_set_object_lalign( obj, FL_ALIGN_CENTER );
  fl_set_object_color( obj, FL_GREEN, FL_GREEN);
  fl_end_form( );
  fdui->stats_form->fdui = fdui;
  return fdui;
}
laurent's avatar
laurent committed
973
#endif