1# Copyright (c) 2023-2024 Intel Corporation
2#
3# SPDX-License-Identifier: Apache-2.0
4
5# Sample code showing an external tool Python module helper for Saleae Logic 2
6# compatible logic analyzer.
7# To use it, the Saleae Logic 2 Automation server must be enabled. For more
8# information on it, check
9# https://saleae.github.io/logic2-automation/getting_started.html
10
11import numpy as np
12import tempfile
13
14from pathlib import Path
15from saleae import automation
16from saleae.automation import (CaptureConfiguration, LogicDeviceConfiguration,
17DigitalTriggerCaptureMode, DigitalTriggerType)
18
19def do_collection(device_id, address, port, channel, sample_rate, threshold_volts,
20                  seconds, output_dir):
21    with automation.Manager.connect(address=address, port=port) as manager:
22
23        device_configuration = LogicDeviceConfiguration(
24            enabled_digital_channels=[channel],
25            digital_sample_rate=sample_rate,
26            digital_threshold_volts=threshold_volts,
27        )
28
29        capture_mode = DigitalTriggerCaptureMode(DigitalTriggerType.RISING,
30                                                 channel,
31                                                 after_trigger_seconds=seconds)
32        capture_configuration = CaptureConfiguration(capture_mode=capture_mode)
33
34        with manager.start_capture(
35                device_id=device_id,
36                device_configuration=device_configuration,
37                capture_configuration=capture_configuration) as capture:
38
39            capture.wait()
40
41            capture.export_raw_data_csv(directory=output_dir,
42                                        digital_channels=[channel])
43
44def do_analysis(output_dir):
45    file_name = Path(output_dir) / 'digital.csv'
46    all_data = np.loadtxt(file_name, delimiter=',', skiprows=1, usecols=0)
47
48    # Pre trigger data is negative on CSV
49    non_negative = all_data[all_data >= 0]
50
51    # Last sample is just captured at last moment of capture, not related
52    # to gpio toggle. Discard it
53    data = non_negative[:-1]
54
55    diff = np.diff(data)
56
57    mean = np.mean(diff)
58    std = np.std(diff)
59    var = np.var(diff)
60    minimum = np.min(diff)
61    maximum = np.max(diff)
62    total_time = data[-1]
63
64    return {'mean': mean, 'stddev': std, 'var': var, 'min': minimum,
65            'max': maximum, 'total_time': total_time}, len(diff)
66
67
68# options should be a string of the format:
69# [device-id=<device_id>,]port=<saleae_logic2_server_port>,
70# channel=<channel_number>,sample-rate=<sample-rate>,
71# threshold-volts=<threshold-volts>
72def run(seconds, options):
73    options = [i for p in options.split(',') for i in p.split('=')]
74    options = dict(zip(options[::2], options[1::2]))
75
76    device_id = options.get('device-id')
77    address = str(options.get('address'))
78    port = int(options.get('port'))
79    channel = int(options.get('channel'))
80    sample_rate = int(options.get('sample-rate'))
81    threshold_volts = float(options.get('threshold-volts'))
82
83    with tempfile.TemporaryDirectory() as output_dir:
84        output_dir = tempfile.mkdtemp()
85        # Add one second to ensure all data is captured
86        do_collection(device_id, address, port, channel, sample_rate, threshold_volts,
87                      seconds + 1, output_dir)
88
89    return do_analysis(output_dir)
90