SCPI-Instrument-Control 2.0.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/CHANGELOG.md +89 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/MANIFEST.in +0 -3
- {scpi_instrument_control-2.0.0/SCPI_Instrument_Control.egg-info → scpi_instrument_control-3.0.0}/PKG-INFO +29 -4
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/README.md +20 -3
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0/SCPI_Instrument_Control.egg-info}/PKG-INFO +29 -4
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/SOURCES.txt +15 -2
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/requires.txt +8 -0
- scpi_instrument_control-3.0.0/examples/README.md +96 -0
- scpi_instrument_control-3.0.0/examples/dialect_override_example.py +59 -0
- scpi_instrument_control-3.0.0/examples/gateway_rest_client.py +71 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/probe_calibration_analysis.py +5 -5
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/report_generation_example.py +5 -5
- scpi_instrument_control-3.0.0/examples/trend_logging_walkthrough.py +52 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/pyproject.toml +9 -1
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/__init__.py +1 -1
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/channel.py +67 -18
- scpi_instrument_control-3.0.0/scpi_control/connection/mock/__init__.py +5 -0
- scpi_instrument_control-2.0.0/scpi_control/connection/mock.py → scpi_instrument_control-3.0.0/scpi_control/connection/mock/base.py +46 -225
- scpi_instrument_control-3.0.0/scpi_control/connection/mock/helpers.py +25 -0
- scpi_instrument_control-3.0.0/scpi_control/connection/mock/lecroy.py +96 -0
- scpi_instrument_control-3.0.0/scpi_control/connection/mock/siglent.py +235 -0
- scpi_instrument_control-3.0.0/scpi_control/connection/mock/tektronix.py +226 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/exceptions.py +6 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_ai_panel.py +2 -8
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/math_channel.py +5 -14
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/measurement.py +66 -15
- scpi_instrument_control-3.0.0/scpi_control/measurement_badges.py +123 -0
- scpi_instrument_control-3.0.0/scpi_control/models.py +613 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/oscilloscope.py +39 -9
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/__init__.py +1 -1
- scpi_instrument_control-3.0.0/scpi_control/report_generator/analysis/__init__.py +1 -0
- scpi_instrument_control-3.0.0/scpi_control/report_generator/analysis/computed_analyzer.py +137 -0
- scpi_instrument_control-3.0.0/scpi_control/report_generator/app.py +109 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/markdown_generator.py +12 -8
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/pdf_generator.py +147 -139
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/analyzer.py +20 -8
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/client.py +134 -91
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/context_builder.py +13 -16
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/daq_analyzer.py +21 -16
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/prompts.py +17 -1
- scpi_instrument_control-3.0.0/scpi_control/report_generator/llm/tools.py +274 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/main_window.py +37 -40
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/report_data.py +48 -21
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/template.py +26 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/utils/waveform_analyzer.py +96 -25
- scpi_instrument_control-3.0.0/scpi_control/report_generator/utils/waveform_loader.py +386 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/ai_analysis_panel.py +22 -3
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/metadata_panel.py +87 -1
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/pdf_preview_dialog.py +5 -2
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/template_manager_dialog.py +29 -0
- scpi_instrument_control-3.0.0/scpi_control/scpi_commands.py +875 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/trigger.py +75 -32
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/waveform.py +61 -208
- scpi_instrument_control-3.0.0/scpi_control/waveform_schema.py +44 -0
- scpi_instrument_control-3.0.0/scpi_control/waveform_transfer.py +370 -0
- scpi_instrument_control-2.0.0/docs/VISUAL_MEASUREMENTS.md +0 -638
- scpi_instrument_control-2.0.0/examples/README.md +0 -254
- scpi_instrument_control-2.0.0/scpi_control/models.py +0 -321
- scpi_instrument_control-2.0.0/scpi_control/report_generator/app.py +0 -38
- scpi_instrument_control-2.0.0/scpi_control/report_generator/utils/waveform_loader.py +0 -316
- scpi_instrument_control-2.0.0/scpi_control/scpi_commands.py +0 -339
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/LICENSE +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/dependency_links.txt +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/entry_points.txt +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/top_level.txt +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/SDS800XHD_Series_ProgrammingGuide_EN11G.pdf +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/01_main_window.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/channel_controls.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/cursors.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/fft_analysis.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/main_window.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/measurements_panel.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/visual_measurements.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/advanced_analysis.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/basic_usage.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/batch_capture.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/continuous_capture.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/data_logger_basic.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/function_generator_basic.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/live_plot.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/measurements.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_advanced_features.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_basic_control.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_gui_test.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_usb_connection.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/simple_capture.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/trigger_based_capture.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/vector_graphics_xy_mode.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/waveform_capture.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment Wide.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment.icns +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment.ico +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment.png +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/analysis.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/automation.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/awg_models.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/awg_output.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/awg_scpi_commands.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/base.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/socket.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/visa_connection.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/daq_models.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/daq_scpi_commands.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/data_logger.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/function_generator.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/app.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/connection_manager.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/daq_worker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/live_view_worker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/main_window.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/utils/validators.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/vnc_window.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/waveform_capture_worker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/channel_control.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/cursor_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_channel_config.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_data_view.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_scan_config.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/data_logger_control.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/error_dialog.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/fft_display.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/math_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_marker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/frequency_marker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/timing_marker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/voltage_marker.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/protocol_decode_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/psu_control.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/reference_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/scope_web_view.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/terminal_widget.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/timebase_control.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/trigger_control.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/vector_graphics_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/visual_measurement_panel.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/waveform_display.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/waveform_display_pg.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/measurement_config.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/power_supply.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/power_supply_output.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decode.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/i2c_decoder.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/spi_decoder.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/uart_decoder.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/psu_data_logger.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/psu_models.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/psu_scpi_commands.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/py.typed +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/reference_waveform.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/base.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/daq_context_builder.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/daq_prompts.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/app_settings.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/criteria.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/plot_style.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/report_options.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/test_types.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/utils/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/utils/image_handler.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/chat_sidebar.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/llm_settings_dialog.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/report_options_dialog.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/screen_capture.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/__main__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/__init__.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/discovery.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/scope.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/sessions.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/stream.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/app.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/compute.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/discovery.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/recorder.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/schemas.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/sessions.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/static/assets/index-0Vpguwg6.js +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/static/assets/index-CyUPLIHk.css +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/static/index.html +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/vector_graphics.py +0 -0
- {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/setup.cfg +0 -0
|
@@ -7,6 +7,95 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.0.0] - 2026-07-17
|
|
11
|
+
|
|
12
|
+
### ⚠️ Breaking Changes
|
|
13
|
+
|
|
14
|
+
- **The report generator's `WaveformData` fields are renamed, and `channel`
|
|
15
|
+
moved from the first constructor argument to the third.** `channel_name`,
|
|
16
|
+
`time_data`, and `voltage_data` are now `channel`, `time`, and `voltage`,
|
|
17
|
+
matching the base class's field order (`time`, `voltage`, `channel`, ...).
|
|
18
|
+
Because the position changed along with the name, positional construction
|
|
19
|
+
such as `WaveformData("CH1", t, v, ...)` does **not** fail with a
|
|
20
|
+
recognizable rename error — it silently assigns `"CH1"` to `time` and
|
|
21
|
+
blows up later with `AttributeError: 'str' object has no attribute
|
|
22
|
+
'shape'`. Construct with keywords (`channel=`, `time=`, `voltage=`) to
|
|
23
|
+
migrate safely. This is a documented public API — see
|
|
24
|
+
[`docs/report-generator/api-reference.md`](docs/report-generator/api-reference.md).
|
|
25
|
+
- **`WaveformData.source` and `WaveformData.description` are removed**, on
|
|
26
|
+
both the library and report waveform types. `WaveformData(..., source="x")`
|
|
27
|
+
now raises `TypeError` instead of silently accepting the keyword.
|
|
28
|
+
- **`WaveformData.timebase` and `WaveformData.voltage_scale` are `None`
|
|
29
|
+
unless an instrument actually reported them**, instead of being derived by
|
|
30
|
+
assuming a 14-division horizontal grid and an 8-division vertical one —
|
|
31
|
+
Siglent's geometry, previously applied to Tektronix and LeCroy captures too
|
|
32
|
+
— with a flat trace given a bare 1.0 V/div. Real acquisitions are
|
|
33
|
+
unaffected: all three vendor backends pass genuine scope values. Code that
|
|
34
|
+
does arithmetic on `timebase`/`voltage_scale` from a *synthetic* waveform
|
|
35
|
+
(a math channel, or hand-built test data) — e.g. `wf.timebase * 1e6` — now
|
|
36
|
+
raises `TypeError` on `None` instead of silently using an invented number.
|
|
37
|
+
Guard with a `None` check, or supply real values.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Tektronix and LeCroy oscilloscope support (core control, waveform
|
|
42
|
+
acquisition, measurements): two more wire dialects (`tektronix`, `lecroy`)
|
|
43
|
+
alongside the existing Siglent legacy/modern pair, auto-detected from
|
|
44
|
+
`*IDN?` via a manufacturer-first routing step. Covers the Tektronix
|
|
45
|
+
TBS1000C Series and 2 Series MSO, and the LeCroy WaveSurfer 3000z and
|
|
46
|
+
WaveRunner 8000 series. See the
|
|
47
|
+
[SCPI Dialects guide](docs/user-guide/scpi-dialects.md) for the full
|
|
48
|
+
per-vendor command tables and known gaps (e.g. LeCroy
|
|
49
|
+
statistics/cursors/holdoff, Tek 16-bit waveform transfer).
|
|
50
|
+
- Tektronix MSO 4/5/6 Series support (MSO44, MSO46, MSO54, MSO56, MSO58,
|
|
51
|
+
MSO58LP, MSO64), including 6- and 8-channel models.
|
|
52
|
+
- Badge-based measurements for the modern Tektronix MSO families, which also
|
|
53
|
+
enables `measure()` on the MSO 2-Series.
|
|
54
|
+
- **Report generator — local-LLM analysis and richer PDFs**
|
|
55
|
+
(`pip install "SCPI-Instrument-Control[report-generator]"`). Everything here
|
|
56
|
+
is local-only — no cloud providers, no API keys.
|
|
57
|
+
- Local-LLM (Ollama) tool calling: the model can call read-only report tools
|
|
58
|
+
to ground its answers, behind a capability gate that no-ops when the local
|
|
59
|
+
model cannot do tool calls.
|
|
60
|
+
- Waveform analysis tools for the model — `analyze_plateaus`, `list_edges`,
|
|
61
|
+
and `analyze_spectrum` — plus `WaveformAnalyzer.calculate_spectrum`.
|
|
62
|
+
- Deterministic no-LLM analysis: a `ComputedAnalyzer` populates per-waveform
|
|
63
|
+
statistics and regions on every report, and composes a summary, findings,
|
|
64
|
+
and recommendations when no LLM wrote them. Reports now attribute their
|
|
65
|
+
summary by source (manual / AI / computed) rather than a bare AI flag.
|
|
66
|
+
- Vector PDF plots: waveform, FFT, and region plots render as scalable vector
|
|
67
|
+
graphics instead of rasterized images.
|
|
68
|
+
- Page framework: a running header/footer and page numbers on every page,
|
|
69
|
+
with section headings kept from stranding at the bottom of a page.
|
|
70
|
+
- Template branding: a template's logo, company name, header/footer text, and
|
|
71
|
+
four brand colours apply to the generated PDF, and a built-in starter
|
|
72
|
+
template can be seeded from the Template Manager.
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- On the Siglent modern dialect, `trigger.holdoff`, measurement statistics,
|
|
77
|
+
cursors, and `channel.unit` now raise `FeatureNotSupportedError` immediately
|
|
78
|
+
instead of writing an unsupported command and timing out
|
|
79
|
+
(`SiglentTimeoutError`). Code that caught the timeout to detect these
|
|
80
|
+
unsupported operations must now catch `FeatureNotSupportedError` instead.
|
|
81
|
+
- Probe-ratio wire format on the legacy and modern dialects now serializes
|
|
82
|
+
floats compactly (`10.0` is sent as `10`), matching how real scopes echo the
|
|
83
|
+
value back.
|
|
84
|
+
- `add_measurement` now validates and case-normalizes its measurement type
|
|
85
|
+
(unknown types raise instead of being sent verbatim to the instrument).
|
|
86
|
+
- Channel numbers are validated against the connected model's channel count
|
|
87
|
+
instead of a fixed 1-4 range. Scopes with fewer than four channels now raise
|
|
88
|
+
`InvalidParameterError` for a channel they do not have, where they
|
|
89
|
+
previously queried it.
|
|
90
|
+
- The report generator's `WaveformData` is now a subclass of
|
|
91
|
+
`scpi_control.waveform.WaveformData` (see Breaking Changes above for the
|
|
92
|
+
field rename and reorder this involved). Report waveforms now inherit the
|
|
93
|
+
library's array-shape validation, and `channel` is now guaranteed to be a
|
|
94
|
+
`str` by the type itself. The loader's explicit `str()` calls at each
|
|
95
|
+
construction site are unchanged and now redundant, not removed — they stay
|
|
96
|
+
as a defensive measure against `np.str_`/`bytes` values handed back at the
|
|
97
|
+
MAT/HDF5 boundary.
|
|
98
|
+
|
|
10
99
|
## [2.0.0] - 2026-07-15
|
|
11
100
|
|
|
12
101
|
### ⚠️ Breaking Changes
|
|
@@ -6,7 +6,6 @@ include pyproject.toml
|
|
|
6
6
|
|
|
7
7
|
# Include user-facing documentation
|
|
8
8
|
recursive-include docs/images *.png *.jpg
|
|
9
|
-
include docs/VISUAL_MEASUREMENTS.md
|
|
10
9
|
include docs/SDS800XHD_Series_ProgrammingGuide_EN11G.pdf
|
|
11
10
|
|
|
12
11
|
# Include resources (logos, icons)
|
|
@@ -23,8 +22,6 @@ recursive-include examples *.md
|
|
|
23
22
|
exclude docs/development/*
|
|
24
23
|
exclude docs/README_SCREENSHOTS.md
|
|
25
24
|
exclude docs/SCREENSHOT_CHECKLIST.md
|
|
26
|
-
exclude docs/CONTRIBUTING.md
|
|
27
|
-
exclude docs/SECURITY.md
|
|
28
25
|
recursive-exclude tests *
|
|
29
26
|
recursive-exclude scripts *
|
|
30
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SCPI-Instrument-Control
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Universal Python library for controlling SCPI-compatible test equipment via Ethernet/LAN. Supports oscilloscopes (Siglent SDS series, generic SCPI scopes), function generators/AWGs (Siglent SDG series, generic SCPI AWGs), and power supplies (Siglent SPD series, generic SCPI PSUs). Features include waveform capture, measurements, FFT analysis, PyQt6 GUI, automated report generation with AI analysis, and comprehensive SCPI command abstraction.
|
|
5
5
|
Author: Robin Mumm
|
|
6
6
|
Maintainer: little-did-I-know
|
|
@@ -64,7 +64,11 @@ Requires-Dist: PyQt6>=6.6.0; extra == "report-generator"
|
|
|
64
64
|
Requires-Dist: Pillow>=10.0.0; extra == "report-generator"
|
|
65
65
|
Requires-Dist: requests>=2.31.0; extra == "report-generator"
|
|
66
66
|
Requires-Dist: reportlab>=4.0.0; extra == "report-generator"
|
|
67
|
+
Requires-Dist: svglib>=1.5.0; extra == "report-generator"
|
|
67
68
|
Requires-Dist: ollama>=0.6.0; extra == "report-generator"
|
|
69
|
+
Requires-Dist: PyMuPDF>=1.23.0; extra == "report-generator"
|
|
70
|
+
Requires-Dist: psutil>=5.9.0; extra == "report-generator"
|
|
71
|
+
Requires-Dist: nvidia-ml-py>=12.0.0; extra == "report-generator"
|
|
68
72
|
Provides-Extra: power-supply-beta
|
|
69
73
|
Provides-Extra: usb
|
|
70
74
|
Requires-Dist: pyvisa>=1.14.0; extra == "usb"
|
|
@@ -89,7 +93,11 @@ Requires-Dist: Pillow>=10.0.0; extra == "all"
|
|
|
89
93
|
Requires-Dist: svgpathtools>=1.6.0; extra == "all"
|
|
90
94
|
Requires-Dist: requests>=2.31.0; extra == "all"
|
|
91
95
|
Requires-Dist: reportlab>=4.0.0; extra == "all"
|
|
96
|
+
Requires-Dist: svglib>=1.5.0; extra == "all"
|
|
92
97
|
Requires-Dist: ollama>=0.6.0; extra == "all"
|
|
98
|
+
Requires-Dist: PyMuPDF>=1.23.0; extra == "all"
|
|
99
|
+
Requires-Dist: psutil>=5.9.0; extra == "all"
|
|
100
|
+
Requires-Dist: nvidia-ml-py>=12.0.0; extra == "all"
|
|
93
101
|
Dynamic: license-file
|
|
94
102
|
|
|
95
103
|
# SCPI Instrument Control
|
|
@@ -694,6 +702,8 @@ built-in mock (`mock: true`) for hardware-free use. The API is documented at
|
|
|
694
702
|
`/docs` (OpenAPI). No authentication in this release — bind to `127.0.0.1`
|
|
695
703
|
(the default) unless your LAN is trusted.
|
|
696
704
|
|
|
705
|
+
Full documentation: [Web Gateway guide](https://little-did-I-know.github.io/SCPI-Instrument-Control/gateway/) — overview, browser UI tour, and the complete REST & WebSocket API reference.
|
|
706
|
+
|
|
697
707
|
- `GET /api/discover` scans the gateway's subnet (or `?cidr=…`) for SCPI
|
|
698
708
|
instruments on port 5025 and lists them with model and dialect — handy when
|
|
699
709
|
DHCP moves your instruments around.
|
|
@@ -895,18 +905,33 @@ See the `examples/` directory for complete working examples:
|
|
|
895
905
|
|
|
896
906
|
## Supported Models
|
|
897
907
|
|
|
898
|
-
### Fully Tested
|
|
908
|
+
### Siglent (Fully Tested)
|
|
899
909
|
|
|
900
910
|
- **SDS800X HD Series**: SDS804X HD, SDS824X HD
|
|
901
911
|
- **SDS1000X-E Series**: SDS1102X-E, SDS1104X-E, SDS1202X-E, SDS1204X-E
|
|
902
912
|
- **SDS2000X Plus Series**: SDS2104X+, SDS2204X+, SDS2354X+
|
|
903
913
|
- **SDS5000X Series**: SDS5034X, SDS5054X, SDS5104X
|
|
904
914
|
|
|
915
|
+
### Tektronix and LeCroy (core control + measurements)
|
|
916
|
+
|
|
917
|
+
- **Tektronix TBS1000C Series**: TBS1102C
|
|
918
|
+
- **Tektronix 2 Series MSO**: MSO24
|
|
919
|
+
- **Tektronix 4 Series MSO**: MSO44, MSO46
|
|
920
|
+
- **Tektronix 5 Series MSO**: MSO54, MSO56, MSO58, MSO58LP
|
|
921
|
+
- **Tektronix 6 Series MSO**: MSO64
|
|
922
|
+
- **LeCroy WaveSurfer 3000z Series**: WaveSurfer 3024z
|
|
923
|
+
- **LeCroy WaveRunner 8000 Series**: WaveRunner 8104
|
|
924
|
+
|
|
925
|
+
All Tektronix MSO models (2/4/5/6 Series) share one command variant and
|
|
926
|
+
support automated measurements — see the [SCPI Dialects guide](https://little-did-I-know.github.io/SCPI-Instrument-Control/user-guide/scpi-dialects/) for the full per-vendor gap list.
|
|
927
|
+
|
|
928
|
+
Command tables were verified command-by-command against the vendor programmer manuals (Tektronix TBS1000C, 2 Series MSO, and 4/5/6 Series MSO/6 Series LPD manuals; the Teledyne LeCroy MAUI Remote Control and Automation Manual) and exercised against a dialect-aware mock; not yet run against real Tektronix or LeCroy hardware.
|
|
929
|
+
|
|
905
930
|
### Compatibility
|
|
906
931
|
|
|
907
|
-
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the `ModelCapability` registry.
|
|
932
|
+
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the `ModelCapability` registry. Unrecognized Tektronix or LeCroy models fall back to a conservative generic profile for that vendor (with a logged warning) rather than being rejected outright.
|
|
908
933
|
|
|
909
|
-
**Note**: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series.
|
|
934
|
+
**Note**: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series (Siglent) and for TBS vs. MSO (2/4/5/6 Series share one variant) (Tektronix).
|
|
910
935
|
|
|
911
936
|
## Contributing
|
|
912
937
|
|
|
@@ -600,6 +600,8 @@ built-in mock (`mock: true`) for hardware-free use. The API is documented at
|
|
|
600
600
|
`/docs` (OpenAPI). No authentication in this release — bind to `127.0.0.1`
|
|
601
601
|
(the default) unless your LAN is trusted.
|
|
602
602
|
|
|
603
|
+
Full documentation: [Web Gateway guide](https://little-did-I-know.github.io/SCPI-Instrument-Control/gateway/) — overview, browser UI tour, and the complete REST & WebSocket API reference.
|
|
604
|
+
|
|
603
605
|
- `GET /api/discover` scans the gateway's subnet (or `?cidr=…`) for SCPI
|
|
604
606
|
instruments on port 5025 and lists them with model and dialect — handy when
|
|
605
607
|
DHCP moves your instruments around.
|
|
@@ -801,18 +803,33 @@ See the `examples/` directory for complete working examples:
|
|
|
801
803
|
|
|
802
804
|
## Supported Models
|
|
803
805
|
|
|
804
|
-
### Fully Tested
|
|
806
|
+
### Siglent (Fully Tested)
|
|
805
807
|
|
|
806
808
|
- **SDS800X HD Series**: SDS804X HD, SDS824X HD
|
|
807
809
|
- **SDS1000X-E Series**: SDS1102X-E, SDS1104X-E, SDS1202X-E, SDS1204X-E
|
|
808
810
|
- **SDS2000X Plus Series**: SDS2104X+, SDS2204X+, SDS2354X+
|
|
809
811
|
- **SDS5000X Series**: SDS5034X, SDS5054X, SDS5104X
|
|
810
812
|
|
|
813
|
+
### Tektronix and LeCroy (core control + measurements)
|
|
814
|
+
|
|
815
|
+
- **Tektronix TBS1000C Series**: TBS1102C
|
|
816
|
+
- **Tektronix 2 Series MSO**: MSO24
|
|
817
|
+
- **Tektronix 4 Series MSO**: MSO44, MSO46
|
|
818
|
+
- **Tektronix 5 Series MSO**: MSO54, MSO56, MSO58, MSO58LP
|
|
819
|
+
- **Tektronix 6 Series MSO**: MSO64
|
|
820
|
+
- **LeCroy WaveSurfer 3000z Series**: WaveSurfer 3024z
|
|
821
|
+
- **LeCroy WaveRunner 8000 Series**: WaveRunner 8104
|
|
822
|
+
|
|
823
|
+
All Tektronix MSO models (2/4/5/6 Series) share one command variant and
|
|
824
|
+
support automated measurements — see the [SCPI Dialects guide](https://little-did-I-know.github.io/SCPI-Instrument-Control/user-guide/scpi-dialects/) for the full per-vendor gap list.
|
|
825
|
+
|
|
826
|
+
Command tables were verified command-by-command against the vendor programmer manuals (Tektronix TBS1000C, 2 Series MSO, and 4/5/6 Series MSO/6 Series LPD manuals; the Teledyne LeCroy MAUI Remote Control and Automation Manual) and exercised against a dialect-aware mock; not yet run against real Tektronix or LeCroy hardware.
|
|
827
|
+
|
|
811
828
|
### Compatibility
|
|
812
829
|
|
|
813
|
-
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the `ModelCapability` registry.
|
|
830
|
+
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the `ModelCapability` registry. Unrecognized Tektronix or LeCroy models fall back to a conservative generic profile for that vendor (with a logged warning) rather than being rejected outright.
|
|
814
831
|
|
|
815
|
-
**Note**: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series.
|
|
832
|
+
**Note**: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series (Siglent) and for TBS vs. MSO (2/4/5/6 Series share one variant) (Tektronix).
|
|
816
833
|
|
|
817
834
|
## Contributing
|
|
818
835
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SCPI-Instrument-Control
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Universal Python library for controlling SCPI-compatible test equipment via Ethernet/LAN. Supports oscilloscopes (Siglent SDS series, generic SCPI scopes), function generators/AWGs (Siglent SDG series, generic SCPI AWGs), and power supplies (Siglent SPD series, generic SCPI PSUs). Features include waveform capture, measurements, FFT analysis, PyQt6 GUI, automated report generation with AI analysis, and comprehensive SCPI command abstraction.
|
|
5
5
|
Author: Robin Mumm
|
|
6
6
|
Maintainer: little-did-I-know
|
|
@@ -64,7 +64,11 @@ Requires-Dist: PyQt6>=6.6.0; extra == "report-generator"
|
|
|
64
64
|
Requires-Dist: Pillow>=10.0.0; extra == "report-generator"
|
|
65
65
|
Requires-Dist: requests>=2.31.0; extra == "report-generator"
|
|
66
66
|
Requires-Dist: reportlab>=4.0.0; extra == "report-generator"
|
|
67
|
+
Requires-Dist: svglib>=1.5.0; extra == "report-generator"
|
|
67
68
|
Requires-Dist: ollama>=0.6.0; extra == "report-generator"
|
|
69
|
+
Requires-Dist: PyMuPDF>=1.23.0; extra == "report-generator"
|
|
70
|
+
Requires-Dist: psutil>=5.9.0; extra == "report-generator"
|
|
71
|
+
Requires-Dist: nvidia-ml-py>=12.0.0; extra == "report-generator"
|
|
68
72
|
Provides-Extra: power-supply-beta
|
|
69
73
|
Provides-Extra: usb
|
|
70
74
|
Requires-Dist: pyvisa>=1.14.0; extra == "usb"
|
|
@@ -89,7 +93,11 @@ Requires-Dist: Pillow>=10.0.0; extra == "all"
|
|
|
89
93
|
Requires-Dist: svgpathtools>=1.6.0; extra == "all"
|
|
90
94
|
Requires-Dist: requests>=2.31.0; extra == "all"
|
|
91
95
|
Requires-Dist: reportlab>=4.0.0; extra == "all"
|
|
96
|
+
Requires-Dist: svglib>=1.5.0; extra == "all"
|
|
92
97
|
Requires-Dist: ollama>=0.6.0; extra == "all"
|
|
98
|
+
Requires-Dist: PyMuPDF>=1.23.0; extra == "all"
|
|
99
|
+
Requires-Dist: psutil>=5.9.0; extra == "all"
|
|
100
|
+
Requires-Dist: nvidia-ml-py>=12.0.0; extra == "all"
|
|
93
101
|
Dynamic: license-file
|
|
94
102
|
|
|
95
103
|
# SCPI Instrument Control
|
|
@@ -694,6 +702,8 @@ built-in mock (`mock: true`) for hardware-free use. The API is documented at
|
|
|
694
702
|
`/docs` (OpenAPI). No authentication in this release — bind to `127.0.0.1`
|
|
695
703
|
(the default) unless your LAN is trusted.
|
|
696
704
|
|
|
705
|
+
Full documentation: [Web Gateway guide](https://little-did-I-know.github.io/SCPI-Instrument-Control/gateway/) — overview, browser UI tour, and the complete REST & WebSocket API reference.
|
|
706
|
+
|
|
697
707
|
- `GET /api/discover` scans the gateway's subnet (or `?cidr=…`) for SCPI
|
|
698
708
|
instruments on port 5025 and lists them with model and dialect — handy when
|
|
699
709
|
DHCP moves your instruments around.
|
|
@@ -895,18 +905,33 @@ See the `examples/` directory for complete working examples:
|
|
|
895
905
|
|
|
896
906
|
## Supported Models
|
|
897
907
|
|
|
898
|
-
### Fully Tested
|
|
908
|
+
### Siglent (Fully Tested)
|
|
899
909
|
|
|
900
910
|
- **SDS800X HD Series**: SDS804X HD, SDS824X HD
|
|
901
911
|
- **SDS1000X-E Series**: SDS1102X-E, SDS1104X-E, SDS1202X-E, SDS1204X-E
|
|
902
912
|
- **SDS2000X Plus Series**: SDS2104X+, SDS2204X+, SDS2354X+
|
|
903
913
|
- **SDS5000X Series**: SDS5034X, SDS5054X, SDS5104X
|
|
904
914
|
|
|
915
|
+
### Tektronix and LeCroy (core control + measurements)
|
|
916
|
+
|
|
917
|
+
- **Tektronix TBS1000C Series**: TBS1102C
|
|
918
|
+
- **Tektronix 2 Series MSO**: MSO24
|
|
919
|
+
- **Tektronix 4 Series MSO**: MSO44, MSO46
|
|
920
|
+
- **Tektronix 5 Series MSO**: MSO54, MSO56, MSO58, MSO58LP
|
|
921
|
+
- **Tektronix 6 Series MSO**: MSO64
|
|
922
|
+
- **LeCroy WaveSurfer 3000z Series**: WaveSurfer 3024z
|
|
923
|
+
- **LeCroy WaveRunner 8000 Series**: WaveRunner 8104
|
|
924
|
+
|
|
925
|
+
All Tektronix MSO models (2/4/5/6 Series) share one command variant and
|
|
926
|
+
support automated measurements — see the [SCPI Dialects guide](https://little-did-I-know.github.io/SCPI-Instrument-Control/user-guide/scpi-dialects/) for the full per-vendor gap list.
|
|
927
|
+
|
|
928
|
+
Command tables were verified command-by-command against the vendor programmer manuals (Tektronix TBS1000C, 2 Series MSO, and 4/5/6 Series MSO/6 Series LPD manuals; the Teledyne LeCroy MAUI Remote Control and Automation Manual) and exercised against a dialect-aware mock; not yet run against real Tektronix or LeCroy hardware.
|
|
929
|
+
|
|
905
930
|
### Compatibility
|
|
906
931
|
|
|
907
|
-
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the `ModelCapability` registry.
|
|
932
|
+
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the `ModelCapability` registry. Unrecognized Tektronix or LeCroy models fall back to a conservative generic profile for that vendor (with a logged warning) rather than being rejected outright.
|
|
908
933
|
|
|
909
|
-
**Note**: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series.
|
|
934
|
+
**Note**: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series (Siglent) and for TBS vs. MSO (2/4/5/6 Series share one variant) (Tektronix).
|
|
910
935
|
|
|
911
936
|
## Contributing
|
|
912
937
|
|
|
@@ -10,7 +10,6 @@ SCPI_Instrument_Control.egg-info/entry_points.txt
|
|
|
10
10
|
SCPI_Instrument_Control.egg-info/requires.txt
|
|
11
11
|
SCPI_Instrument_Control.egg-info/top_level.txt
|
|
12
12
|
docs/SDS800XHD_Series_ProgrammingGuide_EN11G.pdf
|
|
13
|
-
docs/VISUAL_MEASUREMENTS.md
|
|
14
13
|
docs/images/01_main_window.png
|
|
15
14
|
docs/images/channel_controls.png
|
|
16
15
|
docs/images/cursors.png
|
|
@@ -24,7 +23,9 @@ examples/basic_usage.py
|
|
|
24
23
|
examples/batch_capture.py
|
|
25
24
|
examples/continuous_capture.py
|
|
26
25
|
examples/data_logger_basic.py
|
|
26
|
+
examples/dialect_override_example.py
|
|
27
27
|
examples/function_generator_basic.py
|
|
28
|
+
examples/gateway_rest_client.py
|
|
28
29
|
examples/live_plot.py
|
|
29
30
|
examples/measurements.py
|
|
30
31
|
examples/probe_calibration_analysis.py
|
|
@@ -34,6 +35,7 @@ examples/psu_gui_test.py
|
|
|
34
35
|
examples/psu_usb_connection.py
|
|
35
36
|
examples/report_generation_example.py
|
|
36
37
|
examples/simple_capture.py
|
|
38
|
+
examples/trend_logging_walkthrough.py
|
|
37
39
|
examples/trigger_based_capture.py
|
|
38
40
|
examples/vector_graphics_xy_mode.py
|
|
39
41
|
examples/waveform_capture.py
|
|
@@ -55,6 +57,7 @@ scpi_control/exceptions.py
|
|
|
55
57
|
scpi_control/function_generator.py
|
|
56
58
|
scpi_control/math_channel.py
|
|
57
59
|
scpi_control/measurement.py
|
|
60
|
+
scpi_control/measurement_badges.py
|
|
58
61
|
scpi_control/measurement_config.py
|
|
59
62
|
scpi_control/models.py
|
|
60
63
|
scpi_control/oscilloscope.py
|
|
@@ -71,11 +74,18 @@ scpi_control/screen_capture.py
|
|
|
71
74
|
scpi_control/trigger.py
|
|
72
75
|
scpi_control/vector_graphics.py
|
|
73
76
|
scpi_control/waveform.py
|
|
77
|
+
scpi_control/waveform_schema.py
|
|
78
|
+
scpi_control/waveform_transfer.py
|
|
74
79
|
scpi_control/connection/__init__.py
|
|
75
80
|
scpi_control/connection/base.py
|
|
76
|
-
scpi_control/connection/mock.py
|
|
77
81
|
scpi_control/connection/socket.py
|
|
78
82
|
scpi_control/connection/visa_connection.py
|
|
83
|
+
scpi_control/connection/mock/__init__.py
|
|
84
|
+
scpi_control/connection/mock/base.py
|
|
85
|
+
scpi_control/connection/mock/helpers.py
|
|
86
|
+
scpi_control/connection/mock/lecroy.py
|
|
87
|
+
scpi_control/connection/mock/siglent.py
|
|
88
|
+
scpi_control/connection/mock/tektronix.py
|
|
79
89
|
scpi_control/gui/__init__.py
|
|
80
90
|
scpi_control/gui/app.py
|
|
81
91
|
scpi_control/gui/connection_manager.py
|
|
@@ -120,6 +130,8 @@ scpi_control/protocol_decoders/uart_decoder.py
|
|
|
120
130
|
scpi_control/report_generator/__init__.py
|
|
121
131
|
scpi_control/report_generator/app.py
|
|
122
132
|
scpi_control/report_generator/main_window.py
|
|
133
|
+
scpi_control/report_generator/analysis/__init__.py
|
|
134
|
+
scpi_control/report_generator/analysis/computed_analyzer.py
|
|
123
135
|
scpi_control/report_generator/generators/__init__.py
|
|
124
136
|
scpi_control/report_generator/generators/base.py
|
|
125
137
|
scpi_control/report_generator/generators/markdown_generator.py
|
|
@@ -132,6 +144,7 @@ scpi_control/report_generator/llm/daq_analyzer.py
|
|
|
132
144
|
scpi_control/report_generator/llm/daq_context_builder.py
|
|
133
145
|
scpi_control/report_generator/llm/daq_prompts.py
|
|
134
146
|
scpi_control/report_generator/llm/prompts.py
|
|
147
|
+
scpi_control/report_generator/llm/tools.py
|
|
135
148
|
scpi_control/report_generator/models/__init__.py
|
|
136
149
|
scpi_control/report_generator/models/app_settings.py
|
|
137
150
|
scpi_control/report_generator/models/criteria.py
|
|
@@ -12,7 +12,11 @@ Pillow>=10.0.0
|
|
|
12
12
|
svgpathtools>=1.6.0
|
|
13
13
|
requests>=2.31.0
|
|
14
14
|
reportlab>=4.0.0
|
|
15
|
+
svglib>=1.5.0
|
|
15
16
|
ollama>=0.6.0
|
|
17
|
+
PyMuPDF>=1.23.0
|
|
18
|
+
psutil>=5.9.0
|
|
19
|
+
nvidia-ml-py>=12.0.0
|
|
16
20
|
|
|
17
21
|
[build-exe]
|
|
18
22
|
pyinstaller>=6.0.0
|
|
@@ -58,7 +62,11 @@ PyQt6>=6.6.0
|
|
|
58
62
|
Pillow>=10.0.0
|
|
59
63
|
requests>=2.31.0
|
|
60
64
|
reportlab>=4.0.0
|
|
65
|
+
svglib>=1.5.0
|
|
61
66
|
ollama>=0.6.0
|
|
67
|
+
PyMuPDF>=1.23.0
|
|
68
|
+
psutil>=5.9.0
|
|
69
|
+
nvidia-ml-py>=12.0.0
|
|
62
70
|
|
|
63
71
|
[usb]
|
|
64
72
|
pyvisa>=1.14.0
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# SCPI Instrument Control — Examples
|
|
2
|
+
|
|
3
|
+
These scripts show the library in action end to end: oscilloscope capture and
|
|
4
|
+
analysis, the web gateway's REST API, function generator / AWG control,
|
|
5
|
+
power supply control, data acquisition, and report generation. Most connect
|
|
6
|
+
to real hardware over LAN by default (update the IP/host constant near the
|
|
7
|
+
top of each file); a few run entirely against mock connections and need no
|
|
8
|
+
instrument at all — those are called out below.
|
|
9
|
+
|
|
10
|
+
Install the core library, then add the extras a given example needs:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install "SCPI-Instrument-Control"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Oscilloscope
|
|
17
|
+
|
|
18
|
+
| File | What it shows | Requirements |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `basic_usage.py` | Connecting to an oscilloscope, configuring channels and trigger, and performing basic operations. | Oscilloscope on the network |
|
|
21
|
+
| `waveform_capture.py` | Capturing waveform data from the oscilloscope and saving it to a file. | Oscilloscope on the network, matplotlib |
|
|
22
|
+
| `measurements.py` | Automated measurements (frequency, Vpp, RMS, period, etc.) on oscilloscope channels. | Oscilloscope on the network |
|
|
23
|
+
| `live_plot.py` | Real-time waveform acquisition and plotting using matplotlib animation. | Oscilloscope on the network, matplotlib |
|
|
24
|
+
| `simple_capture.py` | Single waveform capture with analysis via the automation API (Vpp, RMS, frequency) and saving to NumPy format. | Oscilloscope on the network |
|
|
25
|
+
| `batch_capture.py` | Capturing multiple waveforms with different timebase and voltage-scale settings, for characterizing signals at different scales. | Oscilloscope on the network |
|
|
26
|
+
| `continuous_capture.py` | Collecting waveforms continuously over a period of time, for monitoring, statistics, or time-varying phenomena. | Oscilloscope on the network |
|
|
27
|
+
| `trigger_based_capture.py` | Waiting for specific trigger conditions and capturing waveforms when they occur, for sporadic events. | Oscilloscope on the network |
|
|
28
|
+
| `advanced_analysis.py` | Advanced waveform analysis and visualization: FFT analysis, statistical analysis, and matplotlib plots. | Oscilloscope on the network, matplotlib |
|
|
29
|
+
| `probe_calibration_analysis.py` | Waveform region extraction for probe compensation analysis: plateau detection, slope analysis, calibration guidance, and zoomed PDF report plots. | Oscilloscope on the network, `SCPI-Instrument-Control[report-generator]` |
|
|
30
|
+
| `dialect_override_example.py` | SCPI dialect auto-detection from `*IDN?` and the `dialect=` override for forcing a command set; runs entirely on mock connections. | Core install only (no hardware) |
|
|
31
|
+
|
|
32
|
+
## Web Gateway
|
|
33
|
+
|
|
34
|
+
| File | What it shows | Requirements |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `gateway_rest_client.py` | Driving the web gateway's REST API from Python: creating a mock session, configuring a channel, fetching waveform JSON, downloading a screenshot, and sending a raw SCPI command — the same API the browser UI uses. | `SCPI-Instrument-Control[web]` + a running `scpi-web` gateway |
|
|
37
|
+
| `trend_logging_walkthrough.py` | Recording measurement trends in-process via the gateway's session layer (no server or browser): polling measurements, recording them, and exporting to CSV. | Core install only (no hardware, no server) |
|
|
38
|
+
|
|
39
|
+
## Function Generator / AWG
|
|
40
|
+
|
|
41
|
+
| File | What it shows | Requirements |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| `function_generator_basic.py` | Basic control of Siglent SDG-series function generators over Ethernet/LAN. | Function generator on the network |
|
|
44
|
+
| `vector_graphics_xy_mode.py` | Using the oscilloscope as a vector display: generating X/Y waveform data for shapes, saving waveform files for an AWG, and animating via rotation/transforms. | `SCPI-Instrument-Control[fun]`, external AWG/DAC feeding the scope's channels |
|
|
45
|
+
|
|
46
|
+
## Power Supply
|
|
47
|
+
|
|
48
|
+
| File | What it shows | Requirements |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `psu_basic_control.py` | Controlling a SCPI power supply (Siglent SPD series or generic SCPI-99) over Ethernet/LAN. | Power supply on the network |
|
|
51
|
+
| `psu_advanced_features.py` | Advanced PSU features: CSV data logging, tracking modes (series/parallel), timer functionality, waveform generation, and OVP/OCP protection. | Power supply on the network |
|
|
52
|
+
| `psu_usb_connection.py` | Connecting to a power supply via USB/GPIB/Serial/TCP-IP using `VISAConnection`. | `SCPI-Instrument-Control[usb]`, PSU reachable via USB-TMC/GPIB/Serial/VXI-11 |
|
|
53
|
+
| `psu_gui_test.py` | Testing the PSU control GUI against a mock connection, with no physical hardware required. | `SCPI-Instrument-Control[gui]` |
|
|
54
|
+
|
|
55
|
+
## Data Acquisition
|
|
56
|
+
|
|
57
|
+
| File | What it shows | Requirements |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `data_logger_basic.py` | Basic usage of the `DataLogger` class for DAQ/switch units (e.g. Keysight 34970A/DAQ970A style). | DAQ instrument on the network |
|
|
60
|
+
|
|
61
|
+
## Report Generator
|
|
62
|
+
|
|
63
|
+
| File | What it shows | Requirements |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `report_generation_example.py` | Generating professional PDF/Markdown test reports: loading waveform data, adding measurements with pass/fail criteria, optional AI analysis, and rendering the report. | `SCPI-Instrument-Control[report-generator]` |
|
|
66
|
+
|
|
67
|
+
## Interactive Tutorial
|
|
68
|
+
|
|
69
|
+
| File | What it shows | Requirements |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `interactive_tutorial.ipynb` | End-to-end Jupyter walkthrough: connect, configure channels/trigger, capture and plot a waveform, run automated measurements, FFT analysis, multi-channel capture, and export — narrated step by step. | Jupyter, oscilloscope on the network, matplotlib, scipy |
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
Most scripts read an IP/host constant (commonly `SCOPE_IP`) near the top of
|
|
76
|
+
the file — update it to match your instrument. To find an oscilloscope's
|
|
77
|
+
LAN address: **Utility → I/O → LAN** on the instrument's front panel.
|
|
78
|
+
|
|
79
|
+
The scripts marked "no hardware" above (`dialect_override_example.py`,
|
|
80
|
+
`trend_logging_walkthrough.py`, `psu_gui_test.py`) use mock connections and
|
|
81
|
+
run as-is.
|
|
82
|
+
|
|
83
|
+
## Running an example
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
python examples/basic_usage.py
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
For `gateway_rest_client.py`, start the gateway first, in another terminal:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
pip install "SCPI-Instrument-Control[web]"
|
|
93
|
+
scpi-web
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then run the client script.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""SCPI dialect auto-detection and manual override.
|
|
2
|
+
|
|
3
|
+
The library speaks two Siglent command sets: "legacy" (SDS1000X-E era,
|
|
4
|
+
e.g. C1:VDIV 500mV) and "modern" (SDS800X HD era, e.g. :CHANnel1:SCALe 0.5).
|
|
5
|
+
The dialect is auto-detected from *IDN? at connect; pass dialect= to force
|
|
6
|
+
one when detection guesses wrong. This example uses mock connections so it
|
|
7
|
+
runs without hardware.
|
|
8
|
+
|
|
9
|
+
Requirements: SCPI-Instrument-Control (core install)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from scpi_control import Oscilloscope
|
|
13
|
+
from scpi_control.connection.mock import MockConnection
|
|
14
|
+
from scpi_control.exceptions import SiglentTimeoutError
|
|
15
|
+
|
|
16
|
+
LEGACY_IDN = "Siglent Technologies,SDS1104X-E,MOCK0001,1.0.0.0"
|
|
17
|
+
MODERN_IDN = "Siglent Technologies,SDS824X HD,MOCK0002,3.8.12"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def show(scope: Oscilloscope, label: str) -> None:
|
|
21
|
+
scope.connect()
|
|
22
|
+
try:
|
|
23
|
+
print(f"{label}: model={scope.device_info.get('model')}, detected dialect={scope.dialect}")
|
|
24
|
+
scope.timebase = 1e-3 # same API call regardless of dialect
|
|
25
|
+
print(f" timebase set to {scope.timebase} s/div via the {scope.dialect} command set")
|
|
26
|
+
finally:
|
|
27
|
+
scope.disconnect()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main() -> None:
|
|
31
|
+
# Auto-detection from *IDN?
|
|
32
|
+
show(Oscilloscope("mock", connection=MockConnection("mock", idn=LEGACY_IDN)), "Legacy scope (auto)")
|
|
33
|
+
show(Oscilloscope("mock", connection=MockConnection("mock", idn=MODERN_IDN)), "Modern scope (auto)")
|
|
34
|
+
|
|
35
|
+
# Manual override: dialect= exists for the case where the model registry
|
|
36
|
+
# misidentifies real hardware from *IDN? and you need to force the wire
|
|
37
|
+
# protocol the instrument *actually* speaks. Forcing a dialect the
|
|
38
|
+
# instrument does NOT speak is a misuse - and our mock is faithful enough
|
|
39
|
+
# to prove it: it answers only the real protocol for its *IDN?, so
|
|
40
|
+
# forcing "modern" onto a legacy-speaking instrument here fails exactly
|
|
41
|
+
# like it would on real mismatched hardware (a timeout, not a crash).
|
|
42
|
+
forced = Oscilloscope("mock", connection=MockConnection("mock", idn=LEGACY_IDN), dialect="modern")
|
|
43
|
+
forced.connect()
|
|
44
|
+
try:
|
|
45
|
+
print(f"Legacy IDN, dialect forced to modern: model={forced.device_info.get('model')}, dialect={forced.dialect}")
|
|
46
|
+
try:
|
|
47
|
+
forced.timebase = 1e-3
|
|
48
|
+
print(f" timebase set to {forced.timebase} s/div via the {forced.dialect} command set")
|
|
49
|
+
except SiglentTimeoutError:
|
|
50
|
+
print(" (expected) a modern-dialect query against a legacy-speaking instrument timed out")
|
|
51
|
+
print(" -- only override dialect to match what the real instrument speaks")
|
|
52
|
+
finally:
|
|
53
|
+
forced.disconnect()
|
|
54
|
+
# On real hardware, override with the dialect the instrument actually
|
|
55
|
+
# speaks: Oscilloscope("192.168.1.100", dialect="modern")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
main()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Drive the web gateway's REST API from Python — no browser needed.
|
|
2
|
+
|
|
3
|
+
Start the gateway first (in another terminal):
|
|
4
|
+
|
|
5
|
+
pip install "SCPI-Instrument-Control[web]"
|
|
6
|
+
scpi-web
|
|
7
|
+
|
|
8
|
+
Then run this script. It creates a hardware-free mock session, configures a
|
|
9
|
+
channel, fetches full-resolution waveform data as JSON, and downloads a
|
|
10
|
+
screenshot PNG — the same API the browser UI uses.
|
|
11
|
+
|
|
12
|
+
Requirements:
|
|
13
|
+
- SCPI-Instrument-Control[web] (for the gateway itself)
|
|
14
|
+
- Python standard library only for this client (urllib)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import urllib.request
|
|
19
|
+
from typing import Optional, Union
|
|
20
|
+
|
|
21
|
+
BASE = "http://127.0.0.1:8765/api"
|
|
22
|
+
|
|
23
|
+
Body = Optional[Union[dict, list]] # examples run on the package floor, Python 3.9
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def call(method: str, path: str, body: Body = None) -> bytes:
|
|
27
|
+
data = None if body is None else json.dumps(body).encode()
|
|
28
|
+
request = urllib.request.Request(BASE + path, data=data, method=method)
|
|
29
|
+
if data is not None:
|
|
30
|
+
request.add_header("Content-Type", "application/json")
|
|
31
|
+
with urllib.request.urlopen(request) as response:
|
|
32
|
+
return response.read()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def call_json(method: str, path: str, body: Body = None):
|
|
36
|
+
return json.loads(call(method, path, body))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main() -> None:
|
|
40
|
+
# 1. Create a mock oscilloscope session (no hardware required)
|
|
41
|
+
session = call_json("POST", "/sessions", {"mock": True, "label": "REST demo"})
|
|
42
|
+
session_id = session["id"]
|
|
43
|
+
print(f"Session {session_id}: {session['model']} ({session['dialect']} dialect)")
|
|
44
|
+
|
|
45
|
+
scope = f"/sessions/{session_id}/scope"
|
|
46
|
+
try:
|
|
47
|
+
# 2. Configure channel 1 and read the full state snapshot back
|
|
48
|
+
state = call_json("PATCH", f"{scope}/channels/1", {"enabled": True, "voltage_scale": 0.5})
|
|
49
|
+
print(f"Timebase: {state['timebase']} s/div, C1 scale: {state['channels']['1']['voltage_scale']} V/div")
|
|
50
|
+
|
|
51
|
+
# 3. Fetch full-resolution waveform data as JSON
|
|
52
|
+
waveform = call_json("GET", f"{scope}/waveform?channels=1&max_points=16")
|
|
53
|
+
channel = waveform["channels"][0]
|
|
54
|
+
print(f"Waveform C{channel['channel']}: {len(channel['points'])} points, dt={channel['dt']:.2e} s")
|
|
55
|
+
|
|
56
|
+
# 4. Download the instrument screenshot
|
|
57
|
+
png = call("GET", f"{scope}/screenshot.png")
|
|
58
|
+
with open("gateway_screenshot.png", "wb") as f:
|
|
59
|
+
f.write(png)
|
|
60
|
+
print(f"Saved gateway_screenshot.png ({len(png)} bytes)")
|
|
61
|
+
|
|
62
|
+
# 5. Send a raw SCPI query through the terminal endpoint
|
|
63
|
+
reply = call_json("POST", f"{scope}/command", {"command": "*IDN?"})
|
|
64
|
+
print(f"*IDN? -> {reply['response']}")
|
|
65
|
+
finally:
|
|
66
|
+
call("DELETE", f"/sessions/{session_id}")
|
|
67
|
+
print("Session closed.")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
main()
|