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.
Files changed (191) hide show
  1. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/CHANGELOG.md +89 -0
  2. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/MANIFEST.in +0 -3
  3. {scpi_instrument_control-2.0.0/SCPI_Instrument_Control.egg-info → scpi_instrument_control-3.0.0}/PKG-INFO +29 -4
  4. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/README.md +20 -3
  5. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0/SCPI_Instrument_Control.egg-info}/PKG-INFO +29 -4
  6. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/SOURCES.txt +15 -2
  7. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/requires.txt +8 -0
  8. scpi_instrument_control-3.0.0/examples/README.md +96 -0
  9. scpi_instrument_control-3.0.0/examples/dialect_override_example.py +59 -0
  10. scpi_instrument_control-3.0.0/examples/gateway_rest_client.py +71 -0
  11. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/probe_calibration_analysis.py +5 -5
  12. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/report_generation_example.py +5 -5
  13. scpi_instrument_control-3.0.0/examples/trend_logging_walkthrough.py +52 -0
  14. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/pyproject.toml +9 -1
  15. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/__init__.py +1 -1
  16. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/channel.py +67 -18
  17. scpi_instrument_control-3.0.0/scpi_control/connection/mock/__init__.py +5 -0
  18. 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
  19. scpi_instrument_control-3.0.0/scpi_control/connection/mock/helpers.py +25 -0
  20. scpi_instrument_control-3.0.0/scpi_control/connection/mock/lecroy.py +96 -0
  21. scpi_instrument_control-3.0.0/scpi_control/connection/mock/siglent.py +235 -0
  22. scpi_instrument_control-3.0.0/scpi_control/connection/mock/tektronix.py +226 -0
  23. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/exceptions.py +6 -0
  24. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_ai_panel.py +2 -8
  25. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/math_channel.py +5 -14
  26. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/measurement.py +66 -15
  27. scpi_instrument_control-3.0.0/scpi_control/measurement_badges.py +123 -0
  28. scpi_instrument_control-3.0.0/scpi_control/models.py +613 -0
  29. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/oscilloscope.py +39 -9
  30. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/__init__.py +1 -1
  31. scpi_instrument_control-3.0.0/scpi_control/report_generator/analysis/__init__.py +1 -0
  32. scpi_instrument_control-3.0.0/scpi_control/report_generator/analysis/computed_analyzer.py +137 -0
  33. scpi_instrument_control-3.0.0/scpi_control/report_generator/app.py +109 -0
  34. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/markdown_generator.py +12 -8
  35. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/pdf_generator.py +147 -139
  36. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/analyzer.py +20 -8
  37. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/client.py +134 -91
  38. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/context_builder.py +13 -16
  39. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/daq_analyzer.py +21 -16
  40. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/prompts.py +17 -1
  41. scpi_instrument_control-3.0.0/scpi_control/report_generator/llm/tools.py +274 -0
  42. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/main_window.py +37 -40
  43. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/report_data.py +48 -21
  44. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/template.py +26 -0
  45. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/utils/waveform_analyzer.py +96 -25
  46. scpi_instrument_control-3.0.0/scpi_control/report_generator/utils/waveform_loader.py +386 -0
  47. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/ai_analysis_panel.py +22 -3
  48. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/metadata_panel.py +87 -1
  49. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/pdf_preview_dialog.py +5 -2
  50. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/template_manager_dialog.py +29 -0
  51. scpi_instrument_control-3.0.0/scpi_control/scpi_commands.py +875 -0
  52. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/trigger.py +75 -32
  53. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/waveform.py +61 -208
  54. scpi_instrument_control-3.0.0/scpi_control/waveform_schema.py +44 -0
  55. scpi_instrument_control-3.0.0/scpi_control/waveform_transfer.py +370 -0
  56. scpi_instrument_control-2.0.0/docs/VISUAL_MEASUREMENTS.md +0 -638
  57. scpi_instrument_control-2.0.0/examples/README.md +0 -254
  58. scpi_instrument_control-2.0.0/scpi_control/models.py +0 -321
  59. scpi_instrument_control-2.0.0/scpi_control/report_generator/app.py +0 -38
  60. scpi_instrument_control-2.0.0/scpi_control/report_generator/utils/waveform_loader.py +0 -316
  61. scpi_instrument_control-2.0.0/scpi_control/scpi_commands.py +0 -339
  62. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/LICENSE +0 -0
  63. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/dependency_links.txt +0 -0
  64. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/entry_points.txt +0 -0
  65. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/SCPI_Instrument_Control.egg-info/top_level.txt +0 -0
  66. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/SDS800XHD_Series_ProgrammingGuide_EN11G.pdf +0 -0
  67. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/01_main_window.png +0 -0
  68. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/channel_controls.png +0 -0
  69. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/cursors.png +0 -0
  70. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/fft_analysis.png +0 -0
  71. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/main_window.png +0 -0
  72. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/measurements_panel.png +0 -0
  73. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/docs/images/visual_measurements.png +0 -0
  74. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/advanced_analysis.py +0 -0
  75. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/basic_usage.py +0 -0
  76. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/batch_capture.py +0 -0
  77. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/continuous_capture.py +0 -0
  78. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/data_logger_basic.py +0 -0
  79. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/function_generator_basic.py +0 -0
  80. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/live_plot.py +0 -0
  81. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/measurements.py +0 -0
  82. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_advanced_features.py +0 -0
  83. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_basic_control.py +0 -0
  84. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_gui_test.py +0 -0
  85. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/psu_usb_connection.py +0 -0
  86. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/simple_capture.py +0 -0
  87. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/trigger_based_capture.py +0 -0
  88. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/vector_graphics_xy_mode.py +0 -0
  89. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/examples/waveform_capture.py +0 -0
  90. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment Wide.png +0 -0
  91. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment.icns +0 -0
  92. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment.ico +0 -0
  93. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/resources/Test Equipment.png +0 -0
  94. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/analysis.py +0 -0
  95. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/automation.py +0 -0
  96. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/awg_models.py +0 -0
  97. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/awg_output.py +0 -0
  98. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/awg_scpi_commands.py +0 -0
  99. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/__init__.py +0 -0
  100. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/base.py +0 -0
  101. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/socket.py +0 -0
  102. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/connection/visa_connection.py +0 -0
  103. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/daq_models.py +0 -0
  104. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/daq_scpi_commands.py +0 -0
  105. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/data_logger.py +0 -0
  106. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/function_generator.py +0 -0
  107. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/__init__.py +0 -0
  108. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/app.py +0 -0
  109. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/connection_manager.py +0 -0
  110. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/daq_worker.py +0 -0
  111. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/live_view_worker.py +0 -0
  112. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/main_window.py +0 -0
  113. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/utils/validators.py +0 -0
  114. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/vnc_window.py +0 -0
  115. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/waveform_capture_worker.py +0 -0
  116. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/__init__.py +0 -0
  117. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/channel_control.py +0 -0
  118. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/cursor_panel.py +0 -0
  119. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_channel_config.py +0 -0
  120. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_data_view.py +0 -0
  121. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/daq_scan_config.py +0 -0
  122. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/data_logger_control.py +0 -0
  123. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/error_dialog.py +0 -0
  124. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/fft_display.py +0 -0
  125. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/math_panel.py +0 -0
  126. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_marker.py +0 -0
  127. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/__init__.py +0 -0
  128. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/frequency_marker.py +0 -0
  129. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/timing_marker.py +0 -0
  130. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_markers/voltage_marker.py +0 -0
  131. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/measurement_panel.py +0 -0
  132. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/protocol_decode_panel.py +0 -0
  133. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/psu_control.py +0 -0
  134. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/reference_panel.py +0 -0
  135. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/scope_web_view.py +0 -0
  136. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/terminal_widget.py +0 -0
  137. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/timebase_control.py +0 -0
  138. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/trigger_control.py +0 -0
  139. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/vector_graphics_panel.py +0 -0
  140. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/visual_measurement_panel.py +0 -0
  141. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/waveform_display.py +0 -0
  142. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/gui/widgets/waveform_display_pg.py +0 -0
  143. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/measurement_config.py +0 -0
  144. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/power_supply.py +0 -0
  145. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/power_supply_output.py +0 -0
  146. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decode.py +0 -0
  147. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/__init__.py +0 -0
  148. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/i2c_decoder.py +0 -0
  149. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/spi_decoder.py +0 -0
  150. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/protocol_decoders/uart_decoder.py +0 -0
  151. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/psu_data_logger.py +0 -0
  152. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/psu_models.py +0 -0
  153. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/psu_scpi_commands.py +0 -0
  154. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/py.typed +0 -0
  155. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/reference_waveform.py +0 -0
  156. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/__init__.py +0 -0
  157. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/generators/base.py +0 -0
  158. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/__init__.py +0 -0
  159. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/daq_context_builder.py +0 -0
  160. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/llm/daq_prompts.py +0 -0
  161. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/__init__.py +0 -0
  162. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/app_settings.py +0 -0
  163. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/criteria.py +0 -0
  164. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/plot_style.py +0 -0
  165. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/report_options.py +0 -0
  166. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/models/test_types.py +0 -0
  167. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/utils/__init__.py +0 -0
  168. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/utils/image_handler.py +0 -0
  169. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/__init__.py +0 -0
  170. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/chat_sidebar.py +0 -0
  171. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/llm_settings_dialog.py +0 -0
  172. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/report_generator/widgets/report_options_dialog.py +0 -0
  173. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/screen_capture.py +0 -0
  174. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/__init__.py +0 -0
  175. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/__main__.py +0 -0
  176. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/__init__.py +0 -0
  177. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/discovery.py +0 -0
  178. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/scope.py +0 -0
  179. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/sessions.py +0 -0
  180. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/api/stream.py +0 -0
  181. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/app.py +0 -0
  182. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/compute.py +0 -0
  183. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/discovery.py +0 -0
  184. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/recorder.py +0 -0
  185. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/schemas.py +0 -0
  186. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/sessions.py +0 -0
  187. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/static/assets/index-0Vpguwg6.js +0 -0
  188. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/static/assets/index-CyUPLIHk.css +0 -0
  189. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/server/static/index.html +0 -0
  190. {scpi_instrument_control-2.0.0 → scpi_instrument_control-3.0.0}/scpi_control/vector_graphics.py +0 -0
  191. {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: 2.0.0
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: 2.0.0
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()