O-RAN E Maintenance Release contribution for ODULOW
[o-du/phy.git] / fhi_lib / test / master.py
1 #!/usr/bin/python
2 #******************************************************************************
3 #
4 #   Copyright (c) 2020 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 signal
27 import subprocess
28 import os
29 import shutil
30 import copy
31 from itertools import dropwhile
32 from datetime import datetime
33 from time import gmtime, strftime
34 import json
35 from threading import Timer
36 import socket
37
38 timeout_sec = 60*3 #3 min max
39
40 nLteNumRbsPerSymF1 = [
41     #  5MHz    10MHz   15MHz   20 MHz
42         [25,    50,     75,     100]  # LTE Numerology 0 (15KHz)
43 ]
44
45 nNumRbsPerSymF1 = [
46     #  5MHz    10MHz   15MHz   20 MHz  25 MHz  30 MHz  40 MHz  50MHz   60 MHz  70 MHz  80 MHz   90 MHz  100 MHz
47         [25,    52,     79,     106,    133,    160,    216,    270,    0,         0,      0,      0,      0],         # Numerology 0 (15KHz)
48         [11,    24,     38,     51,     65,     78,     106,    133,    162,       0,    217,    245,    273],         # Numerology 1 (30KHz)
49         [0,     11,     18,     24,     31,     38,     51,     65,     79,        0,    107,    121,    135]          # Numerology 2 (60KHz)
50 ]
51
52 nNumRbsPerSymF2 = [
53     # 50Mhz  100MHz  200MHz   400MHz
54     [66,    132,    264,     0],       # Numerology 2 (60KHz)
55     [32,    66,     132,     264]      # Numerology 3 (120KHz)
56 ]
57
58
59 nRChBwOptions_keys = ['5','10','15','20', '25', '30', '40', '50', '60','70', '80', '90', '100', '200', '400']
60 nRChBwOptions_values = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
61 nRChBwOptions = dict(zip(nRChBwOptions_keys, nRChBwOptions_values))
62
63 nRChBwOptions_keys_mu2and3 = ['50', '100', '200', '400']
64 nRChBwOptions_values_mu2and3 = [0,1,2,3]
65 nRChBwOptions_mu2and3 = dict(zip(nRChBwOptions_keys_mu2and3, nRChBwOptions_values_mu2and3))
66
67 vf_addr_o_xu=[]
68
69 # values for Jenkins server
70 vf_addr_o_xu_jenkins = [
71     #vf_addr_o_xu_a                     vf_addr_o_xu_b                vf_addr_o_xu_c
72     ["0000:19:02.0,0000:19:0a.0", "0000:19:02.1,0000:19:0a.1", "0000:19:02.2,0000:19:0a.2" ], #O-DU
73     ["0000:af:02.0,0000:af:0a.0", "0000:af:02.1,0000:af:0a.1", "0000:af:02.2,0000:af:0a.2" ], #O-RU
74 ]
75
76 vf_addr_o_xu_sc12 = [ # 2x2x25G with loopback FVL0:port0 to FVL1:port 0 FVL0:port1 to FVL1:port 1
77     #vf_addr_o_xu_a                     vf_addr_o_xu_b                vf_addr_o_xu_c
78     ["0000:88:02.0,0000:88:0a.0", "0000:88:02.1,0000:88:0a.1", "0000:88:02.2,0000:88:0a.2" ], #O-DU
79     ["0000:86:02.0,0000:86:0a.0", "0000:86:02.1,0000:86:0a.1", "0000:86:02.2,0000:86:0a.2" ], #O-RU
80 ]
81
82 vf_addr_o_xu_sc12_cvl = [
83     #vf_addr_o_xu_a                     vf_addr_o_xu_b                vf_addr_o_xu_c
84     ["0000:af:01.0,0000:af:09.0", "0000:af:11.0,0000:af:19.0", "0000:22:01.0,0000:22:09.0" ], #O-DU
85     ["0000:af:01.0,0000:af:09.0", "0000:af:11.0,0000:af:19.0", "0000:1a:01.0,0000:1a:09.0" ], #O-RU
86 ]
87
88 vf_addr_o_xu_scs1_30 = [
89     ["0000:65:01.0,0000:65:01.1,0000:65:01.2,0000:65:01.3", "0000:65:01.4,0000:65:01.5,0000:65:01.6,0000:65:01.7", "0000:65:02.0,0000:65:02.1,0000:65:02.2,0000:65:02.3" ], #O-DU
90     ["0000:65:09.0,0000:65:09.1,0000:65:09.2,0000:65:09.3", "0000:65:09.4,0000:65:09.5,0000:65:09.6,0000:65:09.7", "0000:65:0a.0,0000:65:0a.1,0000:65:0a.2,0000:65:0a.3" ], #O-RU
91 ]
92
93 vf_addr_o_xu_scs1_repo = [
94     ["0000:18:01.0,0000:18:01.1,0000:18:01.2,0000:18:01.3", "0000:18:01.4,0000:18:01.5,0000:18:01.6,0000:18:01.7", "0000:18:02.0,0000:18:02.1,0000:18:02.2,0000:18:02.3" ], #O-DU
95     ["0000:18:11.0,0000:18:11.1,0000:18:11.2,0000:18:11.3", "0000:18:11.4,0000:18:11.5,0000:18:11.6,0000:18:11.7", "0000:18:12.0,0000:18:12.1,0000:18:12.2,0000:18:12.3" ], #O-RU
96 ]
97
98 vf_addr_o_xu_icelake_scs1_1 = [
99         #vf_addr_o_xu_a                                     vf_addr_o_xu_b                                             vf_addr_o_xu_c
100     ["0000:51:01.0,0000:51:09.0", "0000:51:11.0,0000:51:19.0", "0000:18:01.0,0000:18:09.0" ], #O-DU
101     ["0000:17:01.0,0000:17:09.0", "0000:17:11.0,0000:17:19.0", "0000:65:01.0,0000:65:09.0" ], #O-RU
102 ]
103
104 vf_addr_o_xu_icx_npg_scs1_coyote4 = [
105         #vf_addr_o_xu_a                                     vf_addr_o_xu_b                                             vf_addr_o_xu_c
106     ["0000:51:01.0,0000:51:09.0", "0000:51:11.0,0000:51:19.0", "0000:54:01.0,0000:54:11.0" ], #O-DU
107     ["0000:17:01.0,0000:17:09.0", "0000:17:11.0,0000:17:19.0", "0000:65:01.0,0000:65:09.0" ], #O-RU
108 ]
109
110 vf_addr_o_xu_scs1_35 = [
111     ["0000:88:01.0,0000:88:01.1,0000:88:01.2,0000:88:01.3", "0000:88:01.4,0000:88:01.5,0000:88:01.6,0000:88:01.7", "0000:88:02.0,0000:88:02.1,0000:88:02.2,0000:88:02.3" ], #O-DU
112     ["0000:88:11.0,0000:88:11.1,0000:88:11.2,0000:88:11.3", "0000:88:11.4,0000:88:11.5,0000:88:11.6,0000:88:11.7", "0000:88:12.0,0000:88:12.1,0000:88:12.2,0000:88:12.3" ], #O-RU
113 ]
114
115 vf_addr_o_xu_csl_npg_scs1_33 = [
116     #vf_addr_o_xu_a                     vf_addr_o_xu_b                vf_addr_o_xu_c
117     ["0000:1a:01.0,0000:1a:01.1", "0000:1a:01.2,0000:1a:01.3", "0000:1a:01.4,0000:1a:01.5" ], #O-DU
118     ["0000:1a:11.0,0000:1a:11.1", "0000:1a:11.2,0000:1a:11.3", "0000:1a:11.4,0000:1a:11.5" ], #O-RU
119 ]
120
121 # table of all test cases
122 #                 (ran, cat, mu, bw, test case, "test case description")
123 #Cat A
124 NR_test_cases_A = [(0,  0,   0,  5,   0,  "NR_Sub6_Cat_A_5MHz_1_Cell_0"),
125                    (0,  0,   0,  10,  0,  "NR_Sub6_Cat_A_10MHz_1_Cell_0"),
126                    (0,  0,   0,  10,  12, "NR_Sub6_Cat_A_10MHz_12_Cell_12"),
127                    (0,  0,   0,  20,  0,  "NR_Sub6_Cat_A_20MHz_1_Cell_0"),
128                    (0,  0,   0,  20,  12, "NR_Sub6_Cat_A_20MHz_12_Cell_12"),
129                    (0,  0,   0,  20,  20, "NR_Sub6_Cat_A_20MHz_1_Cell_owd_req_resp"),
130                    (0,  0,   0,  20,  21, "NR_Sub6_Cat_A_20MHz_1_Cell_owd_rem_req"),
131                    (0,  0,   0,  20,  22, "NR_Sub6_Cat_A_20MHz_1_Cell_owd_req_wfup"),
132                    (0,  0,   0,  20,  23, "NR_Sub6_Cat_A_20MHz_1_Cell_owd_rem_req_wfup"),
133                    (0,  0,   1,  100, 0,  "NR_Sub6_Cat_A_100MHz_1_Cell_0"),
134                    (0,  0,   3,  100, 0,  "NR_mmWave_Cat_A_100MHz_1_Cell_0"),
135                    (0,  0,   3,  100, 7,  "NR_mmWave_Cat_A_100MHz_1_Cell_0_sc"),
136 ]
137
138 LTE_test_cases_A = [(1,  0,   0,  5,   0, "LTE_Cat_A_5Hz_1_Cell_0"),
139                     (1,  0,   0,  10,  0, "LTE_Cat_A_10Hz_1_Cell_0"),
140                     (1,  0,   0,  20,  0, "LTE_Cat_A_20Hz_1_Cell_0"),
141 ]
142
143 #Cat B
144 NR_test_cases_B  =  [(0, 1,   1,  100, 0, "NR_Sub6_Cat_B_100MHz_1_Cell_0"),
145                      (0, 1,   1,  100, 2, "NR_Sub6_Cat_B_100MHz_1_Cell_2"),
146                      (0, 1,   1,  100, 1, "NR_Sub6_Cat_B_100MHz_1_Cell_1"),
147                      (0, 1,   1,  100, 101, "NR_Sub6_Cat_B_100MHz_1_Cell_101"),
148                      (0, 1,   1,  100, 102, "NR_Sub6_Cat_B_100MHz_1_Cell_102"),
149                      (0, 1,   1,  100, 103, "NR_Sub6_Cat_B_100MHz_1_Cell_103"),
150                      (0, 1,   1,  100, 104, "NR_Sub6_Cat_B_100MHz_1_Cell_104"),
151                      (0, 1,   1,  100, 105, "NR_Sub6_Cat_B_100MHz_1_Cell_105"),
152                      (0, 1,   1,  100, 106, "NR_Sub6_Cat_B_100MHz_1_Cell_106"),
153                      (0, 1,   1,  100, 107, "NR_Sub6_Cat_B_100MHz_1_Cell_107"),
154                      (0, 1,   1,  100, 108, "NR_Sub6_Cat_B_100MHz_1_Cell_108"),
155                      (0, 1,   1,  100, 109, "NR_Sub6_Cat_B_100MHz_1_Cell_109"),
156                      (0, 1,   1,  100, 201, "NR_Sub6_Cat_B_100MHz_1_Cell_201"),
157                      (0, 1,   1,  100, 202, "NR_Sub6_Cat_B_100MHz_1_Cell_202"),
158                      (0, 1,   1,  100, 203, "NR_Sub6_Cat_B_100MHz_1_Cell_203"),
159                      (0, 1,   1,  100, 204, "NR_Sub6_Cat_B_100MHz_1_Cell_204"),
160                      (0, 1,   1,  100, 205, "NR_Sub6_Cat_B_100MHz_1_Cell_205"),
161                      (0, 1,   1,  100, 206, "NR_Sub6_Cat_B_100MHz_1_Cell_206"),
162                      (0, 1,   1,  100, 211, "NR_Sub6_Cat_B_100MHz_1_Cell_211"),
163                      (0, 1,   1,  100, 212, "NR_Sub6_Cat_B_100MHz_1_Cell_212"),
164                      (0, 1,   1,  100, 213, "NR_Sub6_Cat_B_100MHz_1_Cell_213"),
165                      (0, 1,   1,  100, 214, "NR_Sub6_Cat_B_100MHz_1_Cell_214"),
166                      (0, 1,   1,  100, 215, "NR_Sub6_Cat_B_100MHz_1_Cell_215"),
167                      (0, 1,   1,  100, 216, "NR_Sub6_Cat_B_100MHz_1_Cell_216"),
168                      #(0, 1,   1,  100, 401, "NR_Sub6_Cat_B_100MHz_1_Cell_401") 25G not enough
169 ]
170
171 LTE_test_cases_B = [(1,  1,   0,   5,  0, "LTE_Cat_B_5MHz_1_Cell_0"),
172                     (1,  1,   0,  10,  0, "LTE_Cat_B_10MHz_1_Cell_0"),
173                     (1,  1,   0,  20,  0, "LTE_Cat_B_20MHz_1_Cell_0"),
174                     (1,  1,   0,  5,   1, "LTE_Cat_B_5Hz_1_Cell_0_sc"),
175                     (1,  1,   0,  10,  1, "LTE_Cat_B_10Hz_1_Cell_0_sc"),
176                     (1,  1,   0,  20,  1, "LTE_Cat_B_20Hz_1_Cell_0_sc"),
177
178 ]
179
180 V_test_cases_B = [
181                     (0,  1,   1,  100,  301, "NR_Sub6_Cat_B_100MHz_1_Cell_301"),
182                     (0,  1,   1,  100,  302, "NR_Sub6_Cat_B_100MHz_1_Cell_302"),
183                     (0,  1,   1,  100,  303, "NR_Sub6_Cat_B_100MHz_1_Cell_303"),
184                     (0,  1,   1,  100,  304, "NR_Sub6_Cat_B_100MHz_1_Cell_304"),
185                     (0,  1,   1,  100,  305, "NR_Sub6_Cat_B_100MHz_1_Cell_305"),
186                     (0,  1,   1,  100,  306, "NR_Sub6_Cat_B_100MHz_1_Cell_306"),
187                     (0,  1,   1,  100,  602, "NR_Sub6_Cat_B_100MHz_1_Cell_602_sc"),
188 ]
189
190 V_test_cases_B_2xUL = [
191                     (0,  1,   1,  100,  311, "NR_Sub6_Cat_B_100MHz_1_Cell_311"),
192                     (0,  1,   1,  100,  312, "NR_Sub6_Cat_B_100MHz_1_Cell_312"),
193                     (0,  1,   1,  100,  313, "NR_Sub6_Cat_B_100MHz_1_Cell_313"),
194                     (0,  1,   1,  100,  314, "NR_Sub6_Cat_B_100MHz_1_Cell_314"),
195                     (0,  1,   1,  100,  315, "NR_Sub6_Cat_B_100MHz_1_Cell_315"),
196                     (0,  1,   1,  100,  316, "NR_Sub6_Cat_B_100MHz_1_Cell_316"),
197                     (0,  1,   1,  100,  612, "NR_Sub6_Cat_B_100MHz_1_Cell_612_sc"),
198
199 ]
200
201 V_test_cases_B_mtu_1500 = [
202                     (0,  1,   1,  100,  501, "NR_Sub6_Cat_B_100MHz_1_Cell_501"),
203                     (0,  1,   1,  100,  502, "NR_Sub6_Cat_B_100MHz_1_Cell_502"),
204                     (0,  1,   1,  100,  503, "NR_Sub6_Cat_B_100MHz_1_Cell_503"),
205                     (0,  1,   1,  100,  504, "NR_Sub6_Cat_B_100MHz_1_Cell_504"),
206                     (0,  1,   1,  100,  505, "NR_Sub6_Cat_B_100MHz_1_Cell_505"),
207                     (0,  1,   1,  100,  506, "NR_Sub6_Cat_B_100MHz_1_Cell_506"),
208                     (0,  1,   1,  100,  802, "NR_Sub6_Cat_B_100MHz_1_Cell_802_sc"),
209 ]
210
211 V_test_cases_B_mtu_1500_2xUL = [
212                     (0,  1,   1,  100,  511, "NR_Sub6_Cat_B_100MHz_1_Cell_511"),
213                     (0,  1,   1,  100,  512, "NR_Sub6_Cat_B_100MHz_1_Cell_512"),
214                     (0,  1,   1,  100,  513, "NR_Sub6_Cat_B_100MHz_1_Cell_513"),
215                     (0,  1,   1,  100,  514, "NR_Sub6_Cat_B_100MHz_1_Cell_514"),
216                     (0,  1,   1,  100,  515, "NR_Sub6_Cat_B_100MHz_1_Cell_515"),
217                     (0,  1,   1,  100,  516, "NR_Sub6_Cat_B_100MHz_1_Cell_516"),
218                     (0,  1,   1,  100,  812, "NR_Sub6_Cat_B_100MHz_1_Cell_812_sc"),
219 ]
220
221 V_test_cases_B_3Cells = [
222                     (0,  1,   1,  100,  3301, "NR_Sub6_Cat_B_100MHz_1_Cell_3301"),
223                     (0,  1,   1,  100,  3311, "NR_Sub6_Cat_B_100MHz_1_Cell_3311")
224 ]
225
226 V_test_cases_B_3Cells_mtu_1500 = [
227                     (0,  1,   1,  100,  3501, "NR_Sub6_Cat_B_100MHz_1_Cell_3501"),
228                     (0,  1,   1,  100,  3511, "NR_Sub6_Cat_B_100MHz_1_Cell_3511")
229 ]
230
231 all_test_cases = NR_test_cases_A + LTE_test_cases_A + LTE_test_cases_B + NR_test_cases_B + V_test_cases_B + V_test_cases_B_2xUL
232
233 dic_dir      = dict({0:'DL', 1:'UL'})
234 dic_xu       = dict({0:'o-du', 1:'o-ru'})
235 dic_ran_tech = dict({0:'5g_nr', 1:'lte'})
236
237 def init_logger(console_level, logfile_level):
238     """Initializes console and logfile logger with given logging levels"""
239     # File logger
240     logging.basicConfig(filename="runtests.log",
241                         filemode='w',
242                         format="%(asctime)s: %(levelname)s: %(message)s",
243                         level=logfile_level)
244     # Console logger
245     logger = logging.getLogger()
246     handler = logging.StreamHandler()
247     handler.setLevel(console_level)
248     formatter = logging.Formatter("%(levelname)s: %(message)s")
249     handler.setFormatter(formatter)
250     logger.addHandler(handler)
251
252 def parse_args(args):
253     """Configures parser and parses command line configuration"""
254     # Parser configuration
255     parser = argparse.ArgumentParser(description="Run test cases: category numerology bandwidth test_num")
256
257     parser.add_argument("--rem_o_ru_host", type=str, default="", help="remot host to run O-RU", metavar="root@10.10.10.1", dest="rem_o_ru_host")
258     parser.add_argument("--ran", type=int, default=0, help="Radio Access Tehcnology 0 (5G NR) or 1 (LTE)", metavar="ran", dest="rantech")
259     parser.add_argument("--cat", type=int, default=0, help="Category: 0 (A) or 1 (B)", metavar="cat", dest="category")
260     parser.add_argument("--mu", type=int, default=0, help="numerology [0,1,3]", metavar="num", dest="numerology")
261     parser.add_argument("--bw",  type=int, default=20, help="bandwidth [5,10,20,100]", metavar="bw", dest="bandwidth")
262     parser.add_argument("--testcase", type=int, default=0, help="test case number", metavar="testcase", dest="testcase")
263     parser.add_argument("--verbose", type=int, default=0, help="enable verbose output", metavar="verbose", dest="verbose")
264
265
266     # Parse arguments
267     options = parser.parse_args(args)
268     #parser.print_help()
269     logging.info("Options: rem_o_ru_host=%s ran=%d category=%d num=%d bw=%d testcase=%d",
270                   options.rem_o_ru_host, options.rantech, options.category, options.numerology, options.bandwidth, options.testcase)
271     return options
272
273 def is_comment(s):
274     """ function to check if a line
275          starts with some character.
276          Here # for comment
277     """
278     # return true if a line starts with #
279     return s.startswith('#')
280
281 class GetOutOfLoops( Exception ):
282     pass
283
284 def get_re_map(nRB, direction):
285     prb_map        = []
286     PrbElemContent = []
287     if direction == 0:
288         #DL
289         if 'nPrbElemDl' in globals():
290             nPrbElm = nPrbElemDl
291             for i in range(0, nPrbElm):
292                 elm = str('PrbElemDl'+str(i))
293                 #print(elm)
294                 if elm in globals():
295                     PrbElemContent.insert(i,list(globals()[elm]))
296                     xRBStart = PrbElemContent[i][0]
297                     xRBSize  = PrbElemContent[i][1]
298                     #print(PrbElemContent,"RBStart: ", xRBStart, "RBSize: ",xRBSize, list(range(xRBStart, xRBStart + xRBSize)))
299                     prb_map = prb_map + list(range(xRBStart*12, xRBStart*12 + xRBSize*12))
300         else:
301             nPrbElm = 0;
302
303     elif direction == 1:
304         #UL
305         if 'nPrbElemUl' in globals():
306             nPrbElm = nPrbElemUl
307             for i in range(0, nPrbElm):
308                 elm = str('PrbElemUl'+str(i))
309                 #print(elm)
310                 if (elm in globals()):
311                     PrbElemContent.insert(i,list(globals()[elm]))
312                     xRBStart = PrbElemContent[i][0]
313                     xRBSize  = PrbElemContent[i][1]
314                     #print(PrbElemContent,"RBStart: ", xRBStart, "RBSize: ",xRBSize, list(range(xRBStart, xRBStart + xRBSize)))
315                     prb_map = prb_map + list(range(xRBStart*12, xRBStart*12 + xRBSize*12))
316         else:
317             nPrbElm = 0
318
319     elif direction == 2:
320         #UL
321         if 'nPrbElemSrs' in globals():
322             nPrbElm = nPrbElemUl
323             for i in range(0, nPrbElm):
324                 elm = str('PrbElemSrs'+str(i))
325                 #print(elm)
326                 if (elm in globals()):
327                     PrbElemContent.insert(i,list(globals()[elm]))
328                     xRBStart = PrbElemContent[i][0]
329                     xRBSize  = PrbElemContent[i][1]
330                     #print(PrbElemContent,"RBStart: ", xRBStart, "RBSize: ",xRBSize, list(range(xRBStart, xRBStart + xRBSize)))
331                     prb_map = prb_map + list(range(xRBStart*12, xRBStart*12 + xRBSize*12))
332         else:
333             nPrbElm = 0
334
335     if nPrbElm == 0 :
336         prb_map = list(range(0, nRB*12))
337
338     return prb_map
339
340 def check_for_string_present_in_file(file_name, search_string):
341     res = 1
342     with open(file_name, 'r') as read_obj:
343         for line in read_obj:
344              if search_string in line:
345                  read_obj.close()
346                  res = 0
347                  return res
348     read_obj.close()
349     return res
350
351 def check_owdm_test_results(xran_path, o_xu_id):
352     res = 0
353     file_owd_oru = xran_path+"/app/logs/"+"o-ru"+str(o_xu_id)+"-owd_results.txt"
354     file_owd_odu = xran_path+"/app/logs/"+"o-du"+str(o_xu_id)+"-owd_results.txt"
355     print("file_owd_oru :", file_owd_oru)
356     print("file_owd_odu :", file_owd_odu)
357     res = check_for_string_present_in_file(file_owd_oru, 'passed')
358     res = res or check_for_string_present_in_file(file_owd_odu, 'passed')
359     
360     return res
361
362 def compare_results(o_xu_id, rantech, cat, mu, bw, tcase, xran_path, test_cfg, direction):
363     res = 0
364     re_map = []
365     if rantech==1:
366         if mu == 0:
367             nDlRB = nLteNumRbsPerSymF1[mu][nRChBwOptions.get(str(nDLBandwidth))]
368             nUlRB = nLteNumRbsPerSymF1[mu][nRChBwOptions.get(str(nULBandwidth))]
369         else:
370             print("Incorrect arguments\n")
371             res = -1
372             return res
373     elif rantech==0:
374         if mu < 3:
375             nDlRB = nNumRbsPerSymF1[mu][nRChBwOptions.get(str(nDLBandwidth))]
376             nUlRB = nNumRbsPerSymF1[mu][nRChBwOptions.get(str(nULBandwidth))]
377         elif (mu >=2) & (mu <= 3):
378             nDlRB = nNumRbsPerSymF2[mu - 2][nRChBwOptions_mu2and3.get(str(nDLBandwidth))]
379             nUlRB = nNumRbsPerSymF2[mu - 2][nRChBwOptions_mu2and3.get(str(nULBandwidth))]
380             print(nDlRB, nUlRB)
381         else:
382             print("Incorrect arguments\n")
383             res = -1
384             return res
385
386     if 'compression' in globals():
387         comp = compression
388     else:
389         comp = 0
390
391     if 'srsEanble' in globals():
392         srs_enb = srsEanble
393     else:
394         srs_enb = 0
395
396     if 'rachEanble' in globals():
397         rach = rachEanble
398     else:
399         rach = 0
400
401     print("O-RU {} compare results: {} [compression {}]\n".format(o_xu_id, dic_dir.get(direction), comp))
402
403     #if cat == 1:
404     #    print("WARNING: Skip checking IQs and BF Weights for CAT B for now\n");
405     #    return res
406
407     #get slot config
408     if nFrameDuplexType == 1:
409         SlotConfig = []
410         for i in range(nTddPeriod):
411             if i == 0:
412                 SlotConfig.insert(i, sSlotConfig0)
413             elif i == 1:
414                 SlotConfig.insert(i, sSlotConfig1)
415             elif i == 2:
416                 SlotConfig.insert(i, sSlotConfig2)
417             elif i == 3:
418                 SlotConfig.insert(i, sSlotConfig3)
419             elif i == 4:
420                 SlotConfig.insert(i, sSlotConfig4)
421             elif i == 5:
422                 SlotConfig.insert(i, sSlotConfig5)
423             elif i == 6:
424                 SlotConfig.insert(i, sSlotConfig6)
425             elif i == 7:
426                 SlotConfig.insert(i, sSlotConfig7)
427             elif i == 8:
428                 SlotConfig.insert(i, sSlotConfig8)
429             elif i == 9:
430                 SlotConfig.insert(i, sSlotConfig9)
431             else :
432                 raise Exception('i should not exceed nTddPeriod %d. The value of i was: {}'.format(nTddPeriod, i))
433         #print(SlotConfig, type(sSlotConfig0))
434
435     try:
436
437         if (direction == 1) & (cat == 1): #UL
438             flowId = ccNum*antNumUL
439         else:
440             flowId = ccNum*antNum
441
442         if direction == 0:
443             re_map = get_re_map(nDlRB, direction)
444         elif direction == 1:
445             re_map = get_re_map(nUlRB, direction)
446         else:
447             raise Exception('Direction is not supported %d'.format(direction))
448
449         for i in range(0, flowId):
450             #read ref and test files
451             tst = []
452             ref = []
453             if direction == 0:
454                 # DL
455                 nRB = nDlRB
456                 file_tst = xran_path+"/app/logs/"+"o-ru"+str(o_xu_id)+"-rx_log_ant"+str(i)+".txt"
457                 file_ref = xran_path+"/app/logs/"+"o-du"+str(o_xu_id)+"-play_ant"+str(i)+".txt"
458             elif direction == 1:
459                 # UL
460                 nRB = nUlRB
461                 file_tst = xran_path+"/app/logs/"+"o-du"+str(o_xu_id)+"-rx_log_ant"+str(i)+".txt"
462                 file_ref = xran_path+"/app/logs/"+"o-ru"+str(o_xu_id)+"-play_ant"+str(i)+".txt"
463             else:
464                 raise Exception('Direction is not supported %d'.format(direction))
465
466             print("test result   :", file_tst)
467             print("test reference:", file_ref)
468             if os.path.exists(file_tst):
469                 try:
470                     file_tst = open(file_tst, 'r')
471                 except OSError:
472                     print ("Could not open/read file:", file_tst)
473                     sys.exit()
474             else:
475                 print(file_tst, "doesn't exist")
476                 res = -1
477                 return res
478             if os.path.exists(file_ref):
479                 try:
480                     file_ref = open(file_ref, 'r')
481                 except OSError:
482                     print ("Could not open/read file:", file_ref)
483                     sys.exit()
484             else:
485                 print(file_tst, "doesn't exist")
486                 res = -1
487                 return res
488
489             tst = file_tst.readlines()
490             ref = file_ref.readlines()
491
492             print(len(tst))
493             print(len(ref))
494
495             file_tst.close();
496             file_ref.close();
497
498             print(numSlots)
499
500             #skip last slot for UL as we stop on PPS boundary (OTA) and all symbols might not be received by O-DU
501             for slot_idx in range(0, numSlots - (1*direction)):
502                 for sym_idx in range(0, 14):
503                     if nFrameDuplexType==1:
504                         #skip sym if TDD
505                         if direction == 0:
506                             #DL
507                             sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
508                             if(sym_dir != 0):
509                                 continue
510                         elif direction == 1:
511                             #UL
512                             sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
513                             if(sym_dir != 1):
514                                 continue
515
516                     #print("Check:","[",i,"]", slot_idx, sym_idx)
517                     for line_idx in re_map:
518                         offset = (slot_idx*nRB*12*14) + sym_idx*nRB*12 + line_idx
519                         try:
520                             line_tst = tst[offset].rstrip()
521                         except IndexError:
522                             res = -1
523                             print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
524                             raise GetOutOfLoops
525                         try:
526                              line_ref = ref[offset].rstrip()
527                         except IndexError:
528                             res = -1
529                             print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
530                             raise GetOutOfLoops
531
532                         if comp == 1:
533                             # discard LSB bits as BFP compression is not "bit exact"
534                             tst_i_value = int(line_tst.split(" ")[0]) & 0xFF80
535                             tst_q_value = int(line_tst.split(" ")[1]) & 0xFF80
536                             ref_i_value = int(line_ref.split(" ")[0]) & 0xFF80
537                             ref_q_value = int(line_ref.split(" ")[1]) & 0xFF80
538
539                             #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, " ")
540                             if (tst_i_value != ref_i_value) or  (tst_q_value != ref_q_value) :
541                                 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, " ")
542                                 res = -1
543                                 raise GetOutOfLoops
544                         else:
545                             #if line_idx == 0:
546                                 #print("Check:", offset,"[",i,"]", slot_idx, sym_idx,":",line_tst, line_ref)
547                             if line_ref != line_tst:
548                                 print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst:", line_tst, "ref:", line_ref)
549                                 res = -1
550                                 raise GetOutOfLoops
551     except GetOutOfLoops:
552         return res
553
554     if (direction == 1) & (rach == 1) & 0: #UL
555         print("O-RU {} compare results: {} [compression {}]\n".format(o_xu_id, 'PRACH', comp))
556
557         #rach
558         try:
559             if mu == 3: #FR2
560                 re_map = range(0, 144)
561                 nRB = 12
562             elif nFrameDuplexType==0: #FR1 FDD
563                 if prachConfigIndex < 87:
564                     re_map = range(0, 840)
565                     nRB = 70
566                 else:
567                     re_map = range(0, 144)
568                     nRB = 12
569             else: #FR1 TDD
570                 if prachConfigIndex < 67:
571                     re_map = range(0, 144)
572                     nRB = 12
573                 else:
574                     re_map = range(0, 840)
575                     nRB = 70
576             if cat == 1:
577                 flowId = ccNum*antNumUL
578             else:
579                 flowId = ccNum*antNum
580
581             for i in range(0, flowId):
582                 #read ref and test files
583                 tst = []
584                 ref = []
585
586                 file_tst = xran_path+"/app/logs/"+"o-du"+str(o_xu_id)+"-prach_log_ant"+str(i)+".txt"
587                 file_ref = xran_path+"/app/logs/"+"o-ru"+str(o_xu_id)+"-play_prach_ant"+str(i)+".txt"
588                 print("test result   :", file_tst)
589                 print("test reference:", file_ref)
590                 if os.path.exists(file_tst):
591                     try:
592                         file_tst = open(file_tst, 'r')
593                     except OSError:
594                         print ("Could not open/read file:", file_tst)
595                         sys.exit()
596                 else:
597                     print(file_tst, "doesn't exist")
598                     res = -1
599                     return res
600                 if os.path.exists(file_ref):
601                     try:
602                         file_ref = open(file_ref, 'r')
603                     except OSError:
604                         print ("Could not open/read file:", file_ref)
605                         sys.exit()
606                 else:
607                     print(file_tst, "doesn't exist")
608                     res = -1
609                     return res
610
611                 tst = file_tst.readlines()
612                 ref = file_ref.readlines()
613
614                 print(len(tst))
615                 print(len(ref))
616
617                 file_tst.close();
618                 file_ref.close();
619
620                 print(numSlots)
621
622                 #skip last slot for UL as we stop on PPS boundary (OTA) and all symbols might not be received by O-DU
623                 for slot_idx in range(0, numSlots - (1*direction)):
624                 for sym_idx in range(0, 14):
625                     if nFrameDuplexType==1:
626                         #skip sym if TDD
627                         if direction == 0:
628                             #DL
629                             sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
630                             if(sym_dir != 0):
631                                 continue
632                         elif direction == 1:
633                             #UL
634                             sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
635                             if(sym_dir != 1):
636                                 continue
637
638                     #print("Check:","[",i,"]", slot_idx, sym_idx)
639                     for line_idx in re_map:
640                         offset = (slot_idx*nRB*12*14) + sym_idx*nRB*12 + line_idx
641                         try:
642                             line_tst = tst[offset].rstrip()
643                         except IndexError:
644                             res = -1
645                             print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
646                             raise GetOutOfLoops
647                         try:
648                              line_ref = ref[offset].rstrip()
649                         except IndexError:
650                             res = -1
651                             print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
652                             raise GetOutOfLoops
653
654                         if comp == 1:
655                             # discard LSB bits as BFP compression is not "bit exact"
656                             tst_i_value = int(line_tst.split(" ")[0]) & 0xFF80
657                             tst_q_value = int(line_tst.split(" ")[1]) & 0xFF80
658                             ref_i_value = int(line_ref.split(" ")[0]) & 0xFF80
659                             ref_q_value = int(line_ref.split(" ")[1]) & 0xFF80
660
661                             #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, " ")
662                             if (tst_i_value != ref_i_value) or  (tst_q_value != ref_q_value) :
663                                 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, " ")
664                                 res = -1
665                                 raise GetOutOfLoops
666                         else:
667                             #if line_idx == 0:
668                                 #print("Check:", offset,"[",i,"]", slot_idx, sym_idx,":",line_tst, line_ref)
669                             if line_ref != line_tst:
670                                 print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst:", line_tst, "ref:", line_ref)
671                                 res = -1
672                                 raise GetOutOfLoops
673     except GetOutOfLoops:
674         return res
675
676     if (direction == 0) | (cat == 0) | (srs_enb == 0): #DL or Cat A
677         #done
678     return res
679
680     print("O-RU {} compare results: {} [compression {}]\n".format(o_xu_id, 'SRS', comp))
681
682     #srs
683     symbMask    = srsSym
684     re_map = get_re_map(nUlRB, 2)
685     try:
686         flowId = ccNum*antElmTRx
687         for i in range(0, flowId):
688             #read ref and test files
689             tst = []
690             ref = []
691
692             if direction == 1:
693                 # UL
694                 nRB = nUlRB
695                 file_tst = xran_path+"/app/logs/"+"o-du"+str(o_xu_id)+"-srs_log_ant"+str(i)+".txt"
696                 file_ref = xran_path+"/app/logs/"+"o-ru"+str(o_xu_id)+"-play_srs_ant"+str(i)+".txt"
697             else:
698                 raise Exception('Direction is not supported %d'.format(direction))
699
700             print("test result   :", file_tst)
701             print("test reference:", file_ref)
702             if os.path.exists(file_tst):
703                 try:
704                     file_tst = open(file_tst, 'r')
705                 except OSError:
706                     print ("Could not open/read file:", file_tst)
707                     sys.exit()
708             else:
709                 print(file_tst, "doesn't exist")
710                 res = -1
711                 return res
712             if os.path.exists(file_ref):
713                 try:
714                     file_ref = open(file_ref, 'r')
715                 except OSError:
716                     print ("Could not open/read file:", file_ref)
717                     sys.exit()
718             else:
719                 print(file_tst, "doesn't exist")
720                 res = -1
721                 return res
722
723             tst = file_tst.readlines()
724             ref = file_ref.readlines()
725
726             print(len(tst))
727             print(len(ref))
728
729             file_tst.close();
730             file_ref.close();
731
732             print(numSlots)
733
734             for slot_idx in range(0, numSlots - (1*direction)):
735                 for sym_idx in range(0, 14):
736                     if symbMask & (1 << sym_idx) and slot_idx%nTddPeriod == 3:
737                         print("SRS check sym ", slot_idx,  sym_idx)
738                         if nFrameDuplexType==1:
739                             #skip sym if TDD
740                             if direction == 0:
741                                 #DL
742                                 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
743                                 if(sym_dir != 0):
744                                     continue
745                             elif direction == 1:
746                                 #UL
747                                 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
748                                 # ignore if DL symbol for now
749                                 #if(sym_dir != 1):
750                                 #    continue
751
752                         print("Check:","[",i,"]", slot_idx, sym_idx)
753                         for line_idx in re_map:
754                             offset = (slot_idx*nRB*12*14) + sym_idx*nRB*12 + line_idx
755                             try:
756                                 line_tst = tst[offset].rstrip()
757                             except IndexError:
758                                 res = -1
759                                 print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
760                                 raise GetOutOfLoops
761                             try:
762                                 line_ref = ref[offset].rstrip()
763                             except IndexError:
764                                 res = -1
765                                 print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
766                                 raise GetOutOfLoops
767
768                             if comp == 1:
769                                 # discard LSB bits as BFP compression is not "bit exact"
770                                 tst_i_value = int(line_tst.split(" ")[0]) & 0xFF80
771                                 tst_q_value = int(line_tst.split(" ")[1]) & 0xFF80
772                                 ref_i_value = int(line_ref.split(" ")[0]) & 0xFF80
773                                 ref_q_value = int(line_ref.split(" ")[1]) & 0xFF80
774
775                                 #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, " ")
776                                 if (tst_i_value != ref_i_value) or  (tst_q_value != ref_q_value) :
777                                     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, " ")
778                                     res = -1
779                                     raise GetOutOfLoops
780                             else:
781                                 #if line_idx == 0:
782                                     #print("Check:", offset,"[",i,"]", slot_idx, sym_idx,":",line_tst, line_ref)
783                                 if line_ref != line_tst:
784                                     print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst:", line_tst, "ref:", line_ref)
785                                     res = -1
786                                     raise GetOutOfLoops
787     except GetOutOfLoops:
788         #don't threat SRS as error for now
789         res = 0
790         return res
791
792
793     return res
794
795 def parse_usecase_cfg(rantech, cat, mu, bw, tcase, xran_path, usecase_cfg):
796     #parse config files
797     logging.info("parse config files %s\n", usecase_cfg[0])
798     lineList = list()
799     sep = '#'
800     with open(usecase_cfg[0],'r') as fh:
801         for curline in dropwhile(is_comment, fh):
802             my_line = curline.rstrip().split(sep, 1)[0].strip()
803             if my_line:
804                 lineList.append(my_line)
805
806     global_env = {}
807     local_env  = {}
808
809     for line in lineList:
810         exe_line = line.replace(":", ",0x")
811         if exe_line.find("../") > 0 :
812             exe_line = exe_line.replace('../', "'../")
813             exe_line = exe_line+"'"
814         elif exe_line.find("./") > 0 :
815             exe_line = exe_line.replace('./', "'./")
816             exe_line = exe_line+"'"
817
818         code = compile(str(exe_line), '<string>', 'exec')
819         exec (code, global_env, local_env)
820
821     for k, v in local_env.items():
822         globals()[k] = v
823         print(k, v)
824
825     print("Number of O-RU:", oXuNum)
826
827     return local_env
828
829 def parse_dat_file(rantech, cat, mu, bw, tcase, xran_path, test_cfg):
830     #parse config files
831     logging.info("parse config files %s\n", test_cfg[0])
832     lineList = list()
833
834     sep = '#'
835     with open(test_cfg[0],'r') as fh:
836         for curline in dropwhile(is_comment, fh):
837             my_line = curline.rstrip().split(sep, 1)[0].strip()
838             if my_line:
839                 lineList.append(my_line)
840     global_env = {}
841     local_env = {}
842
843     for line in lineList:
844         exe_line = line.replace(":", ",0x")
845         if exe_line.find("../") > 0 :
846             exe_line = exe_line.replace('../', "'../")
847             exe_line = exe_line+"'"
848         elif exe_line.find("./") > 0 :
849             exe_line = exe_line.replace('./', "'./")
850             exe_line = exe_line+"'"
851
852         code = compile(str(exe_line), '<string>', 'exec')
853         exec (code, global_env, local_env)
854
855     for k, v in local_env.items():
856         globals()[k] = v
857         print(k, v)
858
859     return local_env
860
861 def del_dat_file_vars(local_env):
862
863     for k, v in local_env.items():
864         del globals()[k]
865
866     return 0
867
868 def make_copy_mlog(rantech, cat, mu, bw, tcase, xran_path):
869     res = 0
870
871     src_bin = xran_path+"/app/mlog-o-du.bin"
872     src_csv = xran_path+"/app/mlog-o-du_hist.csv"
873     dst_bin = xran_path+"/app/mlog-o-du-ran"+str(rantech)+"-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".bin"
874     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"
875
876     try:
877         d_bin  = shutil.copyfile(src_bin, dst_bin)
878         d_csv  = shutil.copyfile(src_csv, dst_csv)
879     except IOError:
880         logging.info("O-DU MLog is not present\n")
881         res = 1
882         return res
883     else:
884         logging.info("O-DU Mlog was copied\n")
885
886
887     print("Destination path:", d_bin)
888     print("Destination path:", d_csv)
889
890     d_bin  = shutil.copyfile(src_bin, dst_bin)
891     d_csv  = shutil.copyfile(src_csv, dst_csv)
892
893     src_bin = xran_path+"/app/mlog-o-ru.bin"
894     src_csv = xran_path+"/app/mlog-o-ru_hist.csv"
895     dst_bin = xran_path+"/app/mlog-o-ru-ran"+str(rantech)+"-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".bin"
896     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"
897
898     d_bin  = shutil.copyfile(src_bin, dst_bin)
899     d_csv  = shutil.copyfile(src_csv, dst_csv)
900
901     try:
902         d_bin  = shutil.copyfile(src_bin, dst_bin)
903         d_csv  = shutil.copyfile(src_csv, dst_csv)
904     except IOError:
905         logging.info("O-RU MLog is not present\n")
906         res = 1
907         return res
908     else:
909         logging.info("O-RU Mlog was copied\n")
910
911     return res
912
913
914 def run_tcase(rem_o_ru_host, rantech, cat, mu, bw, tcase, verbose, xran_path, vf_addr_o_xu):
915
916     if rantech == 1: #LTE
917         if cat == 1:
918             test_config =xran_path+"/app/usecase/lte_b/mu{0:d}_{1:d}mhz".format(mu, bw)
919         elif cat == 0 :
920             test_config =xran_path+"/app/usecase/lte_a/mu{0:d}_{1:d}mhz".format(mu, bw)
921         else:
922             print("Incorrect cat arguments\n")
923             return -1
924     elif rantech == 0: #5G NR
925         if cat == 1:
926             test_config =xran_path+"/app/usecase/cat_b/mu{0:d}_{1:d}mhz".format(mu, bw)
927         elif cat == 0 :
928             test_config =xran_path+"/app/usecase/cat_a/mu{0:d}_{1:d}mhz".format(mu, bw)
929         else:
930             print("Incorrect cat argument\n")
931             return -1
932     else:
933         print("Incorrect rantech argument\n")
934         return -1
935
936     if(tcase > 0) :
937         test_config = test_config+"/"+str(tcase)
938
939     app = xran_path+"/app/build/sample-app"
940
941     logging.debug("run: %s %s", app, test_config)
942     logging.debug("Started script: master.py, XRAN path %s", xran_path)
943
944     test_cfg = []
945     global oXuOwdmEnabled
946     oXuOwdmEnabled = 0 #Default is owdm measurements are disabled
947     test_cfg.append(test_config+"/usecase_du.cfg")
948     test_cfg.append(test_config+"/usecase_ru.cfg")
949
950     usecase_dirname = os.path.dirname(os.path.realpath(test_cfg[0]))
951     print(usecase_dirname)
952
953     wd = os.getcwd()
954     os.chdir(xran_path+"/app/")
955
956     processes     = []
957     logfile_xu    = []
958     log_file_name = []
959     timer         = []
960
961     os.system('pkill -9 "sample-app"')
962     os.system('rm -rf ./logs')
963
964     usecase_cfg = parse_usecase_cfg(rantech, cat, mu, bw, tcase, xran_path, test_cfg)
965     REM_O_RU_HOST=rem_o_ru_host
966
967     for i in range(2):
968
969         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))
970         with open(log_file_name[i], "w") as f:
971             run_cmd = [app, "--usecasefile", test_cfg[i], "--num_eth_vfs", "6", "--vf_addr_o_xu_a", vf_addr_o_xu[i][0], "--vf_addr_o_xu_b", vf_addr_o_xu[i][1],"--vf_addr_o_xu_c", vf_addr_o_xu[i][2]]
972             #, stdout=f, stderr=f
973             if (verbose==1):
974                 if i == 0 or REM_O_RU_HOST == "":
975                 p = subprocess.Popen(run_cmd)
976             else:
977                     CMD = ' '.join([str(elem) for elem in run_cmd])
978                     ssh = ["ssh", "%s" % REM_O_RU_HOST, "cd " + xran_path + "/app"+"; hostname; pwd; pkill -9 sample-app; rm -rf ./logs;" + CMD]
979                     print(ssh)
980                     print("my_cmd: ", ' '.join([str(elem) for elem in ssh]))
981                     p = subprocess.Popen(ssh, shell=False)
982             else:
983                 if i == 0 or REM_O_RU_HOST == "":
984                 p = subprocess.Popen(run_cmd, stdout=f, stderr=f)
985                 else :
986                     CMD = ' '.join([str(elem) for elem in run_cmd])
987                     ssh = ["ssh", "%s" % REM_O_RU_HOST, "cd " + xran_path + "/app"+"; hostname; pwd; pkill -9 sample-app; rm -rf ./logs; " + CMD]
988                     p = subprocess.Popen(ssh, shell=False, stdout=f, stderr=f)
989                     #stdout=subprocess.PIPE, stderr=subprocess.PIPE)
990
991             t = Timer(timeout_sec, p.kill)
992             t.start()
993             timer.append(t)
994             logfile_xu.insert(i, f)
995         processes.append((p, logfile_xu[i]))
996
997     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)
998     #while (gmtime().tm_sec % 30) <> 0:
999         #pass
1000     print(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()))
1001     i = 0
1002     for p, f in processes:
1003         try:
1004         p.communicate()[0]
1005         p.wait()
1006         except (KeyboardInterrupt, SystemExit):
1007             for i in range(2):
1008                 timer[i].cancel();
1009                 timer[i].cancel();
1010             for pp, ff in processes:
1011                 pp.send_signal(signal.SIGINT)
1012                 pp.wait()
1013             raise
1014
1015         if p.returncode != 0:
1016             print("Application {} failed p.returncode:{}".format(dic_xu.get(i), p.returncode))
1017             print("FAIL")
1018             #logging.info("FAIL\n")
1019             #logging.shutdown()
1020             #sys.exit(p.returncode)
1021         i += 1
1022         f.close()
1023
1024     for i in range(2):
1025         timer[i].cancel();
1026         timer[i].cancel();
1027
1028     logging.info("O-DU and O-RU are done\n")
1029
1030     if REM_O_RU_HOST:
1031         sys_cmd = "scp -r "+REM_O_RU_HOST+":"+ xran_path+"/app/logs/*.txt "+ xran_path+"/app/logs/"
1032         print(sys_cmd)
1033         os.system(sys_cmd)
1034         sys_cmd = "scp -r "+REM_O_RU_HOST+":"+ xran_path+"/app/mlog-o-ru* "+ xran_path+"/app/"
1035         print(sys_cmd)
1036         os.system(sys_cmd)
1037
1038     make_copy_mlog(rantech, cat, mu, bw, tcase, xran_path)
1039     #oXuNum check only O-RU 0 for now
1040     if 'oXuOwdmEnabled==1' in globals():
1041          OwdmTest=1
1042     else:
1043          OwdmTest=0
1044
1045     for o_xu_id in range(0, oXuNum):
1046         o_xu_test_cfg = []
1047         if o_xu_id == 0:
1048             o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile0)
1049         elif o_xu_id == 1:
1050             o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile1)
1051         elif o_xu_id == 2:
1052             o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile2)
1053         elif o_xu_id == 3:
1054             o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile3)
1055
1056         logging.info("O-RU %d parse config files %s\n", o_xu_id, o_xu_test_cfg)
1057
1058         usecase_cfg_per_o_ru = parse_dat_file(rantech, cat, mu, bw, tcase, xran_path, o_xu_test_cfg)
1059
1060         res = compare_results(o_xu_id,rantech, cat, mu, bw, tcase, xran_path, o_xu_test_cfg, 0)
1061         if OwdmTest == 1:
1062         # overwrite PASS/FAIL in res if the owd tests have failed
1063              res1 = check_owdm_test_results(xran_path, o_xu_id)
1064              print("res1 :", res1)
1065              if res1 !=0 :
1066                   res = -1     
1067     if res != 0:
1068         os.chdir(wd)
1069         print("FAIL")
1070             del_dat_file_vars(usecase_cfg_per_o_ru)
1071         return res
1072
1073         res = compare_results(o_xu_id, rantech, cat, mu, bw, tcase, xran_path, o_xu_test_cfg, 1)
1074     if res != 0:
1075         os.chdir(wd)
1076         print("FAIL")
1077             del_dat_file_vars(usecase_cfg_per_o_ru)
1078         return res
1079
1080     os.chdir(wd)
1081     print("PASS")
1082
1083         del_dat_file_vars(usecase_cfg_per_o_ru)
1084
1085     return res
1086
1087 def main():
1088     test_results = []
1089     test_executed_total = 0
1090     run_total = 0
1091     test_fail_cnt = 0
1092     test_pass_cnt = 0
1093     cat   = 0
1094     mu    = 0
1095     bw    = 0
1096     tcase = 0
1097     tcase_description = "n/a"
1098
1099     """Processes input files to produce IACA files"""
1100     # Find path to XRAN
1101     if os.getenv("XRAN_DIR") is not None:
1102         xran_path = os.getenv("XRAN_DIR")
1103     else:
1104         print("please set 'export XRAN_DIR' in the OS")
1105         return -1
1106
1107     # Set up logging with given level (DEBUG, INFO, ERROR) for console end logfile
1108     init_logger(logging.INFO, logging.DEBUG)
1109     host_name =  socket.gethostname()
1110     logging.info("host: %s Started script: master.py from XRAN path %s",host_name, xran_path)
1111
1112     options = parse_args(sys.argv[1:])
1113     rem_o_ru_host = options.rem_o_ru_host
1114
1115     if host_name == "sc12-xran-sub6":
1116         if rem_o_ru_host:
1117             vf_addr_o_xu = vf_addr_o_xu_sc12_cvl
1118         else:
1119             vf_addr_o_xu = vf_addr_o_xu_sc12
1120     elif host_name == "csl-npg-scs1-30":
1121         vf_addr_o_xu = vf_addr_o_xu_scs1_30
1122     elif host_name == "npg-scs1-repo.la.intel.com":
1123         vf_addr_o_xu = vf_addr_o_xu_scs1_repo
1124     elif host_name == "icelake-scs1-1":
1125         vf_addr_o_xu = vf_addr_o_xu_icelake_scs1_1
1126     elif host_name == "icx-npg-scs1-coyote4":
1127         vf_addr_o_xu = vf_addr_o_xu_icx_npg_scs1_coyote4
1128     elif host_name == "csl-npg-scs1-35":
1129         vf_addr_o_xu = vf_addr_o_xu_scs1_35
1130     elif host_name == "csl-npg-scs1-33":
1131         vf_addr_o_xu = vf_addr_o_xu_csl_npg_scs1_33
1132     else:
1133         vf_addr_o_xu = vf_addr_o_xu_jenkins
1134
1135     print(vf_addr_o_xu[0][0],vf_addr_o_xu[0][1],vf_addr_o_xu[0][2])
1136     print(vf_addr_o_xu[1][0],vf_addr_o_xu[1][1],vf_addr_o_xu[1][2])
1137
1138     # Parse input arguments
1139     if len(sys.argv) == 1 or (len(sys.argv) == 3 and rem_o_ru_host):
1140         run_total = len(all_test_cases)
1141         print(run_total)
1142         print("Run All test cases {}\n".format(run_total))
1143     else:
1144         rantech = options.rantech
1145         cat     = options.category
1146         mu      = options.numerology
1147         bw      = options.bandwidth
1148         tcase   = options.testcase
1149         verbose = options.verbose
1150
1151         print(rem_o_ru_host)
1152
1153     if (run_total):
1154         for test_run_ix in range(0, run_total):
1155             rantech = all_test_cases[test_run_ix][0]
1156             cat     = all_test_cases[test_run_ix][1]
1157             mu      = all_test_cases[test_run_ix][2]
1158             bw      = all_test_cases[test_run_ix][3]
1159             tcase   = all_test_cases[test_run_ix][4]
1160             tcase_description = all_test_cases[test_run_ix][5]
1161             verbose = 0
1162
1163             logging.info("Test# %d out of %d [PASS %d FAIL %d]: ran %d cat %d mu %d bw %d test case %d [%s]\n",test_run_ix, run_total, test_pass_cnt, test_fail_cnt, rantech, cat, mu, bw, tcase, tcase_description)
1164             res = run_tcase(rem_o_ru_host, rantech, cat, mu, bw, tcase, verbose,  xran_path, vf_addr_o_xu)
1165             if (res != 0):
1166                 test_fail_cnt += 1
1167                 test_results.append((rantech, cat, mu, bw, tcase,'FAIL', tcase_description))
1168                 continue
1169
1170             test_pass_cnt += 1
1171             test_results.append((rantech, cat, mu, bw, tcase,'PASS', tcase_description))
1172     else:
1173         res = run_tcase(rem_o_ru_host, rantech, cat, mu, bw, tcase, verbose, xran_path, vf_addr_o_xu)
1174         if (res != 0):
1175             test_results.append((rantech, cat, mu, bw, tcase,'FAIL'))
1176         else:
1177         test_results.append((rantech, cat, mu, bw, tcase,'PASS'))
1178
1179         with open('testresult.txt', 'w') as reshandle:
1180             json.dump(test_results, reshandle)
1181
1182     return res
1183
1184 if __name__ == '__main__':
1185     print("Python version")
1186     print (sys.version)
1187     print("Version info.")
1188     print (sys.version_info)
1189     if (sys.version_info[0] < 3):
1190         raise Exception ("Must be Python 3")
1191     START_TIME = datetime.now()
1192     res = main()
1193     END_TIME = datetime.now()
1194     logging.debug("Start time: %s, end time: %s", START_TIME, END_TIME)
1195     logging.info("Execution time: %s", END_TIME - START_TIME)
1196     logging.shutdown()
1197     sys.exit(res)