2 #******************************************************************************
4 # Copyright (c) 2020 Intel.
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 #******************************************************************************/
20 """This script runs test cases with O-DU and O-RU
31 from itertools import dropwhile
32 from datetime import datetime
33 from time import gmtime, strftime
35 from threading import Timer
38 timeout_sec = 60*3 #3 min max
40 nLteNumRbsPerSymF1 = [
41 # 5MHz 10MHz 15MHz 20 MHz
42 [25, 50, 75, 100] # LTE Numerology 0 (15KHz)
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)
53 # 50Mhz 100MHz 200MHz 400MHz
54 [66, 132, 264, 0], # Numerology 2 (60KHz)
55 [32, 66, 132, 264] # Numerology 3 (120KHz)
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))
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))
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
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
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
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
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
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
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
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
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
121 # table of all test cases
122 # (ran, cat, mu, bw, test case, "test case description")
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"),
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"),
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
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"),
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"),
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"),
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"),
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"),
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")
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")
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
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'})
237 def init_logger(console_level, logfile_level):
238 """Initializes console and logfile logger with given logging levels"""
240 logging.basicConfig(filename="runtests.log",
242 format="%(asctime)s: %(levelname)s: %(message)s",
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)
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")
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")
267 options = parser.parse_args(args)
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)
274 """ function to check if a line
275 starts with some character.
278 # return true if a line starts with #
279 return s.startswith('#')
281 class GetOutOfLoops( Exception ):
284 def get_re_map(nRB, direction):
289 if 'nPrbElemDl' in globals():
291 for i in range(0, nPrbElm):
292 elm = str('PrbElemDl'+str(i))
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))
305 if 'nPrbElemUl' in globals():
307 for i in range(0, nPrbElm):
308 elm = str('PrbElemUl'+str(i))
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))
321 if 'nPrbElemSrs' in globals():
323 for i in range(0, nPrbElm):
324 elm = str('PrbElemSrs'+str(i))
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))
336 prb_map = list(range(0, nRB*12))
340 def check_for_string_present_in_file(file_name, search_string):
342 with open(file_name, 'r') as read_obj:
343 for line in read_obj:
344 if search_string in line:
351 def check_owdm_test_results(xran_path, o_xu_id):
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')
362 def compare_results(o_xu_id, rantech, cat, mu, bw, tcase, xran_path, test_cfg, direction):
367 nDlRB = nLteNumRbsPerSymF1[mu][nRChBwOptions.get(str(nDLBandwidth))]
368 nUlRB = nLteNumRbsPerSymF1[mu][nRChBwOptions.get(str(nULBandwidth))]
370 print("Incorrect arguments\n")
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))]
382 print("Incorrect arguments\n")
386 if 'compression' in globals():
391 if 'srsEanble' in globals():
396 if 'rachEanble' in globals():
401 print("O-RU {} compare results: {} [compression {}]\n".format(o_xu_id, dic_dir.get(direction), comp))
404 # print("WARNING: Skip checking IQs and BF Weights for CAT B for now\n");
408 if nFrameDuplexType == 1:
410 for i in range(nTddPeriod):
412 SlotConfig.insert(i, sSlotConfig0)
414 SlotConfig.insert(i, sSlotConfig1)
416 SlotConfig.insert(i, sSlotConfig2)
418 SlotConfig.insert(i, sSlotConfig3)
420 SlotConfig.insert(i, sSlotConfig4)
422 SlotConfig.insert(i, sSlotConfig5)
424 SlotConfig.insert(i, sSlotConfig6)
426 SlotConfig.insert(i, sSlotConfig7)
428 SlotConfig.insert(i, sSlotConfig8)
430 SlotConfig.insert(i, sSlotConfig9)
432 raise Exception('i should not exceed nTddPeriod %d. The value of i was: {}'.format(nTddPeriod, i))
433 #print(SlotConfig, type(sSlotConfig0))
437 if (direction == 1) & (cat == 1): #UL
438 flowId = ccNum*antNumUL
440 flowId = ccNum*antNum
443 re_map = get_re_map(nDlRB, direction)
445 re_map = get_re_map(nUlRB, direction)
447 raise Exception('Direction is not supported %d'.format(direction))
449 for i in range(0, flowId):
450 #read ref and test files
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"
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"
464 raise Exception('Direction is not supported %d'.format(direction))
466 print("test result :", file_tst)
467 print("test reference:", file_ref)
468 if os.path.exists(file_tst):
470 file_tst = open(file_tst, 'r')
472 print ("Could not open/read file:", file_tst)
475 print(file_tst, "doesn't exist")
478 if os.path.exists(file_ref):
480 file_ref = open(file_ref, 'r')
482 print ("Could not open/read file:", file_ref)
485 print(file_tst, "doesn't exist")
489 tst = file_tst.readlines()
490 ref = file_ref.readlines()
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:
507 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
512 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
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
520 line_tst = tst[offset].rstrip()
523 print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
526 line_ref = ref[offset].rstrip()
529 print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
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
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, " ")
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)
551 except GetOutOfLoops:
554 if (direction == 1) & (rach == 1) & 0: #UL
555 print("O-RU {} compare results: {} [compression {}]\n".format(o_xu_id, 'PRACH', comp))
560 re_map = range(0, 144)
562 elif nFrameDuplexType==0: #FR1 FDD
563 if prachConfigIndex < 87:
564 re_map = range(0, 840)
567 re_map = range(0, 144)
570 if prachConfigIndex < 67:
571 re_map = range(0, 144)
574 re_map = range(0, 840)
577 flowId = ccNum*antNumUL
579 flowId = ccNum*antNum
581 for i in range(0, flowId):
582 #read ref and test files
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):
592 file_tst = open(file_tst, 'r')
594 print ("Could not open/read file:", file_tst)
597 print(file_tst, "doesn't exist")
600 if os.path.exists(file_ref):
602 file_ref = open(file_ref, 'r')
604 print ("Could not open/read file:", file_ref)
607 print(file_tst, "doesn't exist")
611 tst = file_tst.readlines()
612 ref = file_ref.readlines()
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:
629 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
634 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
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
642 line_tst = tst[offset].rstrip()
645 print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
648 line_ref = ref[offset].rstrip()
651 print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
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
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, " ")
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)
673 except GetOutOfLoops:
676 if (direction == 0) | (cat == 0) | (srs_enb == 0): #DL or Cat A
680 print("O-RU {} compare results: {} [compression {}]\n".format(o_xu_id, 'SRS', comp))
684 re_map = get_re_map(nUlRB, 2)
686 flowId = ccNum*antElmTRx
687 for i in range(0, flowId):
688 #read ref and test files
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"
698 raise Exception('Direction is not supported %d'.format(direction))
700 print("test result :", file_tst)
701 print("test reference:", file_ref)
702 if os.path.exists(file_tst):
704 file_tst = open(file_tst, 'r')
706 print ("Could not open/read file:", file_tst)
709 print(file_tst, "doesn't exist")
712 if os.path.exists(file_ref):
714 file_ref = open(file_ref, 'r')
716 print ("Could not open/read file:", file_ref)
719 print(file_tst, "doesn't exist")
723 tst = file_tst.readlines()
724 ref = file_ref.readlines()
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:
742 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
747 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
748 # ignore if DL symbol for now
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
756 line_tst = tst[offset].rstrip()
759 print("FAIL:","IndexError on tst: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(tst))
762 line_ref = ref[offset].rstrip()
765 print("FAIL:","IndexError on ref: ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx, len(ref))
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
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, " ")
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)
787 except GetOutOfLoops:
788 #don't threat SRS as error for now
795 def parse_usecase_cfg(rantech, cat, mu, bw, tcase, xran_path, usecase_cfg):
797 logging.info("parse config files %s\n", usecase_cfg[0])
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()
804 lineList.append(my_line)
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+"'"
818 code = compile(str(exe_line), '<string>', 'exec')
819 exec (code, global_env, local_env)
821 for k, v in local_env.items():
825 print("Number of O-RU:", oXuNum)
829 def parse_dat_file(rantech, cat, mu, bw, tcase, xran_path, test_cfg):
831 logging.info("parse config files %s\n", test_cfg[0])
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()
839 lineList.append(my_line)
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+"'"
852 code = compile(str(exe_line), '<string>', 'exec')
853 exec (code, global_env, local_env)
855 for k, v in local_env.items():
861 def del_dat_file_vars(local_env):
863 for k, v in local_env.items():
868 def make_copy_mlog(rantech, cat, mu, bw, tcase, xran_path):
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"
877 d_bin = shutil.copyfile(src_bin, dst_bin)
878 d_csv = shutil.copyfile(src_csv, dst_csv)
880 logging.info("O-DU MLog is not present\n")
884 logging.info("O-DU Mlog was copied\n")
887 print("Destination path:", d_bin)
888 print("Destination path:", d_csv)
890 d_bin = shutil.copyfile(src_bin, dst_bin)
891 d_csv = shutil.copyfile(src_csv, dst_csv)
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"
898 d_bin = shutil.copyfile(src_bin, dst_bin)
899 d_csv = shutil.copyfile(src_csv, dst_csv)
902 d_bin = shutil.copyfile(src_bin, dst_bin)
903 d_csv = shutil.copyfile(src_csv, dst_csv)
905 logging.info("O-RU MLog is not present\n")
909 logging.info("O-RU Mlog was copied\n")
914 def run_tcase(rem_o_ru_host, rantech, cat, mu, bw, tcase, verbose, xran_path, vf_addr_o_xu):
916 if rantech == 1: #LTE
918 test_config =xran_path+"/app/usecase/lte_b/mu{0:d}_{1:d}mhz".format(mu, bw)
920 test_config =xran_path+"/app/usecase/lte_a/mu{0:d}_{1:d}mhz".format(mu, bw)
922 print("Incorrect cat arguments\n")
924 elif rantech == 0: #5G NR
926 test_config =xran_path+"/app/usecase/cat_b/mu{0:d}_{1:d}mhz".format(mu, bw)
928 test_config =xran_path+"/app/usecase/cat_a/mu{0:d}_{1:d}mhz".format(mu, bw)
930 print("Incorrect cat argument\n")
933 print("Incorrect rantech argument\n")
937 test_config = test_config+"/"+str(tcase)
939 app = xran_path+"/app/build/sample-app"
941 logging.debug("run: %s %s", app, test_config)
942 logging.debug("Started script: master.py, XRAN path %s", xran_path)
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")
950 usecase_dirname = os.path.dirname(os.path.realpath(test_cfg[0]))
951 print(usecase_dirname)
954 os.chdir(xran_path+"/app/")
961 os.system('pkill -9 "sample-app"')
962 os.system('rm -rf ./logs')
964 usecase_cfg = parse_usecase_cfg(rantech, cat, mu, bw, tcase, xran_path, test_cfg)
965 REM_O_RU_HOST=rem_o_ru_host
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
974 if i == 0 or REM_O_RU_HOST == "":
975 p = subprocess.Popen(run_cmd)
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]
980 print("my_cmd: ", ' '.join([str(elem) for elem in ssh]))
981 p = subprocess.Popen(ssh, shell=False)
983 if i == 0 or REM_O_RU_HOST == "":
984 p = subprocess.Popen(run_cmd, stdout=f, stderr=f)
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)
991 t = Timer(timeout_sec, p.kill)
994 logfile_xu.insert(i, f)
995 processes.append((p, logfile_xu[i]))
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:
1000 print(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()))
1002 for p, f in processes:
1006 except (KeyboardInterrupt, SystemExit):
1010 for pp, ff in processes:
1011 pp.send_signal(signal.SIGINT)
1015 if p.returncode != 0:
1016 print("Application {} failed p.returncode:{}".format(dic_xu.get(i), p.returncode))
1018 #logging.info("FAIL\n")
1020 #sys.exit(p.returncode)
1028 logging.info("O-DU and O-RU are done\n")
1031 sys_cmd = "scp -r "+REM_O_RU_HOST+":"+ xran_path+"/app/logs/*.txt "+ xran_path+"/app/logs/"
1034 sys_cmd = "scp -r "+REM_O_RU_HOST+":"+ xran_path+"/app/mlog-o-ru* "+ xran_path+"/app/"
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():
1045 for o_xu_id in range(0, oXuNum):
1048 o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile0)
1050 o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile1)
1052 o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile2)
1054 o_xu_test_cfg.append(usecase_dirname+"/"+oXuCfgFile3)
1056 logging.info("O-RU %d parse config files %s\n", o_xu_id, o_xu_test_cfg)
1058 usecase_cfg_per_o_ru = parse_dat_file(rantech, cat, mu, bw, tcase, xran_path, o_xu_test_cfg)
1060 res = compare_results(o_xu_id,rantech, cat, mu, bw, tcase, xran_path, o_xu_test_cfg, 0)
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)
1070 del_dat_file_vars(usecase_cfg_per_o_ru)
1073 res = compare_results(o_xu_id, rantech, cat, mu, bw, tcase, xran_path, o_xu_test_cfg, 1)
1077 del_dat_file_vars(usecase_cfg_per_o_ru)
1083 del_dat_file_vars(usecase_cfg_per_o_ru)
1089 test_executed_total = 0
1097 tcase_description = "n/a"
1099 """Processes input files to produce IACA files"""
1101 if os.getenv("XRAN_DIR") is not None:
1102 xran_path = os.getenv("XRAN_DIR")
1104 print("please set 'export XRAN_DIR' in the OS")
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)
1112 options = parse_args(sys.argv[1:])
1113 rem_o_ru_host = options.rem_o_ru_host
1115 if host_name == "sc12-xran-sub6":
1117 vf_addr_o_xu = vf_addr_o_xu_sc12_cvl
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
1133 vf_addr_o_xu = vf_addr_o_xu_jenkins
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])
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)
1142 print("Run All test cases {}\n".format(run_total))
1144 rantech = options.rantech
1145 cat = options.category
1146 mu = options.numerology
1147 bw = options.bandwidth
1148 tcase = options.testcase
1149 verbose = options.verbose
1151 print(rem_o_ru_host)
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]
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)
1167 test_results.append((rantech, cat, mu, bw, tcase,'FAIL', tcase_description))
1171 test_results.append((rantech, cat, mu, bw, tcase,'PASS', tcase_description))
1173 res = run_tcase(rem_o_ru_host, rantech, cat, mu, bw, tcase, verbose, xran_path, vf_addr_o_xu)
1175 test_results.append((rantech, cat, mu, bw, tcase,'FAIL'))
1177 test_results.append((rantech, cat, mu, bw, tcase,'PASS'))
1179 with open('testresult.txt', 'w') as reshandle:
1180 json.dump(test_results, reshandle)
1184 if __name__ == '__main__':
1185 print("Python 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()
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)