# Saleae Automation API > Automate Saleae Logic 2 captures, exports, and analysis. For Saleae Logic Analyzers only (not Logic MSO). ## Guides ## Getting Started ### Installing the Python Automation API package To get started, you will need the latest build of the Logic 2 Software (2.4.0+), the logic2-automation (1.0.0+) python package, and Python 3.8, 3.9, or 3.10. First, let's install the logic2-automation package: ```bash pip install logic2-automation ``` ### Launching Logic2 The automation interface can be enabled in the software UI. Open the preferences dialog from the main menu, and scroll to the bottom. [Image: Automation server UI] When the checkbox is checked, the automation server will start running in the Logic 2 software on the default port, 10430. ### Using the Python Automation API Next, let's run a simple example. You don't need to have a device connected for this. This example uses a demo device, if you would like to use a connected device follow the steps [here](#finding-the-serial-number-device-id-of-a-device) to find your device's serial number and replace the demo value in the example. Create a new python file called `saleae_example.py`, and paste in these contents: ```python from saleae import automation import os import os.path from datetime import datetime ## Connect to the running Logic 2 Application on port `10430`. ## Alternatively you can use automation.Manager.launch() to launch a new Logic 2 process - see ## the API documentation for more details. ## Using the `with` statement will automatically call manager.close() when exiting the scope. If you ## want to use `automation.Manager` outside of a `with` block, you will need to call `manager.close()` manually. with automation.Manager.connect(port=10430) as manager: # Configure the capturing device to record on digital channels 0, 1, 2, and 3, # with a sampling rate of 10 MSa/s, and a logic level of 3.3V. # The settings chosen here will depend on your device's capabilities and what # you can configure in the Logic 2 UI. device_configuration = automation.LogicDeviceConfiguration( enabled_digital_channels=[0, 1, 2, 3], digital_sample_rate=10_000_000, digital_threshold_volts=3.3, ) # Record 5 seconds of data before stopping the capture capture_configuration = automation.CaptureConfiguration( capture_mode=automation.TimedCaptureMode(duration_seconds=5.0) ) # Start a capture - the capture will be automatically closed when leaving the `with` block # Note: The serial number 'F4241' is for the Logic Pro 16 demo device. # To use a real device, you can: # 1. Omit the `device_id` argument. Logic 2 will choose the first real (non-simulated) device. # 2. Use the serial number for your device. See the "Finding the Serial Number # of a Device" section for information on finding your device's serial number. with manager.start_capture( device_id='F4241', device_configuration=device_configuration, capture_configuration=capture_configuration) as capture: # Wait until the capture has finished # This will take about 5 seconds because we are using a timed capture mode capture.wait() # Add an analyzer to the capture # Note: The simulator output is not actual SPI data spi_analyzer = capture.add_analyzer('SPI', label=f'Test Analyzer', settings={ 'MISO': 0, 'Clock': 1, 'Enable': 2, 'Bits per Transfer': '8 Bits per Transfer (Standard)' }) # Store output in a timestamped directory output_dir = os.path.join(os.getcwd(), f'output-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}') os.makedirs(output_dir) # Export analyzer data to a CSV file analyzer_export_filepath = os.path.join(output_dir, 'spi_export.csv') capture.export_data_table( filepath=analyzer_export_filepath, analyzers=[spi_analyzer] ) # Export raw digital data to a CSV file capture.export_raw_data_csv(directory=output_dir, digital_channels=[0, 1, 2, 3]) # Finally, save the capture to a file capture_filepath = os.path.join(output_dir, 'example_capture.sal') capture.save_capture(filepath=capture_filepath) ``` With the software is running, and the automation interface enabled (as shown above), run the script: ```bash python saleae_example.py ``` There you have it! Take a look at the documentation for Manager and Capture to see how the functionality all works! Also, for most automated applications, you won't want to start the software manually. See [this section](launching-logic2) for more information about different ways to launch the Logic software. ### Finding the Serial Number (Device Id) of a Device To find the serial number of a connected device, open capture info sidebar and click the device dropdown in the top right: [Image: Device info] If the device you want the serial number for is not selected, select it. Then click "Device Info" - this will open a popup with information about your device, including its serial number. [Image: Device serial number] You can copy the serial number from here and use it in your Python script where a "device_id" is required. ### Versioning The `saleae.proto` file contains a version (`major.minor.patch`). It can be found in the file header, and also in the `ThisApiVersion` enum. When generating language bindings, you can get the version of the .proto that was used through the protobuf `ThisApiVersion` enum - `THIS_API_VERSION_MAJOR`, `THIS_API_VERSION_MINOR`, and `THIS_API_VERSION_PATCH`. The version of the .proto file that the server is using can be retrieved using the `GetAppInfo` gRPC method, or the `Manager.get_app_info()` call in the Python API. * For a given major version, the API strives to be forward and backwards compatible. * The major version will change when: * There are any breaking changes * The minor version will change when: * New features are added * Additions are made to the existing API * The patch version will change when: * There are fixes to the API When implementing a client that uses the gRPC API directly, it is recommended to always retrieve the api version via GetAppInfo to validate that the major version is the same, and that the minor version is not older than the client. The Python API does this automatically on creation of the Manager object. ### Headless on Linux We do not currently support running Logic 2 in a headless mode, but it is possible to run Logic 2 in headless Linux environments using XVFB. The specifics for your environment may differ, but on Ubuntu 20.04 we have had success with the following setup. Install xvfb and other depdendencies: ```bash sudo apt install xvfb libatk1.0-0 libatk-bridge2.0-0 libgtk-3-0 libgbm1 ``` Run Logic 2: ```bash xvfb-run path/to/Logic-2.4.0.AppImage ``` ### Troubleshooting #### Failure during install due to `ModuleNotFoundError: No module named 'hatchling'` `logic2-automation` is packaged as a source distribution and built locally on install using `hatchling`. If you are building without isolation (for example, `pip install --no-build-isolation logic2-automation`) and you don't have `hatchling` installed, you will see this error. If you can't install with isolation, you can install `hatchling` (example: `pip install hatchling`) in your local environment to resolve the issue. #### Failure when importing saleae.automation / saleae.grpc If you see an error like this when you import from `saleae.automation`, it may be a protobuf/grpc version incompatibility. This can happen when you upgrade protobuf and/or grpc after installing `logic2-automation`. ```text TypeError: Descriptors cannot not be created directly. If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc >= 3.19.0. If you cannot immediately regenerate your protos, some other possible workarounds are: 1. Downgrade the protobuf package to 3.20.x or lower. 2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will use pure-Python parsing and will be much slower). ``` You can regenerate the protobuf/grpc files by reinstalling `logic2-automation`: ```bash pip install --force-reinstall logic2-automation ``` #### Can't find a solution? Contact us at https://contact.saleae.com/hc/en-us/requests/new ## Launching the Logic 2 Software and Starting the Socket Interface The software can be launched with the automation server enabled with the following commands: ```bash ## windows cmd Logic.exe --automation ## Windows powershell .\Logic.exe --automation ## MacOS ./Logic2/Contents/MacOS/Logic --automation ## Linux ./Logic-2.4.0-master.AppImage --automation ## By default, the gRPC server port number is 10430. However, it can be set with --automationPort N ## Note: When using --automationPort, you will still need to pass --automation to enable the gRPC server. ## Example: Logic.exe --automation --automationPort 10500 ``` Note, the command line argument needs to be set in order for the automation interface to be enabled by default. Additionally, the automation interface can be manually enabled in the UI by following the instructions in the [Getting Started](getting-started) guide. ## Errors The Logic 2 Automation Interface will return errors in certain situations. These errors fall into two main categories: 1. Errors produced by misuse of the API. These errors will contained detailed information about exactly why the command failed, and in some cases, list out what parameter was invalid, as well as the valid options. Be sure to read each error message closely! If these errors occur in production, it may mean there are still bugs in your code. These should not be handled in code. 2. Occasional errors while recording due to USB connectivity problems. These are rare errors, but they can occur at random - like if another USB device consumes a spike of bandwidth, causing the logic analyzer stream buffer to overflow, stopping the capture. We recommend that the developer handle these errors, and restart the capture as appropriate. You will want to catch `CaptureError` errors raised by `start_capture`, `stop`, and `wait`. If an error occurs during the capture start process, then `start_capture` will raise an error. If an error occurs during the capture, for example if the software wasn’t able to receive data over USB fast enough, then the capture will end prematurely. However, the python client won’t be aware of this until stop or wait is called, at which point `CaptureError` will be raised. If any of these commands raise the `CaptureError` exception, we recommend simply starting a new capture. if `stop` or `wait` raise the error, be sure to dispose of the capture before starting the next one. - `SaleaeError` - `UnknownError` - `InternalServerError` - `InvalidRequestError` - `LoadCaptureFailedError` - `ExportError` - `MissingDeviceError` - `CaptureError` - `DeviceError` - `OutOfMemoryError` ## API Reference ### saleae.automation Automation API for controlling the Saleae Logic 2 software. #### `Version` **Attributes:** | Name | Type | Description | |------|------|-------------| | `major` | `int` | | | `minor` | `int` | | | `patch` | `int` | | **Methods:** ##### `__init__(major: int, minor: int, patch: int) -> None` #### `AppInfo` Logic 2 Application Information **Attributes:** | Name | Type | Description | |------|------|-------------| | `api_version` | `Version` | | | `app_version` | `str` | | | `app_pid` | `int` | | **Methods:** ##### `__init__(api_version: Version, app_version: str, app_pid: int) -> None` #### `DeviceType` **Attributes:** | Name | Type | Description | |------|------|-------------| | `LOGIC` | | | | `LOGIC_4` | | | | `LOGIC_8` | | | | `LOGIC_16` | | | | `LOGIC_PRO_8` | | | | `LOGIC_PRO_16` | | | #### `DeviceDesc` **Attributes:** | Name | Type | Description | |------|------|-------------| | `device_id` | `str` | | | `device_type` | `DeviceType` | | | `is_simulation` | `bool` | | **Methods:** ##### `__init__(device_id: str, device_type: DeviceType, is_simulation: bool) -> None` #### `GlitchFilterEntry` Represents the glitch filter specifications for a single digital channel **Attributes:** | Name | Type | Description | |------|------|-------------| | `channel_index` | `int` | | | `pulse_width_seconds` | `float` | | **Methods:** ##### `__init__(channel_index: int, pulse_width_seconds: float) -> None` #### `LogicDeviceConfiguration` Represents the capture configuration for one of the following devices: **Attributes:** | Name | Type | Description | |------|------|-------------| | `enabled_analog_channels` | `List[int]` | | | `enabled_digital_channels` | `List[int]` | | | `analog_sample_rate` | `Optional[int]` | | | `digital_sample_rate` | `Optional[int]` | | | `digital_threshold_volts` | `Optional[float]` | | | `glitch_filters` | `List[GlitchFilterEntry]` | | **Methods:** ##### `__init__(enabled_analog_channels: List[int] = list(), enabled_digital_channels: List[int] = list(), analog_sample_rate: Optional[int] = None, digital_sample_rate: Optional[int] = None, digital_threshold_volts: Optional[float] = None, glitch_filters: List[GlitchFilterEntry] = list()) -> None` #### `DigitalTriggerType` **Attributes:** | Name | Type | Description | |------|------|-------------| | `RISING` | | | | `FALLING` | | | | `PULSE_HIGH` | | | | `PULSE_LOW` | | | #### `DigitalTriggerLinkedChannelState` **Attributes:** | Name | Type | Description | |------|------|-------------| | `LOW` | | | | `HIGH` | | | #### `DigitalTriggerLinkedChannel` Represents a digital channel that must be either high or low while the trigger event (edge or pulse) is active **Attributes:** | Name | Type | Description | |------|------|-------------| | `channel_index` | `int` | | | `state` | `DigitalTriggerLinkedChannelState` | | **Methods:** ##### `__init__(channel_index: int, state: DigitalTriggerLinkedChannelState) -> None` #### `DigitalTriggerCaptureMode` This class represents the Digital Trigger Settings, when using start_capture with a digital trigger. Note: When using this mode, the wait() function will wait until the trigger is found and the post-trigger recording length is complete and the capture has ended. **Attributes:** | Name | Type | Description | |------|------|-------------| | `trigger_type` | `DigitalTriggerType` | | | `trigger_channel_index` | `int` | | | `min_pulse_width_seconds` | `Optional[float]` | | | `max_pulse_width_seconds` | `Optional[float]` | | | `linked_channels` | `List[DigitalTriggerLinkedChannel]` | | | `trim_data_seconds` | `Optional[float]` | | | `after_trigger_seconds` | `Optional[float]` | | **Methods:** ##### `__init__(trigger_type: DigitalTriggerType, trigger_channel_index: int, min_pulse_width_seconds: Optional[float] = None, max_pulse_width_seconds: Optional[float] = None, linked_channels: List[DigitalTriggerLinkedChannel] = list(), trim_data_seconds: Optional[float] = None, after_trigger_seconds: Optional[float] = None) -> None` #### `TimedCaptureMode` This class represents the capture settings when a simple timer mode is used. Note: when using this mode, the wait() function will wait until the specified duration is recorded and the capture has ended. **Attributes:** | Name | Type | Description | |------|------|-------------| | `duration_seconds` | `float` | | | `trim_data_seconds` | `Optional[float]` | | **Methods:** ##### `__init__(duration_seconds: float, trim_data_seconds: Optional[float] = None) -> None` #### `ManualCaptureMode` When this is used, a capture must be triggered/stopped manually. Note: use the stop() command to stop the capture. The wait() function will return an error. **Attributes:** | Name | Type | Description | |------|------|-------------| | `trim_data_seconds` | `Optional[float]` | | **Methods:** ##### `__init__(trim_data_seconds: Optional[float] = None) -> None` #### `CaptureConfiguration` The top-level capture configuration provided to the start_capture function. **Attributes:** | Name | Type | Description | |------|------|-------------| | `buffer_size_megabytes` | `Optional[int]` | | | `capture_mode` | `CaptureMode` | | The capture mode. This can be one of the following: | **Methods:** ##### `__init__(buffer_size_megabytes: Optional[int] = None, capture_mode: CaptureMode = ManualCaptureMode()) -> None` #### `Manager` Manager is the main class for interacting with the Logic 2 software. **Attributes:** | Name | Type | Description | |------|------|-------------| | `logic2_process` | | | | `channel` | | | | `stub` | `saleae_pb2_grpc.ManagerStub` | :meta private: | **Methods:** ##### `__init__(*, port: int, address: str = _DEFAULT_GRPC_ADDRESS, connect_timeout_seconds: Optional[float] = None, grpc_channel_arguments: Optional[List[Tuple[str, Any]]] = None, logic2_process: Optional[subprocess.Popen] = None)` It is recommended that you use Manager.launch() or Manager.connect() instead of using __init__ directly. Create an instance of the Manager class, and connect to the Logic 2 software. This library currently assumes the Logic 2 software is running on the same machine, and will attempt to connect to 127.0.0.1. In the future, we'll add support for supplying an IP address, as well as functions to help launch local copies of the application. Manager.close() is called. - **port**: Port number. By default, Logic 2 uses port 10430. - **address**: Address to connect to. - **connect_timeout_seconds**: Number of seconds to attempt to connect to gRPC server, after which an exception will be thrown. - **grpc_channel_arguments**: A set of arguments to pass through to gRPC. - **logic2_process**: Process object for Logic2 if launched from Python. The process will be shutdown automatically when ##### @classmethod `launch(application_path: Optional[Union[Path, str]] = None, connect_timeout_seconds: Optional[float] = None, grpc_channel_arguments: Optional[List[Tuple[str, Any]]] = None, port: Optional[int] = None) -> Manager` Launch the Logic2 application and shut it down when the returned Manager is closed. a locally installed copy of Logic2 will be searched for. - **application_path**: The path to the Logic2 binary to run. If not specified, - **connect_timeout_seconds**: See __init__ - **grpc_channel_arguments**: See __init__ - **port**: Port to use for the gRPC server. If not specified, 10430 will be used. ##### @classmethod `connect(*, address: str = _DEFAULT_GRPC_ADDRESS, port: int = _DEFAULT_GRPC_PORT, connect_timeout_seconds: Optional[float] = None, grpc_channel_arguments: Optional[List[Tuple[str, Any]]] = None) -> Manager` Connect to an existing instance of Logic 2. - **port**: Port number. By default, Logic 2 uses port 10430. - **address**: Address to connect to. - **connect_timeout_seconds**: See __init__ - **grpc_channel_arguments**: See __init__ ##### `get_app_info() -> AppInfo` Get information about the connected Logic 2 instance. - **Returns**: AppInfo object for the connected Logic 2 instance. ##### `close()` Close connection to Saleae backend, and shut it down if it was created by Manager. ##### `get_devices(*, include_simulation_devices: bool = False) -> List[DeviceDesc]` Returns a list of connected devices. Use this to find the device id of the attached devices. - **include_simulation_devices**: If True, the return value will also include simulation devices. This can be useful for testing without a physical device. ##### `start_capture(*, device_configuration: DeviceConfiguration, device_id: Optional[str] = None, capture_configuration: Optional[CaptureConfiguration] = None) -> Capture` Start a new capture All capture settings need to be provided. The existing software settings, like selected device or added analyzers, are ignored. Be sure to catch DeviceError exceptions raised by this function, and handle them accordingly. See the error section of the library documentation. - **device_configuration**: An instance of LogicDeviceConfiguration, complete with enabled channels, sample rates, and more. - **device_id**: The id of device to record with. - **capture_configuration**: The capture configuration, which selects the capture mode: timer, digital trigger, or manual., defaults to None, indicating manual mode. - **Returns**: Capture instance class. Be sure to call either wait() or stop() before trying to save, export, or close the capture. ##### `load_capture(filepath: str) -> Capture` Load a capture. The returned Capture object will be fully loaded (`wait_until_done` not required). Raises: InvalidFileError - **Returns**: Capture instance class. #### `RadixType` **Attributes:** | Name | Type | Description | |------|------|-------------| | `BINARY` | | | | `DECIMAL` | | | | `HEXADECIMAL` | | | | `ASCII` | | | #### `AnalyzerHandle` **Attributes:** | Name | Type | Description | |------|------|-------------| | `analyzer_id` | `int` | | **Methods:** ##### `__init__(analyzer_id: int) -> None` #### `DataTableExportConfiguration` **Attributes:** | Name | Type | Description | |------|------|-------------| | `analyzer` | `AnalyzerHandle` | | | `radix` | `RadixType` | | **Methods:** ##### `__init__(analyzer: AnalyzerHandle, radix: RadixType) -> None` #### `DataTableFilter` **Attributes:** | Name | Type | Description | |------|------|-------------| | `columns` | `List[str]` | | | `query` | `str` | | **Methods:** ##### `__init__(columns: List[str], query: str) -> None` #### `Capture` This class represents a single capture in the Logic 2 software. **Attributes:** | Name | Type | Description | |------|------|-------------| | `manager` | | | | `capture_id` | | | **Methods:** ##### `__init__(manager: saleae.automation.Manager, capture_id: int)` This class cannot be constructed by the user, and is only returned from the Manager class. ##### `add_analyzer(name: str, *, label: Optional[str] = None, settings: Optional[Dict[str, Union[str, int, float, bool]]] = None) -> AnalyzerHandle` Add an analyzer to the capture Note: analyzers already added to a loaded_capture cannot be accessed from the API at this time. - **name**: The name of the Analyzer, as shown in the Logic 2 application add analyzer list. This must match exactly. - **label**: The user editable display string for the analyzer. This will be shown in the analyzer data table export, defaults to None - **settings**: All settings for the analyzer. The keys and values here must exactly match the Analyzer settings as shown in the UI, defaults to None - **Returns**: Returns an AnalyzerHandle ##### `add_high_level_analyzer(extension_directory: str, name: str, *, input_analyzer: AnalyzerHandle, settings: Optional[Dict[str, Union[str, float]]] = None, label: Optional[str] = None) -> AnalyzerHandle` Add a high level analyzer to the capture. Note: high level analyzers already added to a loaded_capture cannot be accessed from the API at this time. - **extension_directory**: The directory of the extension that the HLA is in. - **name**: The name of the HLA, as specifiied in the extension.json of the extension. - **input_analyzer**: Handle to analyzer (added via add_analyzer) to use as input to this HLA. - **settings**: All settings for the analyzer. The keys and values here must match the HLA settings as shown in the HLA class. - **label**: The user editable display string for the high level analyzer. This will be shown in the analyzer data table export. - **Returns**: Returns an AnalyzerHandle ##### `remove_analyzer(analyzer: AnalyzerHandle)` Removes an analyzer from the capture. - **analyzer**: AnalyzerHandle returned by add_analyzer() ##### `remove_high_level_analyzer(high_level_analyzer: AnalyzerHandle)` Removes a high level analyzer from the capture. - **high_level_analyzer**: AnalyzerHandle returned by add_analyzer() ##### `save_capture(filepath: str)` Saves the capture to a .sal file, which can be loaded later either through the UI or with the load_capture() function. - **filepath**: path to the .sal file. Can be absolute, or relative to the Logic 2 software current working directory. ##### `legacy_export_analyzer(filepath: str, analyzer: AnalyzerHandle, radix: RadixType)` Exports the specified analyzer using the analyzer plugin export format, and not the data table format. Use the export_data_table() function to export analyzer results from the data table. - **filepath**: file name and path to export to. Should include the file name and extension, typically .csv or .txt. - **analyzer**: AnalyzerHandle returned from add_analyzer() - **radix**: Display Radix, from the RadixType enumeration. ##### `export_data_table(filepath: str, analyzers: List[Union[AnalyzerHandle, DataTableExportConfiguration]], *, columns: Optional[List[str]] = None, filter: Optional[DataTableFilter] = None, iso8601_timestamp: bool = False)` Exports the Analyzer Data Table We will be adding more options to this in the future, including the query string, specific columns, specific query columns, and more. - **filepath**: The specified output file, including extension, .csv. - **analyzers**: A list of AnalyzerHandles that should be included in the export, returned from add_analyzer() - **columns**: Columns to include in export. - **filter**: Filter to apply to the exported data. - **iso8601_timestamp**: Use this to output wall clock timestamps, instead of capture relative timestamps. Defaults to False. ##### `export_raw_data_csv(directory: str, *, analog_channels: Optional[List[int]] = None, digital_channels: Optional[List[int]] = None, analog_downsample_ratio: int = 1, iso8601_timestamp: bool = False)` Exports raw data to CSV file(s) This produces exactly the same format as used in the Logic 2 software when using the "Export Raw Data" dialog with the "CSV" option selected. Note, the directory parameter is a specific folder that must already exist, and should not include a filename. The export system will produce an analog.csv and/or digital.csv file(s) in that directory. All selected analog channels will be combined into the analog.csv file, and likewise for digital channels and digital.csv If no channels are specified, all channels will be exported. - **directory**: directory path (not including a filename) to where analog.csv and/or digital.csv will be saved. - **analog_channels**: list of analog channels to export, defaults to None - **digital_channels**: list of digital channels to export, defaults to None - **analog_downsample_ratio**: optional analog downsample ratio, useful to help reduce export file sizes where extra analog resolution isn't needed, defaults to 1 - **iso8601_timestamp**: Use this to output wall clock timestamps, instead of capture relative timestamps. Defaults to False. ##### `export_raw_data_binary(directory: str, *, analog_channels: Optional[List[int]] = None, digital_channels: Optional[List[int]] = None, analog_downsample_ratio: int = 1)` Exports raw data to binary files This produces exactly the same format as used in the Logic 2 software when using the "Export Raw Data" dialog with the "binary" option selected. Documentation for the format can be found here: https://support.saleae.com/faq/technical-faq/binary-export-format-logic-2 Note, the directory parameter is a specific folder that must already exist, and should not include a filename. The export system will produce one .bin file for each channel exported. If no channels are specified, all channels will be exported. - **directory**: directory path (not including a filename) to where .bin files will be saved - **analog_channels**: list of analog channels to export, defaults to None - **digital_channels**: list of digital channels to export, defaults to None - **analog_downsample_ratio**: optional analog downsample ratio, useful to help reduce export file sizes where extra analog resolution isn't needed, defaults to 1 ##### `close()` Closes the capture. Once called, do not use this instance. ##### `stop()` Stops the capture. Can be used with any capture mode, but this is recommended for use with ManualCaptureMode. stop() and wait() should never both be used for a single capture. Do not call stop() more than once. stop() should never be called for loaded captures. If an error occurred during the capture (for example, a USB read timeout, or an out of memory error) that error will be raised by this function. Be sure to catch DeviceError exceptions raised by this function, and handle them accordingly. See the error section of the library documentation. ##### `wait()` Waits for the capture to complete. This should only be used with TimedCaptureMode or DigitalTriggerCaptureMode. for TimedCaptureMode, this will wait for the capture duration to complete. For DigitalTriggerCaptureMode, this will wait for the digital trigger to be found and the capture to complete. stop() and wait() should never both be used for a single capture. Do not call wait() more than once. wait() should never be called for loaded captures. Be sure to catch DeviceError exceptions raised by this function, and handle them accordingly. See the error section of the library documentation. ### saleae.automation.errors Error types raised by the Saleae Automation API. #### `SaleaeError` The base class for all Saleae exceptions. Do not catch this directly. #### `UnknownError` This indicates that the error message from the Logic 2 software was not understood by the python library. This could indicate a version mismatch. #### `Logic2AlreadyRunningError` This indicates that there was an instance of Logic 2 already running. #### `IncompatibleApiVersionError` This indicates that the server is running an incompatible API version. This only happens on major version changes. It is recommended to upgrade to the latest release of Logic 2 and the Python API #### `InternalServerError` An unexpected error occurred in the Logic 2 software. Please submit these errors to Saleae support. #### `InvalidRequestError` The socket request was invalid. See exception message for details. #### `LoadCaptureFailedError` Error loading a saved capture. This could indicate that the file does not exist, or the file was saved with a newer version of the Logic 2 software, or that the file was not a valid saved file. Try manually loading the file in the Logic 2 software for more information. #### `ExportError` An error occurred either while exporting raw data, a single protocol analyzer, or the protocol analyzer data table. Check the exception message for more details. #### `MissingDeviceError` The device ID supplied to the start_capture function is not currently attached to the system, or it has not been detected by the software. For general support for device not detected errors, see this support article: https://support.saleae.com/troubleshooting/logic-not-detected #### `CaptureError` The base class for all capture related errors. We recommend all automation applications handle this exception type. Capture failures occur rarely, and for a handful of reasons. We recommend logging the exception message for later troubleshooting. We do not recommend attempting to access or save captures that end in an error. Instead, we recommend starting a new capture. Check the exception message for details. #### `DeviceError` This error represents any device related error while capturing. USB communication or bandwidth errors, missing calibration, device disconnection while recording, and more. Check the exception message for details. #### `OutOfMemoryError` This exception indicates that the capture was automatically terminated because the capture buffer was filled.