dlsim.c 31.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * 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 <fcntl.h>
23 24
#include <math.h>
#include <string.h>
25 26
#include <sys/ioctl.h>
#include <sys/mman.h>
27 28
#include <unistd.h>
#include "common/ran_context.h"
29 30
#include "common/config/config_userapi.h"
#include "common/utils/LOG/log.h"
31 32 33 34 35 36
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h"
#include "openair2/LAYER2/NR_MAC_UE/mac_extern.h"
#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h"
#include "PHY/defs_gNB.h"
37 38
#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
39
#include "PHY/phy_vars_nr_ue.h"
40 41
#include "PHY/types.h"
#include "PHY/INIT/phy_init.h"
42 43
#include "PHY/MODULATION/modulation_eNB.h"
#include "PHY/MODULATION/modulation_UE.h"
44 45
#include "PHY/NR_REFSIG/nr_mod_table.h"
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
46
#include "PHY/NR_TRANSPORT/nr_transport.h"
47
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
48
#include "SCHED_NR/fapi_nr_l1.h"
49
#include "SCHED_NR/sched_nr.h"
50
#include "SCHED_NR_UE/defs.h"
51 52 53 54
#include "SCHED_NR_UE/fapi_nr_ue_l1.h"
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
#include "NR_UE_PHY_INTERFACE/NR_IF_Module.h"

55
#include "LAYER2/NR_MAC_UE/mac_proto.h"
yilmazt's avatar
yilmazt committed
56 57
//#include "LAYER2/NR_MAC_gNB/mac_proto.h"
//#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h"
58
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
59
#include "NR_asn_constant.h"
60
#include "RRC/NR/MESSAGES/asn1_msg.h"
61 62 63
#include "openair1/SIMULATION/RF/rf.h"
#include "openair1/SIMULATION/TOOLS/sim.h"
#include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h"
Raymond Knopp's avatar
Raymond Knopp committed
64
//#include "openair1/SIMULATION/NR_PHY/nr_dummy_functions.c"
65

Raymond Knopp's avatar
Raymond Knopp committed
66
#include "NR_RRCReconfiguration.h"
67 68 69 70
#define inMicroS(a) (((double)(a))/(cpu_freq_GHz*1000.0))
#include "SIMULATION/LTE_PHY/common_sim.h"


Raymond Knopp's avatar
Raymond Knopp committed
71

72 73 74
PHY_VARS_gNB *gNB;
PHY_VARS_NR_UE *UE;
RAN_CONTEXT_t RC;
75 76
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];

77
double cpuf;
78

79
int sf_ahead=4 ;
80
int sl_ahead=0;
81
uint8_t nfapi_mode = 0;
yilmazt's avatar
yilmazt committed
82
uint16_t NB_UE_INST = 1;
83
uint64_t downlink_frequency[MAX_NUM_CCs][4];
84 85

// dummy functions
Raymond Knopp's avatar
Raymond Knopp committed
86 87 88 89
int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info)              { return(0);  }

void pdcp_run (const protocol_ctxt_t *const  ctxt_pP) { return;}

90 91 92 93 94 95
int8_t nr_mac_rrc_data_ind_ue(const module_id_t     module_id,
			      const int             CC_id,
			      const uint8_t         gNB_index,
			      const int8_t          channel,
			      const uint8_t*        pduP,
			      const sdu_size_t      pdu_len)
96 97 98 99 100
{
  return 0;
}


101
void pdcp_layer_init(void) {}
102 103 104 105 106 107 108 109 110 111
boolean_t
pdcp_data_ind(
  const protocol_ctxt_t *const ctxt_pP,
  const srb_flag_t   srb_flagP,
  const MBMS_flag_t  MBMS_flagP,
  const rb_id_t      rb_idP,
  const sdu_size_t   sdu_buffer_sizeP,
  mem_block_t *const sdu_buffer_pP
) { return(false);}

112 113
int rrc_init_nr_global_param(void){return(0);}

114 115
void config_common(int Mod_idP,
                   int pdsch_AntennaPorts, 
116
		   NR_ServingCellConfigCommon_t *scc
Raymond Knopp's avatar
Raymond Knopp committed
117
		   );
118

119 120 121 122 123 124 125 126 127 128
int generate_dlsch_header(unsigned char *mac_header,
                          unsigned char num_sdus,
                          unsigned short *sdu_lengths,
                          unsigned char *sdu_lcids,
                          unsigned char drx_cmd,
                          unsigned short timing_advance_cmd,
                          unsigned char *ue_cont_res_id,
                          unsigned char short_padding,
                          unsigned short post_padding){return 0;}
void nr_ip_over_LTE_DRB_preconfiguration(void){}
129

130
// needed for some functions
131
openair0_config_t openair0_cfg[MAX_CARDS];
132

133

134 135


136 137 138
int main(int argc, char **argv)
{
  char c;
139
  int i,aa;//,l;
140
  double sigma2, sigma2_dB=10, SNR, snr0=-2.0, snr1=2.0;
141 142 143
  uint8_t snr1set=0;
  int **txdata;
  double **s_re,**s_im,**r_re,**r_im;
144 145
  //double iqim = 0.0;
  //unsigned char pbch_pdu[6];
146 147 148
  //  int sync_pos, sync_pos_slot;
  //  FILE *rx_frame_file;
  FILE *output_fd = NULL;
149
  //uint8_t write_output_file=0;
150
  //int result;
151
  //int freq_offset;
152
  //  int subframe_offset;
153
  //  char fname[40], vname[40];
Ahmed Hussein's avatar
Ahmed Hussein committed
154
  int trial, n_trials = 1, n_errors = 0, n_false_positive = 0;
155
  //int n_errors2, n_alamouti;
156 157 158
  uint8_t transmission_mode = 1,n_tx=1,n_rx=1;

  channel_desc_t *gNB2UE;
159 160 161
  //uint32_t nsymb,tx_lev,tx_lev1 = 0,tx_lev2 = 0;
  //uint8_t extended_prefix_flag=0;
  //int8_t interf1=-21,interf2=-21;
162 163

  FILE *input_fd=NULL,*pbch_file_fd=NULL;
164
  //char input_val_str[50],input_val_str2[50];
165

166
  //uint8_t frame_mod4,num_pdcch_symbols = 0;
167 168 169

  SCM_t channel_model=AWGN;//Rayleigh1_anticorr;

170 171
  //double pbch_sinr;
  //int pbch_tx_ant;
Ahmed Hussein's avatar
Ahmed Hussein committed
172
  int N_RB_DL=106,mu=1;
173
  nfapi_nr_dl_tti_pdsch_pdu_rel15_t dlsch_config;
174
  NR_sched_pucch pucch_sched;
175

176
  //unsigned char frame_type = 0;
177

178
  int frame=0,slot=1;
179 180 181 182 183 184 185
  int frame_length_complex_samples;
  int frame_length_complex_samples_no_prefix;
  NR_DL_FRAME_PARMS *frame_parms;
  UE_nr_rxtx_proc_t UE_proc;
  NR_Sched_Rsp_t Sched_INFO;
  gNB_MAC_INST *gNB_mac;
  NR_UE_MAC_INST_t *UE_mac;
186
  int cyclic_prefix_type = NFAPI_CP_NORMAL;
187 188 189
  int run_initial_sync=0;
  int do_pdcch_flag=1;

Raymond Knopp's avatar
Raymond Knopp committed
190
  int loglvl=OAILOG_INFO;
191 192

  float target_error_rate = 0.01;
193
  int css_flag=0;
194 195 196

  cpuf = get_cpu_freq_GHz();

197
  if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) {
yilmazt's avatar
yilmazt committed
198
    exit_fun("[NR_DLSIM] Error, configuration module init failed\n");
199 200 201 202
  }

  randominit(0);

203
  int mcsIndex_set=0,rbStart_set=0,rbSize_set=0;
204
  int print_perf             = 0;
205

206 207
  FILE *scg_fd=NULL;
  
208
  while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:e:m:")) != -1) {
209
    switch (c) {
210 211
    case 'f':
      scg_fd = fopen(optarg,"r");
212

213
      if (scg_fd==NULL) {
214 215 216
        printf("Error opening %s\n",optarg);
        exit(-1);
      }
217
      break;
218

219
    /*case 'd':
220
      frame_type = 1;
221
      break;*/
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

    case 'g':
      switch((char)*optarg) {
      case 'A':
        channel_model=SCM_A;
        break;

      case 'B':
        channel_model=SCM_B;
        break;

      case 'C':
        channel_model=SCM_C;
        break;

      case 'D':
        channel_model=SCM_D;
        break;

      case 'E':
        channel_model=EPA;
        break;

      case 'F':
        channel_model=EVA;
        break;

      case 'G':
        channel_model=ETU;
        break;

      default:
254
        printf("Unsupported channel model!\n");
255 256 257 258 259
        exit(-1);
      }

      break;

260
    /*case 'i':
261 262 263 264 265
      interf1=atoi(optarg);
      break;

    case 'j':
      interf2=atoi(optarg);
266
      break;*/
267 268 269 270 271 272 273

    case 'n':
      n_trials = atoi(optarg);
      break;

    case 's':
      snr0 = atof(optarg);
274
      printf("Setting SNR0 to %f\n",snr0);
275 276 277 278 279
      break;

    case 'S':
      snr1 = atof(optarg);
      snr1set=1;
280
      printf("Setting SNR1 to %f\n",snr1);
281 282 283 284 285 286 287
      break;

      /*
      case 't':
      Td= atof(optarg);
      break;
      */
288
    /*case 'p':
289
      extended_prefix_flag=1;
290
      break;*/
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306

      /*
      case 'r':
      ricean_factor = pow(10,-.1*atof(optarg));
      if (ricean_factor>1) {
        printf("Ricean factor must be between 0 and 1\n");
        exit(-1);
      }
      break;
      */
    case 'x':
      transmission_mode=atoi(optarg);

      if ((transmission_mode!=1) &&
          (transmission_mode!=2) &&
          (transmission_mode!=6)) {
307
        printf("Unsupported transmission mode %d\n",transmission_mode);
308 309 310 311 312 313 314 315 316
        exit(-1);
      }

      break;

    case 'y':
      n_tx=atoi(optarg);

      if ((n_tx==0) || (n_tx>2)) {
317
        printf("Unsupported number of tx antennas %d\n",n_tx);
318 319 320 321 322 323 324 325 326
        exit(-1);
      }

      break;

    case 'z':
      n_rx=atoi(optarg);

      if ((n_rx==0) || (n_rx>2)) {
327
        printf("Unsupported number of rx antennas %d\n",n_rx);
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
        exit(-1);
      }

      break;

    case 'R':
      N_RB_DL = atoi(optarg);
      break;

    case 'F':
      input_fd = fopen(optarg,"r");

      if (input_fd==NULL) {
        printf("Problem with filename %s\n",optarg);
        exit(-1);
      }

      break;

    case 'P':
348 349
      print_perf=1;
      opp_enabled=1;
350 351 352 353 354
      break;
      
    case 'I':
      run_initial_sync=1;
      target_error_rate=0.1;
355
      slot = 0;
356 357 358 359 360 361
      break;

    case 'L':
      loglvl = atoi(optarg);
      break;

362

363 364 365
    case 'E':
	css_flag=1;
	break;
366

367

368
    case 'a':
Raymond Knopp's avatar
Raymond Knopp committed
369
      dlsch_config.rbStart = atoi(optarg);
370
      rbStart_set=1;
371 372 373
      break;

    case 'b':
Raymond Knopp's avatar
Raymond Knopp committed
374
      dlsch_config.rbSize = atoi(optarg);
375
      rbSize_set=1;
376 377 378
      break;

    case 'e':
Raymond Knopp's avatar
Raymond Knopp committed
379
      dlsch_config.mcsIndex[0] = atoi(optarg);
380
      mcsIndex_set=1;
381 382
      break;

383 384 385
    case 'm':
      mu = atoi(optarg);
      break;
386

387 388 389 390 391
    default:
    case 'h':
      printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n",
             argv[0]);
      printf("-h This message\n");
392 393
      //printf("-p Use extended prefix mode\n");
      //printf("-d Use TDD\n");
394 395 396 397 398
      printf("-n Number of frames to simulate\n");
      printf("-s Starting SNR, runs from SNR0 to SNR0 + 5 dB.  If n_frames is 1 then just SNR is simulated\n");
      printf("-S Ending SNR, runs from SNR0 to SNR1\n");
      printf("-t Delay spread for multipath channel\n");
      printf("-g [A,B,C,D,E,F,G] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) models (ignores delay spread and Ricean factor)\n");
399
      printf("-y Number of TX antennas used in gNB\n");
400
      printf("-z Number of RX antennas used in UE\n");
401 402
      //printf("-i Relative strength of first intefering gNB (in dB) - cell_id mod 3 = 1\n");
      //printf("-j Relative strength of second intefering gNB (in dB) - cell_id mod 3 = 2\n");
403 404 405
      printf("-R N_RB_DL\n");
      printf("-O oversampling factor (1,2,4,8,16)\n");
      printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n");
406
      //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n");
407
      printf("-f raw file containing RRC configuration (generated by gNB)\n");
408
      printf("-F Input filename (.txt format) for RX conformance testing\n");
409
      printf("-E used CSS scheduler\n");
410
      printf("-o CORESET offset\n");
411 412
      printf("-a Start PRB for PDSCH\n");
      printf("-b Number of PRB for PDSCH\n");
413 414
      printf("-c Start symbol for PDSCH (fixed for now)\n");
      printf("-j Number of symbols for PDSCH (fixed for now)\n");
415
      printf("-e MSC index\n");
416 417 418 419
      exit (-1);
      break;
    }
  }
Raymond Knopp's avatar
Raymond Knopp committed
420
  
421 422 423 424
  logInit();
  set_glog(loglvl);
  T_stdout = 1;

425 426
  get_softmodem_params()->phy_test = 1;
  
427 428 429 430
  if (snr1set==0)
    snr1 = snr0+10;


431 432 433
  RC.gNB = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *));
  RC.gNB[0] = (PHY_VARS_gNB*) malloc(sizeof(PHY_VARS_gNB ));
  memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB));
Raymond Knopp's avatar
Raymond Knopp committed
434

435
  gNB = RC.gNB[0];
436 437 438 439 440 441
  frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
  frame_parms->nb_antennas_tx = n_tx;
  frame_parms->nb_antennas_rx = n_rx;
  frame_parms->N_RB_DL = N_RB_DL;
  frame_parms->N_RB_UL = N_RB_DL;

Raymond Knopp's avatar
Raymond Knopp committed
442
  RC.nb_nr_macrlc_inst = 1;
cig's avatar
cig committed
443 444 445
  RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int));
  for (i = 0; i < RC.nb_nr_macrlc_inst; i++)
    RC.nb_nr_mac_CC[i] = 1;
Raymond Knopp's avatar
Raymond Knopp committed
446 447 448
  mac_top_init_gNB();
  gNB_mac = RC.nrmac[0];
  gNB_RRC_INST rrc;
Raymond Knopp's avatar
Raymond Knopp committed
449
  memset((void*)&rrc,0,sizeof(rrc));
450

451
  /*
Raymond Knopp's avatar
Raymond Knopp committed
452
  // read in SCGroupConfig
Raymond Knopp's avatar
Raymond Knopp committed
453
  AssertFatal(scg_fd != NULL,"no reconfig.raw file\n");
Raymond Knopp's avatar
Raymond Knopp committed
454 455 456 457
  char buffer[1024];
  int msg_len=fread(buffer,1,1024,scg_fd);
  NR_RRCReconfiguration_t *NR_RRCReconfiguration;

Raymond Knopp's avatar
Raymond Knopp committed
458
  printf("Decoding NR_RRCReconfiguration (%d bytes)\n",msg_len);
Raymond Knopp's avatar
Raymond Knopp committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472
  asn_dec_rval_t dec_rval = uper_decode_complete( NULL,
						  &asn_DEF_NR_RRCReconfiguration,
						  (void **)&NR_RRCReconfiguration,
						  (uint8_t *)buffer,
						  msg_len); 
  
  if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
    AssertFatal(1==0,"NR_RRCReConfiguration decode error\n");
    // free the memory
    SEQUENCE_free( &asn_DEF_NR_RRCReconfiguration, NR_RRCReconfiguration, 1 );
    exit(-1);
  }      
  fclose(scg_fd);

Raymond Knopp's avatar
Raymond Knopp committed
473 474
  AssertFatal(NR_RRCReconfiguration->criticalExtensions.present == NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration,"wrong NR_RRCReconfiguration->criticalExstions.present type\n");

Raymond Knopp's avatar
Raymond Knopp committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
  NR_RRCReconfiguration_IEs_t *reconfig_ies = NR_RRCReconfiguration->criticalExtensions.choice.rrcReconfiguration;
  NR_CellGroupConfig_t *secondaryCellGroup;
  dec_rval = uper_decode_complete( NULL,
				   &asn_DEF_NR_CellGroupConfig,
				   (void **)&secondaryCellGroup,
				   (uint8_t *)reconfig_ies->secondaryCellGroup->buf,
				   reconfig_ies->secondaryCellGroup->size); 
  
  if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
    AssertFatal(1==0,"NR_CellGroupConfig decode error\n");
    // free the memory
    SEQUENCE_free( &asn_DEF_NR_CellGroupConfig, secondaryCellGroup, 1 );
    exit(-1);
  }      
  
490 491
  NR_ServingCellConfigCommon_t *scc = secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon;
  */
Raymond Knopp's avatar
Raymond Knopp committed
492

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510

  rrc.carrier.servingcellconfigcommon = calloc(1,sizeof(*rrc.carrier.servingcellconfigcommon));

  NR_ServingCellConfigCommon_t *scc = rrc.carrier.servingcellconfigcommon;
  NR_CellGroupConfig_t *secondaryCellGroup=calloc(1,sizeof(*secondaryCellGroup));
  prepare_scc(rrc.carrier.servingcellconfigcommon);
  uint64_t ssb_bitmap;
  fill_scc(rrc.carrier.servingcellconfigcommon,&ssb_bitmap,N_RB_DL,N_RB_DL,mu,mu);

  fill_default_secondaryCellGroup(scc,
				  secondaryCellGroup,
				  0,
				  1,
				  n_tx,
				  0);
  fix_scc(scc,ssb_bitmap);

  xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
Raymond Knopp's avatar
Raymond Knopp committed
511

Raymond Knopp's avatar
Raymond Knopp committed
512 513
  AssertFatal((gNB->if_inst         = NR_IF_Module_init(0))!=NULL,"Cannot register interface");
  gNB->if_inst->NR_PHY_config_req      = nr_phy_config_request;
Raymond Knopp's avatar
Raymond Knopp committed
514
  // common configuration
515
  rrc_mac_config_req_gNB(0,0,1,scc,0,0,NULL);
Raymond Knopp's avatar
Raymond Knopp committed
516
  // UE dedicated configuration
517
  rrc_mac_config_req_gNB(0,0,1,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup);
Raymond Knopp's avatar
Raymond Knopp committed
518
  phy_init_nr_gNB(gNB,0,0);
519
  N_RB_DL = gNB->frame_parms.N_RB_DL;
Raymond Knopp's avatar
Raymond Knopp committed
520
  // stub to configure frame_parms
Raymond Knopp's avatar
Raymond Knopp committed
521
  //  nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions);
Raymond Knopp's avatar
Raymond Knopp committed
522 523 524
  // call MAC to configure common parameters


525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
  double fs,bw;

  if (mu == 1 && N_RB_DL == 217) { 
    fs = 122.88e6;
    bw = 80e6;
  }					       
  else if (mu == 1 && N_RB_DL == 245) {
    fs = 122.88e6;
    bw = 90e6;
  }
  else if (mu == 1 && N_RB_DL == 273) {
    fs = 122.88e6;
    bw = 100e6;
  }
  else if (mu == 1 && N_RB_DL == 106) { 
    fs = 61.44e6;
    bw = 40e6;
  }
543 544 545 546
  else if (mu == 3 && N_RB_DL == 66) {
    fs = 122.88e6;
    bw = 100e6;
  }
547 548 549 550
  else if (mu == 3 && N_RB_DL == 32) {
    fs = 61.44e6;
    bw = 50e6;
  }
551 552 553 554 555
  else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL);

  gNB2UE = new_channel_desc_scm(n_tx,
                                n_rx,
                                channel_model,
556 557
 				fs,
				bw,
558 559 560 561 562
                                0,
                                0,
                                0);

  if (gNB2UE==NULL) {
563
    printf("Problem generating channel model. Exiting.\n");
564 565 566 567
    exit(-1);
  }

  frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
568
  frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589

  s_re = malloc(2*sizeof(double*));
  s_im = malloc(2*sizeof(double*));
  r_re = malloc(2*sizeof(double*));
  r_im = malloc(2*sizeof(double*));
  txdata = malloc(2*sizeof(int*));

  for (i=0; i<2; i++) {

    s_re[i] = malloc(frame_length_complex_samples*sizeof(double));
    bzero(s_re[i],frame_length_complex_samples*sizeof(double));
    s_im[i] = malloc(frame_length_complex_samples*sizeof(double));
    bzero(s_im[i],frame_length_complex_samples*sizeof(double));

    r_re[i] = malloc(frame_length_complex_samples*sizeof(double));
    bzero(r_re[i],frame_length_complex_samples*sizeof(double));
    r_im[i] = malloc(frame_length_complex_samples*sizeof(double));
    bzero(r_im[i],frame_length_complex_samples*sizeof(double));

    printf("Allocating %d samples for txdata\n",frame_length_complex_samples);
    txdata[i] = malloc(frame_length_complex_samples*sizeof(int));
590
    bzero(txdata[i],frame_length_complex_samples*sizeof(int));
591 592 593 594 595 596 597 598 599 600
  
  }

  if (pbch_file_fd!=NULL) {
    load_pbch_desc(pbch_file_fd);
  }


  //configure UE
  UE = malloc(sizeof(PHY_VARS_NR_UE));
Raymond Knopp's avatar
Raymond Knopp committed
601
  memset((void*)UE,0,sizeof(PHY_VARS_NR_UE));
602 603 604 605
  PHY_vars_UE_g = malloc(sizeof(PHY_VARS_NR_UE**));
  PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE*));
  PHY_vars_UE_g[0][0] = UE;
  memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
Raymond Knopp's avatar
Raymond Knopp committed
606

607
  if (run_initial_sync==1)  UE->is_synchronized = 0;
608
  else                      {UE->is_synchronized = 1; UE->UE_mode[0]=PUSCH;}
609 610
                      
  UE->perfect_ce = 0;
611
  for (i=0;i<10;i++) UE->current_thread_id[i] = 0;
612 613 614 615 616 617 618

  if (init_nr_ue_signal(UE, 1, 0) != 0)
  {
    printf("Error at UE NR initialisation\n");
    exit(-1);
  }

619 620
  init_nr_ue_transport(UE,0);

621
  nr_gold_pbch(UE);
622
  nr_gold_pdcch(UE,0,2);
623

624
  nr_l2_init_ue(NULL);
625
  UE_mac = get_mac_inst(0);
Guy De Souza's avatar
Guy De Souza committed
626
  
627 628 629
  UE->if_inst = nr_ue_if_module_init(0);
  UE->if_inst->scheduled_response = nr_ue_scheduled_response;
  UE->if_inst->phy_config_request = nr_ue_phy_config_request;
630
  UE->if_inst->dl_indication = nr_ue_dl_indication;
631 632 633
  UE->if_inst->ul_indication = dummy_nr_ue_ul_indication;
  

634
  UE_mac->if_module = nr_ue_if_module_init(0);
Ahmed Hussein's avatar
Ahmed Hussein committed
635
  
636
  unsigned int available_bits=0;
Ahmed Hussein's avatar
Ahmed Hussein committed
637 638 639 640 641
  unsigned char *estimated_output_bit;
  unsigned char *test_input_bit;
  unsigned int errors_bit    = 0;
  uint32_t errors_scrambling = 0;

642

Ahmed Hussein's avatar
Ahmed Hussein committed
643 644
  test_input_bit       = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384);
  estimated_output_bit = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384);
645 646
  
  // generate signal
647 648 649 650 651
  AssertFatal(input_fd==NULL,"Not ready for input signal file\n");
  gNB->pbch_configured = 1;
  gNB->ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234;
  
  if (mcsIndex_set==0) dlsch_config.mcsIndex[0]=9;
652
  
653
  if (rbStart_set==0) dlsch_config.rbStart=0;
654
  if (rbSize_set==0) dlsch_config.rbSize=N_RB_DL-dlsch_config.rbStart;
Raymond Knopp's avatar
Raymond Knopp committed
655

656
  //Configure UE
657 658
  rrc.carrier.MIB = (uint8_t*) malloc(4);
  rrc.carrier.sizeof_MIB = do_MIB_NR(&rrc,0);
659

660
  nr_rrc_mac_config_req_ue(0,0,0,rrc.carrier.mib.message.choice.mib,secondaryCellGroup);
661

662 663 664 665 666 667 668 669

  nr_dcireq_t dcireq;
  nr_scheduled_response_t scheduled_response;
  memset((void*)&dcireq,0,sizeof(dcireq));
  memset((void*)&scheduled_response,0,sizeof(scheduled_response));
  dcireq.module_id = 0;
  dcireq.gNB_index = 0;
  dcireq.cc_id     = 0;
670
  
671 672 673 674 675 676 677
  scheduled_response.dl_config = &dcireq.dl_config_req;
  scheduled_response.ul_config = &dcireq.ul_config_req;
  scheduled_response.tx_request = NULL;
  scheduled_response.module_id = 0;
  scheduled_response.CC_id     = 0;
  scheduled_response.frame = frame;
  scheduled_response.slot  = slot;
678
  
Francesco Mani's avatar
Francesco Mani committed
679

680 681
  nr_ue_phy_config_request(&UE_mac->phy_config);

Ahmed Hussein's avatar
Ahmed Hussein committed
682
  for (SNR = snr0; SNR < snr1; SNR += .2) {
683

684 685 686 687 688 689 690 691 692 693 694 695 696
    varArray_t *table_tx=initVarArray(1000,sizeof(double));
    reset_meas(&gNB->phy_proc_tx); // total gNB tx
    reset_meas(&gNB->dlsch_scrambling_stats);
    reset_meas(&gNB->dlsch_interleaving_stats);
    reset_meas(&gNB->dlsch_rate_matching_stats);
    reset_meas(&gNB->dlsch_segmentation_stats);
    reset_meas(&gNB->dlsch_modulation_stats);
    reset_meas(&gNB->dlsch_encoding_stats);
    reset_meas(&gNB->tinput);
    reset_meas(&gNB->tprep);
    reset_meas(&gNB->tparity);
    reset_meas(&gNB->toutput);  

697
    n_errors = 0;
698 699
    //n_errors2 = 0;
    //n_alamouti = 0;
700
    errors_scrambling=0;
701
    n_false_positive = 0;
Ahmed Hussein's avatar
Ahmed Hussein committed
702
    for (trial = 0; trial < n_trials; trial++) {
703

704
      errors_bit = 0;
Ahmed Hussein's avatar
Ahmed Hussein committed
705
      //multipath channel
706
      //multipath_channel(gNB2UE,s_re,s_im,r_re,r_im,frame_length_complex_samples,0);
707 708 709

      memset(RC.nrmac[0]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int));
      clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot);
710
      if (css_flag == 0) nr_schedule_uss_dlsch_phytest(0,frame,slot,&pucch_sched,&dlsch_config);
711 712 713 714 715 716 717 718 719 720 721 722 723
      else               nr_schedule_css_dlsch_phytest(0,frame,slot);
      
      
      Sched_INFO.module_id = 0;
      Sched_INFO.CC_id     = 0;
      Sched_INFO.frame     = frame;
      Sched_INFO.slot      = slot;
      Sched_INFO.DL_req    = &gNB_mac->DL_req[0];
      Sched_INFO.UL_tti_req    = &gNB_mac->UL_tti_req[0];
      Sched_INFO.UL_dci_req  = NULL;
      Sched_INFO.TX_req    = &gNB_mac->TX_req[0];
      nr_schedule_response(&Sched_INFO);
      
Sakthivel Velumani's avatar
Sakthivel Velumani committed
724 725 726 727
      if (run_initial_sync)
        nr_common_signal_procedures(gNB,frame,slot);
      else
        phy_procedures_gNB_TX(gNB,frame,slot,0);
728 729 730 731 732 733 734 735
          
      int txdataF_offset = (slot%2) * frame_parms->samples_per_slot_wCP;
      
      if (n_trials==1) {
	LOG_M("txsigF0.m","txsF0", gNB->common_vars.txdataF[0],frame_length_complex_samples_no_prefix,1,1);
	if (gNB->frame_parms.nb_antennas_tx>1)
	  LOG_M("txsigF1.m","txsF1", gNB->common_vars.txdataF[1],frame_length_complex_samples_no_prefix,1,1);
      }
736
      int tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
      if (n_trials==1) printf("samples_per_slot_wCP = %d\n", frame_parms->samples_per_slot_wCP);
      
      //TODO: loop over slots
      for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++) {
	
	if (cyclic_prefix_type == 1) {
	  PHY_ofdm_mod(&gNB->common_vars.txdataF[aa][txdataF_offset],
		       &txdata[aa][tx_offset],
		       frame_parms->ofdm_symbol_size,
		       12,
		       frame_parms->nb_prefix_samples,
		       CYCLIC_PREFIX);
	} else {
	  nr_normal_prefix_mod(&gNB->common_vars.txdataF[aa][txdataF_offset],
			       &txdata[aa][tx_offset],
			       14,
			       frame_parms);
	}
      }
     
      if (n_trials==1) {
	LOG_M("txsig0.m","txs0", txdata[0],frame_length_complex_samples,1,1);
	if (gNB->frame_parms.nb_antennas_tx>1)
	  LOG_M("txsig1.m","txs1", txdata[1],frame_length_complex_samples,1,1);
      }
      if (output_fd) 
	fwrite(txdata[0],sizeof(int32_t),frame_length_complex_samples,output_fd);
      
765
      int txlev = signal_energy(&txdata[0][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)+5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0],
766 767 768 769
				frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples);
      
      //  if (n_trials==1) printf("txlev %d (%f)\n",txlev,10*log10((double)txlev));
      
770 771
      for (i=(frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)); 
	   i<(frame_parms->get_samples_slot_timestamp(slot+1,frame_parms,0)); 
772
	   i++) {
773 774 775 776 777 778 779 780
	for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
	  r_re[aa][i] = ((double)(((short *)txdata[aa]))[(i<<1)]);
	  r_im[aa][i] = ((double)(((short *)txdata[aa]))[(i<<1)+1]);
	}
      }
      
      NR_gNB_DLSCH_t *gNB_dlsch = gNB->dlsch[0][0];
      nfapi_nr_dl_tti_pdsch_pdu_rel15_t rel15 = gNB_dlsch->harq_processes[0]->pdsch_pdu.pdsch_pdu_rel15;
781 782
      
      //AWGN
783
      sigma2_dB = 10 * log10((double)txlev * ((double)UE->frame_parms.ofdm_symbol_size/(12*rel15.rbSize))) - SNR;
Ahmed Hussein's avatar
Ahmed Hussein committed
784
      sigma2    = pow(10, sigma2_dB/10);
785
      if (n_trials==1) printf("sigma2 %f (%f dB), txlev %f (factor %f)\n",sigma2,sigma2_dB,10*log10((double)txlev),(double)(double)UE->frame_parms.ofdm_symbol_size/(12*rel15.rbSize));
786
      
787 788
      for (i=frame_parms->get_samples_slot_timestamp(slot,frame_parms,0); 
	   i<frame_parms->get_samples_slot_timestamp(slot+1,frame_parms,0);
789
	   i++) {
790 791 792 793 794
	for (aa=0; aa<frame_parms->nb_antennas_rx; aa++) {
	  ((short*) UE->common_vars.rxdata[aa])[2*i]   = (short) ((r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
	  ((short*) UE->common_vars.rxdata[aa])[2*i+1] = (short) ((r_im[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
	}
      }
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
      
      UE->rx_offset=0;
      UE_proc.frame_rx = frame;
      UE_proc.nr_tti_rx= slot;
      UE_proc.subframe_rx = slot;
      
      dcireq.frame     = frame;
      dcireq.slot      = slot;
      
      nr_ue_dcireq(&dcireq); //to be replaced with function pointer later
      nr_ue_scheduled_response(&scheduled_response);
      
      phy_procedures_nrUE_RX(UE,
			     &UE_proc,
			     0,
			     do_pdcch_flag,
			     normal_txrx);
      
      if (UE->dlsch[UE->current_thread_id[slot]][0][0]->last_iteration_cnt >= 
	  UE->dlsch[UE->current_thread_id[slot]][0][0]->max_ldpc_iterations+1)
	n_errors++;
      
      //----------------------------------------------------------
      //---------------------- count errors ----------------------
      //----------------------------------------------------------
      
      
      
      NR_UE_DLSCH_t *dlsch0 = UE->dlsch[UE->current_thread_id[UE_proc.nr_tti_rx]][0][0];
      
      int harq_pid = dlsch0->current_harq_pid;
      NR_DL_UE_HARQ_t *UE_harq_process = dlsch0->harq_processes[harq_pid];
      
      NR_UE_PDSCH **pdsch_vars = UE->pdsch_vars[UE->current_thread_id[UE_proc.nr_tti_rx]];
      int16_t *UE_llr = pdsch_vars[0]->llr[0];
      
      
      uint32_t TBS         = rel15.TBSize[0];
      uint16_t length_dmrs = 1;
      uint16_t nb_rb       = rel15.rbSize;
      uint8_t  nb_re_dmrs  = rel15.dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
      uint8_t  mod_order   = rel15.qamModOrder[0];
      uint8_t  nb_symb_sch = rel15.NrOfSymbols;
      
      available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, mod_order, rel15.nrOfLayers);
      
      for (i = 0; i < available_bits; i++) {
Raymond Knopp's avatar
Raymond Knopp committed
842
	
843 844 845 846 847 848
	if(((gNB_dlsch->harq_processes[harq_pid]->f[i] == 0) && (UE_llr[i] <= 0)) || 
	   ((gNB_dlsch->harq_processes[harq_pid]->f[i] == 1) && (UE_llr[i] >= 0)))
	  {
	    if(errors_scrambling == 0) {
	      LOG_D(PHY,"\n");
	      LOG_D(PHY,"First bit in error in unscrambling = %d\n",i);
Raymond Knopp's avatar
Raymond Knopp committed
849
	    }
850
	    errors_scrambling++;
Raymond Knopp's avatar
Raymond Knopp committed
851 852
	  }
	
853 854
      }
      for (i = 0; i < TBS; i++) {
Raymond Knopp's avatar
Raymond Knopp committed
855
	
856 857
	estimated_output_bit[i] = (UE_harq_process->b[i/8] & (1 << (i & 7))) >> (i & 7);
	test_input_bit[i]       = (gNB_dlsch->harq_processes[harq_pid]->b[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments
Raymond Knopp's avatar
Raymond Knopp committed
858
	
859 860 861 862
	if (estimated_output_bit[i] != test_input_bit[i]) {
	  if(errors_bit == 0)
	    LOG_D(PHY,"First bit in error in decoding = %d (errors scrambling %d)\n",i,errors_scrambling);
	  errors_bit++;
Raymond Knopp's avatar
Raymond Knopp committed
863 864
	}
	
865 866 867 868 869 870
      }
      
      ////////////////////////////////////////////////////////////
      
      if (errors_scrambling > 0) {
	if (n_trials == 1)
871
	  printf("errors_scrambling = %d/%d (trial %d)\n", errors_scrambling, available_bits,trial);
872 873 874 875 876 877 878
      }
      
      if (errors_bit > 0) {
	n_false_positive++;
	if (n_trials == 1)
	  printf("errors_bit = %u (trial %d)\n", errors_bit, trial);
      }
Raymond Knopp's avatar
Raymond Knopp committed
879
      
Ahmed Hussein's avatar
Ahmed Hussein committed
880
    } // noise trials
881

Ahmed Hussein's avatar
Ahmed Hussein committed
882 883
    printf("*****************************************\n");
    printf("SNR %f, (false positive %f)\n", SNR,
Sakthivel Velumani's avatar
Sakthivel Velumani committed
884
           (float) n_errors / (float) n_trials);
Ahmed Hussein's avatar
Ahmed Hussein committed
885 886
    printf("*****************************************\n");
    printf("\n");
887
    printf("SNR %f : n_errors (negative CRC) = %d/%d, Channel BER %e\n", SNR, n_errors, n_trials,(double)errors_scrambling/available_bits/n_trials);
Ahmed Hussein's avatar
Ahmed Hussein committed
888
    printf("\n");
889

890 891 892 893 894 895 896 897 898 899
    if (n_trials == 1) {
      
      LOG_M("rxsig0.m","rxs0", UE->common_vars.rxdata[0], frame_length_complex_samples, 1, 1);
      if (UE->frame_parms.nb_antennas_rx>1)
	LOG_M("rxsig1.m","rxs1", UE->common_vars.rxdata[1], frame_length_complex_samples, 1, 1);
      LOG_M("chestF0.m","chF0",UE->pdsch_vars[0][0]->dl_ch_estimates_ext,N_RB_DL*12*14,1,1);
      write_output("rxF_comp.m","rxFc",&UE->pdsch_vars[0][0]->rxdataF_comp0[0][0],N_RB_DL*12*14,1,1);
      break;
    }

900
    if ((float)n_errors/(float)n_trials <= target_error_rate) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
901
      printf("PDSCH test OK\n");
902 903 904
      break;
    }

905 906

    if (print_perf==1) {
907 908 909 910 911
      printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, TBS %d, Kr %d (Zc %d))\n",
	     1000>>*scc->ssbSubcarrierSpacing,dlsch_config.rbSize,dlsch_config.mcsIndex[0],
	     gNB->dlsch[0][0]->harq_processes[0]->pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3,
	     gNB->dlsch[0][0]->harq_processes[0]->K,
	     gNB->dlsch[0][0]->harq_processes[0]->K/((gNB->dlsch[0][0]->harq_processes[0]->pdsch_pdu.pdsch_pdu_rel15.TBSize[0]<<3)>3824?22:10));
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
      printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx");
      printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time");
      printStatIndent3(&gNB->dlsch_segmentation_stats,"DLSCH segmentation time");
      printStatIndent3(&gNB->tinput,"DLSCH LDPC input processing time");
      printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time");
      printStatIndent3(&gNB->tparity,"DLSCH LDPC parity generation time");
      printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time");
      printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Mataching time");
      printStatIndent3(&gNB->dlsch_interleaving_stats,  "DLSCH Interleaving time");
      printStatIndent2(&gNB->dlsch_modulation_stats,"DLSCH modulation time");
      printStatIndent2(&gNB->dlsch_scrambling_stats,  "DLSCH scrambling time");


      printf("\nUE RX function statistics (per %d us slot)\n",1000>>*scc->ssbSubcarrierSpacing);
      /*
      printDistribution(&phy_proc_rx_tot, table_rx,"Total PHY proc rx");
      printStatIndent(&ue_front_end_tot,"Front end processing");
      printStatIndent(&dlsch_llr_tot,"rx_pdsch processing");
      printStatIndent2(&pdsch_procedures_tot,"pdsch processing");
      printStatIndent2(&dlsch_procedures_tot,"dlsch processing");
      printStatIndent2(&UE->crnti_procedures_stats,"C-RNTI processing");
      printStatIndent(&UE->ofdm_demod_stats,"ofdm demodulation");
      printStatIndent(&UE->dlsch_channel_estimation_stats,"DLSCH channel estimation time");
      printStatIndent(&UE->dlsch_freq_offset_estimation_stats,"DLSCH frequency offset estimation time");
      printStatIndent(&dlsch_decoding_tot, "DLSCH Decoding time ");
      printStatIndent(&UE->dlsch_unscrambling_stats,"DLSCH unscrambling time");
      printStatIndent(&UE->dlsch_rate_unmatching_stats,"DLSCH Rate Unmatching");
      printf("|__ DLSCH Turbo Decoding(%d bits), avg iterations: %.1f       %.2f us (%d cycles, %d trials)\n",
	     UE->dlsch[UE->current_thread_id[subframe]][0][0]->harq_processes[0]->Cminus ?
	     UE->dlsch[UE->current_thread_id[subframe]][0][0]->harq_processes[0]->Kminus :
	     UE->dlsch[UE->current_thread_id[subframe]][0][0]->harq_processes[0]->Kplus,
	     UE->dlsch_tc_intl1_stats.trials/(double)UE->dlsch_tc_init_stats.trials,
	     (double)UE->dlsch_turbo_decoding_stats.diff/UE->dlsch_turbo_decoding_stats.trials*timeBase,
	     (int)((double)UE->dlsch_turbo_decoding_stats.diff/UE->dlsch_turbo_decoding_stats.trials),
	     UE->dlsch_turbo_decoding_stats.trials);
      printStatIndent2(&UE->dlsch_tc_init_stats,"init");
      printStatIndent2(&UE->dlsch_tc_alpha_stats,"alpha");
      printStatIndent2(&UE->dlsch_tc_beta_stats,"beta");
      printStatIndent2(&UE->dlsch_tc_gamma_stats,"gamma");
      printStatIndent2(&UE->dlsch_tc_ext_stats,"ext");
      printStatIndent2(&UE->dlsch_tc_intl1_stats,"turbo internal interleaver");
      printStatIndent2(&UE->dlsch_tc_intl2_stats,"intl2+HardDecode+CRC");
      */
    }
956 957
  } // NSR

Ahmed Hussein's avatar
Ahmed Hussein committed
958
  for (i = 0; i < 2; i++) {
959 960 961 962 963 964 965 966 967 968 969 970
    free(s_re[i]);
    free(s_im[i]);
    free(r_re[i]);
    free(r_im[i]);
    free(txdata[i]);
  }

  free(s_re);
  free(s_im);
  free(r_re);
  free(r_im);
  free(txdata);
Ahmed Hussein's avatar
Ahmed Hussein committed
971 972 973
  free(test_input_bit);
  free(estimated_output_bit);
  
974 975 976 977 978 979 980
  if (output_fd)
    fclose(output_fd);

  if (input_fd)
    fclose(input_fd);

  return(n_errors);
Raymond Knopp's avatar
Raymond Knopp committed
981
  
982
}