Update to odulow per maintenance bronze
[o-du/phy.git] / fhi_lib / test / master.py
1 #!/usr/bin/python
2 #******************************************************************************
3 #
4 #   Copyright (c) 2019 Intel.
5 #
6 #   Licensed under the Apache License, Version 2.0 (the "License");
7 #   you may not use this file except in compliance with the License.
8 #   You may obtain a copy of the License at
9 #
10 #       http://www.apache.org/licenses/LICENSE-2.0
11 #
12 #   Unless required by applicable law or agreed to in writing, software
13 #   distributed under the License is distributed on an "AS IS" BASIS,
14 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 #   See the License for the specific language governing permissions and
16 #   limitations under the License.
17 #
18 #******************************************************************************/
19
20 """This script runs test cases with O-DU and O-RU
21 """
22 import logging
23 import sys
24 import argparse
25 import re
26 import subprocess
27 import os
28 import shutil
29 from itertools import dropwhile
30 from datetime import datetime
31 from time import gmtime, strftime
32 import json
33 from threading import Timer
34 import socket
35
36 timeout_sec = 60*3 #3 min max
37
38 nLteNumRbsPerSymF1 = [
39     #  5MHz    10MHz   15MHz   20 MHz
40         [25,    50,     75,     100]  # LTE Numerology 0 (15KHz)
41 ]
42
43 nNumRbsPerSymF1 = [
44     #  5MHz    10MHz   15MHz   20 MHz  25 MHz  30 MHz  40 MHz  50MHz   60 MHz  70 MHz  80 MHz   90 MHz  100 MHz
45         [25,    52,     79,     106,    133,    160,    216,    270,    0,         0,      0,      0,      0],         # Numerology 0 (15KHz)
46         [11,    24,     38,     51,     65,     78,     106,    133,    162,       0,    217,    245,    273],         # Numerology 1 (30KHz)
47         [0,     11,     18,     24,     31,     38,     51,     65,     79,        0,    107,    121,    135]          # Numerology 2 (60KHz)
48 ]
49
50 nNumRbsPerSymF2 = [
51     # 50Mhz  100MHz  200MHz   400MHz
52     [66,    132,    264,     0],       # Numerology 2 (60KHz)
53     [32,    66,     132,     264]      # Numerology 3 (120KHz)
54 ]
55
56
57 nRChBwOptions_keys = ['5','10','15','20', '25', '30', '40', '50', '60','70', '80', '90', '100', '200', '400']
58 nRChBwOptions_values = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
59 nRChBwOptions = dict(zip(nRChBwOptions_keys, nRChBwOptions_values))
60
61 nRChBwOptions_keys_mu2and3 = ['50', '100', '200', '400']
62 nRChBwOptions_values_mu2and3 = [0,1,2,3]
63 nRChBwOptions_mu2and3 = dict(zip(nRChBwOptions_keys_mu2and3, nRChBwOptions_values_mu2and3))
64
65 # values for Jenkins server
66 eth_cp_dev = ["0000:19:02.1", "0000:19:0a.1"]
67 eth_up_dev = ["0000:19:02.0", "0000:19:0a.0"]
68
69 # table of all test cases
70 #                 (ran, cat, mu, bw, test case)
71 #Cat A
72 NR_test_cases_A = [(0,  0,   0,  5,   0),
73                    (0,  0,   0,  10,  0),
74                    (0,  0,   0,  10,  12),
75                    (0,  0,   0,  20,  0),
76                    (0,  0,   0,  20,  12),
77                    (0,  0,   1,  100, 0),
78                    (0,  0,   3,  100, 0),
79 ]
80
81 LTE_test_cases_A = [(1,  0,   0,  5,   0),
82                     (1,  0,   0,  10,  0),
83                     (1,  0,   0,  20,  0),
84 ]
85
86 #Cat B
87 NR_test_cases_B  =  [(0, 1,   1,  100, 0),
88                      (0, 1,   1,  100, 2),
89                      (0, 1,   1,  100, 1),
90                      (0, 1,   1,  100, 101),
91                      (0, 1,   1,  100, 102),
92                      (0, 1,   1,  100, 103),
93                      (0, 1,   1,  100, 104),
94                      (0, 1,   1,  100, 105),
95                      #(0, 1,   1,  100, 106), 25G not enough
96                      (0, 1,   1,  100, 107),
97                      (0, 1,   1,  100, 108),
98                      #(0, 1,   1,  100, 109), 25G not enough
99                      (0, 1,   1,  100, 201),
100                      #(0, 1,   1,  100, 202), 25G not enough
101                      #(0, 1,   1,  100, 203),
102                      (0, 1,   1,  100, 204),
103                      (0, 1,   1,  100, 205),
104                      (0, 1,   1,  100, 206),
105                      (0, 1,   1,  100, 211),
106                      #(0, 1,   1,  100, 212), 25G not enough
107                      (0, 1,   1,  100, 213),
108                      (0, 1,   1,  100, 214),
109                      (0, 1,   1,  100, 215),
110                      (0, 1,   1,  100, 216)
111 ]
112
113 LTE_test_cases_B = [(1,  1,   0,   5,  0),
114                     (1,  1,   0,  10,  0),
115                     (1,  1,   0,  20,  0),
116 ]
117
118 V_test_cases_B = [
119                    # (0,  1,   1,  100,  301), 25G not enough
120                     (0,  1,   1,  100,  302),
121                     (0,  1,   1,  100,  303),
122                     (0,  1,   1,  100,  304),
123                     (0,  1,   1,  100,  305),
124                     (0,  1,   1,  100,  306)
125 ]
126
127 all_test_cases = NR_test_cases_A + LTE_test_cases_A + LTE_test_cases_B + NR_test_cases_B + V_test_cases_B
128
129 dic_dir      = dict({0:'DL', 1:'UL'})
130 dic_xu       = dict({0:'o-du', 1:'o-ru'})
131 dic_ran_tech = dict({0:'5g_nr', 1:'lte'})
132
133 def init_logger(console_level, logfile_level):
134     """Initializes console and logfile logger with given logging levels"""
135     # File logger
136     logging.basicConfig(filename="runtests.log",
137                         filemode='w',
138                         format="%(asctime)s: %(levelname)s: %(message)s",
139                         level=logfile_level)
140     # Console logger
141     logger = logging.getLogger()
142     handler = logging.StreamHandler()
143     handler.setLevel(console_level)
144     formatter = logging.Formatter("%(levelname)s: %(message)s")
145     handler.setFormatter(formatter)
146     logger.addHandler(handler)
147
148 def parse_args(args):
149     """Configures parser and parses command line configuration"""
150     # Parser configuration
151     parser = argparse.ArgumentParser(description="Run test cases: category numerology bandwidth test_num")
152
153     parser.add_argument("--ran", type=int, default=0, help="Radio Access Tehcnology 0 (5G NR) or 1 (LTE)", metavar="ran", dest="rantech")
154     parser.add_argument("--cat", type=int, default=0, help="Category: 0 (A) or 1 (B)", metavar="cat", dest="category")
155     parser.add_argument("--mu", type=int, default=0, help="numerology [0,1,3]", metavar="num", dest="numerology")
156     parser.add_argument("--bw",  type=int, default=20, help="bandwidth [5,10,20,100]", metavar="bw", dest="bandwidth")
157     parser.add_argument("--testcase", type=int, default=0, help="test case number", metavar="testcase", dest="testcase")
158     parser.add_argument("--verbose", type=int, default=0, help="enable verbose output", metavar="verbose", dest="verbose")
159
160     # Parse arguments
161     options = parser.parse_args(args)
162     #parser.print_help()
163     logging.debug("Options: ran=%d category=%d num=%d bw=%d testcase=%d",
164                   options.rantech, options.category, options.numerology, options.bandwidth, options.testcase)
165     return options
166
167 def is_comment(s):
168     """ function to check if a line
169          starts with some character.
170          Here # for comment
171     """
172     # return true if a line starts with #
173     return s.startswith('#')
174
175 class GetOutOfLoops( Exception ):
176     pass
177
178 def get_re_map(nRB, direction):
179     prb_map        = []
180     PrbElemContent = []
181     if direction == 0:
182         #DL
183         if 'nPrbElemDl' in globals():
184             nPrbElm = nPrbElemDl
185             for i in range(0, nPrbElm):
186                 elm = str('PrbElemDl'+str(i))
187                 #print(elm)
188                 if elm in globals():
189                     PrbElemContent.insert(i,list(globals()[elm]))
190                     xRBStart = PrbElemContent[i][0]
191                     xRBSize  = PrbElemContent[i][1]
192                     #print(PrbElemContent,"RBStart: ", xRBStart, "RBSize: ",xRBSize, list(range(xRBStart, xRBStart + xRBSize)))
193                     prb_map = prb_map + list(range(xRBStart*12, xRBStart*12 + xRBSize*12))
194         else:
195             nPrbElm = 0;
196
197     elif direction == 1:
198         #UL
199         if 'nPrbElemUl' in globals():
200             nPrbElm = nPrbElemUl
201             for i in range(0, nPrbElm):
202                 elm = str('PrbElemUl'+str(i))
203                 #print(elm)
204                 if (elm in globals()):
205                     PrbElemContent.insert(i,list(globals()[elm]))
206                     xRBStart = PrbElemContent[i][0]
207                     xRBSize  = PrbElemContent[i][1]
208                     #print(PrbElemContent,"RBStart: ", xRBStart, "RBSize: ",xRBSize, list(range(xRBStart, xRBStart + xRBSize)))
209                     prb_map = prb_map + list(range(xRBStart*12, xRBStart*12 + xRBSize*12))
210         else:
211             nPrbElm = 0;
212
213     if nPrbElm == 0 :
214         prb_map = list(range(0, nRB*12))
215
216     return prb_map
217
218 def compare_resuts(rantech, cat, mu, bw, tcase, xran_path, test_cfg, direction):
219     res = 0
220     re_map = []
221     if rantech==1:
222         if mu == 0:
223             nDlRB = nLteNumRbsPerSymF1[mu][nRChBwOptions.get(str(nDLBandwidth))]
224             nUlRB = nLteNumRbsPerSymF1[mu][nRChBwOptions.get(str(nULBandwidth))]
225         else:
226             print("Incorrect arguments\n")
227             res = -1
228             return res
229     elif rantech==0:
230         if mu < 3:
231             nDlRB = nNumRbsPerSymF1[mu][nRChBwOptions.get(str(nDLBandwidth))]
232             nUlRB = nNumRbsPerSymF1[mu][nRChBwOptions.get(str(nULBandwidth))]
233         elif (mu >=2) & (mu <= 3):
234             nDlRB = nNumRbsPerSymF2[mu - 2][nRChBwOptions_mu2and3.get(str(nDLBandwidth))]
235             nUlRB = nNumRbsPerSymF2[mu - 2][nRChBwOptions_mu2and3.get(str(nULBandwidth))]
236             print(nDlRB, nUlRB)
237         else:
238             print("Incorrect arguments\n")
239             res = -1
240             return res
241
242     if 'compression' in globals():
243         comp = compression
244     else:
245         comp = 0
246
247     if 'srsEanble' in globals():
248         srs_enb = srsEanble
249     else:
250         srs_enb = 0
251
252     print("compare results: {} [compression {}]\n".format(dic_dir.get(direction), comp))
253
254     #if cat == 1:
255     #    print("WARNING: Skip checking IQs and BF Weights for CAT B for now\n");
256     #    return res
257
258     #get slot config
259     if nFrameDuplexType == 1:
260         SlotConfig = []
261         for i in range(nTddPeriod):
262             if i == 0:
263                 SlotConfig.insert(i, sSlotConfig0)
264             elif i == 1:
265                 SlotConfig.insert(i, sSlotConfig1)
266             elif i == 2:
267                 SlotConfig.insert(i, sSlotConfig2)
268             elif i == 3:
269                 SlotConfig.insert(i, sSlotConfig3)
270             elif i == 4:
271                 SlotConfig.insert(i, sSlotConfig4)
272             elif i == 5:
273                 SlotConfig.insert(i, sSlotConfig5)
274             elif i == 6:
275                 SlotConfig.insert(i, sSlotConfig6)
276             elif i == 7:
277                 SlotConfig.insert(i, sSlotConfig7)
278             elif i == 8:
279                 SlotConfig.insert(i, sSlotConfig8)
280             elif i == 9:
281                 SlotConfig.insert(i, sSlotConfig9)
282             else :
283                 raise Exception('i should not exceed nTddPeriod %d. The value of i was: {}'.format(nTddPeriod, i))
284         #print(SlotConfig, type(sSlotConfig0))
285     try:
286
287         if (direction == 1) & (cat == 1): #UL
288             flowId = ccNum*antNumUL
289         else:
290             flowId = ccNum*antNum
291
292         if direction == 0:
293             re_map = get_re_map(nDlRB, direction)
294         elif direction == 1:
295             re_map = get_re_map(nUlRB, direction)
296         else:
297             raise Exception('Direction is not supported %d'.format(direction))
298
299         for i in range(0, flowId):
300             #read ref and test files
301             tst = []
302             ref = []
303             if direction == 0:
304                 # DL
305                 nRB = nDlRB
306                 file_tst = xran_path+"/app/logs/"+"o-ru-rx_log_ant"+str(i)+".txt"
307                 file_ref = xran_path+"/app/logs/"+"o-du-play_ant"+str(i)+".txt"
308             elif direction == 1:
309                 # UL
310                 nRB = nUlRB
311                 file_tst = xran_path+"/app/logs/"+"o-du-rx_log_ant"+str(i)+".txt"
312                 file_ref = xran_path+"/app/logs/"+"o-ru-play_ant"+str(i)+".txt"
313             else:
314                 raise Exception('Direction is not supported %d'.format(direction))
315
316             print("test result   :", file_tst)
317             print("test reference:", file_ref)
318             if os.path.exists(file_tst):
319                 try:
320                     file_tst = open(file_tst, 'r')
321                 except OSError:
322                     print ("Could not open/read file:", file_tst)
323                     sys.exit()
324             else:
325                 print(file_tst, "doesn't exist")
326                 res = -1
327                 return res
328             if os.path.exists(file_ref):
329                 try:
330                     file_ref = open(file_ref, 'r')
331                 except OSError:
332                     print ("Could not open/read file:", file_ref)
333                     sys.exit()
334             else:
335                 print(file_tst, "doesn't exist")
336                 res = -1
337                 return res
338
339             tst = file_tst.readlines()
340             ref = file_ref.readlines()
341
342             print(len(tst))
343             print(len(ref))
344
345             file_tst.close();
346             file_ref.close();
347
348             print(numSlots)
349
350             for slot_idx in range(0, numSlots):
351                 for sym_idx in range(0, 14):
352                     if nFrameDuplexType==1:
353                         #skip sym if TDD
354                         if direction == 0:
355                             #DL
356                             sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
357                             if(sym_dir != 0):
358                                 continue
359                         elif direction == 1:
360                             #UL
361                             sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
362                             if(sym_dir != 1):
363                                 continue
364
365                     #print("Check:","[",i,"]", slot_idx, sym_idx)
366                     for line_idx in re_map:
367                         offset = (slot_idx*nRB*12*14) + sym_idx*nRB*12 + line_idx
368                         try:
369                             line_tst = tst[offset].rstrip()
370                         except IndexError:
371                             res = -1
372                             print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
373                             raise GetOutOfLoops
374                         try:
375                              line_ref = ref[offset].rstrip()
376                         except IndexError:
377                             res = -1
378                             print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
379                             raise GetOutOfLoops
380
381                         if comp == 1:
382                             # discard LSB bits as BFP compression is not "bit exact"
383                             tst_i_value = int(line_tst.split(" ")[0]) & 0xFF80
384                             tst_q_value = int(line_tst.split(" ")[1]) & 0xFF80
385                             ref_i_value = int(line_ref.split(" ")[0]) & 0xFF80
386                             ref_q_value = int(line_ref.split(" ")[1]) & 0xFF80
387
388                             #print("check:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst: ", tst_i_value, " ", tst_q_value, " " , "ref: ", ref_i_value, " ", ref_q_value, " ")
389                             if (tst_i_value != ref_i_value) or  (tst_q_value != ref_q_value) :
390                                 print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst: ", tst_i_value, " ", tst_q_value, " " , "ref: ", ref_i_value, " ", ref_q_value, " ")
391                                 res = -1
392                                 raise GetOutOfLoops
393                         else:
394                             #if line_idx == 0:
395                                 #print("Check:", offset,"[",i,"]", slot_idx, sym_idx,":",line_tst, line_ref)
396                             if line_ref != line_tst:
397                                 print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst:", line_tst, "ref:", line_ref)
398                                 res = -1
399                                 raise GetOutOfLoops
400     except GetOutOfLoops:
401         return res
402
403     #if (direction == 0) | (cat == 0) | (srs_enb == 0): #DL or Cat A
404         #done
405     return res
406
407     print("compare results: {} [compression {}]\n".format('SRS', comp))
408
409     #srs
410     symbMask    = srsSym
411     try:
412         flowId = ccNum*antElmTRx
413         for i in range(0, flowId):
414             #read ref and test files
415             tst = []
416             ref = []
417
418             if direction == 1:
419                 # UL
420                 nRB = nUlRB
421                 file_tst = xran_path+"/app/logs/"+"o-du-srs_log_ant"+str(i)+".txt"
422                 file_ref = xran_path+"/app/logs/"+"o-ru-play_srs_ant"+str(i)+".txt"
423             else:
424                 raise Exception('Direction is not supported %d'.format(direction))
425
426             print("test result   :", file_tst)
427             print("test reference:", file_ref)
428             if os.path.exists(file_tst):
429                 try:
430                     file_tst = open(file_tst, 'r')
431                 except OSError:
432                     print ("Could not open/read file:", file_tst)
433                     sys.exit()
434             else:
435                 print(file_tst, "doesn't exist")
436                 res = -1
437                 return res
438             if os.path.exists(file_ref):
439                 try:
440                     file_ref = open(file_ref, 'r')
441                 except OSError:
442                     print ("Could not open/read file:", file_ref)
443                     sys.exit()
444             else:
445                 print(file_tst, "doesn't exist")
446                 res = -1
447                 return res
448
449             tst = file_tst.readlines()
450             ref = file_ref.readlines()
451
452             print(len(tst))
453             print(len(ref))
454
455             file_tst.close();
456             file_ref.close();
457
458             print(numSlots)
459
460             for slot_idx in range(0, numSlots):
461                 for sym_idx in range(0, 14):
462                     if symbMask & (1 << sym_idx):
463                         print("SRS check sym ", sym_idx)
464                         if nFrameDuplexType==1:
465                             #skip sym if TDD
466                             if direction == 0:
467                                 #DL
468                                 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
469                                 if(sym_dir != 0):
470                                     continue
471                             elif direction == 1:
472                                 #UL
473                                 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
474                                 if(sym_dir != 1):
475                                     continue
476
477                         #print("Check:","[",i,"]", slot_idx, sym_idx)
478                         for line_idx in range(0, nRB*12):
479                             offset = (slot_idx*nRB*12*14) + sym_idx*nRB*12 + line_idx
480                             try:
481                                 line_tst = tst[offset].rstrip()
482                             except IndexError:
483                                 res = -1
484                                 print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
485                                 raise GetOutOfLoops
486                             try:
487                                 line_ref = ref[offset].rstrip()
488                             except IndexError:
489                                 res = -1
490                                 print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
491                                 raise GetOutOfLoops
492                             if False : #SRS sent as not compressed
493                                 #comp == 1:
494                                 # discard LSB bits as BFP compression is not Bit Exact
495                                 tst_i_value = int(line_tst.split(" ")[0]) & 0xFF80
496                                 tst_q_value = int(line_tst.split(" ")[1]) & 0xFF80
497                                 ref_i_value = int(line_ref.split(" ")[0]) & 0xFF80
498                                 ref_q_value = int(line_ref.split(" ")[1]) & 0xFF80
499
500                                 print("check:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst: ", tst_i_value, " ", tst_q_value, " " , "ref: ", ref_i_value, " ", ref_q_value, " ")
501                                 if (tst_i_value != ref_i_value) or  (tst_q_value != ref_q_value) :
502                                     print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst: ", tst_i_value, " ", tst_q_value, " " , "ref: ", ref_i_value, " ", ref_q_value, " ")
503                                     res = -1
504                                     raise GetOutOfLoops
505                             else:
506                                 #if line_idx == 0:
507                                     #print("Check:", offset,"[",i,"]", slot_idx, sym_idx,":",line_tst, line_ref)
508                                 if line_ref != line_tst:
509                                     print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst:", line_tst, "ref:", line_ref)
510                                     res = -1
511                                     raise GetOutOfLoops
512     except GetOutOfLoops:
513         pass
514
515
516     return res
517
518 def parse_dat_file(rantech, cat, mu, bw, tcase, xran_path, test_cfg):
519     #parse config files
520     logging.info("parse config files %s\n", test_cfg[0])
521     lineList = list()
522     sep = '#'
523     with open(test_cfg[0],'r') as fh:
524         for curline in dropwhile(is_comment, fh):
525             my_line = curline.rstrip().split(sep, 1)[0].strip()
526             if my_line:
527                 lineList.append(my_line)
528     global_env = {}
529     local_env = {}
530
531     for line in lineList:
532         exe_line = line.replace(":", ",")
533         if exe_line.find("/") > 0 :
534             exe_line = exe_line.replace('./', "'")
535             exe_line = exe_line+"'"
536
537         code = compile(str(exe_line), '<string>', 'exec')
538         exec (code, global_env, local_env)
539
540     for k, v in local_env.items():
541         globals()[k] = v
542         print(k, v)
543
544     return local_env
545
546 def del_dat_file_vars(local_env):
547
548     for k, v in local_env.items():
549         del globals()[k]
550
551     return 0
552
553 def make_copy_mlog(rantech, cat, mu, bw, tcase, xran_path):
554     res = 0
555
556     src_bin = xran_path+"/app/mlog-o-du-c0.bin"
557     src_csv = xran_path+"/app/mlog-o-du-hist.csv"
558     dst_bin = xran_path+"/app/mlog-o-du-c0-ran"+str(rantech)+"-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".bin"
559     dst_csv = xran_path+"/app/mlog-o-du-hist-ran"+str(rantech)+"-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".csv"
560
561     try:
562         d_bin  = shutil.copyfile(src_bin, dst_bin)
563         d_csv  = shutil.copyfile(src_csv, dst_csv)
564     except IOError:
565         logging.info("MLog is not present\n")
566         res = 1
567         return res
568     else:
569         logging.info("Mlog was copied\n")
570
571
572     print("Destination path:", d_bin)
573     print("Destination path:", d_csv)
574
575     d_bin  = shutil.copyfile(src_bin, dst_bin)
576     d_csv  = shutil.copyfile(src_csv, dst_csv)
577
578     src_bin = xran_path+"/app/mlog-o-ru-c0.bin"
579     src_csv = xran_path+"/app/mlog-o-ru-hist.csv"
580     dst_bin = xran_path+"/app/mlog-o-ru-c0-ran"+str(rantech)+"-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".bin"
581     dst_csv = xran_path+"/app/mlog-o-ru-hist-ran"+str(rantech)+"-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".csv"
582
583     d_bin  = shutil.copyfile(src_bin, dst_bin)
584     d_csv  = shutil.copyfile(src_csv, dst_csv)
585
586     try:
587         d_bin  = shutil.copyfile(src_bin, dst_bin)
588         d_csv  = shutil.copyfile(src_csv, dst_csv)
589     except IOError:
590         logging.info("MLog is not present\n")
591         res = 1
592         return res
593     else:
594         logging.info("Mlog was copied\n")
595
596     return res
597
598
599 def run_tcase(rantech, cat, mu, bw, tcase, verbose, xran_path):
600
601     if rantech == 1: #LTE
602         if cat == 1:
603             test_config =xran_path+"/app/usecase/lte_b/mu{0:d}_{1:d}mhz".format(mu, bw)
604         elif cat == 0 :
605             test_config =xran_path+"/app/usecase/lte_a/mu{0:d}_{1:d}mhz".format(mu, bw)
606         else:
607             print("Incorrect cat arguments\n")
608             return -1
609     elif rantech == 0: #5G NR
610         if cat == 1:
611             test_config =xran_path+"/app/usecase/cat_b/mu{0:d}_{1:d}mhz".format(mu, bw)
612         elif cat == 0 :
613             test_config =xran_path+"/app/usecase/mu{0:d}_{1:d}mhz".format(mu, bw)
614         else:
615             print("Incorrect cat argument\n")
616             return -1
617     else:
618         print("Incorrect rantech argument\n")
619         return -1
620
621     if(tcase > 0) :
622         test_config = test_config+"/"+str(tcase)
623
624     app = xran_path+"/app/build/sample-app"
625
626     logging.debug("run: %s %s", app, test_config)
627     logging.debug("Started script: master.py, XRAN path %s", xran_path)
628
629     test_cfg = []
630
631     test_cfg.append(test_config+"/config_file_o_du.dat")
632     test_cfg.append(test_config+"/config_file_o_ru.dat")
633
634     wd = os.getcwd()
635     os.chdir(xran_path+"/app/")
636
637     processes     = []
638     logfile_xu    = []
639     log_file_name = []
640     timer         = []
641
642     os.system('pkill -9 "sample-app"')
643     os.system('rm -rf ./logs')
644
645     for i in range(2):
646         log_file_name.append("sampleapp_log_{}_{}_cat_{}_mu{}_{}mhz_tst_{}.log".format(dic_ran_tech.get(rantech), dic_xu.get(i),cat, mu, bw, tcase))
647         with open(log_file_name[i], "w") as f:
648             run_cmd = [app, "-c", test_cfg[i], "-p", "2", eth_up_dev[i], eth_cp_dev[i]]
649             #, stdout=f, stderr=f
650             if (verbose==1):
651                 p = subprocess.Popen(run_cmd)
652             else:
653                 p = subprocess.Popen(run_cmd, stdout=f, stderr=f)
654             t = Timer(timeout_sec, p.kill)
655             t.start()
656             timer.append(t)
657             logfile_xu.insert(i, f)
658         processes.append((p, logfile_xu[i]))
659
660     logging.info("Running O-DU and O-RU see output in:\n    O-DU: %s\n    O-RU: %s\n", xran_path+"/app/"+logfile_xu[0].name, xran_path+"/app/"+logfile_xu[1].name)
661     #while (gmtime().tm_sec % 30) <> 0:
662         #pass
663     print(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()))
664     i = 0
665     for p, f in processes:
666         p.communicate()[0]
667         p.wait()
668         if p.returncode != 0:
669             print("Application {} failed p.returncode:{}".format(dic_xu.get(i), p.returncode))
670             print("FAIL")
671             #logging.info("FAIL\n")
672             #logging.shutdown()
673             #sys.exit(p.returncode)
674         i += 1
675         f.close()
676
677     for i in range(2):
678         timer[i].cancel();
679         timer[i].cancel();
680
681     logging.info("O-DU and O-RU are done\n")
682
683     make_copy_mlog(rantech, cat, mu, bw, tcase, xran_path)
684
685     usecase_cfg = parse_dat_file(rantech, cat, mu, bw, tcase, xran_path, test_cfg)
686
687     res = compare_resuts(rantech, cat, mu, bw, tcase, xran_path, test_cfg, 0)
688     if res != 0:
689         os.chdir(wd)
690         print("FAIL")
691         return res
692
693     res = compare_resuts(rantech, cat, mu, bw, tcase, xran_path, test_cfg, 1)
694     if res != 0:
695         os.chdir(wd)
696         print("FAIL")
697         return res
698
699     os.chdir(wd)
700     print("PASS")
701
702     del_dat_file_vars(usecase_cfg)
703
704     return res
705
706 def main():
707     test_results = []
708     test_executed_total = 0
709     run_total = 0
710     cat   = 0
711     mu    = 0
712     bw    = 0
713     tcase = 0
714     """Processes input files to produce IACA files"""
715     # Find path to XRAN
716     if os.getenv("XRAN_DIR") is not None:
717         xran_path = os.getenv("XRAN_DIR")
718     else:
719         print("please set 'export XRAN_DIR' in the OS")
720         return -1
721
722     # Set up logging with given level (DEBUG, INFO, ERROR) for console end logfile
723     init_logger(logging.INFO, logging.DEBUG)
724     host_name =  socket.gethostname()
725     logging.info("host: %s Started script: master.py from XRAN path %s",host_name, xran_path)
726
727     #custom config for dev station
728     if host_name == "sc12-xran-sub6":
729         eth_cp_dev[0] = "0000:21:02.1"
730         eth_cp_dev[1] = "0000:21:0a.1"
731         eth_up_dev[0] = "0000:21:02.0"
732         eth_up_dev[1] = "0000:21:0a.0"
733
734     # Parse input arguments
735     if len(sys.argv) == 1 :
736         run_total = len(all_test_cases)
737         print(run_total)
738         print("Run All test cases {}\n".format(run_total))
739     else:
740         options = parse_args(sys.argv[1:])
741         rantech = options.rantech
742         cat     = options.category
743         mu      = options.numerology
744         bw      = options.bandwidth
745         tcase   = options.testcase
746         verbose = options.verbose
747
748
749     if (run_total):
750         for test_run_ix in range(0, run_total):
751             rantech = all_test_cases[test_run_ix][0]
752             cat     = all_test_cases[test_run_ix][1]
753             mu      = all_test_cases[test_run_ix][2]
754             bw      = all_test_cases[test_run_ix][3]
755             tcase   = all_test_cases[test_run_ix][4]
756             verbose = 0
757
758             logging.info("Test# %d out of %d: ran %d cat %d mu %d bw %d test case %d\n",test_run_ix, run_total, rantech, cat, mu, bw, tcase)
759             res = run_tcase(rantech, cat, mu, bw, tcase, verbose,  xran_path)
760             if (res != 0):
761                 test_results.append((rantech, cat, mu, bw, tcase,'FAIL'))
762                 continue
763
764             test_results.append((rantech, cat, mu, bw, tcase,'PASS'))
765
766             with open('testresult.txt', 'w') as reshandle:
767                 json.dump(test_results, reshandle)
768     else:
769         res = run_tcase(rantech, cat, mu, bw, tcase, verbose, xran_path)
770         if (res != 0):
771             test_results.append((rantech, cat, mu, bw, tcase,'FAIL'))
772         test_results.append((rantech, cat, mu, bw, tcase,'PASS'))
773
774         with open('testresult.txt', 'w') as reshandle:
775             json.dump(test_results, reshandle)
776
777     return res
778
779 if __name__ == '__main__':
780     START_TIME = datetime.now()
781     res = main()
782     END_TIME = datetime.now()
783     logging.debug("Start time: %s, end time: %s", START_TIME, END_TIME)
784     logging.info("Execution time: %s", END_TIME - START_TIME)
785     logging.shutdown()
786     sys.exit(res)