11# SPDX-License-Identifier: Apache-2.0
22from __future__ import annotations
33
4+ import glob
45import json
56import logging
67import os
1314import threading
1415import time
1516import xml .etree .ElementTree as ET
17+ import random
1618from collections import OrderedDict
1719from enum import Enum
1820
@@ -952,13 +954,15 @@ class Bsim(Harness):
952954 DEFAULT_VERBOSITY = 2
953955 DEFAULT_SIM_LENGTH = 60e6
954956
955- BSIM_READY_TIMEOUT_S = 20
957+ BSIM_READY_TIMEOUT_S = 60
956958
957959 cacheable = True
958960
959961 def __init__ (self ):
960962 super ().__init__ ()
961963 self ._bsim_out_path = os .getenv ('BSIM_OUT_PATH' , '' )
964+ if self ._bsim_out_path :
965+ self ._bsim_out_path = os .path .join (self ._bsim_out_path , 'bin' )
962966 self ._exe_paths = []
963967 self ._tc_output = []
964968 self ._start_time = 0
@@ -985,7 +989,7 @@ def configure(self, instance):
985989 exe_names = [f'bs_{ self .instance .name } ' ]
986990
987991 self ._exe_paths = \
988- [os .path .join (self ._bsim_out_path , 'bin' , exe_name ) for exe_name in exe_names ]
992+ [os .path .join (self ._bsim_out_path , exe_name ) for exe_name in exe_names ]
989993
990994 def clean_exes (self ):
991995 for exe_path in [self ._get_exe_path (i ) for i in range (len (self ._exe_paths ))]:
@@ -1028,8 +1032,9 @@ def build(self):
10281032 self .instance .execution_time = time .time () - self ._start_time
10291033
10301034 def _run_cmd (self , cmd , timeout ):
1035+ logger .debug (' ' .join (cmd ))
10311036 with subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE ,
1032- cwd = os . path . join ( self ._bsim_out_path , 'bin' ) ) as proc :
1037+ cwd = self ._bsim_out_path ) as proc :
10331038 try :
10341039 reader_t = threading .Thread (target = self ._output_reader , args = (proc ,), daemon = True )
10351040 reader_t .start ()
@@ -1044,8 +1049,11 @@ def _run_cmd(self, cmd, timeout):
10441049 self .status = TwisterStatus .ERROR
10451050 proc .kill ()
10461051
1047- if self .status == TwisterStatus .NONE :
1048- self .status = TwisterStatus .FAIL if proc .returncode != 0 else TwisterStatus .PASS
1052+ if proc .returncode != 0 :
1053+ self .status = TwisterStatus .ERROR
1054+ self .instance .reason = f'Bsim error - return code { proc .returncode } '
1055+ else :
1056+ self .status = TwisterStatus .PASS if self .status == TwisterStatus .NONE else self .status
10491057
10501058 def _output_reader (self , proc ):
10511059 while proc .stdout .readable () and proc .poll () is None :
@@ -1057,25 +1065,48 @@ def _output_reader(self, proc):
10571065 proc .communicate ()
10581066
10591067 def _generate_commands (self ):
1060- bsim_phy_path = os .path .join (self ._bsim_out_path , 'bin' , 'bs_2G4_phy_v1' )
1068+ def rs ():
1069+ return f'-rs={ random .randint (0 , 2 ** 10 - 1 )} '
1070+
1071+ def expand_args (dev_id ):
1072+ try :
1073+ args = [str (eval (v )[dev_id ]) if v .startswith ('[' ) else v for v in extra_args ]
1074+ return [arg for arg in args if args if arg ]
1075+ except Exception as e :
1076+ logger .warning (f'Unable to expand extra arguments set { extra_args } : { e } ' )
1077+ return extra_args
1078+
1079+ bsim_phy_path = os .path .join (self ._bsim_out_path , 'bs_2G4_phy_v1' )
10611080 suite_id = f'-s={ self .instance .name .split (os .path .sep )[- 1 ].replace ("." , "_" )} '
10621081
10631082 cfg = self .instance .testsuite .harness_config
10641083 verbosity = f'-v={ cfg .get ("bsim_verbosity" , self .DEFAULT_VERBOSITY )} '
10651084 sim_length = f'-sim_length={ cfg .get ("bsim_sim_length" , self .DEFAULT_SIM_LENGTH )} '
10661085 extra_args = cfg .get ('bsim_options' , [])
1086+ phy_extra_args = cfg .get ('bsim_phy_options' , [])
10671087 test_ids = cfg .get ('bsim_test_ids' , [])
10681088 if not test_ids :
10691089 logger .error ('No test ids specified for bsim test' )
10701090 self .status = TwisterStatus .ERROR
10711091 return []
10721092
1073- cmds = [[self ._get_exe_path (i ), verbosity , suite_id , f'-d={ i } ' , f'-testid={ t_id } ' ] + extra_args
1074- for i , t_id in enumerate (test_ids )]
1075- cmds .append ([bsim_phy_path , verbosity , suite_id , f'-D={ len (test_ids )} ' , sim_length ])
1093+ cmds = [[self ._get_exe_path (i ), verbosity , suite_id , f'-d={ i } ' , f'-testid={ t_id } ' , rs ()]
1094+ + expand_args (i ) for i , t_id in enumerate (test_ids )]
1095+ cmds .append ([bsim_phy_path , verbosity , suite_id , f'-D={ len (test_ids )} ' , sim_length ]
1096+ + phy_extra_args )
10761097
10771098 return cmds
10781099
1100+ def _clean_up_files (self ):
1101+ # Clean-up any log files that the test may have generated
1102+ files = glob .glob (os .path .join (self ._bsim_out_path , '*.log' ))
1103+ # files += glob.glob(os.path.join(self._bsim_out_path, '*.bin'))
1104+ try :
1105+ for file in [f for f in files if os .path .getctime (f ) > self ._start_time ]:
1106+ os .remove (file )
1107+ except Exception as e :
1108+ logger .warning (f'Failed to clean up bsim log files: { e } ' )
1109+
10791110 def bsim_run (self , timeout ):
10801111 try :
10811112 self ._set_start_time ()
@@ -1093,6 +1124,7 @@ def bsim_run(self, timeout):
10931124 self .status = TwisterStatus .ERROR
10941125 finally :
10951126 self ._update_test_status ()
1127+ self ._clean_up_files ()
10961128
10971129 def _update_test_status (self ):
10981130 self .instance .execution_time += time .time () - self ._start_time
0 commit comments