Beispiel #1
0
def _wait_for( serial_numbers, timeout = 5 ):
    """
    Wait until the given serial numbers are all online

    :param serial_numbers: A collection of serial-numbers to wait for
    :param timeout: Number of seconds of maximum wait time
    :return: True if all have come online; False if timeout was reached
    """
    did_some_waiting = False
    while True:
        #
        have_all_devices = True
        enabled_sns = enabled()
        for sn in serial_numbers:
            if sn not in enabled_sns:
                have_all_devices = False
                break
        #
        if have_all_devices:
            if did_some_waiting:
                # Wait an extra second, just in case -- let the devices properly power up
                log.d( 'all devices powered up' )
                time.sleep( 1 )
            return True
        #
        if timeout <= 0:
            return False
        timeout -= 1
        time.sleep( 1 )
        did_some_waiting = True
Beispiel #2
0
def query( monitor_changes = True ):
    """
    Start a new LRS context, and collect all devices
    :param monitor_changes: If True, devices will update dynamically as they are removed/added
    """
    global rs
    if not rs:
        return
    #
    # Before we can start a context and query devices, we need to enable all the ports
    # on the acroname, if any:
    if acroname:
        acroname.connect()  # MAY THROW!
        acroname.enable_ports( sleep_on_change = 5 )  # make sure all connected!
    #
    # Get all devices, and store by serial-number
    global _device_by_sn, _context, _port_to_sn
    _context = rs.context()
    _device_by_sn = dict()
    try:
        log.d( 'discovering devices ...' )
        log.debug_indent()
        for dev in _context.query_devices():
            if dev.is_update_device():
                sn = dev.get_info( rs.camera_info.firmware_update_id )
            else:
                sn = dev.get_info( rs.camera_info.serial_number )
            _device_by_sn[sn] = Device( sn, dev )
            log.d( '...', dev )
    finally:
        log.debug_unindent()
    #
    if monitor_changes:
        _context.set_devices_changed_callback( _device_change_callback )
Beispiel #3
0
def generate_cmake(builddir, testdir, testname, filelist):
    makefile = builddir + '/' + testdir + '/CMakeLists.txt'
    log.d('   creating:', makefile)
    handle = open(makefile, 'w')
    filelist = '\n    '.join(filelist)
    handle.write('''
# This file is automatically generated!!
# Do not modify or your changes will be lost!

cmake_minimum_required( VERSION 3.1.0 )
project( ''' + testname + ''' )

set( SRC_FILES ''' + filelist + '''
)
add_executable( ''' + testname + ''' ${SRC_FILES} )
source_group( "Common Files" FILES ${ELPP_FILES} ${CATCH_FILES} )
set_property(TARGET ''' + testname + ''' PROPERTY CXX_STANDARD 11)
target_link_libraries( ''' + testname + ''' ${DEPENDENCIES})

set_target_properties( ''' + testname + ''' PROPERTIES FOLDER "Unit-Tests/''' +
                 os.path.dirname(testdir) + '''" )

target_include_directories(''' + testname + ''' PRIVATE ''' + src + ''')

''')
    handle.close()
 def debug_dump(self):
     if self._priority != 1000:
         log.d( 'priority:', self._priority )
     if self._timeout != 200:
         log.d( 'timeout:', self._timeout)
     if self._tags:
         log.d( 'tags:', self._tags )
     if self._flags:
         log.d( 'flags:', self._flags )
     if len(self._configurations) > 1:
         log.d( len( self._configurations ), 'configurations' )
Beispiel #5
0
def find_first_device_or_exit():
    """
    :return: the first device that was found, if no device is found the test is skipped. That way we can still run
        the unit-tests when no device is connected and not fail the tests that check a connected device
    """
    import pyrealsense2 as rs
    c = rs.context()
    if not c.devices.size():  # if no device is connected we skip the test
        log.f("No device found")
    dev = c.devices[0]
    log.d( 'found', dev )
    return dev
Beispiel #6
0
 def debug_dump(self):
     if self._priority != 1000:
         log.d('priority:', self._priority)
     if self._timeout != 200:
         log.d('timeout:', self._timeout)
     if len(self._tags) > 1:
         log.d('tags:',
               {tag
                for tag in self._tags if tag != "exe" and tag != "py"})
     if self._flags:
         log.d('flags:', self._flags)
     if len(self._configurations) > 1:
         log.d(len(self._configurations), 'configurations')
Beispiel #7
0
def expect(depth_frame=None, color_frame=None, nothing_else=False):
    """
    Looks at the syncer queue and gets the next frame from it if available, checking its contents
    against the expected frame numbers.
    """
    global syncer, playback_status
    f = syncer.poll_for_frame()
    if playback_status is not None:
        countdown = 50  # 5 seconds
        while not f and playback_status != rs.playback_status.stopped:
            countdown -= 1
            if countdown == 0:
                break
            time.sleep(0.1)
            f = syncer.poll_for_frame()
    # NOTE: f will never be None
    if not f:
        test.check(depth_frame is None, "expected a depth frame")
        test.check(color_frame is None, "expected a color frame")
        return False

    log.d("Got", f)

    fs = rs.composite_frame(f)

    if fs:
        depth = fs.get_depth_frame()
    else:
        depth = rs.depth_frame(f)
    test.info("actual depth", depth)
    test.check_equal(depth_frame is None, not depth)
    if depth_frame is not None and depth:
        test.check_equal(depth.get_frame_number(), depth_frame)

    if fs:
        color = fs.get_color_frame()
    elif not depth:
        color = rs.video_frame(f)
    else:
        color = None
    test.info("actual color", color)
    test.check_equal(color_frame is None, not color)
    if color_frame is not None and color:
        test.check_equal(color.get_frame_number(), color_frame)

    if nothing_else:
        f = syncer.poll_for_frame()
        test.info("Expected nothing else; actual", f)
        test.check(not f)

    return True
Beispiel #8
0
def find_devices_by_product_line_or_exit( product_line ):
    """
    :param product_line: The product line of the wanted devices
    :return: A list of devices of specific product line that was found, if no device is found the test is skipped.
        That way we can still run the unit-tests when no device is connected
        and not fail the tests that check a connected device
    """
    import pyrealsense2 as rs
    c = rs.context()
    devices_list = c.query_devices(product_line)
    if devices_list.size() == 0:
        log.f( "No device of the", product_line, "product line was found" )
    log.d( 'found', devices_list.size(), product_line, 'devices:', [dev for dev in devices_list] )
    return devices_list
Beispiel #9
0
def load_specs_from_file( filename ):
    """
    Loads a set of specs from a file:
        - Comments (#) are removed
        - Each word in the file is a spec
    :param filename: the path to the text file we want to load
    :return: a set of specs that can then be expanded to a set of serial-numbers (see expand_specs())
    """
    from rspy import file
    exceptions = set()
    for line, comment in file.split_comments( filename ):
        specs = line.split()
        if specs:
            log.d( '...', specs, comment and ('  # ' + comment) or '', )
            exceptions.update( specs )
    return exceptions
Beispiel #10
0
    def __init__( self, testname, exe = None, context = None ):
        """
        :param testname: name of the test
        :param exe: full path to executable
        :param context: context in which the test will run
        """
        global unit_tests_dir
        if exe and not os.path.isfile( exe ):
            log.d( "Tried to create exe test with invalid exe file: " + exe )
        Test.__init__( self, testname )
        self.exe = exe

        relative_test_path = self.find_source_path()
        if relative_test_path:
            self._config = TestConfigFromCpp( unit_tests_dir + os.sep + relative_test_path, context )
        else:
            self._config = TestConfig(context)
def find_build_dir( dir ):
    """
    Given a directory we know must be within the build tree, go up the tree until we find
    a file we know must be in the root build directory...

    :return: the build directory if found, or None otherwise
    """
    build_dir = dir
    while True:
        if os.path.isfile( os.path.join( build_dir, 'CMakeCache.txt' )):
            log.d( 'assuming build dir path:', build_dir )
            return build_dir
        base = os.path.dirname( build_dir )
        if base == build_dir:
            log.d( 'could not find CMakeCache.txt; cannot assume build dir from', dir )
            break
        build_dir = base
Beispiel #12
0
def run(cmd, stdout=None, timeout=200, append=False):
    """
    Wrapper function for subprocess.run.
    If the child process times out or ends with a non-zero exit status an exception is raised!

    :param cmd: the command and argument for the child process, as a list
    :param stdout: path of file to direct the output of the process to (None to disable)
    :param timeout: number of seconds to give the process before forcefully ending it (None to disable)
    :param append: if True and stdout is not None, the log of the test will be appended to the file instead of
                   overwriting it
    :return: the output written by the child, if stdout is None -- otherwise N/A
    """
    log.d('running:', cmd)
    handle = None
    start_time = time.time()
    try:
        log.debug_indent()
        if stdout and stdout != subprocess.PIPE:
            if append:
                handle = open(stdout, "a")
                handle.write(
                    "\n---------------------------------------------------------------------------------\n\n"
                )
                handle.flush()
            else:
                handle = open(stdout, "w")
            stdout = handle
        rv = subprocess.run(cmd,
                            stdout=stdout,
                            stderr=subprocess.STDOUT,
                            universal_newlines=True,
                            timeout=timeout,
                            check=True)
        result = rv.stdout
        if not result:
            result = []
        else:
            result = result.split('\n')
        return result
    finally:
        if handle:
            handle.close()
        log.debug_unindent()
        run_time = time.time() - start_time
        log.d("test took", run_time, "seconds")
Beispiel #13
0
def discover():
    """
    Return all Acroname module specs in a list. Raise NoneFoundError if one is not found!
    """

    log.d('discovering Acroname modules ...')
    # see https://acroname.com/reference/_modules/brainstem/module.html#Module.discoverAndConnect
    try:
        log.debug_indent()
        specs = brainstem.discover.findAllModules(brainstem.link.Spec.USB)
        if not specs:
            raise NoneFoundError()
        for spec in specs:
            log.d('...', spec)
    finally:
        log.debug_unindent()

    return specs
Beispiel #14
0
def generate_color_frame(frame_number, timestamp):
    """
    """
    global playback_status
    if playback_status is not None:
        raise RuntimeError("cannot generate frames when playing back")
    #
    global color_profile, domain, pixels, color_sensor, w, bpp
    color_frame = rs.software_video_frame()
    color_frame.pixels = pixels
    color_frame.stride = w * bpp
    color_frame.bpp = bpp
    color_frame.frame_number = frame_number
    color_frame.timestamp = timestamp
    color_frame.domain = domain
    color_frame.profile = color_profile
    #
    log.d("-->", color_frame)
    color_sensor.on_video_frame(color_frame)
Beispiel #15
0
def generate_depth_frame(frame_number, timestamp):
    """
    """
    global playback_status
    if playback_status is not None:
        raise RuntimeError("cannot generate frames when playing back")
    #
    global depth_profile, domain, pixels, depth_sensor, w, bpp
    depth_frame = rs.software_video_frame()
    depth_frame.pixels = pixels
    depth_frame.stride = w * bpp
    depth_frame.bpp = bpp
    depth_frame.frame_number = frame_number
    depth_frame.timestamp = timestamp
    depth_frame.domain = domain
    depth_frame.profile = depth_profile
    #
    log.d("-->", depth_frame)
    depth_sensor.on_video_frame(depth_frame)
Beispiel #16
0
def expand_specs(specs):
    """
    Given a collection of configuration specs, expand them into actual serial numbers.
    Specs can be loaded from a file: see load_specs_from_file()
    :param specs: a collection of specs
    :return: a set of serial-numbers
    """
    expanded = set()
    for spec in specs:
        sns = {sn for sn in _get_sns_from_spec(spec)}
        if sns:
            expanded.update(sns)
        else:
            # maybe the spec is a specific serial-number?
            if get(spec):
                expanded.add(spec)
            else:
                log.d('unknown spec:', spec)
    return expanded
Beispiel #17
0
def _device_change_callback(info):
    """
    Called when librealsense detects a device change (see query())
    """
    global _device_by_sn
    new_device_by_sn = dict()
    for sn, dev in _device_by_sn.items():
        if info.was_removed(dev):
            log.d('device removed:', sn)
        else:
            new_device_by_sn[sn] = dev
    for dev in info.get_new_devices():
        if dev.is_update_device():
            sn = dev.get_info(rs.camera_info.firmware_update_id)
        else:
            sn = dev.get_info(rs.camera_info.serial_number)
        log.d('device added:', dev)
        new_device_by_sn[sn] = dev
    _device_by_sn = new_device_by_sn
Beispiel #18
0
 def __init__( self, sn, dev ):
     self._sn = sn
     self._dev = dev
     self._name = None
     if dev.supports( rs.camera_info.name ):
         self._name = dev.get_info( rs.camera_info.name )
     self._product_line = None
     if dev.supports( rs.camera_info.product_line ):
         self._product_line = dev.get_info( rs.camera_info.product_line )
     self._physical_port = dev.supports( rs.camera_info.physical_port ) and dev.get_info( rs.camera_info.physical_port ) or None
     self._usb_location = _get_usb_location( self._physical_port )
     self._port = None
     if acroname:
         try:
             self._port = _get_port_by_loc( self._usb_location )
         except Exception as e:
             log.e( 'Failed to get device port:', e )
             log.d( '    physical port is', self._physical_port )
             log.d( '    USB location is', self._usb_location )
     self._removed = False
Beispiel #19
0
def connect( spec = None ):
    """
    Connect to the hub. Raises RuntimeError on failure
    """

    global hub
    if not hub:
        hub = brainstem.stem.USBHub3p()

    if spec:
        specs = [spec]
    else:
        specs = discover()
        spec = specs[0]

    result = hub.connectFromSpec( spec )
    if result != brainstem.result.Result.NO_ERROR:
        raise RuntimeError( "failed to connect to acroname (result={})".format( result ))
    elif len(specs) > 1:
        log.d( 'connected to', spec )
Beispiel #20
0
def log_settings_differences( data ):
    global depth_sensor, sd
    depth_sensor.set_option(rs.option.visual_preset, int(rs.l500_visual_preset.low_ambient_light))
    actual_data = str( sd.serialize_json() )
    data_dict = json_to_dict( data )
    actual_data_dict = json_to_dict( actual_data )
    log.debug_indent()
    try:
        # logging the differences in the settings between the expected and the actual values
        for key in actual_data_dict.keys():
            if key not in data_dict:
                log.d( "New setting added to json:", key)
            elif "Visual Preset" in key or "Temperature" in key or "temperature" in key:
                # the line regarding the visual preset will always be different because we load 1 from data but set it to
                # 3 for low ambient. Also all lines regarding temperatures depend on the camera and don't affect the preset
                continue
            elif data_dict[ key ] != actual_data_dict[ key ]:
                log.d( key, "was expected to have value of", data_dict[ key ],
                       "but actually had value of", actual_data_dict[ key ])
    finally:
        log.debug_unindent()
Beispiel #21
0
def enable_only( serial_numbers, recycle = False, timeout = 5 ):
    """
    Enable only the devices corresponding to the given serial-numbers. This can work either
    with or without Acroname: without, the devices will simply be HW-reset, but other devices
    will still be present.

    NOTE: will raise an exception if any SN is unknown!

    :param serial_numbers: A collection of serial-numbers to enable - all others' ports are
                           disabled and will no longer be usable!
    :param recycle: If False, the devices will not be reset if they were already enabled. If
                    True, the devices will be recycled by disabling the port, waiting, then
                    re-enabling
    :param timeout: The maximum seconds to wait to make sure the devices are indeed online
    """
    if acroname:
        #
        ports = [ get_port( sn ) for sn in serial_numbers ]
        #
        if recycle:
            #
            log.d( 'recycling ports via acroname:', ports )
            #
            acroname.disable_ports( acroname.ports() )
            _wait_until_removed( serial_numbers, timeout = timeout )
            #
            acroname.enable_ports( ports )
            #
        else:
            #
            acroname.enable_ports( ports, disable_other_ports = True )
        #
        _wait_for( serial_numbers, timeout = timeout )
        #
    elif recycle:
        #
        hw_reset( serial_numbers )
        #
    else:
        log.d( 'no acroname; ports left as-is' )
Beispiel #22
0
def set_env_vars( env_vars ):
    """
    We want certain environment variables set when we get here. We assume they're not set.

    However, it is impossible to change the current running environment to see them. Instead, we rerun ourselves
    in a child process that inherits the environment we set.

    To do this, we depend on a specific argument in sys.argv that tells us this is the rerun (meaning child
    process). When we see it, we assume the variables are set and don't do anything else.

    For this to work well, the environment variable requirement (set_env_vars call) should appear as one of the
    first lines of the test.

    :param env_vars: A dictionary where the keys are the name of the environment variable and the values are the
        wanted values in string form (environment variables must be strings)
    """
    if sys.argv[-1] != 'rerun':
        log.d( 'environment variables needed:', env_vars )
        for env_var, val in env_vars.items():
            os.environ[env_var] = val
        cmd = [sys.executable]
        if 'site' not in sys.modules:
            #     -S     : don't imply 'import site' on initialization
            cmd += ["-S"]
        if sys.flags.verbose:
            #     -v     : verbose (trace import statements)
            cmd += ["-v"]
        cmd += sys.argv  # --debug, or any other args
        cmd += ["rerun"]
        log.d( 'running:', cmd )
        p = subprocess.run( cmd, stderr=subprocess.PIPE, universal_newlines=True )
        sys.exit( p.returncode )
    log.d( 'rerun detected' )
    sys.argv = sys.argv[:-1]  # Remove the rerun
Beispiel #23
0
def find_includes(filepath, filelist=set()):
    """
    Recursively searches a .cpp file for #include directives and returns
    a set of all of them.
    :return: a list of all includes found
    """
    filedir = os.path.dirname(filepath)
    try:
        log.debug_indent()
        for include_line in file.grep(r'^\s*#\s*include\s+("(.*)"|<(.*)>)\s*$',
                                      filepath):
            m = include_line['match']
            index = include_line['index']
            include = find_include(
                m.group(2), filedir) or find_include_in_dirs(
                    m.group(2)) or find_include_in_dirs(m.group(3))
            if include:
                if include in filelist:
                    log.d(m.group(0), '->', include, '(already processed)')
                else:
                    log.d(m.group(0), '->', include)
                    filelist.add(include)
                    filelist = find_includes(include, filelist)
            else:
                log.d('not found:', m.group(0))
    finally:
        log.debug_unindent()
    return filelist
Beispiel #24
0
def _wait_for(serial_numbers, timeout=5):
    """
    Wait until the given serial numbers are all online

    :param serial_numbers: A collection of serial-numbers to wait for
    :param timeout: Number of seconds of maximum wait time
    :return: True if all have come online; False if timeout was reached
    """
    did_some_waiting = False
    #
    # In Linux, we don't have an active notification mechanism - we query devices every 5 seconds
    # (see POLLING_DEVICES_INTERVAL_MS) - so we add extra timeout
    if timeout and platform.system() == 'Linux':
        timeout += 5
    #
    while True:
        #
        have_all_devices = True
        enabled_sns = enabled()
        for sn in serial_numbers:
            if sn not in enabled_sns:
                have_all_devices = False
                break
        #
        if have_all_devices:
            if did_some_waiting:
                # Wait an extra second, just in case -- let the devices properly power up
                #log.d( 'all devices powered up' )
                time.sleep(1)
            return True
        #
        if timeout <= 0:
            if did_some_waiting:
                log.d('timed out')
            return False
        timeout -= 1
        time.sleep(1)
        did_some_waiting = True
Beispiel #25
0
def subprocess_run(cmd, stdout = None):
    log.d( 'running:', cmd )
    handle = None
    try:
        log.debug_indent()
        if stdout  and  stdout != subprocess.PIPE:
            handle = open( stdout, "w" )
            stdout = handle
        rv = subprocess.run( cmd,
                             stdout = stdout,
                             stderr = subprocess.STDOUT,
                             universal_newlines = True,
                             check = True)
        result = rv.stdout
        if not result:
            result = []
        else:
            result = result.split( '\n' )
        return result
    finally:
        if handle:
            handle.close()
        log.debug_unindent()
Beispiel #26
0
def query(monitor_changes=True):
    """
    Start a new LRS context, and collect all devices
    :param monitor_changes: If True, devices will update dynamically as they are removed/added
    """
    global rs
    if not rs:
        return
    #
    # Before we can start a context and query devices, we need to enable all the ports
    # on the acroname, if any:
    if acroname:
        if not acroname.hub:
            acroname.connect()  # MAY THROW!
            acroname.enable_ports(
                sleep_on_change=5)  # make sure all connected!
    #
    # Get all devices, and store by serial-number
    global _device_by_sn, _context, _port_to_sn
    _context = rs.context()
    _device_by_sn = dict()
    try:
        log.d('discovering devices ...')
        log.debug_indent()
        for retry in range(3):
            try:
                devices = _context.query_devices()
                break
            except RuntimeError as e:
                log.d('FAILED to query devices:', e)
                if retry > 1:
                    log.e('FAILED to query devices', retry + 1, 'times!')
                    raise
                else:
                    time.sleep(1)
        for dev in devices:
            # The FW update ID is always available, it seems, and is the ASIC serial number
            # whereas the Serial Number is the OPTIC serial number and is only available in
            # non-recovery devices. So we use the former...
            sn = dev.get_info(rs.camera_info.firmware_update_id)
            device = Device(sn, dev)
            _device_by_sn[sn] = device
            log.d(
                '... port {}:'.format(device.port is None and '?'
                                      or device.port), sn, dev)
    finally:
        log.debug_unindent()
    #
    if monitor_changes:
        _context.set_devices_changed_callback(_device_change_callback)
def test_option_changes(sensor):
    options = sensor.get_supported_options()
    for option in options:
        try:
            if sensor.is_option_read_only(option):
                continue
            old_value = sensor.get_option(option)
            range = sensor.get_option_range(option)
            new_value = range.min
            if old_value == new_value:
                new_value = range.max
            if not log.d(str(option), old_value, '->', new_value):
                test.info(str(option), new_value, persistent=True)
            set_new_value(sensor, option, new_value)
            sensor.set_option(option, old_value)
        except:
            test.unexpected_exception()
            break
        finally:
            test.reset_info(persistent=True)
Beispiel #28
0
def _device_change_callback( info ):
    """
    Called when librealsense detects a device change (see query())
    """
    global _device_by_sn
    for device in _device_by_sn.values():
        if device.enabled  and  info.was_removed( device.handle ):
            log.d( 'device removed:', device.serial_number )
            device._removed = True
    for handle in info.get_new_devices():
        if handle.is_update_device():
            sn = handle.get_info( rs.camera_info.firmware_update_id )
        else:
            sn = handle.get_info( rs.camera_info.serial_number )
        log.d( 'device added:', handle )
        if sn in _device_by_sn:
            _device_by_sn[sn]._removed = False
        else:
            log.d( 'New device detected!?' )   # shouldn't see new devices...
            _device_by_sn[sn] = Device( sn, handle )
Beispiel #29
0
depth_options = depth_sensor.get_supported_options()
color_options = color_sensor.get_supported_options()

test.start("Checking for frame drops when setting any option")

for option in depth_options:
    try:
        if depth_sensor.is_option_read_only(option):
            continue
        old_value = depth_sensor.get_option(option)
        range = depth_sensor.get_option_range(option)
        new_value = range.min
        if old_value == new_value:
            new_value = range.max
        if not log.d(str(option), old_value, '->', new_value):
            test.info(str(option), new_value, persistent=True)
        set_new_value(depth_sensor, option, new_value)
        depth_sensor.set_option(option, old_value)
    except:
        test.unexpected_exception()
        test.abort()
    finally:
        test.reset_info(persistent=True)

for option in color_options:
    try:
        if color_sensor.is_option_read_only(option):
            continue
        new_value = color_sensor.get_option_range(option).min
        set_new_value(color_sensor, option, new_value)
Beispiel #30
0

# find the update tool exe
fw_updater_exe = None
for tool in file.find(repo.build, '(^|/)rs-fw-update.exe$'):
    fw_updater_exe = os.path.join(repo.build, tool)
if not fw_updater_exe:
    log.f("Could not find the update tool file (rs-fw-update.exe)")

devices.query(monitor_changes=False)
sn_list = devices.all()
# acroname should ensure there is always 1 available device
if len(sn_list) != 1:
    log.f("Expected 1 device, got", len(sn_list))
device = devices.get_first(sn_list).handle
log.d('found:', device)
product_line = device.get_info(rs.camera_info.product_line)
log.d('product line:', product_line)

###############################################################################
#
test.start("Update FW")
# check if recovery. If so recover
recovered = False
if device.is_update_device():
    log.d("recovering device ...")
    try:
        # TODO: this needs to improve for L535
        image_name = product_line[:-2] + "XX_FW_Image-"
        image_mask = '(^|/)' + image_name + '(\d+\.){4}bin$'
        image_file = None