Run a BLE scan for a defined interval and return results.
        
        Alternative to :meth:`begin_scan/:meth:`end_scan`. 

        Args:
            timeout (float): time in seconds to run the scanning process for
            interval (int): BLE scan interval, in units of 625us
            window (int): BLE scan window, in units of 625us

        Returns:
            a :class:`ScanResults` object containing the scan results.

def scan_devices(self, devnames, timeout=DEF_TIMEOUT, interval=DEF_SCAN_INTERVAL, window=DEF_SCAN_WINDOW):
        """Run a BLE scan for a defined interval and return results.
        
        Alternative to :meth:`begin_scan/:meth:`end_scan`. 

        Args:
            timeout (float): time in seconds to run the scanning process for
            interval (int): BLE scan interval, in units of 625us
            window (int): BLE scan window, in units of 625us

        Returns:
            a :class:`ScanResults` object containing the scan results.
        """

        # TODO validate params and state
        logger.debug('configuring scan parameters') 
        self.api.ble_cmd_gap_set_scan_parameters(interval, window, 1)
        self._set_state(self._STATE_CONFIGURE_SCAN)
        self.api.ble_cmd_gap_discover(1) # any discoverable devices
        self._wait_for_state(self._STATE_CONFIGURE_SCAN)

        logger.debug('starting scan for devices {}'.format(devnames))
        self.scan_targets = devnames
        self._set_state(self._STATE_SCANNING)
        self._wait_for_state(self._STATE_SCANNING, timeout)

        self._set_state(self._STATE_GAP_END)
        self.api.ble_cmd_gap_end_procedure()
        self._wait_for_state(self._STATE_GAP_END)

        logger.debug('scanning completed')

        return self.scan_responses