Headless logic2-automation Support

Hello!

When we launched logic2-automation, the API for automating capture, analysis, save, and export from our devices, we embedded the API server directly into the Logic 2 desktop software.

The main reason for this was because much of the necessary application logic to drive the API was only implemented in the GUI application, and in typescript.

Today, we’re releasing a preview of a new, native, headless implementation of the same API. Existing python automation scripts can use this with just one change.

We’re still working on this, but as of right now, it fully implements all the functionality of the existing API for the Logic 8, Logic Pro 8, and Logic Pro 16 devices.

We’re going to start adding Logic MSO support next week, and we think that will be out shortly after.

We’re making this available right now in two different ways:

  • A Python wheel file you can download and install with pip install. The python library is almost unchanged, and it includes a copy of the new automation server binary.
  • A zip file containing the gRPC proto files and the automation server binary. This is for users who have or will consume the the API from other programing languages.

Python Downloads

Note: We don’t provide an Windows-arm64 python Library because a pre-built gRPC library is not available for that platform. There are workarounds for this.

Server Binary Downloads

Requirements

  • Only supports Logic 8, Logic Pro 8, and Logic Pro 16. MSO coming soon. Let us know if you need support for our older devices.
  • Windows: you need to have installed our drivers first. These come with the Logic 2 software.
  • Linux: you need to install the udev rules file first. Our software normally helps you with this.

Documentation

We haven’t updated our public documentation yet. This release is just a few hours old, and we haven’t even merged the PR for it yet. We’ll be working on updating our documentation on docs.saleae.com once we have MSO support shipped. However, our existing documentation mostly applies, with a few changes.

Our existing automation documentation can be found here: Getting Started - Saleae API Documentation

There are only 2 changes to the python interface, and 1 change to the gRPC interface.

First, to use the headless automation API from the python library, you must use the launch class method with the headless=true argument. Otherwise, it will attempt to launch the Logic 2 GUI software. automation.Manager.connect can still be used to connect to the GUI application, or, you can manually launch the automation server binary first and connect to that - no headless argument needed.

Required: Specify headless when using the Python library

# typical usage:
with automation.Manager.launch(headless=True) as manager:

Second, there is a new method, which you can call to enable crash reporting and/or analytics. Both are optional and are disabled by default.
If you experience crashes when using the headless automation API, please turn on crash reporting, repeat the operation, then contact Saleae support.
Analytics are helpful too, since these capture non-crash errors and help us find bugs in the application. Also, it makes us feel better when we can see that all this work is going to good use. Totally optional of course.

manager.set_reporting(analytics=True, crashes=True)

This wraps a matching method in the gRPC proto specification. It’s use is optional.

Getting Started Sample

This example is taken from our public documentation, with the two changes above.

from saleae import automation
import os
import os.path
from datetime import datetime

# launch the headless automation server binary by providing headless=True.
with automation.Manager.launch(headless=True) as manager:

    # Optional: Enable crash reporting and analytics to help Saleae catch issues, both hard crashes and unexpected behavior.
    manager.set_reporting(analytics=True, crashes=True)

    # 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)
5 Likes

Logic MSO support is out now! I created a new post for it here:

That is great news! It fits our use case perfectly, which is using Logic 2 in a CI pipeline.

I am trying to get started with this headless automation server, but the server application immediately crashes with a stack trace at startup. This happens both from Python, and when I download the server zip file and launch the server executable. I am working on Windows 11.

Here is all the command line output:

C:\src\misc\logic_automation_server-windows-x64\automation_server> .\logic_automation_server.exe --version
2.4.45-insider.1
C:\src\misc\logic_automation_server-windows-x64\automation_server> .\logic_automation_server.exe --automation
[2026-09-25 09:22:20.969687] [I] [tid  11504] [main] [saleae_log.cpp:84] flushing log due to SetUnhandledExceptionFilter
[2026-09-25 09:22:20.998071] [C] [tid  11504] [main] [:] Stack trace (most recent call first):
#0  0x00007ff713637861 in cereal::detail::StaticObject<cereal::detail::Versions>::operator=
#1  0x00007ff71364b5ac in cereal::detail::StaticObject<cereal::detail::Versions>::operator=
#2  0x00007ff713675e15 in cereal::detail::StaticObject<cereal::detail::Versions>::operator=
#3  0x00007ff713670c9b in cereal::detail::StaticObject<cereal::detail::Versions>::operator=
#4  0x00007ff713671d91 in cereal::detail::StaticObject<cereal::detail::Versions>::operator=
#5  0x00007ff7134461e3 in  ??
#6  0x00007ff7155dd25b in PyInit_analog_span_adc
#7  0x00007ffa3f21cd86 in BaseThreadInitThunk
#8  0x00007ffa4030caeb in RtlUserThreadStart

C:\src\misc\logic_automation_server-windows-x64\automation_server>

The --help and --version commands are working, but nothing else. I also tried using --no-use-scan, --report-crashes and --report-analytics.

The regular Logic 2.4.46 GUI application is working fine on the same computer.

Do you have an idea what I am doing wrong? Is there a way I can enable more information about what is going wrong?

Thanks for reporting this, and sorry for the trouble with it! It looks like it’s crashing pretty early in the pipeline, probably before --report-crashes is reached. Could you check for crash reports in this directory?

%APPDATA%\LogicAutomation\crashes\reports

That folder might not exist depending on where the crash occurs. If it does exist, please send in one or more *.dmp files to support: Contact Us | Saleae

If there are no *.dmp files, we’ll need to take more steps to force the creation of a dmp file for analysis. We can do that either by setting a registry key to enable local dumps, or by using the Microsoft ProcDump utility. Both are a little annoying to setup, so I hope that the directory above already contains the needed file.

Hi Mark,

There were no crash reports in the %APPDATA%\LogicAutomation\crashes\reports.

I finally figured out the issue, with a little bit of assistance from Claude. I have a %USERPROFILE% directory that contains non-ASCII characters (for instance "C:\Users\ÅsmundØrnesen"), which means that my %APPDATA% path also contains non-ASCII characters. It seems like something in saleae_log.cpp does not properly handle non-ASCII character paths and throws an exception. I guess that is the reason I did not get any crash reports either, since the crash handler can not reach my %APPDATA% directory.

The workaround is to create alternative %USERPROFILE% and %APPDATA% locations that contains only ASCII characters. I simply create "C:\UsersASCII\dummy" and "C:\UsersASCII\dummy\AppData\roaming", and change the %USERPROFILE% and %APPDATA% environment variables in my Python program when launching the automation server. This works well enough for now, even though it is a little bit annoying.

Edit: To be on the safe side, I have overridden USERPROFILE, APPDATA, LOCALAPPDATA, TEMP and TMP. I actually had issues with non-ASCII characters in the TEMP/TMP directory in Logic 1 as well, but that is water under the bridge by now. :slight_smile:

Cheers,

Thanks @endrebsb,

Good catch, and sorry for the trouble with this! You would think that in 2026, software should handle non-ASCII UTF-8 characters reliably…

I used to have an extra user account on my system with non-ASCII characters just to test this. We really need to add regression tests for this since it seems like we manage to break it every few years.

I’ll get this logged, hopefully it will be an easy fix!

Thanks for following up Mark. I am looking forward to the fix.

It caught me a little bit by surprise since I have used Logic 2 for a while without any problems with non-ASCII %USERPROFILE%. So there is something new in Logic Automation Server that is different from Logic 2. I do not really prefer to have non-ASCII user path since it tends to break stuff from time to time (even Matlab…), but Windows+AzureDomain forces me into this corner.

It should be fairly easy to add a regression test for this. I fixed it by making an alternative user directory and overriding the %USERPROFILE% environment variable. So it should be equally simple to break it by making a difficult alternative user directory and overriding %USERPROFILE% (and the others). You do not need an extra user account as long as you can change environment variables.