├── docs ├── release-notes.md ├── api │ ├── types.md │ ├── config.md │ ├── enumerations.md │ ├── connection.md │ ├── interfaces │ │ ├── gpib.md │ │ ├── sdk.md │ │ ├── vxi11.md │ │ ├── hislip.md │ │ ├── serial.md │ │ ├── socket.md │ │ ├── zeromq.md │ │ ├── prologix.md │ │ └── index.md │ ├── backends │ │ ├── nidaq.md │ │ ├── pyvisa.md │ │ └── index.md │ └── exceptions.md ├── license.md ├── resources │ ├── types.md │ ├── multi_message_based.md │ ├── aim-tti │ │ └── mx_series.md │ ├── mks │ │ └── pr4000b.md │ ├── nkt │ │ └── nktpdll.md │ ├── raicol │ │ └── tec.md │ ├── dataray │ │ └── wincamd.md │ ├── energetiq │ │ └── eq99.md │ ├── isotech │ │ └── millik.md │ ├── omega │ │ └── ithx.md │ ├── picotech │ │ ├── pt104.md │ │ ├── picoscope.md │ │ └── types.md │ ├── vaisala │ │ ├── ptu300.md │ │ └── ptb330.md │ ├── cmi │ │ └── sia3.md │ ├── optosigma │ │ └── shot702.md │ ├── thorlabs │ │ └── fwxx2c.md │ ├── optronic_labs │ │ ├── ol756.md │ │ └── olxxa.md │ ├── greisinger │ │ └── gmh3000.md │ ├── electron_dynamics │ │ └── tc_series.md │ ├── princeton_instruments │ │ └── arc_instrument.md │ ├── avantes │ │ └── avaspec.md │ └── index.md ├── assets │ └── images │ │ └── favicon.ico ├── schema │ ├── any.md │ ├── status.md │ ├── firmware.md │ ├── component.md │ ├── financial.md │ ├── measurand.md │ ├── accessories.md │ ├── adjustment.md │ ├── alteration.md │ ├── competency.md │ ├── conditions.md │ ├── maintenance.md │ ├── planned_task.md │ ├── deserialised.md │ ├── completed_task.md │ ├── quality_manual.md │ ├── specifications.md │ ├── performance_check.md │ ├── acceptance_criteria.md │ ├── capital_expenditure.md │ ├── reference_materials.md │ ├── specified_requirements.md │ ├── report.md │ ├── digital_report.md │ ├── equipment.md │ ├── index.md │ └── file.md ├── javascripts │ └── arithmatex.js ├── webapp.md ├── getting-started │ └── index.md └── index.md ├── packages ├── validate │ ├── CHANGELOG.md │ ├── src │ │ └── msl │ │ │ └── equipment_validate │ │ │ └── py.typed │ ├── tests │ │ ├── registers │ │ │ ├── do_not_modify_this_file.txt │ │ │ ├── duplicate_id_a.xml │ │ │ └── duplicate_id_b.xml │ │ ├── conftest.py │ │ └── test_osc8.py │ ├── LICENSE.txt │ └── README.md └── resources │ ├── src │ └── msl │ │ ├── equipment_resources │ │ ├── py.typed │ │ ├── aim_tti │ │ │ └── __init__.py │ │ ├── omega │ │ │ └── __init__.py │ │ ├── energetiq │ │ │ └── __init__.py │ │ ├── dataray │ │ │ └── __init__.py │ │ ├── raicol │ │ │ ├── __init__.py │ │ │ └── tec.py │ │ ├── thorlabs │ │ │ └── __init__.py │ │ ├── greisinger │ │ │ └── __init__.py │ │ ├── vaisala │ │ │ └── __init__.py │ │ ├── cmi │ │ │ └── __init__.py │ │ ├── princeton_instruments │ │ │ └── __init__.py │ │ ├── picotech │ │ │ └── __init__.py │ │ ├── optronic_labs │ │ │ └── __init__.py │ │ ├── isotech │ │ │ └── __init__.py │ │ ├── mks │ │ │ └── __init__.py │ │ ├── optosigma │ │ │ └── __init__.py │ │ ├── electron_dynamics │ │ │ └── __init__.py │ │ ├── nkt │ │ │ └── __init__.py │ │ ├── __init__.py │ │ ├── types.py │ │ └── avantes │ │ │ └── __init__.py │ │ └── equipment │ │ └── resources │ │ └── thorlabs │ │ ├── __init__.py │ │ └── kinesis │ │ ├── callbacks.py │ │ ├── __init__.py │ │ └── messages.py │ ├── README.md │ ├── examples │ ├── picotech │ │ ├── pt104_find.py │ │ ├── ps5000a_find.py │ │ ├── pt104.py │ │ ├── ps5000a_block_mode.py │ │ ├── ps5000a_data_ready_callback.py │ │ ├── ps5000a_streaming_ready_callback.py │ │ ├── ps5000a_AWG_builtin.py │ │ └── ps5000a_block_ready_callback.py │ ├── omega │ │ └── ithx.py │ ├── avantes │ │ ├── find_devices.py │ │ └── avaspec_callback.py │ ├── raicol │ │ └── tec_oven.py │ ├── cmi │ │ └── sia.py │ ├── mks │ │ └── pr4000b.py │ ├── electron_dynamics │ │ └── tc_series.py │ ├── thorlabs │ │ ├── fw212c.py │ │ ├── kinesis_device_info.py │ │ ├── mff101.py │ │ ├── ksc101.py │ │ ├── kdc101.py │ │ ├── kst101.py │ │ └── lts150.py │ ├── vaisala │ │ ├── ptb330.py │ │ └── ptu300.py │ ├── princeton_instruments │ │ └── find_devices.py │ ├── energetiq │ │ └── eq99.py │ ├── nkt │ │ └── find_devices.py │ ├── optronic_laboratories │ │ ├── ol756.py │ │ └── ol83a.py │ ├── isotech │ │ ├── milliskanner.py │ │ └── millik.py │ ├── aim_tti │ │ └── mx100tp.py │ ├── greisinger │ │ └── gmh3710.py │ ├── optosigma │ │ └── shot702.py │ └── dataray │ │ └── wincamd.py │ ├── LICENSE.txt │ └── tests │ └── test_greisinger_gmh3000.py ├── src └── msl │ └── equipment │ ├── py.typed │ ├── resources │ └── __init__.py │ ├── __about__.py │ ├── interfaces │ └── __init__.py │ ├── record_types.py │ ├── enumerations.py │ └── __init__.py ├── tests ├── resources │ ├── gpib.dll │ ├── gpib.so │ ├── gpib.dylib │ ├── irradiance.xlsx │ ├── mass │ │ ├── not-a-register.xml │ │ └── .hidden │ │ │ └── bad.xml │ ├── config.xml │ ├── connections.xml │ ├── gpib.h │ ├── gpib.cpp │ └── light │ │ └── register.xml ├── test_nidaq.py └── test_record_types.py ├── docs-old ├── _api │ ├── msl.equipment.rst │ ├── msl.equipment.utils.rst │ ├── msl.equipment.vxi11.rst │ ├── msl.equipment.config.rst │ ├── msl.equipment.hislip.rst │ ├── msl.equipment.factory.rst │ ├── msl.equipment.database.rst │ ├── msl.equipment.connection.rst │ ├── msl.equipment.constants.rst │ ├── msl.equipment.exceptions.rst │ ├── msl.equipment.connection_demo.rst │ ├── msl.equipment.connection_gpib.rst │ ├── msl.equipment.connection_sdk.rst │ ├── msl.equipment.resources.utils.rst │ ├── msl.equipment.connection_nidaq.rst │ ├── msl.equipment.connection_pyvisa.rst │ ├── msl.equipment.connection_serial.rst │ ├── msl.equipment.connection_socket.rst │ ├── msl.equipment.connection_zeromq.rst │ ├── msl.equipment.connection_prologix.rst │ ├── msl.equipment.resources.cmi.sia3.rst │ ├── msl.equipment.resources.omega.ithx.rst │ ├── msl.equipment.dns_service_discovery.rst │ ├── msl.equipment.connection_tcpip_vxi11.rst │ ├── msl.equipment.resources.vaisala.ptb330.rst │ ├── msl.equipment.resources.vaisala.ptu300.rst │ ├── msl.equipment.connection_tcpip_hislip.rst │ ├── msl.equipment.resources.energetiq.eq99.rst │ ├── msl.equipment.resources.isotech.millik.rst │ ├── msl.equipment.connection_message_based.rst │ ├── msl.equipment.resources.avantes.avaspec.rst │ ├── msl.equipment.resources.bentham.benhw32.rst │ ├── msl.equipment.resources.bentham.benhw64.rst │ ├── msl.equipment.resources.bentham.errors.rst │ ├── msl.equipment.resources.bentham.tokens.rst │ ├── msl.equipment.resources.picotech.errors.rst │ ├── msl.equipment.resources.picotech.pt104.rst │ ├── msl.equipment.resources.thorlabs.fwxx2c.rst │ ├── msl.equipment.resources.aim_tti.mx_series.rst │ ├── msl.equipment.resources.greisinger.gmh3000.rst │ ├── msl.equipment.resources.optosigma.shot702.rst │ ├── msl.equipment.resources.raicol.raicol_tec.rst │ ├── msl.equipment.resources.nkt.nktpdll.rst │ ├── msl.equipment.resources.dataray.datarayocx_32.rst │ ├── msl.equipment.resources.dataray.datarayocx_64.rst │ ├── msl.equipment.resources.thorlabs.kinesis.enums.rst │ ├── msl.equipment.resources.mks_instruments.pr4000b.rst │ ├── msl.equipment.resources.thorlabs.kinesis.errors.rst │ ├── msl.equipment.resources.picotech.picoscope.enums.rst │ ├── msl.equipment.resources.picotech.picoscope.helper.rst │ ├── msl.equipment.resources.picotech.picoscope.ps2000.rst │ ├── msl.equipment.resources.picotech.picoscope.ps3000.rst │ ├── msl.equipment.resources.picotech.picoscope.ps4000.rst │ ├── msl.equipment.resources.picotech.picoscope.ps5000.rst │ ├── msl.equipment.resources.picotech.picoscope.ps6000.rst │ ├── msl.equipment.resources.thorlabs.kinesis.messages.rst │ ├── msl.equipment.resources.thorlabs.kinesis.structs.rst │ ├── msl.equipment.resources.picotech.picoscope.channel.rst │ ├── msl.equipment.resources.picotech.picoscope.ps2000a.rst │ ├── msl.equipment.resources.picotech.picoscope.ps3000a.rst │ ├── msl.equipment.resources.picotech.picoscope.ps4000a.rst │ ├── msl.equipment.resources.picotech.picoscope.ps5000a.rst │ ├── msl.equipment.resources.picotech.picoscope.structs.rst │ ├── msl.equipment.resources.thorlabs.kinesis.callbacks.rst │ ├── msl.equipment.resources.electron_dynamics.tc_series.rst │ ├── msl.equipment.resources.picotech.picoscope.callbacks.rst │ ├── msl.equipment.resources.picotech.picoscope.functions.rst │ ├── msl.equipment.resources.picotech.picoscope.picoscope.rst │ ├── msl.equipment.resources.thorlabs.kinesis.api_functions.rst │ ├── msl.equipment.resources.thorlabs.kinesis.filter_flipper.rst │ ├── msl.equipment.resources.thorlabs.kinesis.kcube_solenoid.rst │ ├── msl.equipment.resources.thorlabs.kinesis.motion_control.rst │ ├── msl.equipment.resources.picotech.picoscope.picoscope_api.rst │ ├── msl.equipment.resources.optronic_laboratories.ol756ocx_32.rst │ ├── msl.equipment.resources.optronic_laboratories.ol756ocx_64.rst │ ├── msl.equipment.resources.picotech.picoscope.picoscope_2k3k.rst │ ├── msl.equipment.resources.nkt.rst │ ├── msl.equipment.resources.thorlabs.kinesis.kcube_dc_servo.rst │ ├── msl.equipment.resources.cmi.rst │ ├── msl.equipment.resources.omega.rst │ ├── msl.equipment.resources.princeton_instruments.arc_instrument.rst │ ├── msl.equipment.resources.aim_tti.rst │ ├── msl.equipment.resources.avantes.rst │ ├── msl.equipment.resources.thorlabs.kinesis.benchtop_stepper_motor.rst │ ├── msl.equipment.resources.thorlabs.kinesis.kcube_stepper_motor.rst │ ├── msl.equipment.resources.optosigma.rst │ ├── msl.equipment.resources.raicol.rst │ ├── msl.equipment.resources.thorlabs.kinesis.integrated_stepper_motors.rst │ ├── msl.equipment.resources.isotech.rst │ ├── msl.equipment.resources.energetiq.rst │ ├── msl.equipment.resources.greisinger.rst │ ├── msl.equipment.resources.mks_instruments.rst │ ├── msl.equipment.resources.electron_dynamics.rst │ ├── msl.equipment.resources.vaisala.rst │ ├── msl.equipment.resources.dataray.rst │ ├── msl.equipment.resources.princeton_instruments.rst │ ├── msl.equipment.resources.optronic_laboratories.ol_current_source.rst │ ├── msl.equipment.resources.picotech.rst │ ├── msl.equipment.resources.thorlabs.rst │ ├── msl.equipment.resources.bentham.rst │ ├── msl.equipment.resources.optronic_laboratories.rst │ ├── msl.equipment.record_types.rst │ ├── msl.equipment.resources.thorlabs.kinesis.rst │ ├── msl.equipment.resources.rst │ └── msl.equipment.resources.picotech.picoscope.rst ├── _templates │ └── layout.html ├── examples.rst ├── _static │ └── custom.css └── install.rst ├── .gitignore ├── CHANGELOG.md ├── .github └── workflows │ ├── ci.yml │ └── docs.yml ├── LICENSE.txt └── README.md /docs/release-notes.md: -------------------------------------------------------------------------------- 1 | --8<-- "CHANGELOG.md" 2 | -------------------------------------------------------------------------------- /packages/validate/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ### unreleased 3 | -------------------------------------------------------------------------------- /docs/api/types.md: -------------------------------------------------------------------------------- 1 | # types 2 | 3 | ::: msl.equipment._types 4 | -------------------------------------------------------------------------------- /docs/api/config.md: -------------------------------------------------------------------------------- 1 | # Config 2 | 3 | ::: msl.equipment.config 4 | -------------------------------------------------------------------------------- /src/msl/equipment/py.typed: -------------------------------------------------------------------------------- 1 | # Marker file for PEP 561 (inline types) -------------------------------------------------------------------------------- /docs/license.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | ``` 4 | --8<-- "LICENSE.txt" 5 | ``` -------------------------------------------------------------------------------- /docs/resources/types.md: -------------------------------------------------------------------------------- 1 | # types 2 | 3 | ::: msl.equipment_resources.types 4 | -------------------------------------------------------------------------------- /docs/api/enumerations.md: -------------------------------------------------------------------------------- 1 | # enumerations 2 | 3 | ::: msl.equipment.enumerations 4 | -------------------------------------------------------------------------------- /packages/validate/src/msl/equipment_validate/py.typed: -------------------------------------------------------------------------------- 1 | # Marker file for PEP 561 (inline types) -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/py.typed: -------------------------------------------------------------------------------- 1 | # Marker file for PEP 561 (inline types) -------------------------------------------------------------------------------- /tests/resources/gpib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSLNZ/msl-equipment/HEAD/tests/resources/gpib.dll -------------------------------------------------------------------------------- /tests/resources/gpib.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSLNZ/msl-equipment/HEAD/tests/resources/gpib.so -------------------------------------------------------------------------------- /tests/resources/gpib.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSLNZ/msl-equipment/HEAD/tests/resources/gpib.dylib -------------------------------------------------------------------------------- /docs/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSLNZ/msl-equipment/HEAD/docs/assets/images/favicon.ico -------------------------------------------------------------------------------- /docs/resources/multi_message_based.md: -------------------------------------------------------------------------------- 1 | # MultiMessageBased 2 | 3 | ::: msl.equipment_resources.multi_message_based 4 | -------------------------------------------------------------------------------- /tests/resources/irradiance.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSLNZ/msl-equipment/HEAD/tests/resources/irradiance.xlsx -------------------------------------------------------------------------------- /docs/resources/aim-tti/mx_series.md: -------------------------------------------------------------------------------- 1 | # MX Series DC Power Supply 2 | 3 | ::: msl.equipment_resources.aim_tti.mx_series 4 | -------------------------------------------------------------------------------- /packages/validate/tests/registers/do_not_modify_this_file.txt: -------------------------------------------------------------------------------- 1 | The SHA-256 checksum of this file must remain constant. Do not modify. -------------------------------------------------------------------------------- /docs/resources/mks/pr4000b.md: -------------------------------------------------------------------------------- 1 | # PR4000B 2 | 3 | ::: msl.equipment_resources.mks.pr4000b 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/nkt/nktpdll.md: -------------------------------------------------------------------------------- 1 | # NKTPDLL 2 | 3 | ::: msl.equipment_resources.nkt.nktpdll 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/raicol/tec.md: -------------------------------------------------------------------------------- 1 | # TEC Oven 2 | 3 | ::: msl.equipment_resources.raicol.tec 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/dataray/wincamd.md: -------------------------------------------------------------------------------- 1 | # WinCamD 2 | 3 | ::: msl.equipment_resources.dataray.wincamd 4 | options: 5 | inherited_members: false -------------------------------------------------------------------------------- /docs/resources/energetiq/eq99.md: -------------------------------------------------------------------------------- 1 | # EQ-99 2 | 3 | ::: msl.equipment_resources.energetiq.eq99 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/isotech/millik.md: -------------------------------------------------------------------------------- 1 | # milliK 2 | 3 | ::: msl.equipment_resources.isotech.millik 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/omega/ithx.md: -------------------------------------------------------------------------------- 1 | # ITHX iServer 2 | 3 | ::: msl.equipment_resources.omega.ithx 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/picotech/pt104.md: -------------------------------------------------------------------------------- 1 | # PT-104 2 | 3 | ::: msl.equipment_resources.picotech.pt104 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/vaisala/ptu300.md: -------------------------------------------------------------------------------- 1 | # PTU300 2 | 3 | ::: msl.equipment_resources.vaisala.ptu300 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/cmi/sia3.md: -------------------------------------------------------------------------------- 1 | # Switched Integrator Amplifier 2 | 3 | ::: msl.equipment_resources.cmi.sia3 4 | options: 5 | inherited_members: false -------------------------------------------------------------------------------- /docs/schema/any.md: -------------------------------------------------------------------------------- 1 | # Any 2 | 3 | ::: msl.equipment.schema.Any 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/resources/optosigma/shot702.md: -------------------------------------------------------------------------------- 1 | # SHOT-702 2 | 3 | ::: msl.equipment_resources.optosigma.shot702 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/picotech/picoscope.md: -------------------------------------------------------------------------------- 1 | # PicoScope 2 | 3 | ::: msl.equipment_resources.picotech.picoscope 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/thorlabs/fwxx2c.md: -------------------------------------------------------------------------------- 1 | # FW102C/FW212C 2 | 3 | ::: msl.equipment_resources.thorlabs.fwxx2c 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/resources/optronic_labs/ol756.md: -------------------------------------------------------------------------------- 1 | # OL 756 2 | 3 | ::: msl.equipment_resources.optronic_labs.ol756ocx_64 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/schema/status.md: -------------------------------------------------------------------------------- 1 | # Status 2 | 3 | ::: msl.equipment.schema.Status 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/resources/optronic_labs/olxxa.md: -------------------------------------------------------------------------------- 1 | # OL 16A, 65A, 83A 2 | 3 | ::: msl.equipment_resources.optronic_labs.olxxa 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/schema/firmware.md: -------------------------------------------------------------------------------- 1 | # Firmware 2 | 3 | ::: msl.equipment.schema.Firmware 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/connection.md: -------------------------------------------------------------------------------- 1 | # Connection 2 | 3 | ::: msl.equipment.schema.Connection 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/gpib.md: -------------------------------------------------------------------------------- 1 | # GPIB 2 | 3 | ::: msl.equipment.interfaces.gpib.GPIB 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/sdk.md: -------------------------------------------------------------------------------- 1 | # SDK 2 | 3 | ::: msl.equipment.interfaces.sdk.SDK 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/component.md: -------------------------------------------------------------------------------- 1 | # Component 2 | 3 | ::: msl.equipment.schema.Component 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/financial.md: -------------------------------------------------------------------------------- 1 | # Financial 2 | 3 | ::: msl.equipment.schema.Financial 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/measurand.md: -------------------------------------------------------------------------------- 1 | # Measurand 2 | 3 | ::: msl.equipment.schema.Measurand 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/backends/nidaq.md: -------------------------------------------------------------------------------- 1 | # NIDAQ 2 | 3 | ::: msl.equipment.interfaces.nidaq.NIDAQ 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/vxi11.md: -------------------------------------------------------------------------------- 1 | # VXI11 2 | 3 | ::: msl.equipment.interfaces.vxi11.VXI11 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/resources/greisinger/gmh3000.md: -------------------------------------------------------------------------------- 1 | # GMH 3000 Series thermometer 2 | 3 | ::: msl.equipment_resources.greisinger.gmh3000 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/schema/accessories.md: -------------------------------------------------------------------------------- 1 | # Accessories 2 | 3 | ::: msl.equipment.schema.Accessories 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/adjustment.md: -------------------------------------------------------------------------------- 1 | # Adjustment 2 | 3 | ::: msl.equipment.schema.Adjustment 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/alteration.md: -------------------------------------------------------------------------------- 1 | # Alteration 2 | 3 | ::: msl.equipment.schema.Alteration 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/competency.md: -------------------------------------------------------------------------------- 1 | # Competency 2 | 3 | ::: msl.equipment.schema.Competency 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/conditions.md: -------------------------------------------------------------------------------- 1 | # Conditions 2 | 3 | ::: msl.equipment.schema.Conditions 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/maintenance.md: -------------------------------------------------------------------------------- 1 | # Maintenance 2 | 3 | ::: msl.equipment.schema.Maintenance 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/planned_task.md: -------------------------------------------------------------------------------- 1 | # PlannedTask 2 | 3 | ::: msl.equipment.schema.PlannedTask 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.rst: -------------------------------------------------------------------------------- 1 | msl.equipment package 2 | ===================== 3 | 4 | .. automodule:: msl.equipment 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: -------------------------------------------------------------------------------- /docs/api/backends/pyvisa.md: -------------------------------------------------------------------------------- 1 | # PyVISA 2 | 3 | ::: msl.equipment.interfaces.pyvisa.PyVISA 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/hislip.md: -------------------------------------------------------------------------------- 1 | # HiSLIP 2 | 3 | ::: msl.equipment.interfaces.hislip.HiSLIP 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/serial.md: -------------------------------------------------------------------------------- 1 | # Serial 2 | 3 | ::: msl.equipment.interfaces.serial.Serial 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/socket.md: -------------------------------------------------------------------------------- 1 | # Socket 2 | 3 | ::: msl.equipment.interfaces.socket.Socket 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/zeromq.md: -------------------------------------------------------------------------------- 1 | # ZeroMQ 2 | 3 | ::: msl.equipment.interfaces.zeromq.ZeroMQ 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/deserialised.md: -------------------------------------------------------------------------------- 1 | # Deserialised 2 | 3 | ::: msl.equipment.schema.Deserialised 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/resources/electron_dynamics/tc_series.md: -------------------------------------------------------------------------------- 1 | # TC Temperature Controller 2 | 3 | ::: msl.equipment_resources.electron_dynamics.tc_series 4 | options: 5 | inherited_members: false -------------------------------------------------------------------------------- /docs/schema/completed_task.md: -------------------------------------------------------------------------------- 1 | # CompletedTask 2 | 3 | ::: msl.equipment.schema.CompletedTask 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/quality_manual.md: -------------------------------------------------------------------------------- 1 | # QualityManual 2 | 3 | ::: msl.equipment.schema.QualityManual 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/specifications.md: -------------------------------------------------------------------------------- 1 | # Specifications 2 | 3 | ::: msl.equipment.schema.Specifications 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/api/interfaces/prologix.md: -------------------------------------------------------------------------------- 1 | # Prologix 2 | 3 | ::: msl.equipment.interfaces.prologix.Prologix 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/performance_check.md: -------------------------------------------------------------------------------- 1 | # PerformanceCheck 2 | 3 | ::: msl.equipment.schema.PerformanceCheck 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs-old/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {% block extrahead %} 4 | 5 | {% endblock %} -------------------------------------------------------------------------------- /docs/resources/picotech/types.md: -------------------------------------------------------------------------------- 1 | # Enums/Structs 2 | 3 | ::: msl.equipment_resources.picotech.status.PicoInfo 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/resources/princeton_instruments/arc_instrument.md: -------------------------------------------------------------------------------- 1 | # ARC Instrument SDK 2 | 3 | ::: msl.equipment_resources.princeton_instruments.arc_instrument 4 | options: 5 | inherited_members: false 6 | -------------------------------------------------------------------------------- /docs/schema/acceptance_criteria.md: -------------------------------------------------------------------------------- 1 | # AcceptanceCriteria 2 | 3 | ::: msl.equipment.schema.AcceptanceCriteria 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/capital_expenditure.md: -------------------------------------------------------------------------------- 1 | # CapitalExpenditure 2 | 3 | ::: msl.equipment.schema.CapitalExpenditure 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs/schema/reference_materials.md: -------------------------------------------------------------------------------- 1 | # ReferenceMaterials 2 | 3 | ::: msl.equipment.schema.ReferenceMaterials 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.utils.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.utils module 2 | ========================== 3 | 4 | .. automodule:: msl.equipment.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.vxi11.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.vxi11 module 2 | ========================== 3 | 4 | .. automodule:: msl.equipment.vxi11 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/schema/specified_requirements.md: -------------------------------------------------------------------------------- 1 | # SpecifiedRequirements 2 | 3 | ::: msl.equipment.schema.SpecifiedRequirements 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.config.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.config module 2 | =========================== 3 | 4 | .. automodule:: msl.equipment.config 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.hislip.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.hislip module 2 | =========================== 3 | 4 | .. automodule:: msl.equipment.hislip 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.factory.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.factory module 2 | ============================ 3 | 4 | .. automodule:: msl.equipment.factory 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.database.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.database module 2 | ============================= 3 | 4 | .. automodule:: msl.equipment.database 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection module 2 | =============================== 3 | 4 | .. automodule:: msl.equipment.connection 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.constants.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.constants module 2 | ============================== 3 | 4 | .. automodule:: msl.equipment.constants 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.exceptions.rst: -------------------------------------------------------------------------------- 1 | msl\.equipment\.exceptions module 2 | ================================= 3 | 4 | .. automodule:: msl.equipment.exceptions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_demo.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection_demo module 2 | ==================================== 3 | 4 | .. automodule:: msl.equipment.connection_demo 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_gpib.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection\_gpib module 2 | ===================================== 3 | 4 | .. automodule:: msl.equipment.connection_gpib 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_sdk.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection_sdk module 2 | =================================== 3 | 4 | .. automodule:: msl.equipment.connection_sdk 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.utils.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.utils module 2 | ==================================== 3 | 4 | .. automodule:: msl.equipment.resources.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_nidaq.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection\_nidaq module 2 | ====================================== 3 | 4 | .. automodule:: msl.equipment.connection_nidaq 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_pyvisa.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection_pyvisa module 2 | ====================================== 3 | 4 | .. automodule:: msl.equipment.connection_pyvisa 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_serial.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection_serial module 2 | ====================================== 3 | 4 | .. automodule:: msl.equipment.connection_serial 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_socket.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection_socket module 2 | ====================================== 3 | 4 | .. automodule:: msl.equipment.connection_socket 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_zeromq.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection\_zeromq module 2 | ======================================= 3 | 4 | .. automodule:: msl.equipment.connection_zeromq 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_prologix.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection\_prologix module 2 | ========================================= 3 | 4 | .. automodule:: msl.equipment.connection_prologix 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/aim_tti/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from Aim-TTi.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .mx_series import MXSeries 6 | 7 | __all__: list[str] = [ 8 | "MXSeries", 9 | ] 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.cmi.sia3.rst: -------------------------------------------------------------------------------- 1 | msl\.equipment\.resources\.cmi\.sia3 module 2 | =========================================== 3 | 4 | .. automodule:: msl.equipment.resources.cmi.sia3 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.omega.ithx.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.omega.ithx module 2 | ========================================= 3 | 4 | .. automodule:: msl.equipment.resources.omega.ithx 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/resources/vaisala/ptb330.md: -------------------------------------------------------------------------------- 1 | # PTB330 2 | 3 | ::: msl.equipment_resources.vaisala.ptb330 4 | options: 5 | inherited_members: true 6 | filters: [PTB330, ^device_info$, units, check_for_errors, get_format, get_reading_str, set_format, set_units] 7 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.dns_service_discovery.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.dns\_service\_discovery module 2 | ============================================ 3 | 4 | .. automodule:: msl.equipment.dns_service_discovery 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/omega/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [OMEGA](https://www.omega.co.uk/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .ithx import ITHX 6 | 7 | __all__: list[str] = [ 8 | "ITHX", 9 | ] 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_tcpip_vxi11.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection\_tcpip\_vxi11 module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.connection_tcpip_vxi11 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.vaisala.ptb330.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.vaisala.ptb330 package 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.vaisala.ptb330 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.vaisala.ptu300.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.vaisala.ptu300 package 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.vaisala.ptu300 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_tcpip_hislip.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection\_tcpip\_hislip module 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.connection_tcpip_hislip 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.energetiq.eq99.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.energetiq.eq99 module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.resources.energetiq.eq99 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.isotech.millik.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.isotech.millik module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.resources.isotech.millik 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/energetiq/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Energetiq](https://www.energetiq.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .eq99 import EQ99 6 | 7 | __all__: list[str] = [ 8 | "EQ99", 9 | ] 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.connection_message_based.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.connection_message_based module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.connection_message_based 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.avantes.avaspec.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.avantes.avaspec module 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.avantes.avaspec 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.bentham.benhw32.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.bentham.benhw32 module 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.bentham.benhw32 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.bentham.benhw64.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.bentham.benhw64 module 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.bentham.benhw64 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.bentham.errors.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.bentham.errors module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.resources.bentham.errors 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.bentham.tokens.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.bentham.tokens module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.resources.bentham.tokens 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.errors.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.errors module 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.errors 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.pt104.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.pt104 module 2 | ============================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.pt104 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.fwxx2c.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.fwxx2c module 2 | ============================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.fwxx2c 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/dataray/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [DataRay](https://www.dataray.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .wincamd import WinCamD 6 | 7 | __all__: list[str] = [ 8 | "WinCamD", 9 | ] 10 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/raicol/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Raicol Crystals](https://raicol.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .tec import RaicolTEC 6 | 7 | __all__: list[str] = [ 8 | "RaicolTEC", 9 | ] 10 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/thorlabs/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Thorlabs](https://www.thorlabs.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .fwxx2c import FWxx2C 6 | 7 | __all__: list[str] = [ 8 | "FWxx2C", 9 | ] 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.aim_tti.mx_series.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.aim\_tti.mx_series module 2 | ================================================= 3 | 4 | .. automodule:: msl.equipment.resources.aim_tti.mx_series 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.greisinger.gmh3000.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.greisinger.gmh3000 module 2 | ================================================= 3 | 4 | .. automodule:: msl.equipment.resources.greisinger.gmh3000 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.optosigma.shot702.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.optosigma.shot702 module 2 | ================================================ 3 | 4 | .. automodule:: msl.equipment.resources.optosigma.shot702 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.raicol.raicol_tec.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.raicol.raicol\_tec module 2 | ================================================= 3 | 4 | .. automodule:: msl.equipment.resources.raicol.raicol_tec 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/greisinger/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Greisinger](https://www.greisinger.de/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .gmh3000 import GMH3000 6 | 7 | __all__: list[str] = [ 8 | "GMH3000", 9 | ] 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.nkt.nktpdll.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.nkt.nktpdll module 2 | ========================================== 3 | 4 | .. automodule:: msl.equipment.resources.nkt.nktpdll 5 | :members: 6 | :member-order: bysource 7 | :undoc-members: 8 | :show-inheritance: 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Global directories 2 | __pycache__/ 3 | 4 | # Global files 5 | *.py[codz] 6 | 7 | # Root directories 8 | /.cache/ 9 | /.idea/ 10 | /.vscode/ 11 | /.venv/ 12 | /dist/ 13 | /site/ 14 | /venv/ 15 | 16 | # Root files 17 | /uv.lock 18 | 19 | # Auto-generated during build 20 | /**/_version.py 21 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.dataray.datarayocx_32.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.dataray.datarayocx\_32 module 2 | ===================================================== 3 | 4 | .. automodule:: msl.equipment.resources.dataray.datarayocx_32 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.dataray.datarayocx_64.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.dataray.datarayocx\_64 module 2 | ===================================================== 3 | 4 | .. automodule:: msl.equipment.resources.dataray.datarayocx_64 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.enums.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.enums module 2 | ===================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.enums 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/schema/report.md: -------------------------------------------------------------------------------- 1 | # Report 2 | 3 | ::: msl.equipment.schema.Report 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | 8 | ::: msl.equipment.schema.IssuingLaboratory 9 | options: 10 | show_root_full_path: false 11 | show_root_heading: true 12 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.mks_instruments.pr4000b.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.mks\_instruments.pr4000b module 2 | ======================================================= 3 | 4 | .. automodule:: msl.equipment.resources.mks_instruments.pr4000b 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.errors.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.errors module 2 | ====================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.errors 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/javascripts/arithmatex.js: -------------------------------------------------------------------------------- 1 | window.MathJax = { 2 | tex: { 3 | inlineMath: [["\\(", "\\)"]], 4 | displayMath: [["\\[", "\\]"]], 5 | processEscapes: true, 6 | processEnvironments: true 7 | }, 8 | options: { 9 | ignoreHtmlClass: ".*|", 10 | processHtmlClass: "arithmatex" 11 | } 12 | }; -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.enums.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.enums module 2 | ======================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.enums 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.helper.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.helper module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.helper 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps2000.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps2000 module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps2000 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps3000.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps3000 module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps3000 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps4000.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps4000 module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps4000 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps5000.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps5000 module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps5000 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps6000.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps6000 module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps6000 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.messages.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.messages module 2 | ======================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.messages 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.structs.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.structs module 2 | ======================================================= 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.structs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/examples.rst: -------------------------------------------------------------------------------- 1 | .. _equipment-examples: 2 | 3 | ======== 4 | Examples 5 | ======== 6 | Some example scripts that illustrate how to use MSL-Equipment to communicate 7 | with equipment can be found in the repository_. 8 | 9 | .. _repository: https://github.com/MSLNZ/msl-equipment/tree/main/msl/examples/equipment 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.channel.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.channel module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.channel 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps2000a.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps2000a module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps2000a 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps3000a.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps3000a module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps3000a 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps4000a.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps4000a module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps4000a 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.ps5000a.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.ps5000a module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.ps5000a 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.structs.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.structs module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.structs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.callbacks.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.callbacks module 2 | ========================================================= 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.callbacks 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/schema/digital_report.md: -------------------------------------------------------------------------------- 1 | # DigitalReport 2 | 3 | ::: msl.equipment.schema.DigitalReport 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | 8 | ::: msl.equipment.schema.DigitalFormat 9 | options: 10 | show_root_full_path: false 11 | show_root_heading: true 12 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/vaisala/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Vaisala](https://www.vaisala.com/en).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .ptb330 import PTB330 6 | from .ptu300 import PTU300 7 | 8 | __all__: list[str] = [ 9 | "PTB330", 10 | "PTU300", 11 | ] 12 | -------------------------------------------------------------------------------- /src/msl/equipment/resources/__init__.py: -------------------------------------------------------------------------------- 1 | """Import the `msl-equipment-resources` package (if installed).""" 2 | 3 | from __future__ import annotations 4 | 5 | import contextlib 6 | 7 | with contextlib.suppress(ImportError): 8 | from msl.equipment_resources import * # pyright: ignore[reportWildcardImportFromLibrary] # noqa: F403 9 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.electron_dynamics.tc_series.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.electron\_dynamics.tc\_series module 2 | ============================================================ 3 | 4 | .. automodule:: msl.equipment.resources.electron_dynamics.tc_series 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.callbacks.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.callbacks module 2 | =========================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.callbacks 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.functions.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.functions module 2 | =========================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.functions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.picoscope.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.picoscope module 2 | =========================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.picoscope 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/cmi/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from the Czech Metrology Institute.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .sia3 import SIA3, IntegrationTime, PreScale 6 | 7 | __all__: list[str] = [ 8 | "SIA3", 9 | "IntegrationTime", 10 | "PreScale", 11 | ] 12 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/princeton_instruments/__init__.py: -------------------------------------------------------------------------------- 1 | """Wrapper around the `ARC_Instrument.dll` SDK from Princeton Instruments.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .arc_instrument import PrincetonInstruments 6 | 7 | __all__: list[str] = [ 8 | "PrincetonInstruments", 9 | ] 10 | -------------------------------------------------------------------------------- /tests/resources/mass/not-a-register.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | true 9 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.api_functions.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.api_functions module 2 | ============================================================= 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.api_functions 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.filter_flipper.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.filter_flipper module 2 | ============================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.filter_flipper 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.kcube_solenoid.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.kcube_solenoid module 2 | ============================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.kcube_solenoid 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.motion_control.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.motion_control module 2 | ============================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.motion_control 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/picotech/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Pico Technology](https://www.picotech.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .picoscope import PicoScope 6 | from .pt104 import PT104 7 | 8 | __all__: list[str] = [ 9 | "PT104", 10 | "PicoScope", 11 | ] 12 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.picoscope_api.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.picoscope_api module 2 | =============================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.picoscope_api 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/optronic_labs/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [Optronic Laboratories](https://optroniclabs.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .ol756ocx_64 import OL756 6 | from .olxxa import OLxxA 7 | 8 | __all__: list[str] = [ 9 | "OL756", 10 | "OLxxA", 11 | ] 12 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.optronic_laboratories.ol756ocx_32.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.optronic\_laboratories.ol756ocx\_32 module 2 | ================================================================== 3 | 4 | .. automodule:: msl.equipment.resources.optronic_laboratories.ol756ocx_32 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.optronic_laboratories.ol756ocx_64.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.optronic\_laboratories.ol756ocx\_64 module 2 | ================================================================== 3 | 4 | .. automodule:: msl.equipment.resources.optronic_laboratories.ol756ocx_64 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.picoscope_2k3k.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope.picoscope_2k3k module 2 | ================================================================ 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope.picoscope_2k3k 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /src/msl/equipment/__about__.py: -------------------------------------------------------------------------------- 1 | """Project information.""" 2 | 3 | from __future__ import annotations 4 | 5 | from ._version import __version__, version_tuple 6 | 7 | __all__: list[str] = ["__version__", "version_tuple"] 8 | __author__: str = "Measurement Standards Laboratory of New Zealand" 9 | __copyright__: str = f"\xa9 2017 - 2025, {__author__}" 10 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.nkt.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.nkt package 2 | =================================== 3 | 4 | .. automodule:: msl.equipment.resources.nkt 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.nkt.nktpdll 15 | 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.kcube_dc_servo.rst: -------------------------------------------------------------------------------- 1 | msl\.equipment\.resources\.thorlabs\.kinesis\.kcube\_dc\_servo module 2 | ===================================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.kcube_dc_servo 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.cmi.rst: -------------------------------------------------------------------------------- 1 | msl\.equipment\.resources\.cmi package 2 | ====================================== 3 | 4 | .. automodule:: msl.equipment.resources.cmi 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.cmi.sia3 15 | 16 | -------------------------------------------------------------------------------- /docs/api/exceptions.md: -------------------------------------------------------------------------------- 1 | # exceptions 2 | 3 | ::: msl.equipment.interfaces.message_based.MSLConnectionError 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | 8 | ::: msl.equipment.interfaces.message_based.MSLTimeoutError 9 | options: 10 | show_root_full_path: false 11 | show_root_heading: true 12 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.omega.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.omega package 2 | ===================================== 3 | 4 | .. automodule:: msl.equipment.resources.omega 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.omega.ithx 15 | 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.princeton_instruments.arc_instrument.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.princeton\_instruments.arc\_instrument module 2 | ===================================================================== 3 | 4 | .. automodule:: msl.equipment.resources.princeton_instruments.arc_instrument 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.aim_tti.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.aim\_tti package 2 | ======================================== 3 | 4 | .. automodule:: msl.equipment.resources.aim_tti 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.aim_tti.mx_series 15 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.avantes.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.avantes package 2 | ======================================= 3 | 4 | .. automodule:: msl.equipment.resources.avantes 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.avantes.avaspec 15 | 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.benchtop_stepper_motor.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.benchtop\_stepper\_motor module 2 | ======================================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.benchtop_stepper_motor 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.kcube_stepper_motor.rst: -------------------------------------------------------------------------------- 1 | msl\.equipment\.resources\.thorlabs\.kinesis\.kcube\_stepper\_motor module 2 | ========================================================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.kcube_stepper_motor 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.optosigma.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.optosigma package 2 | ========================================= 3 | 4 | .. automodule:: msl.equipment.resources.optosigma 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.optosigma.shot702 15 | 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.raicol.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.raicol package 2 | ====================================== 3 | 4 | .. automodule:: msl.equipment.resources.raicol 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | msl.equipment.resources.raicol.raicol_tec 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.integrated_stepper_motors.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis.integrated_stepper_motors module 2 | ========================================================================= 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis.integrated_stepper_motors 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/isotech/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [IsoTech](https://isotech.co.uk/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .millik import Current, MilliK, Resistance, Type, Voltage 6 | 7 | __all__: list[str] = [ 8 | "Current", 9 | "MilliK", 10 | "Resistance", 11 | "Type", 12 | "Voltage", 13 | ] 14 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/mks/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [MKS](https://www.mks.com/) Instruments.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .pr4000b import PR4000B, UNIT, LimitMode, SignalMode, Tag 6 | 7 | __all__: list[str] = [ 8 | "PR4000B", 9 | "UNIT", 10 | "LimitMode", 11 | "SignalMode", 12 | "Tag", 13 | ] 14 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/optosigma/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [OptoSigma](https://jp.optosigma.com/en_jp/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .shot702 import SHOT702, Mode, Speed, State, Status 6 | 7 | __all__: list[str] = [ 8 | "SHOT702", 9 | "Mode", 10 | "Speed", 11 | "State", 12 | "Status", 13 | ] 14 | -------------------------------------------------------------------------------- /tests/resources/mass/.hidden/bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is an invalid XML document, but since it is within a ".hidden" folder 4 | (folder name starts with .) this file is not parsed when Config.registers() 5 | recursively looks for register files within the tests directory. 6 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.isotech.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.isotech package 2 | ======================================= 3 | 4 | .. automodule:: msl.equipment.resources.isotech 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | msl.equipment.resources.isotech.millik 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.energetiq.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.energetiq package 2 | ========================================= 3 | 4 | .. automodule:: msl.equipment.resources.energetiq 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | msl.equipment.resources.energetiq.eq99 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.greisinger.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.greisinger package 2 | ========================================== 3 | 4 | .. automodule:: msl.equipment.resources.greisinger 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | msl.equipment.resources.greisinger.gmh3000 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.mks_instruments.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.mks\_instruments package 2 | ================================================ 3 | 4 | .. automodule:: msl.equipment.resources.mks_instruments 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.mks_instruments.pr4000b 15 | -------------------------------------------------------------------------------- /docs/webapp.md: -------------------------------------------------------------------------------- 1 | # Web Application 2 | 3 | !!! info 4 | Development on the web application has not started. 5 | 6 | The web application provides a server for running a website that allows people to search for equipment records with equipment registers and (maybe) to add equipment records to a register. 7 | 8 | ## Install 9 | 10 | Eventually... 11 | 12 | ```console 13 | pip install msl-equipment-webapp 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/api/backends/index.md: -------------------------------------------------------------------------------- 1 | # Backends 2 | 3 | The following classes may be used to interface with equipment using external packages 4 | 5 | * [NIDAQ][] — Use the [NIDAQmx](https://nidaqmx-python.readthedocs.io/en/stable/index.html) package to establish a connection to the equipment 6 | * [PyVISA][] — Use the [PyVISA](https://pyvisa.readthedocs.io/en/stable/index.html) package to establish a connection to the equipment 7 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.electron_dynamics.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.electron\_dynamics package 2 | ================================================== 3 | 4 | .. automodule:: msl.equipment.resources.electron_dynamics 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.electron_dynamics.tc_series 15 | 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.vaisala.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.vaisala package 2 | ======================================= 3 | 4 | .. automodule:: msl.equipment.resources.vaisala 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | msl.equipment.resources.vaisala.ptu300 16 | msl.equipment.resources.vaisala.ptb330 -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.dataray.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.dataray package 2 | ======================================= 3 | 4 | .. automodule:: msl.equipment.resources.dataray 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.dataray.datarayocx_32 15 | msl.equipment.resources.dataray.datarayocx_64 16 | 17 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.princeton_instruments.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.princeton\_instruments package 2 | ====================================================== 3 | 4 | .. automodule:: msl.equipment.resources.princeton_instruments 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.princeton_instruments.arc_instrument 15 | 16 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.optronic_laboratories.ol_current_source.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.optronic\_laboratories.ol\_current\_source module 2 | ========================================================================= 3 | 4 | .. automodule:: msl.equipment.resources.optronic_laboratories.ol_current_source 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :exclude-members: ol_current_source_factory, OLCurrentSourceGPIB, OLCurrentSourceASRL 9 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech package 2 | ======================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.picotech.errors 15 | msl.equipment.resources.picotech.picoscope 16 | msl.equipment.resources.picotech.pt104 17 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs package 2 | ======================================== 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.thorlabs.kinesis 15 | 16 | Submodules 17 | ---------- 18 | 19 | .. toctree:: 20 | 21 | msl.equipment.resources.thorlabs.fwxx2c 22 | 23 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.bentham.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.bentham package 2 | ======================================= 3 | 4 | .. automodule:: msl.equipment.resources.bentham 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.bentham.benhw32 15 | msl.equipment.resources.bentham.benhw64 16 | msl.equipment.resources.bentham.errors 17 | msl.equipment.resources.bentham.tokens 18 | 19 | -------------------------------------------------------------------------------- /packages/resources/README.md: -------------------------------------------------------------------------------- 1 | # msl-equipment-resources 2 | 3 | Resources to communicate with equipment. 4 | 5 | ## Compatibility 6 | `msl-equipment` is tested with Python 3.8+ on Windows, Linux and macOS; however, some of the [resources] might not work for your application because the resource may depend on an external dependency (e.g., the SDK provided by a manufacturer) and this external dependency might not be available for your operating system. 7 | 8 | [resources]: https://msl-equipment.readthedocs.io/en/latest/resources.html 9 | -------------------------------------------------------------------------------- /packages/validate/tests/conftest.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import pytest 4 | from msl.equipment_validate.validate import Info, Summary 5 | 6 | 7 | @pytest.fixture 8 | def reset_summary() -> None: 9 | for item in dir(Summary): 10 | if item.startswith("num"): 11 | setattr(Summary, item, 0) 12 | elif item.startswith("unchecked"): 13 | setattr(Summary, item, ()) 14 | 15 | 16 | @pytest.fixture 17 | def info() -> Info: 18 | return Info(url="register.xml", exit_first=False, uri_scheme=None, debug_name="Name", no_colour=True) 19 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.optronic_laboratories.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.optronic\_laboratories package 2 | ====================================================== 3 | 4 | .. automodule:: msl.equipment.resources.optronic_laboratories 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | msl.equipment.resources.optronic_laboratories.ol756ocx_32 16 | msl.equipment.resources.optronic_laboratories.ol756ocx_64 17 | msl.equipment.resources.optronic_laboratories.ol_current_source 18 | -------------------------------------------------------------------------------- /docs/schema/equipment.md: -------------------------------------------------------------------------------- 1 | # Equipment 2 | 3 | ::: msl.equipment.schema.Equipment 4 | options: 5 | show_root_full_path: false 6 | show_root_heading: true 7 | 8 | ::: msl.equipment.schema.Latest 9 | options: 10 | show_root_full_path: false 11 | show_root_heading: true 12 | 13 | ::: msl.equipment.schema.LatestPerformanceCheck 14 | options: 15 | show_root_full_path: false 16 | show_root_heading: true 17 | 18 | ::: msl.equipment.schema.LatestReport 19 | options: 20 | show_root_full_path: false 21 | show_root_heading: true 22 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/pt104_find.py: -------------------------------------------------------------------------------- 1 | """Print the PT-104 Data Logger's that are connected to the computer.""" 2 | 3 | import os 4 | 5 | from msl.equipment.resources import PT104 6 | 7 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 8 | # Alternatively, you can specify the full path to the library file as an argument to enumerate_units() 9 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 10 | 11 | print("The following PT-104's were found:") 12 | for unit in PT104.enumerate_units(): 13 | print(f" {unit}") 14 | -------------------------------------------------------------------------------- /docs/api/interfaces/index.md: -------------------------------------------------------------------------------- 1 | # Interfaces 2 | 3 | Generic interface classes for computer control 4 | 5 | * [Interface][msl.equipment.schema.Interface] — Base class for all interfaces 6 | * [MessageBased][msl.equipment.interfaces.message_based.MessageBased] — Base class for all message-based interfaces 7 | 8 | ::: msl.equipment.schema.Interface 9 | options: 10 | show_root_full_path: false 11 | show_root_heading: true 12 | 13 | ::: msl.equipment.interfaces.message_based.MessageBased 14 | options: 15 | show_root_full_path: false 16 | show_root_heading: true 17 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/ps5000a_find.py: -------------------------------------------------------------------------------- 1 | """Print the PicoScopes that are connected to the computer.""" 2 | 3 | import os 4 | 5 | from msl.equipment.resources import PicoScope 6 | 7 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 8 | # Alternatively, you can specify the full path to the library file as an argument to enumerate_units() 9 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 10 | 11 | print("The following PicoScope's were found:") 12 | for unit in PicoScope.enumerate_units("ps5000a"): 13 | print(f" {unit}") 14 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment/resources/thorlabs/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Resources for equipment from `Thorlabs `_. 3 | """ 4 | from __future__ import annotations 5 | 6 | from .fwxx2c import FilterWheelXX2C 7 | from .kinesis import enums 8 | from .kinesis import structs 9 | from .kinesis.benchtop_stepper_motor import BenchtopStepperMotor 10 | from .kinesis.callbacks import MotionControlCallback 11 | from .kinesis.filter_flipper import FilterFlipper 12 | from .kinesis.integrated_stepper_motors import IntegratedStepperMotors 13 | from .kinesis.kcube_dc_servo import KCubeDCServo 14 | from .kinesis.kcube_solenoid import KCubeSolenoid 15 | from .kinesis.kcube_stepper_motor import KCubeStepperMotor 16 | from .kinesis.motion_control import MotionControl 17 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/electron_dynamics/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from Electron Dynamics Ltd.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .tc_series import ( 6 | Alarm, 7 | AlarmType, 8 | Control, 9 | ControlType, 10 | Method, 11 | Output, 12 | Polarity, 13 | PowerUpState, 14 | Sensor, 15 | SensorType, 16 | Setpoint, 17 | Status, 18 | TCSeries, 19 | Unit, 20 | ) 21 | 22 | __all__: list[str] = [ 23 | "Alarm", 24 | "AlarmType", 25 | "Control", 26 | "ControlType", 27 | "Method", 28 | "Output", 29 | "Polarity", 30 | "PowerUpState", 31 | "Sensor", 32 | "SensorType", 33 | "Setpoint", 34 | "Status", 35 | "TCSeries", 36 | "Unit", 37 | ] 38 | -------------------------------------------------------------------------------- /src/msl/equipment/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | """Interfaces for computer control.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .gpib import GPIB 6 | from .hislip import HiSLIP 7 | from .message_based import MessageBased, MSLConnectionError, MSLTimeoutError 8 | from .nidaq import NIDAQ 9 | from .prologix import Prologix 10 | from .pyvisa import PyVISA 11 | from .sdk import SDK 12 | from .serial import Serial 13 | from .socket import Socket 14 | from .vxi11 import VXI11 15 | from .zeromq import ZeroMQ 16 | 17 | __all__: list[str] = [ 18 | "GPIB", 19 | "NIDAQ", 20 | "SDK", 21 | "VXI11", 22 | "HiSLIP", 23 | "MSLConnectionError", 24 | "MSLTimeoutError", 25 | "MessageBased", 26 | "Prologix", 27 | "PyVISA", 28 | "Serial", 29 | "Socket", 30 | "ZeroMQ", 31 | ] 32 | -------------------------------------------------------------------------------- /tests/resources/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30 5 | true 6 | OD: 2.0 7 | 8 | smtp.server.nz 9 | 25 10 | me@measurement.govt.nz 11 | you@measurement.govt.nz 12 | 13 | 14 | 15 | 16 | 17 | 18 | tests/resources/mass 19 | tests/resources/light 20 | 21 | tests/resources/connections.xml 22 | 23 | -------------------------------------------------------------------------------- /docs-old/_static/custom.css: -------------------------------------------------------------------------------- 1 | .red { 2 | color: red; 3 | } 4 | 5 | .blue { 6 | color: blue; 7 | font-style: italic; 8 | } 9 | 10 | /* allow table to wrap the text */ 11 | .wy-table-responsive table th { 12 | white-space: normal; 13 | } 14 | 15 | /* fix rendering of @property methods on ReadTheDocs */ 16 | .rst-content dl:not(.docutils) .property { 17 | display: revert; 18 | } 19 | html.writer-html4 .rst-content dl:not(.docutils) .property, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .property { 20 | display: revert; 21 | } 22 | html.writer-html4 .rst-content dl:not(.docutils) .property, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property { 23 | display: revert; 24 | padding-right: 8px; 25 | max-width: 100%; 26 | } -------------------------------------------------------------------------------- /packages/resources/examples/omega/ithx.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an OMEGA iTHX Series Temperature and Humidity Chart Recorder.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import ITHX 11 | 12 | 13 | connection = Connection( 14 | "TCP::192.168.1.100::2000", # update for your OMEGA iServer 15 | manufacturer="OMEGA", 16 | model="iTHX-W3", # update for your OMEGA iServer 17 | timeout=2, 18 | ) 19 | 20 | # Connect to the iServer 21 | ithx: ITHX = connection.connect() 22 | 23 | # Read the temperature, relative humidity and dewpoint 24 | print(f"T {ithx.temperature()} °C") 25 | print(f"H {ithx.humidity()} %") 26 | print(f"DP {ithx.dewpoint(celsius=False)} °F") 27 | 28 | # Disconnect from the iServer 29 | ithx.disconnect() 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | --- 4 | 5 | ## 0.2.0 (2025-03-28) 6 | 7 | ***Added:*** 8 | 9 | - support for Python 3.12 and 3.13 10 | - `find-equipment` console script 11 | - `msl.equipment.connection_gpib.ConnectionGPIB` class 12 | - `msl.equipment.resources.greisinger.gmh3000.GMH3000` resource 13 | - `msl.equipment.resources.isotech.millik.MilliK` resource 14 | - `msl.equipment.resources.vaisala.ptu300.PTU300` resource 15 | - `msl.equipment.resources.vaisala.ptb330.PTB330` resource 16 | 17 | ***Fixed:*** 18 | 19 | - issue [#9](https://github.com/MSLNZ/msl-equipment/issues/9) — Missing functions from Avantes AvaSpec DLL 20 | - issue [#8](https://github.com/MSLNZ/msl-equipment/issues/8) — Invalid URL for LXI XML identification document 21 | 22 | ***Removed:*** 23 | 24 | - support for Python 2.7, 3.5, 3.6 and 3.7 25 | 26 | ## 0.1.0 (2023-06-18) 27 | 28 | Initial release. 29 | 30 | It is also the last release to support Python 2.7, 3.5, 3.6 and 3.7 31 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | PY_COLORS: 1 7 | COLUMNS: 110 8 | 9 | jobs: 10 | test: 11 | name: Test 12 | runs-on: ${{ matrix.os }}-latest 13 | timeout-minutes: 10 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | os: [ubuntu, windows, macos] 18 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v5 22 | - name: Install locales (Ubuntu) 23 | if: ${{ matrix.os == 'ubuntu' }} 24 | run: | 25 | sudo apt-get update 26 | sudo apt-get install -y language-pack-en language-pack-de 27 | - name: Install uv 28 | uses: astral-sh/setup-uv@v6 29 | with: 30 | enable-cache: false 31 | - name: Run tests 32 | run: uv run --all-packages --python ${{ matrix.python-version }} --no-dev --group test -- pytest 33 | -------------------------------------------------------------------------------- /packages/resources/examples/avantes/find_devices.py: -------------------------------------------------------------------------------- 1 | """Example showing how to find all AvaSpec devices that are available. 2 | 3 | The AvaSpec shared library may require a Visual C++ Redistributable Package to be installed (on Windows). 4 | """ 5 | 6 | import os 7 | 8 | from msl.equipment.resources import AvaSpec 9 | 10 | # You can either specify the full path to the SDK 11 | # (e.g., C:/AvaSpecX64-DLL_9.7/avaspecx64.dll) in the Avantes.find() 12 | # function, or, you can add the directory where the avaspecx64 library file is located 13 | # to your PATH environment variable 14 | os.environ["PATH"] += os.pathsep + r"C:\AvaSpecX64-DLL_9.7" 15 | 16 | devices = AvaSpec.find() 17 | if devices: 18 | print("Found the following Avantes devices: ") 19 | for device in devices: 20 | print(f" SerialNumber: {device.SerialNumber}") 21 | print(f" UserFriendlyName: {device.UserFriendlyName}") 22 | print(f" Status: {device.Status}") 23 | else: 24 | print("Could not find any AvaSpec devices") 25 | -------------------------------------------------------------------------------- /docs/resources/avantes/avaspec.md: -------------------------------------------------------------------------------- 1 | # AvaSpec SDK 2 | 3 | Wrapper around the `avaspec` SDK from [Avantes](https://www.avantes.com/){:target="_blank"}. 4 | 5 | The wrapper was written using v9.7.0.0 of the SDK. The `avaspec` SDK may require a Visual C++ Redistributable Package to be installed (on Windows). 6 | 7 | The main class is [AvaSpec][msl.equipment_resources.avantes.avaspec.AvaSpec] and the [Enums and Structs][avaspec-enums-structs] are available once the `avantes` module is imported, for example, 8 | 9 | ```python 10 | from msl.equipment.resources import avantes 11 | 12 | cfg = avantes.MeasConfigType() 13 | cfg.m_IntegrationTime = 5 # in milliseconds 14 | cfg.m_NrAverages = 1 # number of averages 15 | ``` 16 | 17 | ::: msl.equipment_resources.avantes.avaspec.AvaSpec 18 | options: 19 | show_root_full_path: false 20 | show_root_heading: true 21 | 22 | ## Enums and Structs {: #avaspec-enums-structs } 23 | 24 | ::: msl.equipment_resources.avantes.avaspec 25 | options: 26 | filters: ["!AvaSpec"] 27 | -------------------------------------------------------------------------------- /packages/resources/examples/raicol/tec_oven.py: -------------------------------------------------------------------------------- 1 | """Example showing how to control a TEC (Peltier-based) oven from Raicol Crystals.""" 2 | 3 | from __future__ import annotations 4 | 5 | import time 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import RaicolTEC 12 | 13 | connection = Connection( 14 | "COM4", # update for your oven 15 | manufacturer="Raicol Crystals", 16 | model="TEC 20-60", 17 | ) 18 | 19 | # connect to the TEC controller 20 | tec: RaicolTEC = connection.connect() 21 | 22 | # set the setpoint temperature, in Celsius 23 | tec.set_setpoint(25.0) 24 | 25 | # get the setpoint temperature 26 | print("setpoint=", tec.get_setpoint()) 27 | 28 | # turn the TEC on 29 | tec.on() 30 | 31 | # read the current temperature 32 | for _ in range(30): 33 | time.sleep(1) 34 | print("temperature=", tec.temperature()) 35 | 36 | # turn the TEC off 37 | tec.off() 38 | 39 | # disconnect from the TEC controller 40 | tec.disconnect() 41 | -------------------------------------------------------------------------------- /packages/resources/examples/cmi/sia.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a Switched Integrator Amplifier (SIA).""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | from msl.equipment.resources import cmi 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import SIA3 12 | 13 | connection = Connection( 14 | "COM3", # update for your amplifier 15 | manufacturer="CMI", 16 | model="SIA3", 17 | ) 18 | 19 | # Connect to the amplifier 20 | sia: SIA3 = connection.connect() 21 | 22 | # These are equivalent to set the pre-scale factor to 7 23 | sia.set_ps(cmi.PreScale.PS_7) # use the enum 24 | sia.set_ps(7) # use the enum value 25 | 26 | # These are equivalent to set the integration time to 2 seconds 27 | sia.set_integration_time(cmi.IntegrationTime.TIME_2s) # use the enum 28 | sia.set_integration_time("2s") # use the last part of the enum member name 29 | sia.set_integration_time(14) # use the enum value 30 | 31 | # Disconnect from the amplifier 32 | sia.disconnect() 33 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.record_types.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.record_types module 2 | ================================= 3 | 4 | Records from :ref:`equipment-database`\'s or :ref:`connections-database`\'s. 5 | 6 | .. autoclass:: msl.equipment.record_types.EquipmentRecord 7 | :members: 8 | :show-inheritance: 9 | :inherited-members: 10 | 11 | .. autoclass:: msl.equipment.record_types.CalibrationRecord 12 | :members: 13 | :show-inheritance: 14 | :inherited-members: 15 | 16 | .. autoclass:: msl.equipment.record_types.MeasurandRecord 17 | :members: 18 | :show-inheritance: 19 | :inherited-members: 20 | 21 | .. autoclass:: msl.equipment.record_types.MaintenanceRecord 22 | :members: 23 | :show-inheritance: 24 | :inherited-members: 25 | 26 | .. autoclass:: msl.equipment.record_types.ConnectionRecord 27 | :members: 28 | :show-inheritance: 29 | :inherited-members: 30 | 31 | .. autoclass:: msl.equipment.record_types.RecordDict 32 | :members: 33 | :show-inheritance: 34 | :no-undoc-members: 35 | 36 | .. autoclass:: msl.equipment.record_types.Record 37 | :members: 38 | :show-inheritance: 39 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/nkt/__init__.py: -------------------------------------------------------------------------------- 1 | """Resources for equipment from [NKT Photonics](https://www.nktphotonics.com/).""" 2 | 3 | from __future__ import annotations 4 | 5 | from .nktpdll import ( 6 | NKT, 7 | DateTime, 8 | DeviceMode, 9 | DeviceStatus, 10 | DeviceStatusCallback, 11 | ParameterSet, 12 | PointToPoint, 13 | PortStatus, 14 | PortStatusCallback, 15 | RegisterData, 16 | RegisterPriority, 17 | RegisterStatus, 18 | RegisterStatusCallback, 19 | Unit, 20 | device_status_callback, 21 | port_status_callback, 22 | register_status_callback, 23 | ) 24 | 25 | __all__: list[str] = [ 26 | "NKT", 27 | "DateTime", 28 | "DeviceMode", 29 | "DeviceStatus", 30 | "DeviceStatusCallback", 31 | "ParameterSet", 32 | "PointToPoint", 33 | "PortStatus", 34 | "PortStatusCallback", 35 | "RegisterData", 36 | "RegisterPriority", 37 | "RegisterStatus", 38 | "RegisterStatusCallback", 39 | "Unit", 40 | "device_status_callback", 41 | "port_status_callback", 42 | "register_status_callback", 43 | ] 44 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.thorlabs.kinesis.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.thorlabs.kinesis package 2 | ================================================ 3 | 4 | .. automodule:: msl.equipment.resources.thorlabs.kinesis 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.thorlabs.kinesis.api_functions 15 | msl.equipment.resources.thorlabs.kinesis.benchtop_stepper_motor 16 | msl.equipment.resources.thorlabs.kinesis.callbacks 17 | msl.equipment.resources.thorlabs.kinesis.enums 18 | msl.equipment.resources.thorlabs.kinesis.errors 19 | msl.equipment.resources.thorlabs.kinesis.filter_flipper 20 | msl.equipment.resources.thorlabs.kinesis.integrated_stepper_motors 21 | msl.equipment.resources.thorlabs.kinesis.kcube_dc_servo 22 | msl.equipment.resources.thorlabs.kinesis.kcube_solenoid 23 | msl.equipment.resources.thorlabs.kinesis.kcube_stepper_motor 24 | msl.equipment.resources.thorlabs.kinesis.messages 25 | msl.equipment.resources.thorlabs.kinesis.motion_control 26 | msl.equipment.resources.thorlabs.kinesis.structs 27 | -------------------------------------------------------------------------------- /src/msl/equipment/record_types.py: -------------------------------------------------------------------------------- 1 | """Deprecated classes.""" 2 | 3 | from __future__ import annotations 4 | 5 | import warnings 6 | from typing import Any 7 | 8 | from .schema import Connection, Equipment 9 | 10 | 11 | class _Warn: 12 | show: bool = True 13 | 14 | @staticmethod 15 | def warn() -> None: 16 | msg = ( 17 | "The EquipmentRecord and ConnectionRecord classes are deprecated and will be removed in a future release. " 18 | "Replace `EquipmentRecord` with `Equipment` and replace `ConnectionRecord` with `Connection`." 19 | ) 20 | warnings.warn(msg, FutureWarning, stacklevel=3) 21 | _Warn.show = False 22 | 23 | 24 | def EquipmentRecord(**kwargs: Any) -> Equipment: # noqa: ANN401, N802 25 | """Deprecated. Replace `EquipmentRecord` with `Equipment`.""" 26 | if _Warn.show: 27 | _Warn.warn() 28 | return Equipment(**kwargs) 29 | 30 | 31 | def ConnectionRecord(**kwargs: Any) -> Connection: # noqa: ANN401, N802 32 | """Deprecated. Replace `ConnectionRecord` with `Connection`.""" 33 | if _Warn.show: 34 | _Warn.warn() 35 | return Connection(**kwargs) 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 - 2025, Measurement Standards Laboratory of New Zealand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources package 2 | =============================== 3 | 4 | .. automodule:: msl.equipment.resources 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.utils 15 | 16 | Subpackages 17 | ----------- 18 | 19 | .. toctree:: 20 | 21 | msl.equipment.resources.aim_tti 22 | msl.equipment.resources.avantes 23 | msl.equipment.resources.bentham 24 | msl.equipment.resources.cmi 25 | msl.equipment.resources.dataray 26 | msl.equipment.resources.electron_dynamics 27 | msl.equipment.resources.energetiq 28 | msl.equipment.resources.greisinger 29 | msl.equipment.resources.isotech 30 | msl.equipment.resources.mks_instruments 31 | msl.equipment.resources.nkt 32 | msl.equipment.resources.omega 33 | msl.equipment.resources.optosigma 34 | msl.equipment.resources.optronic_laboratories 35 | msl.equipment.resources.picotech 36 | msl.equipment.resources.princeton_instruments 37 | msl.equipment.resources.raicol 38 | msl.equipment.resources.thorlabs 39 | msl.equipment.resources.vaisala 40 | -------------------------------------------------------------------------------- /packages/resources/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025, Measurement Standards Laboratory of New Zealand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/validate/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025, Measurement Standards Laboratory of New Zealand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/resources/examples/mks/pr4000b.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a PR4000B Flow and Pressure controller from MKS.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection, Parity 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import PR4000B 11 | 12 | 13 | connection = Connection( 14 | "COM3", # update for your controller 15 | manufacturer="MKS Instruments", 16 | model="PR4000BF2V2", 17 | baud_rate=9600, # the baud rate can be changed on the PR4000B 18 | parity=Parity.ODD, # the parity can be changed on the PR4000B 19 | ) 20 | 21 | # connect to the controller 22 | mks: PR4000B = connection.connect() 23 | 24 | # get the identity of the controller 25 | identity = mks.identity() 26 | print(f"Identity: {identity}") 27 | 28 | # reset to the default pressure configuration 29 | mks.default("pressure") 30 | 31 | # set the pressure range for channel 2 to be 133 Pa 32 | mks.set_range(2, 133, "Pa") 33 | 34 | # read the pressure from channel 2 35 | pressure = mks.get_actual_value(2) 36 | print(f"pressure: {pressure}") 37 | 38 | # disconnect from the controller 39 | mks.disconnect() 40 | -------------------------------------------------------------------------------- /packages/resources/examples/electron_dynamics/tc_series.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a TC Series Temperature Controller from Electron Dynamics Ltd.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | from msl.equipment.resources import electron_dynamics as ed 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import TCSeries 12 | 13 | 14 | connection = Connection( 15 | "COM5", # update for your controller 16 | manufacturer="Electron Dynamics", 17 | model="TC Lite", 18 | ) 19 | 20 | # Connect to the Temperature Controller 21 | tc: TCSeries = connection.connect() 22 | 23 | # Get all available information about the Temperature Controller 24 | print(f"alarm: {tc.get_alarm()}") 25 | print(f"control: {tc.get_control()}") 26 | print(f"output: {tc.get_output()}") 27 | print(f"sensor: {tc.get_sensor()}") 28 | print(f"setpoint: {tc.get_setpoint()}") 29 | print(f"status: {tc.get_status()}") 30 | 31 | # Set the sensor to be PT100 32 | tc.set_sensor(ed.Sensor(type=ed.SensorType.PT100, x2=0, x=0.722, c=0.02, unit=ed.Unit.C, averaging=False)) 33 | 34 | # Disconnect from the Controller 35 | tc.disconnect() 36 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/fw212c.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a FW102C/FW212C Motorized Filter Wheel.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import FWxx2C 11 | 12 | 13 | connection = Connection( 14 | "COM6", 15 | manufacturer="Thorlabs", 16 | model="FW212C", # alternatively FW102C (can also include the NEB suffix) 17 | ) 18 | 19 | # Connect to the filter wheel 20 | wheel: FWxx2C = connection.connect() 21 | 22 | # Print the mode settings 23 | print(f"Is in fast speed mode? {wheel.fast_mode}") 24 | print(f"Are sensors always on? {wheel.sensor_mode}") 25 | print(f"Is in output trigger mode? {wheel.output_mode}") 26 | 27 | # Make the filter wheel return to the first position if it is at 28 | # the last position, otherwise increment to the next position 29 | print(f"Initial position is {wheel.position}") 30 | 31 | if wheel.position == wheel.position_count: 32 | wheel.position = 1 33 | else: 34 | wheel.position += 1 35 | 36 | print(f"Final position is {wheel.position}") 37 | 38 | # Disconnect from the filter wheel 39 | wheel.disconnect() 40 | -------------------------------------------------------------------------------- /packages/resources/examples/vaisala/ptb330.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a Vaisala PTB330 Barometer.""" 2 | 3 | from __future__ import annotations 4 | 5 | from pprint import pprint 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import PTB330 12 | 13 | 14 | connection = Connection( 15 | "COM3", # update for your device 16 | manufacturer="Vaisala", 17 | model="PTB330", 18 | serial="L2310094", 19 | ) 20 | 21 | # Connect to the device 22 | ptb: PTB330 = connection.connect() 23 | 24 | # Display information about the device 25 | pprint(ptb.device_info) 26 | 27 | # A mapping between a quantity and the unit to use for the quantity 28 | ptb.set_units({"P": "hPa", "P3h": "mbar", "TP1": "'C"}) 29 | print("Units set:", ptb.units) 30 | 31 | # Set the format that data will be returned as 32 | ptb.set_format('4.3 P " " 4.3 P3h " " 2.1 TP1 #r #n') 33 | 34 | # There are two ways to check the format string that has been set 35 | print(ptb.get_format()) 36 | print(ptb.device_info["Output format"]) 37 | 38 | # Get a reading from the device (in the specified format) 39 | print(ptb.get_reading_str()) 40 | 41 | # Disconnect from the device 42 | ptb.disconnect() 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > This repository is undergoing a significant refactoring. Do not install from source since it will be in an unknown state. The next release will have breaking changes with the v0.x release series. 3 | 4 | # MSL-Equipment 5 | 6 | [![CI Status](https://github.com/MSLNZ/msl-equipment/actions/workflows/ci.yml/badge.svg)](https://github.com/MSLNZ/msl-equipment/actions/workflows/ci.yml) 7 | [![Docs Status](https://github.com/MSLNZ/msl-equipment/actions/workflows/docs.yml/badge.svg)](https://github.com/MSLNZ/msl-equipment/actions/workflows/docs.yml) 8 | 9 | The purpose of `msl-equipment` is to manage information about equipment and to interface with equipment for computer control. The information that is managed is focused on testing and calibration laboratories that are accredited for the [ISO/IEC 17025] standard. 10 | 11 | ## Install 12 | To install `msl-equipment` run 13 | 14 | ```console 15 | pip install https://github.com/MSLNZ/msl-equipment/releases/download/v0.2.0/msl_equipment-0.2.0-py3-none-any.whl 16 | ``` 17 | 18 | ## Documentation 19 | The documentation for `msl-equipment` can be found [here]. 20 | 21 | [ISO/IEC 17025]: https://www.iso.org/ISO-IEC-17025-testing-and-calibration-laboratories.html 22 | [here]: https://mslnz.github.io/msl-equipment/dev/ -------------------------------------------------------------------------------- /docs/schema/index.md: -------------------------------------------------------------------------------- 1 | # Schema Classes 2 | 3 | Class representations of the [XML Schema Definition](https://mslnz.github.io/equipment-register-schema/latest/){:target="_blank"} for an equipment register. 4 | 5 | The primary class is [Register][] which contains a sequence of [Equipment][] classes that are each composed of the following classes: 6 | 7 | * [AcceptanceCriteria][] 8 | * [Accessories][] 9 | * [Adjustment][] 10 | * [Alteration][] 11 | * [CapitalExpenditure][] 12 | * [Competency][] 13 | * [CompletedTask][] 14 | * [Component][] 15 | * [Conditions][] 16 | * [CVDEquation][] (Callendar-Van Dusen equation, uses the [cvdCoefficients][type_cvdCoefficients]{:target="_blank"}) 17 | * [Deserialised][] (opposite of [serialised][type_serialised]{:target="_blank"}) 18 | * [DigitalReport][] 19 | * [Equation][] 20 | * [File][] 21 | * [Financial][] 22 | * [Firmware][] 23 | * [Maintenance][] 24 | * [Measurand][] 25 | * [PerformanceCheck][] 26 | * [PlannedTask][] 27 | * [QualityManual][] 28 | * [ReferenceMaterials][] 29 | * [Report][] 30 | * [Specifications][] 31 | * [SpecifiedRequirements][] 32 | * [Status][] 33 | * [Table][] 34 | 35 | The [Any][] class is used as a base class for elements that are currently represented by the [any][type_any]{:target="_blank"} type in the XML Schema Definition. 36 | -------------------------------------------------------------------------------- /packages/resources/examples/princeton_instruments/find_devices.py: -------------------------------------------------------------------------------- 1 | """Example showing how to find all devices from Princeton Instruments.""" 2 | 3 | from msl.equipment.resources import PrincetonInstruments 4 | 5 | # Load the SDK (update the path for your computer) 6 | PrincetonInstruments.init(r"C:\Program Files (x86)\Princeton Instruments\ARC_Instrument_x64.dll") 7 | 8 | major, minor, build = PrincetonInstruments.ver() 9 | print(f"Using version {major}.{minor}.{build} of the SDK") 10 | 11 | # Find all devices from Princeton Instruments 12 | num_found = PrincetonInstruments.search_for_inst() 13 | print(f"Found {num_found} device(s):") 14 | for enum in range(num_found): 15 | model = PrincetonInstruments.get_enum_preopen_model(enum) 16 | serial = PrincetonInstruments.get_enum_preopen_serial(enum) 17 | port = PrincetonInstruments.get_enum_preopen_com(enum) 18 | print(f" Model#: {model!r}, Serial#: {serial} -> at COM{port}") 19 | 20 | # List all Monochromator's that are available 21 | print("Monochromator's available:") 22 | for enum in range(num_found): 23 | try: 24 | model = PrincetonInstruments.get_mono_preopen_model(enum) 25 | except RuntimeError: 26 | continue 27 | else: 28 | print(f" {model!r} at COM{PrincetonInstruments.get_enum_preopen_com(enum)}") 29 | -------------------------------------------------------------------------------- /packages/resources/examples/vaisala/ptu300.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a Vaisala PTU300-series Barometer.""" 2 | 3 | from __future__ import annotations 4 | 5 | from pprint import pprint 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import PTU300 12 | 13 | 14 | connection = Connection( 15 | "COM3", # update for your device 16 | manufacturer="Vaisala", 17 | model="PTU300", 18 | serial="P4040154", 19 | ) 20 | 21 | # Connect to the device 22 | ptu: PTU300 = connection.connect() 23 | 24 | # Display information about the device 25 | pprint(ptu.device_info) 26 | 27 | # A mapping between a quantity and the unit to use for the quantity 28 | ptu.set_units({"P": "hPa", "P3h": "hPa", "T": "'C", "RH": "%RH"}) 29 | print("Units set:", ptu.units) 30 | 31 | # Set the format that data will be returned as 32 | ptu.set_format('4.3 P " " U5 " " 3.3 T " " U5" " 3.3 RH " " U5" " SN " " #r #n') 33 | 34 | # There are two ways to check the format string that has been set 35 | print(ptu.get_format()) 36 | print(ptu.device_info["Output format"]) 37 | 38 | # Get a reading from the device (in the specified format) 39 | print(ptu.get_reading_str()) 40 | 41 | # Disconnect from the device 42 | ptu.disconnect() 43 | -------------------------------------------------------------------------------- /packages/resources/examples/energetiq/eq99.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an EQ-99 Manager from Energetiq.""" 2 | 3 | from __future__ import annotations 4 | 5 | import time 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import EQ99 12 | 13 | connection = Connection( 14 | "COM6", # update for your Manager 15 | manufacturer="Energetiq", 16 | model="EQ-99", 17 | ) 18 | 19 | # connect to the Manager 20 | eq99: EQ99 = connection.connect() 21 | 22 | # get the total number of running hours of the lamp 23 | print(f"Lamp runtime is {eq99.get_lamp_runtime()} hours") 24 | 25 | # turn the output on 26 | eq99.set_output_state(enable=True) 27 | 28 | # wait for the lamp to turn on 29 | t0 = time.time() 30 | while True: 31 | bit_mask = eq99.condition_register() 32 | if bit_mask & 1 << 5: # index 5 represents the "Lamp on" state 33 | print("Lamp is on") 34 | break 35 | 36 | time.sleep(1) 37 | dt = int(time.time() - t0) 38 | print(f"Elapsed time: {dt} seconds, bit mask: {bit_mask}") 39 | 40 | # do other stuff while the lamp is on 41 | time.sleep(5) 42 | 43 | # turn the output off when done 44 | eq99.set_output_state(enable=False) 45 | 46 | # disconnect from the Manager 47 | eq99.disconnect() 48 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment/resources/thorlabs/kinesis/callbacks.py: -------------------------------------------------------------------------------- 1 | """ 2 | A callback to register for a :class:`~msl.equipment.resources.thorlabs.kinesis.motion_control.MotionControl` 3 | message queue. 4 | 5 | .. code-block:: python 6 | 7 | from msl.equipment import Config 8 | from msl.equipment.resources.thorlabs import MotionControlCallback 9 | 10 | @MotionControlCallback 11 | def msg_callback(): 12 | print('MotionControlCallback: ', flipper.convert_message(*flipper.get_next_message())) 13 | 14 | # The "example2.xml" configuration file contains the following element: 15 | # 16 | 17 | db = Config('config.xml').database() 18 | 19 | flipper = db.equipment['filter_flipper'].connect() 20 | flipper.register_message_callback(msg_callback) 21 | 22 | # ... do stuff with the `flipper` ... 23 | 24 | """ 25 | from __future__ import annotations 26 | 27 | import sys 28 | 29 | if sys.platform == 'win32': 30 | from ctypes import WINFUNCTYPE 31 | FUNCTYPE = WINFUNCTYPE 32 | else: 33 | from ctypes import CFUNCTYPE 34 | FUNCTYPE = CFUNCTYPE 35 | 36 | MotionControlCallback = FUNCTYPE(None) 37 | """ 38 | A callback to register for a :class:`~msl.equipment.resources.thorlabs.kinesis.motion_control.MotionControl` 39 | message queue. 40 | """ 41 | -------------------------------------------------------------------------------- /docs-old/_api/msl.equipment.resources.picotech.picoscope.rst: -------------------------------------------------------------------------------- 1 | msl.equipment.resources.picotech.picoscope package 2 | ================================================== 3 | 4 | .. automodule:: msl.equipment.resources.picotech.picoscope 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | 14 | msl.equipment.resources.picotech.picoscope.callbacks 15 | msl.equipment.resources.picotech.picoscope.channel 16 | msl.equipment.resources.picotech.picoscope.enums 17 | msl.equipment.resources.picotech.picoscope.functions 18 | msl.equipment.resources.picotech.picoscope.helper 19 | msl.equipment.resources.picotech.picoscope.picoscope 20 | msl.equipment.resources.picotech.picoscope.picoscope_2k3k 21 | msl.equipment.resources.picotech.picoscope.picoscope_api 22 | msl.equipment.resources.picotech.picoscope.ps2000 23 | msl.equipment.resources.picotech.picoscope.ps2000a 24 | msl.equipment.resources.picotech.picoscope.ps3000 25 | msl.equipment.resources.picotech.picoscope.ps3000a 26 | msl.equipment.resources.picotech.picoscope.ps4000 27 | msl.equipment.resources.picotech.picoscope.ps4000a 28 | msl.equipment.resources.picotech.picoscope.ps5000 29 | msl.equipment.resources.picotech.picoscope.ps5000a 30 | msl.equipment.resources.picotech.picoscope.ps6000 31 | msl.equipment.resources.picotech.picoscope.structs 32 | 33 | -------------------------------------------------------------------------------- /packages/validate/README.md: -------------------------------------------------------------------------------- 1 | # msl-equipment-validate 2 | 3 | [![CI Status](https://github.com/MSLNZ/msl-equipment/actions/workflows/ci.yml/badge.svg)](https://github.com/MSLNZ/msl-equipment/actions/workflows/ci.yml) 4 | [![Docs Status](https://github.com/MSLNZ/msl-equipment/actions/workflows/docs.yml/badge.svg)](https://github.com/MSLNZ/msl-equipment/actions/workflows/docs.yml) 5 | 6 | A command-line tool to validate equipment registers and connection files that are used by [msl-equipment](https://pypi.org/project/msl-equipment/). 7 | 8 | ## Install 9 | `msl-equipment-validate` is available on [PyPI](https://pypi.org/project/msl-equipment-validate/) and can be installed with a variety of Python package managers (e.g., pip, pipx, uv, ...). The following command uses pip 10 | 11 | ```console 12 | pip install msl-equipment-validate 13 | ``` 14 | 15 | If you used a package manager that does not automatically add the `msl-equipment-validate` executable to your PATH environment variable (without activating a [virtual environment](https://docs.python.org/3/library/venv.html)), you may want to add the directory to where the `msl-equipment-validate` executable is located to your PATH. This will allow you to validate XML documents from any directory without having to first activate a virtual environment. 16 | 17 | ## Documentation 18 | The documentation for `msl-equipment-validate` can be found [here](https://mslnz.github.io/msl-equipment/dev/validate). 19 | -------------------------------------------------------------------------------- /docs/getting-started/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | Three concepts are used by `msl-equipment` 4 | 5 | 1. [Equipment registers][] — to comply with the [ISO/IEC 17025]{:target="_blank"} standard 6 | 2. [Connections][] — to interface with equipment for computer control 7 | 3. [Configuration files][] — define requirements for a measurement (links items 1 and 2 together) 8 | 9 | You do not need to use all three concepts for your application. You can choose to only use the [equipment-register classes][schema-classes] to help manage information about the equipment in your laboratory and use a different Python package to communicate with equipment. Similarly, you can choose to use one of the supported [backends][connections-backend] for communication. You can choose to ignore the [equipment registers][] concept and solely use the package to [communicate with equipment][connections-python-examples]. You can also choose to not use `msl-equipment` at all, but just use the [Schema][er-schema] to create equipment registers that comply with [ISO/IEC 17025]{:target="_blank"}. Since an equipment register is written in the eXtensible Markup Language (XML) file format, it may be parsed by many programming languages. This allows people to share a common equipment register but use different programming languages to read information from the same equipment register. 10 | 11 | [ISO/IEC 17025]: https://www.iso.org/ISO-IEC-17025-testing-and-calibration-laboratories.html 12 | -------------------------------------------------------------------------------- /packages/resources/examples/nkt/find_devices.py: -------------------------------------------------------------------------------- 1 | """Example showing how to find all devices from NKT Photonics.""" 2 | 3 | from __future__ import annotations 4 | 5 | from msl.equipment.resources import NKT 6 | 7 | # When installing the SDK a NKTP_SDK_PATH environment variable is created 8 | # and this variable specifies the path to the DLL file; however, you 9 | # can also explicitly specify the path to the DLL file. 10 | NKT.load_sdk("C:/NKTPDLL.dll") 11 | 12 | print("Finding all available ports...") 13 | all_ports = NKT.get_all_ports() 14 | print(f" Found the following ports: {all_ports}") 15 | 16 | # Open all ports (in Auto and Live modes) 17 | print("Opening all ports (in Auto and Live modes)...") 18 | NKT.open_ports(*all_ports) 19 | 20 | # All ports returned by the get_open_ports() function have modules 21 | # (ports without modules will be closed automatically) 22 | opened_ports = NKT.get_open_ports() 23 | print(f" Devices from NKT Photonics are open on the following ports: {opened_ports}") 24 | 25 | # Traverse the opened_ports list and retrieve information about the device types and the addresses 26 | # See the Register Files section in the SDK manual 27 | all_types = NKT.device_get_all_types(*opened_ports) 28 | for name, types in all_types.items(): 29 | print(f" Port: {name}") 30 | for module, device_id in types.items(): 31 | print(f" ModuleType={module} DeviceID={device_id}") 32 | 33 | # Close all ports 34 | NKT.close_ports() 35 | print("Closed all ports") 36 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/__init__.py: -------------------------------------------------------------------------------- 1 | """Custom resources for communicating with equipment.""" 2 | 3 | from __future__ import annotations 4 | 5 | from . import avantes, cmi, electron_dynamics, isotech, mks, nkt, optosigma 6 | from .aim_tti import MXSeries 7 | from .avantes import AvaSpec 8 | from .cmi import SIA3 9 | from .dataray import WinCamD 10 | from .electron_dynamics import TCSeries 11 | from .energetiq import EQ99 12 | from .greisinger import GMH3000 13 | from .isotech import MilliK 14 | from .mks import PR4000B 15 | from .nkt import NKT 16 | from .omega import ITHX 17 | from .optosigma import SHOT702 18 | from .optronic_labs import OL756, OLxxA 19 | from .picotech import PT104, PicoScope, picoscope 20 | from .princeton_instruments import PrincetonInstruments 21 | from .raicol import RaicolTEC 22 | from .thorlabs import FWxx2C 23 | from .vaisala import PTB330, PTU300 24 | 25 | __all__: list[str] = [ 26 | "EQ99", 27 | "GMH3000", 28 | "ITHX", 29 | "NKT", 30 | "OL756", 31 | "PR4000B", 32 | "PT104", 33 | "PTB330", 34 | "PTU300", 35 | "SHOT702", 36 | "SIA3", 37 | "AvaSpec", 38 | "FWxx2C", 39 | "MXSeries", 40 | "MilliK", 41 | "OLxxA", 42 | "PicoScope", 43 | "PrincetonInstruments", 44 | "RaicolTEC", 45 | "TCSeries", 46 | "WinCamD", 47 | "avantes", 48 | "cmi", 49 | "electron_dynamics", 50 | "isotech", 51 | "mks", 52 | "nkt", 53 | "optosigma", 54 | "picoscope", 55 | ] 56 | -------------------------------------------------------------------------------- /packages/resources/examples/optronic_laboratories/ol756.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an Optronic Laboratories 756 UV-VIS spectroradiometer.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import OL756 11 | 12 | 13 | connection = Connection( 14 | "SDK::OL756SDKACTIVEX.OL756SDKActiveXCtrl.1", 15 | manufacturer="Optronic Laboratories Inc", 16 | model="756", 17 | serial="05001009", 18 | mode=1, # connection mode: 0=RS232, 1=USB 19 | com_port=1, # the COM port number (if using RS232 mode) 20 | ) 21 | 22 | # Connect to the spectroradiometer 23 | ol756: OL756 = connection.connect() 24 | 25 | # Load the settings from flash memory 26 | ol756.import_registry() 27 | ol756.read_ol756_flash_settings() 28 | 29 | # Get some information from the spectroradiometer 30 | start = ol756.get_start_wavelength() 31 | end = ol756.get_ending_wavelength() 32 | increment = ol756.get_increment() 33 | print(f"SDK version: {ol756.get_ocx_version()}") 34 | print(f"Wavelength scan range: {start} .. {end} @ {increment} nm") 35 | 36 | # Acquire a scan 37 | ol756.send_down_parameters(0) # Point to point scan. Must be called before take_point_to_point_measurement 38 | ol756.take_point_to_point_measurement(0) # Irradiance type 39 | 40 | # Get the data 41 | data = ol756.get_signal_array() 42 | print(data) 43 | 44 | # Disconnect from the spectroradiometer 45 | ol756.disconnect() 46 | -------------------------------------------------------------------------------- /docs-old/install.rst: -------------------------------------------------------------------------------- 1 | .. _equipment-install: 2 | 3 | ===================== 4 | Install MSL-Equipment 5 | ===================== 6 | 7 | To install MSL-Equipment run 8 | 9 | .. code-block:: console 10 | 11 | pip install https://github.com/MSLNZ/msl-equipment/releases/download/v0.2.0/msl_equipment-0.2.0-py3-none-any.whl 12 | 13 | Alternatively, using the `MSL Package Manager`_ run 14 | 15 | .. code-block:: console 16 | 17 | msl install equipment 18 | 19 | .. _equipment-dependencies: 20 | 21 | Dependencies 22 | ------------ 23 | * Python 3.8+ 24 | * msl-loadlib_ 25 | * msl-io_ 26 | * numpy_ 27 | * pyserial_ 28 | * pyzmq_ 29 | 30 | Optional Dependencies 31 | --------------------- 32 | * PyVISA_ 33 | * PyVISA-py_ 34 | * NI-DAQmx_ 35 | 36 | Some of the :ref:`equipment-resources` might not work in your application 37 | because the resource might depend on an external dependency (e.g., the SDK 38 | provided by a manufacturer) and this external dependency might not be 39 | available for your operating system. 40 | 41 | .. _MSL Package Manager: https://msl-package-manager.readthedocs.io/en/stable/ 42 | .. _PyVISA: https://pyvisa.readthedocs.io/en/stable/ 43 | .. _PyVISA-py: https://pyvisa-py.readthedocs.io/en/stable/ 44 | .. _NI-DAQmx: https://nidaqmx-python.readthedocs.io/en/stable/ 45 | .. _numpy: https://www.numpy.org/ 46 | .. _msl-loadlib: https://msl-loadlib.readthedocs.io/en/stable/ 47 | .. _msl-io: https://msl-io.readthedocs.io/en/latest/ 48 | .. _pyserial: https://pythonhosted.org/pyserial/ 49 | .. _pyzmq: https://pyzmq.readthedocs.io/en/stable/ 50 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/types.py: -------------------------------------------------------------------------------- 1 | """Custom type annotations.""" 2 | 3 | from __future__ import annotations 4 | 5 | from ctypes import _Pointer, c_int32 # pyright: ignore[reportPrivateUsage] 6 | from typing import Callable 7 | 8 | AvaSpecCallback = Callable[[_Pointer[c_int32], _Pointer[c_int32]], None] 9 | """Callback handler for the [AvaSpec][msl.equipment_resources.avantes.avaspec.AvaSpec] SDK.""" 10 | 11 | NKTPortStatusCallback = Callable[[str, int, int, int, int], None] 12 | """Callback handler for the [NKT][msl.equipment_resources.nkt.nktpdll.NKT] SDK when the status of a port changes.""" 13 | 14 | NKTDeviceStatusCallback = Callable[[str, int, int, int, int], None] 15 | """Callback handler for the [NKT][msl.equipment_resources.nkt.nktpdll.NKT] SDK when the status of a device changes.""" 16 | 17 | NKTRegisterStatusCallback = Callable[[str, int, int, int, int, int, int], None] 18 | """Callback handler for the [NKT][msl.equipment_resources.nkt.nktpdll.NKT] SDK when the status of a register changes.""" 19 | 20 | PicoTechBlockReadyCallback = Callable[[int, int, None], None] 21 | """Block-ready callback handler for the [PicoScope][msl.equipment_resources.picotech.picoscope.PicoScope] SDK.""" 22 | 23 | PicoTechDataReadyCallback = Callable[[int, int, int, int, None], None] 24 | """Data-ready callback handler for the [PicoScope][msl.equipment_resources.picotech.picoscope.PicoScope] SDK.""" 25 | 26 | PicoTechStreamingReadyCallback = Callable[[int, int, int, int, int, int, int, None], None] 27 | """Streaming-ready callback handler for the [PicoScope][msl.equipment_resources.picotech.picoscope.PicoScope] SDK.""" 28 | -------------------------------------------------------------------------------- /tests/resources/connections.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MSLE.M.092 5 |
COM1
6 |
7 | 8 | MSLE.M.001 9 |
GPIB::22
10 | MSL 11 |
12 | 13 | MSLE.M.100 14 |
TCPIP::dev.company.com::hislip0
15 | 16 |
17 | 18 | MSLE.O.231 19 |
SDK::library.dll
20 | 21 |
22 | 23 | MSLE.O.103 24 |
TCPIP::192.168.1.100
25 | 26 |
27 | 28 | MSLE.O.061 29 |
TCP::192.168.1.100::5000
30 | 31 |
32 | 33 | MSLE.O.023 34 |
ASRL/dev/ttyS1
35 | PyVISA 36 | Manufacturer 37 | Model 38 | Serial 39 | 40 | 19200 41 | \n 42 | \r 43 | \r\n 44 | 10.2 45 | true 46 | 47 | 48 |
49 |
50 | -------------------------------------------------------------------------------- /packages/resources/examples/optronic_laboratories/ol83a.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an Optronic Laboratories 83A DC Current Source.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import OLxxA 11 | 12 | 13 | connection = Connection( 14 | "COM3", # update for your current source 15 | manufacturer="Optronic Laboratories", 16 | model="83A", 17 | # address=1, # internal address of device (optional) 18 | ) 19 | 20 | # Connect to the current source 21 | ol83a: OLxxA = connection.connect() 22 | 23 | # Turn the output off 24 | ol83a.turn_off() 25 | 26 | # Select a lamp 27 | ol83a.select_lamp(9) 28 | 29 | # Get target information: lamp number, target value, target unit 30 | print(f"target info: {ol83a.target_info()}") 31 | 32 | # Get the output state (on or off) 33 | print(f"is the output on? {ol83a.state()}") 34 | 35 | # Set the target current 36 | actual = ol83a.set_current(0.2345) 37 | print(f"the actual current that was set is {actual}") 38 | 39 | # Get the system status byte of the latest command that was executed 40 | print(f"system status byte: {ol83a.system_status_byte:b}") 41 | 42 | # Read the output current, voltage and wattage 43 | print(f"output current is {ol83a.get_current()} A") 44 | print(f"output voltage is {ol83a.get_voltage()} V") 45 | print(f"output wattage is {ol83a.get_wattage()} W") 46 | 47 | # Get the number of hours for lamp 9 48 | hours = ol83a.get_option(9, 40) 49 | print(f"hours: {hours}") 50 | 51 | # Disconnect from the current source 52 | ol83a.disconnect() 53 | -------------------------------------------------------------------------------- /src/msl/equipment/enumerations.py: -------------------------------------------------------------------------------- 1 | """Enumeration constants.""" 2 | 3 | from __future__ import annotations 4 | 5 | import enum 6 | 7 | import serial 8 | 9 | 10 | class Backend(enum.Enum): 11 | """The backend library to use for communication with the equipment. 12 | 13 | Attributes: 14 | MSL (str): "MSL" 15 | PyVISA (str): "PyVISA" 16 | NIDAQ (str): "NIDAQ" 17 | """ 18 | 19 | MSL = "MSL" 20 | PyVISA = "PyVISA" 21 | NIDAQ = "NIDAQ" 22 | 23 | 24 | class Parity(enum.Enum): 25 | """The parity type to use for Serial communication. 26 | 27 | Attributes: 28 | NONE (str): "N" 29 | ODD (str): "O" 30 | EVEN (str): "E" 31 | MARK (str): "M" 32 | SPACE (str): "S" 33 | """ 34 | 35 | NONE = serial.PARITY_NONE 36 | ODD = serial.PARITY_ODD 37 | EVEN = serial.PARITY_EVEN 38 | MARK = serial.PARITY_MARK 39 | SPACE = serial.PARITY_SPACE 40 | 41 | 42 | class StopBits(enum.Enum): 43 | """The number of stop bits to use for Serial communication. 44 | 45 | Attributes: 46 | ONE (int): 1 47 | ONE_POINT_FIVE (float): 1.5 48 | TWO (int): 2 49 | """ 50 | 51 | ONE = serial.STOPBITS_ONE 52 | ONE_POINT_FIVE = serial.STOPBITS_ONE_POINT_FIVE 53 | TWO = serial.STOPBITS_TWO 54 | 55 | 56 | class DataBits(enum.IntEnum): 57 | """The number of data bits to use for Serial communication. 58 | 59 | Attributes: 60 | FIVE (int): 5 61 | SIX (int): 6 62 | SEVEN (int): 7 63 | EIGHT (int): 8 64 | """ 65 | 66 | FIVE = serial.FIVEBITS 67 | SIX = serial.SIXBITS 68 | SEVEN = serial.SEVENBITS 69 | EIGHT = serial.EIGHTBITS 70 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/avantes/__init__.py: -------------------------------------------------------------------------------- 1 | """Wrapper around the `avaspec.dll` SDK from Avantes.""" 2 | 3 | # cSpell: ignore Meas Resp Sens 4 | from __future__ import annotations 5 | 6 | from .avaspec import ( 7 | AvaSpec, 8 | AvsIdentityType, 9 | BroadcastAnswerType, 10 | ControlSettingsType, 11 | DarkCorrectionType, 12 | DetectorType, 13 | DeviceConfigType, 14 | DeviceStatus, 15 | DynamicStorageType, 16 | EthernetSettingsType, 17 | HeartbeatRespType, 18 | InterfaceType, 19 | IrradianceType, 20 | MeasConfigType, 21 | MeasureCallback, 22 | OemDataType, 23 | ProcessControlType, 24 | SensType, 25 | SmoothingType, 26 | SpectrumCalibrationType, 27 | SpectrumCorrectionType, 28 | StandAloneType, 29 | TecControlType, 30 | TempSensorType, 31 | TimeStampType, 32 | TriggerType, 33 | avaspec_callback, 34 | ) 35 | 36 | __all__: list[str] = [ 37 | "AvaSpec", 38 | "AvsIdentityType", 39 | "BroadcastAnswerType", 40 | "ControlSettingsType", 41 | "DarkCorrectionType", 42 | "DetectorType", 43 | "DeviceConfigType", 44 | "DeviceStatus", 45 | "DynamicStorageType", 46 | "EthernetSettingsType", 47 | "HeartbeatRespType", 48 | "InterfaceType", 49 | "IrradianceType", 50 | "MeasConfigType", 51 | "MeasureCallback", 52 | "OemDataType", 53 | "ProcessControlType", 54 | "SensType", 55 | "SmoothingType", 56 | "SpectrumCalibrationType", 57 | "SpectrumCorrectionType", 58 | "StandAloneType", 59 | "TecControlType", 60 | "TempSensorType", 61 | "TimeStampType", 62 | "TriggerType", 63 | "avaspec_callback", 64 | ] 65 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | push: 5 | branches: ['main'] 6 | tags: 7 | - '*' 8 | pull_request: 9 | branches: ['main'] 10 | 11 | permissions: 12 | contents: write 13 | pages: write 14 | id-token: write 15 | 16 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 17 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 18 | concurrency: 19 | group: 'pages' 20 | cancel-in-progress: false 21 | 22 | jobs: 23 | deploy: 24 | name: Build and deploy documentation 25 | runs-on: ubuntu-latest 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v5 29 | with: 30 | fetch-depth: 0 # fetch all commits/branches 31 | - name: Install uv 32 | uses: astral-sh/setup-uv@v6 33 | with: 34 | enable-cache: false 35 | - name: Configure Git for GitHub Actions bot 36 | run: | 37 | git config --local user.name "github-actions[bot]" 38 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 39 | - name: Validate docs 40 | run: uv run --all-packages -- mkdocs build --strict 41 | - name: Deploy dev docs 42 | if: github.ref == 'refs/heads/main' 43 | run: | 44 | uv run --all-packages -- mike deploy --push --update-aliases dev 45 | - name: Deploy release docs 46 | if: github.ref_type == 'tag' 47 | run: | 48 | uv run --all-packages -- mike deploy --push --update-aliases ${{ github.ref_name }} latest 49 | uv run --all-packages -- mike set-default --push latest 50 | -------------------------------------------------------------------------------- /packages/resources/examples/isotech/milliskanner.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an IsoTech millisKanner (via a milliK).""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import MilliK 11 | 12 | connection = Connection( 13 | "COM6", # could also be a Socket, e.g., "TCP::10.12.102.30::1000" 14 | manufacturer="IsoTech", 15 | model="milliK", 16 | ) 17 | 18 | # Connect to the milliK device (automatically configures for REMOTE mode) 19 | thermometer: MilliK = connection.connect() 20 | 21 | # Print information about the device 22 | print("Number of devices connected:", thermometer.num_devices) 23 | print("Connected devices:", thermometer.connected_devices) 24 | print("Available channel numbers:", thermometer.channel_numbers) 25 | 26 | # Configure channels using the largest resistance value that is expected for that channel 27 | resistances = [13000, 470, 220, 820, 3300, 100, 1800, 100] 28 | for i, r in enumerate(resistances, start=10): # here the sensors are all on the first millisKanner only 29 | thermometer.configure_resistance_measurement(channel=i, resistance=r) 30 | 31 | # Read resistance for a specific channel, returning 5 readings 32 | print("Resistance values for Channel 13:", thermometer.read_channel(13, n=5)) 33 | 34 | # Once the desired channels have been configured, you can yield values from them all 35 | # Here, we request the average resistance of 5 readings for every configured channel 36 | for ch, resistance in thermometer.read_all_channels(n=5): 37 | print(f"Channel {ch}:", resistance) 38 | 39 | # Disconnect from the milliK device (automatically configures for LOCAL mode) 40 | thermometer.disconnect() 41 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/kinesis_device_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to get information about Kinesis devices 3 | found on USB ports (that are not already connected to). 4 | """ 5 | import os 6 | import sys 7 | 8 | from msl.equipment.resources.thorlabs import MotionControl 9 | 10 | # ensure that the Kinesis folder is available on PATH 11 | os.environ['PATH'] += os.pathsep + 'C:/Program Files/Thorlabs/Kinesis' 12 | 13 | print('Building the device list...') 14 | MotionControl.build_device_list() 15 | 16 | n_devices = MotionControl.get_device_list_size() 17 | if n_devices == 0: 18 | print('There are no devices in the device list') 19 | sys.exit(0) 20 | elif n_devices == 1: 21 | print('There is 1 device in the device list') 22 | else: 23 | print('There are {} devices in the device list'.format(n_devices)) 24 | 25 | all_devices = MotionControl.get_device_list() 26 | print('The serial numbers of all the devices are: {}'.format(all_devices)) 27 | 28 | filter_flippers = MotionControl.get_device_list(MotionControl.Filter_Flipper) 29 | print('The Filter Flipper\'s that are connected are: {}'.format(filter_flippers)) 30 | 31 | lts = MotionControl.get_device_list(MotionControl.Long_Travel_Stage) 32 | print('The Long Travel Stage\'s that are connected are: {}'.format(lts)) 33 | 34 | devices = MotionControl.get_device_list(MotionControl.Filter_Flipper, MotionControl.Long_Travel_Stage) 35 | print('The Filter Flipper\'s and Long Travel Stage\'s that are connected are: {}'.format(devices)) 36 | 37 | info = MotionControl.get_device_info(all_devices[0]) 38 | print('The device info for the device with serial# {} is:'.format(all_devices[0])) 39 | for item in dir(info): 40 | if item.startswith('_'): 41 | continue 42 | print(' {}: {}'.format(item, getattr(info, item))) 43 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/mff101.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example communicates with a Thorlabs 3 | Filter Flipper (MFF101 or MFF102). 4 | """ 5 | import os 6 | import time 7 | 8 | from msl.equipment import ( 9 | EquipmentRecord, 10 | ConnectionRecord, 11 | Backend, 12 | ) 13 | from msl.equipment.resources.thorlabs import MotionControl 14 | 15 | # ensure that the Kinesis folder is available on PATH 16 | os.environ['PATH'] += os.pathsep + 'C:/Program Files/Thorlabs/Kinesis' 17 | 18 | record = EquipmentRecord( 19 | manufacturer='Thorlabs', 20 | model='MFF101/M', # specify MFF102 if you have the 2" version 21 | serial='37871232', # update for your device 22 | connection=ConnectionRecord( 23 | backend=Backend.MSL, 24 | address='SDK::Thorlabs.MotionControl.FilterFlipper.dll', 25 | ), 26 | ) 27 | 28 | # Build the device list before connecting to the Filter Flipper 29 | MotionControl.build_device_list() 30 | 31 | # connect to the Filter Flipper 32 | flipper = record.connect() 33 | print('Connected to {}'.format(flipper)) 34 | 35 | # wait a little bit for the Thorlabs SDK to open the serial port 36 | time.sleep(1) 37 | 38 | # start polling at 200 ms 39 | flipper.start_polling(200) 40 | 41 | position = flipper.get_position() 42 | print('Flipper is at position {}'.format(position)) 43 | 44 | # move the flipper to the other position and wait for the move to finish 45 | position = 1 if position == 2 else 2 46 | print('Moving the flipper to position {}'.format(position)) 47 | flipper.move_to_position(position) 48 | while flipper.get_position() != position: 49 | print(' waiting...') 50 | time.sleep(0.1) 51 | print('Move done. Flipper is now at position {}'.format(flipper.get_position())) 52 | 53 | # stop polling and close the connection 54 | flipper.stop_polling() 55 | flipper.disconnect() 56 | -------------------------------------------------------------------------------- /packages/resources/examples/isotech/millik.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an IsoTech milliK Precision Thermometer.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import MilliK 11 | 12 | 13 | connection = Connection( 14 | "TCP::10.12.102.30::1000", # could also be a Serial port, e.g., "COM4" 15 | manufacturer="IsoTech", 16 | model="milliK", 17 | timeout=5, 18 | ) 19 | 20 | # Connect to the milliK device (automatically configures for REMOTE mode) 21 | thermometer: MilliK = connection.connect() 22 | 23 | # Print information about the device 24 | print("Number of devices connected:", thermometer.num_devices) 25 | print("Connected devices:", thermometer.connected_devices) 26 | print("Available channel numbers:", thermometer.channel_numbers) 27 | 28 | # Configure channel 1 for resistance measurements 29 | # Specify the largest resistance value that is expected to be measured 30 | thermometer.configure_resistance_measurement(channel=1, resistance=130) 31 | 32 | # Configure channel 2 for voltage measurements with reference junction compensation 33 | # enabled for a Type K thermocouple 34 | thermometer.configure_voltage_measurement(channel=2, rjc=True, thermocouple="K") 35 | 36 | # Read measurement data for a specific channel, returning n readings 37 | print("Resistance value for Channel 1:", thermometer.read_channel(1)) 38 | print("Voltage values for Channel 2:", thermometer.read_channel(2, n=5)) 39 | 40 | # Read a value from all configured channels 41 | for channel, value in thermometer.read_all_channels(): 42 | print(f"Channel {channel}:", value) 43 | 44 | # Disconnect from the milliK device (automatically configures for LOCAL mode) 45 | thermometer.disconnect() 46 | -------------------------------------------------------------------------------- /packages/resources/examples/aim_tti/mx100tp.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an MX100TP DC power supply.""" 2 | 3 | from __future__ import annotations 4 | 5 | import time 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import MXSeries 12 | 13 | 14 | connection = Connection( 15 | "COM5", # if using the USB or RS232 port (update the port number) 16 | # "TCP::169.254.100.2::9221", # if using the LAN port (update the IP address) 17 | # "GPIB::5", # if using the GPIB port (must also disable termination characters) 18 | # "Prologix::169.254.100.5::1234::GPIB::5", # if using Prologix hardware (update the hardware address) 19 | manufacturer="Aim-TTi", 20 | model="MX100TP", 21 | timeout=5, 22 | # termination=None, # uncomment if using GPIB 23 | # escape_characters=False, # uncomment if using Prologix 24 | ) 25 | 26 | # The output channel to use 27 | channel = 1 28 | 29 | # Establish the connection to the DC power supply 30 | tti: MXSeries = connection.connect() 31 | 32 | # Turn the output on and set the voltage to 0.1 volts 33 | tti.turn_on(channel) 34 | tti.set_voltage(channel, 0.1) 35 | voltage = tti.get_voltage(channel) 36 | print(f"The output of channel {channel} is {voltage}V") 37 | 38 | # Increment the output voltage by 0.1 volts for each iteration 39 | tti.set_voltage_step_size(channel, 0.1) 40 | for _ in range(10): 41 | tti.increment_voltage(channel) 42 | setpoint = tti.get_voltage_setpoint(channel) 43 | voltage = tti.get_voltage(channel) 44 | current = tti.get_current(channel) 45 | print(f"V_set={setpoint}V, V_out={voltage}V, I_out={current}A") 46 | time.sleep(0.5) 47 | 48 | # Turn off all outputs (the multi-off feature) 49 | tti.turn_off_multi() 50 | 51 | # Disconnect from the DC power supply 52 | tti.disconnect() 53 | -------------------------------------------------------------------------------- /tests/resources/gpib.h: -------------------------------------------------------------------------------- 1 | // gpib.h 2 | // Mocks a GPIB library for testing purposes. 3 | // 4 | 5 | #if defined(_MSC_VER) 6 | // Microsoft 7 | #define EXPORT __declspec(dllexport) 8 | #elif defined(__GNUC__) 9 | // G++ 10 | #define EXPORT __attribute__((visibility("default"))) 11 | #else 12 | # error "Unknown EXPORT semantics" 13 | #endif 14 | 15 | int EARG = 4; 16 | int END = 0x2000; 17 | int TIMO = 0x4000; 18 | int ERR = 0x8000; 19 | 20 | extern "C" { 21 | EXPORT volatile long ibcntl; 22 | 23 | EXPORT int ThreadIbsta( void ); 24 | EXPORT int ThreadIberr( void ); 25 | EXPORT int ThreadIbcnt( void ); 26 | EXPORT int ibask( int ud, int option, int *value ); 27 | EXPORT int ibcac( int ud, int synchronous ); 28 | EXPORT int ibclr( int ud ); 29 | EXPORT int ibcmd( int ud, const void *cmd, long cnt ); 30 | EXPORT int ibconfig( int ud, int option, int value ); 31 | EXPORT int ibdev( int board_index, int pad, int sad, int timo, int send_eoi, int eosmode ); 32 | EXPORT int ibgts(int ud, int shadow_handshake); 33 | EXPORT int iblines( int ud, short *line_status ); 34 | EXPORT int ibln( int ud, int pad, int sad, short *found_listener ); 35 | EXPORT int ibloc( int ud ); 36 | EXPORT int ibonl( int ud, int onl ); 37 | EXPORT int ibpct( int ud ); 38 | EXPORT int ibrd( int ud, void *buf, long count ); 39 | EXPORT int ibrsp( int ud, char *spr ); 40 | EXPORT int ibsic( int ud ); 41 | EXPORT int ibspb( int ud, short *sp_bytes ); 42 | EXPORT int ibtrg( int ud ); 43 | EXPORT int ibwait( int ud, int mask ); 44 | EXPORT int ibwrt( int ud, const void *buf, long count ); 45 | EXPORT int ibwrta( int ud, const void *buf, long count ); 46 | 47 | #if defined(_MSC_VER) 48 | EXPORT int ibfindW(const wchar_t *dev); 49 | #else 50 | EXPORT int ibfind( const char *dev ); 51 | EXPORT void ibvers( char **version); 52 | #endif 53 | } -------------------------------------------------------------------------------- /packages/resources/examples/greisinger/gmh3710.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with an GMH3710 thermometer from Greisinger, GHM Group.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment import Connection 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.resources import GMH3000 11 | 12 | connection = Connection( 13 | "COM4", # change for your thermometer 14 | manufacturer="Greisinger", 15 | model="GMH3710-GE", 16 | timeout=2, 17 | # gmh_address=11 # Optional: change for your thermometer, default gmh_address is 1 18 | ) 19 | 20 | thermometer: GMH3000 = connection.connect() 21 | 22 | # Read information about the device 23 | unit = thermometer.unit() 24 | print("Current value", thermometer.value(), unit) 25 | print("Minimum value", thermometer.min_value(), unit) 26 | print("Maximum value", thermometer.max_value(), unit) 27 | print("Measurement range", thermometer.measurement_range()) 28 | print("Display range", thermometer.display_range()) 29 | print("Scale correction", thermometer.scale_correction()) 30 | print("Offset correction", thermometer.offset_correction()) 31 | print("Channel count", thermometer.channel_count()) 32 | print("Power-off time", thermometer.power_off_time()) 33 | print("Resolution", thermometer.resolution()) 34 | print("ID (serial) number", thermometer.id_number()) 35 | print("Firmware version", thermometer.firmware_version()) 36 | 37 | # Check if the battery is low 38 | bit_mask = thermometer.status() 39 | print(f"System status: {bit_mask}") 40 | if bit_mask & 1 << 15: 41 | print("Warning! Battery is low") 42 | 43 | # Clears the minimum and maximum values that are stored in the device 44 | # thermometer.clear_min_value() 45 | # thermometer.clear_max_value() 46 | 47 | # Sets the power-off time to 30 minutes 48 | # thermometer.set_power_off_time(30) 49 | 50 | # Disconnect from the device 51 | thermometer.disconnect() 52 | -------------------------------------------------------------------------------- /packages/resources/tests/test_greisinger_gmh3000.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | import threading 5 | import time 6 | 7 | try: 8 | import pty 9 | except ImportError: 10 | pty = None 11 | 12 | import pytest 13 | 14 | from msl.equipment import ConnectionRecord 15 | from msl.equipment import EquipmentRecord 16 | from msl.equipment.exceptions import GreisingerError 17 | 18 | 19 | def easybus_server(port): 20 | os.read(port, 3) # value() request 21 | os.write(port, b'\xfe\x05&q\x00H\xf7\x80\t') # 21.76 22 | os.read(port, 3) # value() request 23 | os.write(port, b'\xFE\x05&\x72\xFF\x84\x00\xFC\x05') # -0.04 24 | os.read(port, 6) # min measurement range request 25 | os.write(port, b'\xfe\xf5\xf8O\x00g\xbf0\xe3') # -200.0 26 | os.read(port, 6) # max measurement range request 27 | os.write(port, b'\xfe\xf5\xf8N\x00r\x964\xec') # 850.0 28 | os.read(port, 3) # value() request 29 | os.write(port, b'\xfe\r\x1ep\xf6\x91\xdf\xed\x0b') # "No sensor" error code 30 | 31 | 32 | @pytest.mark.skipif(pty is None, reason='pty is not available') 33 | def test_easybus(): 34 | # simulate a Serial port 35 | primary, secondary = pty.openpty() 36 | 37 | thread = threading.Thread(target=easybus_server, args=(primary,), daemon=True) 38 | thread.start() 39 | 40 | time.sleep(0.5) # allow some time for the easybus server to start 41 | 42 | record = EquipmentRecord( 43 | manufacturer='Greisinger', 44 | model='GMH3710-GE', 45 | connection=ConnectionRecord( 46 | address='ASRL' + os.ttyname(secondary), 47 | properties={'timeout': 5}, 48 | ) 49 | ) 50 | 51 | dev = record.connect() 52 | assert dev.value() == 21.76 53 | assert dev.value() == -0.04 54 | assert dev.measurement_range() == (-200.0, 850.0) 55 | with pytest.raises(GreisingerError, match='No sensor'): 56 | dev.value() 57 | -------------------------------------------------------------------------------- /docs/resources/index.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | Resources are custom classes for interfacing with specific equipment. In previous releases of `msl-equipment` (versions < 1.0), the resources were automatically bundled with `msl-equipment`. As of v1.0, the resources are maintained in another package, `msl-equipment-resources`, that must be installed separately. 4 | 5 | Some of the resources might not work in your application because the resource might depend on an external dependency, e.g., the Software Development Kit (SDK) provided by a manufacturer, and this external dependency might not be available for your operating system. 6 | 7 | !!! examples 8 | There are examples on how to use the resources in the [repository](https://github.com/MSLNZ/msl-equipment/tree/main/packages/resources/examples){:target="_blank"}. 9 | 10 | !!! danger "Attention" 11 | Companies that sell equipment that are used for scientific research are identified in this guide in order to illustrate how to adequately use `msl-equipment-resources` in your application. Such identification is not intended to imply recommendation or endorsement by the Measurement Standards Laboratory of New Zealand, nor is it intended to imply that the companies identified are necessarily the best for the purpose. 12 | 13 | ## Install 14 | 15 | Installing `msl-equipment-resources` will also install `msl-equipment` 16 | 17 | ```console 18 | pip install msl-equipment-resources 19 | ``` 20 | 21 | ## Create a new resource 22 | 23 | TODO... 24 | 25 | ## Multiple interfaces 26 | 27 | If the equipment supports multiple interfaces for message-based protocols (e.g., [Socket][msl.equipment.interfaces.socket.Socket], [Serial][msl.equipment.interfaces.serial.Serial], [GPIB][msl.equipment.interfaces.gpib.GPIB], ...) you can create a resource that inherits from the [MultiMessageBased][msl.equipment_resources.multi_message_based.MultiMessageBased] class. Upon calling [super][] in the subclass, the connection is established with the appropriate protocol class. 28 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/ksc101.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to communicate with a SH05 (shutter) 3 | connected to a KSC101 (KCube Solenoid). 4 | """ 5 | import os 6 | import time 7 | 8 | from msl.equipment import ( 9 | EquipmentRecord, 10 | ConnectionRecord, 11 | Backend, 12 | ) 13 | from msl.equipment.resources.thorlabs import MotionControl 14 | 15 | # ensure that the Kinesis folder is available on PATH 16 | os.environ['PATH'] += os.pathsep + 'C:/Program Files/Thorlabs/Kinesis' 17 | 18 | record = EquipmentRecord( 19 | manufacturer='Thorlabs', 20 | model='KSC101', 21 | serial='68000297', # update for your device 22 | connection=ConnectionRecord( 23 | backend=Backend.MSL, 24 | address='SDK::Thorlabs.MotionControl.KCube.Solenoid.dll', 25 | ), 26 | ) 27 | 28 | 29 | def is_open(): 30 | return shutter.get_operating_state() == 1 31 | 32 | 33 | # avoid the FT_DeviceNotFound error 34 | MotionControl.build_device_list() 35 | 36 | # connect to the KCube Solenoid 37 | shutter = record.connect() 38 | print('Connected to {}'.format(shutter)) 39 | 40 | # start polling at 200 ms 41 | shutter.start_polling(200) 42 | 43 | # set the operating mode to SC_OperatingModes.SC_Manual 44 | shutter.set_operating_mode('Manual') 45 | 46 | for i in range(5): 47 | 48 | # set the operating state to SC_OperatingStates.SC_Active 49 | print('Opening the shutter...') 50 | shutter.set_operating_state('Active') 51 | while not is_open(): 52 | time.sleep(0.05) 53 | print(' Is the shutter open? {}'.format(is_open())) 54 | 55 | time.sleep(1) 56 | 57 | # set the operating state to SC_OperatingStates.SC_Inactive 58 | print('Closing the shutter...') 59 | shutter.set_operating_state('Inactive') 60 | while is_open(): 61 | time.sleep(0.05) 62 | print(' Is the shutter open? {}'.format(is_open())) 63 | 64 | time.sleep(1) 65 | 66 | # stop polling and close the connection 67 | shutter.stop_polling() 68 | shutter.disconnect() 69 | -------------------------------------------------------------------------------- /packages/validate/tests/test_osc8.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pytest 4 | from msl.equipment_validate import osc8 5 | 6 | file = "does-not-exist.txt:4:10" 7 | 8 | 9 | @pytest.mark.parametrize( 10 | ("command", "expect"), 11 | [ 12 | ("vs", False), 13 | ("vs://ftp", False), 14 | ("vs://file/", False), 15 | ("vs://file/a", True), 16 | ("vs://file/a:10", True), 17 | ("vs://file/a:10:5", True), 18 | ("vs://ftp/a:10:5", False), 19 | ("vs://file//path/to/file.xml:10:5", True), 20 | ("vs://file//C:\\path\\to\\file.xml:10:5", True), 21 | ("vs://file//C:\\path\\to file\\ with spaces.xml:10:5", True), 22 | ], 23 | ) 24 | def test_regex(command: str, expect: bool) -> None: # noqa: FBT001 25 | assert osc8.uri_scheme_handler(command) is expect 26 | 27 | 28 | def test_uri_scheme_handler_invalid_command() -> None: 29 | assert not osc8.uri_scheme_handler(f"pycharm://wrong/{file}") 30 | 31 | 32 | def test_uri_scheme_handler_unknown() -> None: 33 | assert not osc8.uri_scheme_handler(f"unknown://file/{file}") 34 | 35 | 36 | def test_uri_scheme_handler_notepad_pp() -> None: 37 | assert osc8.uri_scheme_handler(f"n++://file/{file}") 38 | 39 | 40 | def test_uri_scheme_handler_pycharm() -> None: 41 | assert osc8.uri_scheme_handler(f"pycharm://file/{file}") 42 | 43 | 44 | def test_uri_scheme_handler_vs() -> None: 45 | assert osc8.uri_scheme_handler(f"vs://file/{file}") 46 | 47 | 48 | def test_uri_scheme_handler_vscode() -> None: 49 | # vscode registers it's own handler in the Windows registry 50 | assert not osc8.uri_scheme_handler(f"vscode://file/{file}") 51 | 52 | 53 | @pytest.mark.skipif(sys.platform != "win32", reason="only test on Windows, requires winreg") 54 | def test_register_uri_scheme_vscode() -> None: 55 | assert not osc8.register_uri_scheme("vscode") 56 | 57 | 58 | @pytest.mark.skipif(sys.platform != "win32", reason="only test on Windows, requires winreg") 59 | def test_unregister_uri_scheme_vscode() -> None: 60 | assert not osc8.unregister_uri_scheme("vscode") 61 | -------------------------------------------------------------------------------- /tests/test_nidaq.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | # pyright: reportUnknownMemberType=false, reportUnknownVariableType=false 4 | import nidaqmx # type: ignore[import-untyped] # pyright: ignore[reportMissingTypeStubs] 5 | import pytest 6 | 7 | from msl.equipment import NIDAQ, Connection, Equipment 8 | 9 | 10 | def test_equivalent_to_importing_nidaqmx() -> None: 11 | daq = NIDAQ(Equipment(connection=Connection(address="Dev1"))) 12 | 13 | assert f"{daq.address}/ai0" == "Dev1/ai0" 14 | 15 | assert daq.CtrFreq is nidaqmx.CtrFreq 16 | assert daq.CtrTick is nidaqmx.CtrTick 17 | assert daq.CtrTime is nidaqmx.CtrTime 18 | assert daq.DaqError is nidaqmx.DaqError 19 | assert daq.DaqReadError is nidaqmx.DaqReadError 20 | assert daq.DaqResourceWarning is nidaqmx.DaqResourceWarning 21 | assert daq.DaqWarning is nidaqmx.DaqWarning 22 | assert daq.DaqWriteError is nidaqmx.DaqWriteError 23 | assert daq.GRPC_SERVICE_INTERFACE_NAME is nidaqmx.GRPC_SERVICE_INTERFACE_NAME 24 | assert daq.GrpcSessionOptions is nidaqmx.GrpcSessionOptions 25 | assert daq.Scale is nidaqmx.Scale 26 | assert daq.Task is nidaqmx.Task 27 | assert daq.constants is nidaqmx.constants 28 | assert daq.error_codes is nidaqmx.error_codes 29 | assert daq.errors is nidaqmx.errors 30 | assert daq.grpc_session_options is nidaqmx.grpc_session_options 31 | assert daq.scale is nidaqmx.scale 32 | assert daq.system is nidaqmx.system 33 | assert daq.task is nidaqmx.task 34 | assert daq.types is nidaqmx.types 35 | assert daq.utils is nidaqmx.utils 36 | assert daq.version is nidaqmx.version 37 | 38 | # these must not raise AttributeError 39 | assert daq.stream_readers 40 | assert daq.stream_writers 41 | 42 | with pytest.raises(AttributeError): 43 | _ = nidaqmx.doesnotexist 44 | 45 | with pytest.raises(AttributeError): 46 | _ = daq.doesnotexist 47 | 48 | 49 | def test_no_connection_instance() -> None: 50 | with pytest.raises(TypeError, match=r"A Connection is not associated"): 51 | _ = NIDAQ(Equipment()) 52 | -------------------------------------------------------------------------------- /packages/resources/examples/optosigma/shot702.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a SHOT-702 (2-axis stage controller) from OptoSigma.""" 2 | 3 | from __future__ import annotations 4 | 5 | import time 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import SHOT702, optosigma 12 | 13 | 14 | connection = Connection( 15 | "COM1", # update for your controller 16 | manufacturer="OptoSigma", 17 | model="SHOT-702", 18 | timeout=2, 19 | ) 20 | 21 | 22 | def print_status(status: optosigma.Status) -> None: 23 | """Callback function that is used by the "wait" method.""" 24 | print(f" p1={status.position1}, p2={status.position2}, state={status.state!r}, is_moving={status.is_moving}") 25 | 26 | 27 | # connect to the controller 28 | shot: SHOT702 = connection.connect() 29 | 30 | # move stage 1 to the home position 31 | print("Homing...") 32 | shot.home(1) 33 | 34 | # wait for the stage to finish moving while printing the status 35 | shot.wait(print_status) 36 | 37 | # move stage 1 to a position 38 | print("Move to 10000...") 39 | shot.move_absolute(1, 10000) 40 | 41 | # wait for the stage to finish moving while printing the status 42 | shot.wait(print_status) 43 | 44 | # move stage 1 by -1000 45 | print("Move by -1000...") 46 | shot.move_relative(1, -1000) 47 | 48 | # wait for the stage to finish moving while printing the status 49 | shot.wait(print_status) 50 | 51 | # get the status of the stages 52 | status = shot.status() 53 | print("position1={}, position2={}, state={}, is_moving={}".format(*status)) 54 | 55 | # start moving stage 1 at the minimum speed in the + direction for 5 seconds 56 | print("Start moving stage 1 for 5 seconds...") 57 | shot.move(1, "+") 58 | time.sleep(5) 59 | 60 | # slowly stop stage 1 61 | print("Stopping stage 1") 62 | shot.stop_slowly(1) 63 | 64 | # get the status of the stages 65 | status = shot.status() 66 | print("position1={}, position2={}, state={}, is_moving={}".format(*status)) 67 | 68 | # disconnect from the controller 69 | shot.disconnect() 70 | -------------------------------------------------------------------------------- /packages/resources/examples/dataray/wincamd.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a WinCamD beam-profiling camera from DataRay. 2 | 3 | Tested with the WinCamD-LCM-8.0E45 (x64) software version. 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | from typing import TYPE_CHECKING 9 | 10 | from msl.equipment import Connection 11 | 12 | if TYPE_CHECKING: 13 | from msl.equipment.resources import WinCamD 14 | 15 | connection = Connection( 16 | "SDK::DATARAYOCX", 17 | manufacturer="DataRay", 18 | model="WinCamD", 19 | # plateau_uniformity=True, # these are some examples of the properties that can be specified 20 | # full_scale_filter=0.5, 21 | ) 22 | 23 | # Connect to the camera (a GUI will be displayed). 24 | # The GUI must remain open to have access to the DataRay OCX library. 25 | # The text "Error in oglInitialize invalid operation" might be printed, ignore it. 26 | camera: WinCamD = connection.connect() 27 | 28 | # Wait until the camera has been configured (e.g., set the image size, ROI, major/minor mode, ...) 29 | camera.wait_to_configure() 30 | 31 | # Capture an image, 32 | camera.capture() 33 | 34 | # and then you can get information about the image 35 | print("image", camera.image) 36 | print("profile_x", camera.profile_x) 37 | print("profile_y", camera.profile_y) 38 | print("pixel_size", camera.pixel_size) 39 | print("centroid", camera.centroid) 40 | print("roi", camera.roi) 41 | print("xc", camera.xc) 42 | print("xg", camera.xg) 43 | print("xp", camera.xp) 44 | print("yc", camera.yc) 45 | print("yg", camera.yg) 46 | print("yp", camera.yp) 47 | print("major", camera.major) 48 | print("mean", camera.mean) 49 | print("minor", camera.minor) 50 | print("orientation", camera.orientation) 51 | print("plateau_uniformity", camera.plateau_uniformity) 52 | print("homogeneity", camera.homogeneity) 53 | print("adc_peak_percent", camera.adc_peak_percent) 54 | print("effective_2w", camera.effective_2w) 55 | print("ellipticity", camera.ellipticity) 56 | print("exposure_time", camera.exposure_time) 57 | 58 | # You can also access properties of the SDK 59 | print("ImagerGain", camera.sdk.ImagerGain) 60 | print("CameraType", camera.sdk.CameraType()) 61 | 62 | # Disconnect from the camera (also closes the GUI) 63 | camera.disconnect() 64 | -------------------------------------------------------------------------------- /packages/validate/tests/registers/duplicate_id_a.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MSLE.M.001 5 | Sky-net 6 | T-1000 7 | 00000000001 8 | A mimetic poly-alloy (liquid metal) 9 | 10 | Kibble Balance 11 | Active 12 | false 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | MSLE.M.003 24 | Sky-net 25 | T-1000 26 | 00000000003 27 | A mimetic poly-alloy (liquid metal) 28 | 29 | Kibble Balance 30 | Active 31 | false 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | MSLE.M.002 43 | Sky-net 44 | T-1000 45 | 00000000002 46 | A mimetic poly-alloy (liquid metal) 47 | 48 | Kibble Balance 49 | Active 50 | false 51 | true 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /packages/validate/tests/registers/duplicate_id_b.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MSLE.M.004 5 | Sky-net 6 | T-1000 7 | 00000000004 8 | A mimetic poly-alloy (liquid metal) 9 | 10 | Kibble Balance 11 | Active 12 | false 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | MSLE.M.002 24 | Sky-net 25 | T-1000 26 | 00000000002 27 | A mimetic poly-alloy (liquid metal) 28 | 29 | Kibble Balance 30 | Active 31 | false 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | MSLE.M.005 43 | Sky-net 44 | T-1000 45 | 00000000005 46 | A mimetic poly-alloy (liquid metal) 47 | 48 | Kibble Balance 49 | Active 50 | false 51 | true 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | !!! info 4 | The docs are being rewritten. See [here](https://msl-equipment.readthedocs.io/en/latest/index.html) for the old docs. 5 | 6 | The purpose of `msl-equipment` is to manage information about equipment and to interface with equipment for computer control. The information that is managed is focused on testing and calibration laboratories that are accredited for the [ISO/IEC 17025](https://www.iso.org/ISO-IEC-17025-testing-and-calibration-laboratories.html){:target="_blank"} standard, but the information may also be selectively specified for laboratories that are not required to meet the standard. See the [Getting Started][] page to learn how information is managed and how equipment is controlled. 7 | 8 | ## Install 9 | 10 | The `msl-equipment` [repository](https://github.com/MSLNZ/msl-equipment/){:target="_blank"} is organised as a [workspace project](https://docs.astral.sh/uv/concepts/projects/workspaces/){:target="_blank"} that is split across multiple packages: `msl-equipment`, [msl-equipment-resources][resources], [msl-equipment-validate][validate], and [msl-equipment-webapp][web-application]. 11 | 12 | The core package is `msl-equipment` and it is available through the [Python Package Index](https://pypi.org/project/msl-equipment/){:target="_blank"}. It can be installed using a variety of package managers 13 | 14 | === "pip" 15 | ```console 16 | pip install msl-equipment 17 | ``` 18 | 19 | === "uv" 20 | ```console 21 | uv add msl-equipment 22 | ``` 23 | 24 | === "poetry" 25 | ```console 26 | poetry add msl-equipment 27 | ``` 28 | 29 | === "pdm" 30 | ```console 31 | pdm add msl-equipment 32 | ``` 33 | 34 | ### Dependencies 35 | 36 | The `msl-equipment` package depends on the following packages: [msl-loadlib](https://mslnz.github.io/msl-loadlib/latest/), [numpy](https://www.numpy.org/){:target="_blank"}, [pyserial](https://pyserial.readthedocs.io/en/latest/){:target="_blank"}, [pyzmq](https://pyzmq.readthedocs.io/en/stable/){:target="_blank"} 37 | 38 | The following packages are optional dependencies that may be installed to interface with equipment: [msl-equipment-resources][resources], [NI-DAQmx](https://nidaqmx-python.readthedocs.io/en/stable/){:target="_blank"}, [PyVISA](https://pyvisa.readthedocs.io/en/stable/){:target="_blank"}, [PyVISA-py](https://pyvisa.readthedocs.io/projects/pyvisa-py/en/stable/){:target="_blank"} 39 | -------------------------------------------------------------------------------- /packages/resources/examples/avantes/avaspec_callback.py: -------------------------------------------------------------------------------- 1 | """Example showing how to use a callback with an AvaSpec-2048L spectrometer. 2 | 3 | The AvaSpec shared library may require a Visual C++ Redistributable Package to be installed (on Windows). 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | import time 9 | from typing import TYPE_CHECKING 10 | 11 | from msl.equipment import Connection 12 | from msl.equipment.resources import avantes 13 | 14 | if TYPE_CHECKING: 15 | from ctypes import _Pointer, c_int32 # pyright: ignore[reportPrivateUsage] 16 | 17 | from msl.equipment.resources import AvaSpec 18 | 19 | 20 | @avantes.avaspec_callback 21 | def callback(handle: _Pointer[c_int32], info: _Pointer[c_int32]) -> None: 22 | """This function is called every time a measurement scan is available.""" 23 | print(f"The DLL handle is: {handle.contents.value}") 24 | if info.contents.value == 0: # equals 0 if everything is okay (see manual) 25 | print(f" callback data: {ava.get_data()}") 26 | 27 | 28 | connection = Connection( 29 | "SDK::C:/Path/to/avaspecx64.dll", # update path to avaspec library 30 | manufacturer="Avantes", 31 | model="AvaSpec-2048L", # update for your device 32 | serial="1807344U1", # update for your device 33 | ) 34 | 35 | # initializes the Avantes SDK and establishes the connection to the spectrometer 36 | ava: AvaSpec = connection.connect() 37 | 38 | # get the number of pixels that the spectrometer has 39 | num_pixels = ava.get_num_pixels() 40 | print(f"The spectrometer has {num_pixels} pixels") 41 | 42 | # get the wavelength value of each pixel 43 | wavelengths = ava.get_lambda() 44 | 45 | # enable the 16-bit AD converter 46 | ava.use_high_res_adc(enable=True) 47 | 48 | # prepare the measurement type of the spectrometer 49 | # (the values of just a few parameters are updated here, see the manual for more details) 50 | cfg = avantes.MeasConfigType() 51 | cfg.m_StopPixel = num_pixels - 1 52 | cfg.m_IntegrationTime = 5 # in milliseconds 53 | cfg.m_NrAverages = 1 # number of averages 54 | ava.prepare_measure(cfg) 55 | 56 | # start continuous measurements 57 | # (use a callback function to be notified when a measurement is ready) 58 | ava.measure_callback(-1, callback) 59 | 60 | # get as many scans as possible for 2 seconds 61 | time.sleep(2) 62 | 63 | # stop continuous measurements 64 | ava.stop_measure() 65 | 66 | # disconnect from the spectrometer 67 | ava.disconnect() 68 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/pt104.py: -------------------------------------------------------------------------------- 1 | """Example showing how to communicate with a PT-104 Data Logger. 2 | 3 | This examples assumes that a voltage is applied to channel 1 and a PT100 is connected to channel 2. 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | import os 9 | import time 10 | from typing import TYPE_CHECKING 11 | 12 | from msl.equipment import Connection 13 | 14 | if TYPE_CHECKING: 15 | from msl.equipment.resources import PT104 16 | 17 | 18 | connection = Connection( 19 | "SDK::usbpt104", # Alternatively, specify the full path to the SDK, "SDK::path/to/lib/usbpt104" 20 | manufacturer="PicoTech", 21 | model="PT-104", 22 | serial="JO332/224", # Change for your device 23 | ip_address="192.168.1.20:1875", # Optional: Specify the IP address and port (change for your device) 24 | # open_via_ip=True, # Optional: True: connect via ethernet, False: connect via USB (default) 25 | ) 26 | 27 | # Optional: Ensure that the Pico Technology SDK is available on PATH (if not already) 28 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 29 | 30 | # Connect to the PT-104 31 | pt104: PT104 = connection.connect() 32 | 33 | # Get all available information about the PT-104 34 | print(pt104.get_unit_info()) 35 | 36 | # Use the enum value to get the calibration date and do not print the member-name prefix 37 | info = pt104.get_unit_info(5, prefix=False) 38 | print(f"The PT-104 was calibrated on {info}") 39 | 40 | # Use the enum member name to get the MAC address 41 | print(pt104.get_unit_info("mac_address")) 42 | 43 | # Get the details of the ethernet connection 44 | enabled, ip_address, port = pt104.get_ip_details() 45 | print(f"Ethernet enabled? {enabled}") 46 | print(f"Address: {ip_address}:{port}") 47 | 48 | # Set channel 1 to measure the resistance of a PT1000 in a 4-wire arrangement 49 | pt104.set_channel(1, pt104.Mode.RESISTANCE_TO_10K, 4) 50 | 51 | # Set channel 2 to measure the temperature of a PT100 in a 4-wire arrangement 52 | pt104.set_channel(2, pt104.Mode.PT100, 4) 53 | 54 | # Wait for the samples to be available 55 | # A measurement cycle takes about 1 second per active channel 56 | # 2 channels are active, so we should wait at least 2 seconds 57 | time.sleep(3) 58 | 59 | # Read the values 60 | ch1 = pt104.get_value(1) 61 | ch2 = pt104.get_value(2) 62 | print(f"Resistance={ch1}, Temperature={ch2}") 63 | 64 | # Disconnect from the Data Logger 65 | pt104.disconnect() 66 | -------------------------------------------------------------------------------- /tests/resources/gpib.cpp: -------------------------------------------------------------------------------- 1 | // gpib.cpp 2 | // Mocks a GPIB library for testing purposes. 3 | // 4 | // Compiled using: 5 | // cl /LD gpib.cpp /link /OUT:gpib.dll 6 | // g++ gpib.cpp -fPIC -shared -Bstatic -Wall -o gpib.so 7 | // g++ gpib.cpp -fPIC -shared -Bstatic -Wall -o gpib.dylib 8 | // 9 | #include "gpib.h" 10 | #include 11 | 12 | int ThreadIbsta( void ) { return 0; } 13 | int ThreadIberr( void ) { return EARG; } 14 | int ThreadIbcnt( void ) { 15 | return 10; // pretend 10 bytes are sent or received. 16 | } 17 | int ibask( int ud, int option, int *value ) { 18 | if (option == 0x03) { 19 | *value = 11; // timeout of 1 second 20 | } 21 | return 0; 22 | } 23 | int ibcac( int ud, int synchronous ) { return synchronous + 10; } 24 | int ibclr( int ud ) { return TIMO; } 25 | int ibcmd( int ud, const void *cmd, long cnt ) { return ERR; } 26 | int ibconfig( int ud, int option, int value ) { return 22; } 27 | int ibdev( int board_index, int pad, int sad, int timo, int send_eoi, int eosmode ) { 28 | if (board_index == 3) { 29 | return -1; 30 | } 31 | return 3; 32 | } 33 | int ibgts(int ud, int shadow_handshake) { return shadow_handshake + 1; } 34 | int iblines( int ud, short *line_status ) { *line_status=24; return 0; } 35 | int ibln( int ud, int pad, int sad, short *found_listener ) { 36 | if ((ud == 0 && pad == 5 && sad ==0 ) || (ud == 15 && pad == 11 && sad == 0) || (ud == 15 && pad == 11 && sad == 123)) { 37 | *found_listener = 1; 38 | return 0; 39 | }; 40 | return ERR; 41 | } 42 | int ibloc( int ud ) { return 25; } 43 | int ibonl( int ud, int onl ) { return 26; } 44 | int ibpct( int ud ) { return 27; } 45 | int ibrd( int ud, void *buf, long count ) { 46 | memset(buf, 'A', 10); 47 | return END; 48 | } 49 | int ibrsp( int ud, char *spr ) { memset(spr, 'p', 1); return 0; } 50 | int ibsic( int ud ) { return 29; } 51 | int ibspb( int ud, short *sp_bytes ) { *sp_bytes=30; return 0; } 52 | int ibtrg( int ud ) { return 31; } 53 | int ibwait( int ud, int mask ) { return 32; } 54 | int ibwrt( int ud, const void *buf, long count ) { return 33; } 55 | int ibwrta( int ud, const void *buf, long count ) { return 34; } 56 | 57 | #if defined(_MSC_VER) 58 | int ibfindW(const wchar_t *dev) { 59 | if (wcscmp(dev, L"bad") == 0) return -1; 60 | return 2; 61 | } 62 | #else 63 | int ibfind( const char *dev ) { 64 | if (strcmp(dev, "bad") == 0) return -1; 65 | return 2; 66 | } 67 | void ibvers( char **version) { *version = (char*)"1.2"; } 68 | #endif 69 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment/resources/thorlabs/kinesis/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Wrapper package around the Thorlabs.MotionControl.C_API. 3 | 4 | The Kinesis software can be downloaded from the `Thorlabs website`_ 5 | 6 | .. _Thorlabs website: 7 | https://www.thorlabs.com/software_pages/ViewSoftwarePage.cfm?Code=Motion_Control 8 | """ 9 | from __future__ import annotations 10 | 11 | 12 | def _print(cls, fcns, header_filename): 13 | # useful when creating/updating a new wrapper class 14 | 15 | from msl.equipment.resources.utils import CHeader 16 | from msl.equipment.resources.utils import camelcase_to_underscore as convert 17 | 18 | def get_comment(lines, name): 19 | # used when creating a new wrapper class 20 | comments = [] 21 | found_it = False 22 | for line in lines: 23 | if name in line and '__cdecl' in line: 24 | found_it = True 25 | continue 26 | if found_it: 27 | if line.startswith('///'): 28 | comments.append(line[3:].strip()) 29 | else: 30 | break 31 | return ' """{}\n """'.format(' \n '.join(comments[::-1])) 32 | 33 | already_defined = (vars(cls)) 34 | 35 | header = CHeader('C:/Program Files/Thorlabs/Kinesis/' + header_filename, remove_comments=False) 36 | lines = header.get_lines()[::-1] 37 | 38 | for item in sorted(fcns): 39 | method_name = item[0].replace('MMIparams', 'MmiParams') 40 | method_name = method_name.replace('LEDswitches', 'LedSwitches') 41 | method_name = convert(method_name.split('_')[1]) 42 | args_p = '' 43 | args_c = '' 44 | for i, arg in enumerate(item[3]): 45 | if i == 0 and 'c_char_p' in str(arg[0]): 46 | args_c += 'self._serial, ' 47 | elif 'PyCPointerType' in str(type(arg[0])): 48 | args_c += 'byref({}), '.format(convert(arg[1])) 49 | else: 50 | a = convert(arg[1]) 51 | args_p += '{}, '.format(a) 52 | args_c += '{}, '.format(a) 53 | 54 | if method_name in already_defined: 55 | continue 56 | 57 | args_p = args_p[:-2] 58 | if args_p: 59 | print(' def {}(self, {}):'.format(method_name, args_p)) 60 | else: 61 | print(' def {}(self):'.format(method_name)) 62 | print(get_comment(lines, item[0])) 63 | print(' return self.sdk.{}({})\n'.format(item[0], args_c[:-2])) 64 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/ps5000a_block_mode.py: -------------------------------------------------------------------------------- 1 | """Acquire PicoScope data in Block Mode.""" 2 | 3 | from __future__ import annotations 4 | 5 | import os 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | 10 | if TYPE_CHECKING: 11 | from msl.equipment.resources import PicoScope 12 | 13 | connection = Connection( 14 | "SDK::ps5000a", # Alternatively, specify the full path to the SDK, "SDK::path/to/lib/ps5000a" 15 | manufacturer="Pico Technology", 16 | model="5244B", # Update for your PicoScope 17 | serial="DY135/055", # Update for your PicoScope 18 | # resolution="16bit", # Optional: Specify the device resolution (bit depth) 19 | ) 20 | 21 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 22 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 23 | 24 | print("Example :: Using block mode") 25 | 26 | # Connect to the PicoScope 27 | scope: PicoScope = connection.connect() 28 | 29 | # Enable Channel A and set the voltage range to be +/- 1V 30 | scope.set_channel("A", range="1V") 31 | 32 | # Request to sample the voltage every 1 ms, for 20 ms 33 | # Returns the sampling interval and the number of samples that will be acquired 34 | actual_dt, num_samples = scope.set_timebase(1e-3, 20e-3) 35 | print(f"The actual time between samples is {actual_dt} seconds and there will be {num_samples} samples") 36 | 37 | # Channel A is the trigger source with a trigger threshold value of 0.0 V and a timeout of 0.1 second 38 | scope.set_trigger("A", threshold=0.0, timeout=0.1) 39 | 40 | # Start acquisition 41 | wait_time = scope.run_block() 42 | print(f"Acquiring the samples should take approximately {wait_time} seconds") 43 | 44 | # Wait until all requested samples are acquired (polls scope to see if it is ready) 45 | scope.wait_until_ready() 46 | 47 | # Set the data buffer for Channel A 48 | scope.set_data_buffer("A") 49 | 50 | # Fill the data buffer of Channel A with the values saved in the PicoScope's internal memory 51 | num_acquired, overflow_mask = scope.get_values() 52 | print(f"Number of samples acquired is {num_acquired}") 53 | print(f"Overflow bit mask => {overflow_mask}") 54 | 55 | # Get the time when the trigger occurred 56 | trigger_time = scope.get_trigger_time_offset64() 57 | print(f"Trigger occurred at {trigger_time} seconds") 58 | 59 | # Stop the oscilloscope from sampling data 60 | scope.stop() 61 | 62 | print("The voltages are:") 63 | print(scope.channel["A"].volts) 64 | 65 | print("The raw ADU counts are:") 66 | print(scope.channel["A"].adu) 67 | 68 | # Disconnect from the scope 69 | scope.disconnect() 70 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/ps5000a_data_ready_callback.py: -------------------------------------------------------------------------------- 1 | """This example handles post-collection data returned by the driver. 2 | 3 | It registers a DataReady callback function that the driver calls when the data has been collected. 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | import os 9 | import time 10 | from typing import TYPE_CHECKING 11 | 12 | from msl.equipment import Connection 13 | from msl.equipment.resources import picoscope as ps 14 | 15 | if TYPE_CHECKING: 16 | from msl.equipment.resources import PicoScope 17 | 18 | connection = Connection( 19 | "SDK::ps5000a", # Alternatively, specify the full path to the SDK, "SDK::path/to/lib/ps5000a" 20 | manufacturer="Pico Technology", 21 | model="5244B", # Update for your PicoScope 22 | serial="DY135/055", # Update for your PicoScope 23 | # resolution="16bit", # Optional: Specify the device resolution (bit depth) 24 | ) 25 | 26 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 27 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 28 | 29 | 30 | @ps.data_ready 31 | def my_data_ready(handle: int, status: int, num_samples: int, overflow: int, _: None) -> None: 32 | """Called when post-data collection is ready.""" 33 | print(f"Callback: Data ready! {handle=}, {status=}, {num_samples=}, {overflow=}") 34 | print("The voltages are:") 35 | print(scope.channel["A"].volts) 36 | 37 | 38 | print("Example :: Using block mode with a DataReady callback") 39 | 40 | # Connect to the PicoScope 41 | scope: PicoScope = connection.connect() 42 | 43 | # Enable Channel A and set the voltage range to be +/- 1V 44 | scope.set_channel(ps.Channel.A, range=ps.Range.R_1V) 45 | 46 | # Request to sample the voltage every 1 ms, for 100 ms 47 | actual_dt, num_samples = scope.set_timebase(1e-3, 100e-3) 48 | print(f"The actual time between samples is {actual_dt} seconds and there will be {num_samples} samples") 49 | 50 | # Channel A is the trigger source with a trigger threshold value of 0.0 V and a timeout of 0.1 second 51 | scope.set_trigger(ps.Channel.A, threshold=0.0, timeout=0.1) 52 | 53 | print("Start data acquisition...") 54 | _ = scope.run_block() 55 | scope.wait_until_ready() 56 | 57 | # Set the data buffer for Channel A 58 | scope.set_data_buffer("A") 59 | 60 | print("Start data-ready callback...") 61 | scope.get_values_async(my_data_ready) 62 | 63 | # Sleep to make sure the callback function gets called before this script terminates 64 | time.sleep(0.1) 65 | 66 | # Stop the oscilloscope from sampling data 67 | scope.stop() 68 | 69 | # Disconnect from the scope 70 | scope.disconnect() 71 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment_resources/raicol/tec.py: -------------------------------------------------------------------------------- 1 | """Control a TEC (Peltier-based) oven from [Raicol Crystals](https://raicol.com/){:target="_blank"}.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import TYPE_CHECKING 6 | 7 | from msl.equipment.interfaces import MSLConnectionError, Serial 8 | 9 | if TYPE_CHECKING: 10 | from msl.equipment.schema import Equipment 11 | 12 | 13 | class RaicolTEC(Serial, manufacturer=r"Raicol", model=r"TEC"): 14 | """Control a TEC (Peltier-based) oven from [Raicol Crystals](https://raicol.com/){:target="_blank"}.""" 15 | 16 | def __init__(self, equipment: Equipment) -> None: 17 | """Control a TEC (Peltier-based) oven from Raicol Crystals. 18 | 19 | Args: 20 | equipment: An [Equipment][] instance. 21 | """ 22 | super().__init__(equipment) 23 | self.write_termination: bytes = b"\n" 24 | 25 | def get_setpoint(self) -> float: 26 | """Get the setpoint temperature. 27 | 28 | Returns: 29 | The setpoint temperature, in Celsius. 30 | """ 31 | return float(self.query("Get_T_Set", size=6)[2:]) 32 | 33 | def off(self) -> None: 34 | """Turn the TEC off.""" 35 | reply = self.query("OFF", size=4) 36 | if reply != "ofOK": 37 | msg = "Cannot turn the TEC off" 38 | raise MSLConnectionError(self, msg) 39 | 40 | def on(self) -> None: 41 | """Turn the TEC on.""" 42 | reply = self.query("ON", size=4) 43 | if reply != "onOK": 44 | msg = "Cannot turn the TEC on" 45 | raise MSLConnectionError(self, msg) 46 | 47 | def set_setpoint(self, temperature: float) -> None: 48 | """Set the setpoint temperature. 49 | 50 | Args: 51 | temperature: The setpoint temperature, in Celsius. Must be in the range [20.1, 60.0]. 52 | """ 53 | t = round(temperature, 1) 54 | if t < 20.1 or t > 60.0: # noqa: PLR2004 55 | msg = f"The setpoint temperature must be between 20.1 and 60.0, got {t}" 56 | raise ValueError(msg) 57 | 58 | reply = self.query(f"Set_T{t:.1f}", size=4, delay=0.05) 59 | if reply != "stOK": 60 | msg = "Cannot change the setpoint temperature" 61 | raise MSLConnectionError(self, msg) 62 | 63 | def temperature(self) -> float: 64 | """Returns the current temperature of the oven. 65 | 66 | The temperature is measured by a PT1000 sensor that is located near the crystal in the metallic mount. 67 | 68 | Returns: 69 | The temperature of the oven, in Celsius. 70 | """ 71 | return float(self.query("Data_T", size=7)[2:]) 72 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/ps5000a_streaming_ready_callback.py: -------------------------------------------------------------------------------- 1 | """Acquire PicoScope data in Streaming Mode.""" 2 | 3 | from __future__ import annotations 4 | 5 | import os 6 | from typing import TYPE_CHECKING 7 | 8 | from msl.equipment import Connection 9 | from msl.equipment.resources import picoscope as ps 10 | 11 | if TYPE_CHECKING: 12 | from msl.equipment.resources import PicoScope 13 | 14 | connection = Connection( 15 | "SDK::ps5000a", # Alternatively, specify the full path to the SDK, "SDK::path/to/lib/ps5000a" 16 | manufacturer="Pico Technology", 17 | model="5244B", # Update for your PicoScope 18 | serial="DY135/055", # Update for your PicoScope 19 | # resolution="16bit", # Optional: Specify the device resolution (bit depth) 20 | ) 21 | 22 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 23 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 24 | 25 | 26 | @ps.streaming_ready 27 | def my_streaming_ready( 28 | handle: int, 29 | num_samples: int, 30 | start_index: int, 31 | overflow: int, 32 | trigger_at: int, 33 | triggered: int, 34 | auto_stop: int, 35 | _: None, 36 | ) -> None: 37 | """Called when a stream is ready.""" 38 | print(f"{handle=}, {num_samples=}, {start_index=}, {overflow=}, {trigger_at=}, {triggered=}, {auto_stop=}") 39 | scope.streaming_done = bool(auto_stop) 40 | 41 | 42 | print("Example :: Using streaming mode") 43 | 44 | # Connect to the PicoScope 45 | scope: PicoScope = connection.connect() 46 | 47 | # Enable Channel A and set the voltage range to be +/- 10V 48 | scope.set_channel(ps.Channel.A, range=ps.Range.R_10V) 49 | 50 | # Request to sample the voltage every 1 ms, for 5 s 51 | # Returns the sampling interval and the number of samples that will be acquired 52 | actual_dt, num_samples = scope.set_timebase(1e-3, 5) 53 | print(f"The actual time between samples is {actual_dt} seconds and there will be {num_samples} samples") 54 | 55 | # Channel A is the trigger source with a trigger threshold value of 0.0 V and a timeout of 0.1 second 56 | scope.set_trigger(ps.Channel.A, threshold=0.0, timeout=0.1) 57 | 58 | # Set the data buffer for Channel A to hold the samples 59 | scope.set_data_buffer(channel=ps.Channel.A) 60 | 61 | # Start streaming mode 62 | _ = scope.run_streaming() 63 | while not scope.streaming_done: 64 | scope.get_streaming_latest_values(my_streaming_ready) 65 | 66 | print("Stopping the PicoScope") 67 | scope.stop() 68 | 69 | print("The voltages are:") 70 | print(scope.channel["A"].volts) 71 | 72 | print("The raw ADU counts are:") 73 | print(scope.channel["A"].adu) 74 | 75 | # Disconnect from the scope 76 | scope.disconnect() 77 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/kdc101.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to communicate with Thorlabs 3 | KDC101, KCube DC Servo. 4 | """ 5 | import os 6 | from pprint import pprint 7 | 8 | from msl.equipment import ( 9 | EquipmentRecord, 10 | ConnectionRecord, 11 | Backend, 12 | ) 13 | from msl.equipment.resources.thorlabs import MotionControl 14 | 15 | # ensure that the Kinesis folder is available on PATH 16 | os.environ['PATH'] += os.pathsep + 'C:/Program Files/Thorlabs/Kinesis' 17 | 18 | record = EquipmentRecord( 19 | manufacturer='Thorlabs', 20 | model='KDC101', 21 | serial='27251265', # update for your device 22 | connection=ConnectionRecord( 23 | backend=Backend.MSL, 24 | address='SDK::Thorlabs.MotionControl.KCube.DCServo.dll', 25 | ), 26 | ) 27 | 28 | 29 | def wait(): 30 | motor.clear_message_queue() 31 | while True: 32 | status = motor.convert_message(*motor.wait_for_message())['id'] 33 | if status == 'Homed' or status == 'Moved': 34 | break 35 | position = motor.get_position() 36 | real = motor.get_real_value_from_device_unit(position, 'DISTANCE') 37 | print(' at position {} [device units] {:.3f} [real-world units]'.format(position, real)) 38 | 39 | 40 | # avoid the FT_DeviceNotFound error 41 | MotionControl.build_device_list() 42 | 43 | # connect to the KCube DC Servo 44 | motor = record.connect() 45 | print('Connected to {}'.format(motor)) 46 | 47 | # load the configuration settings, so that we can call 48 | # the get_real_value_from_device_unit() method 49 | motor.load_settings() 50 | 51 | # start polling at 200 ms 52 | motor.start_polling(200) 53 | 54 | # home the device 55 | print('Homing...') 56 | motor.home() 57 | wait() 58 | print('Homing done. At position {} [device units]'.format(motor.get_position())) 59 | 60 | # move to position 100000 61 | print('Moving to 100000...') 62 | motor.move_to_position(100000) 63 | wait() 64 | print('Moving done. At position {} [device units]'.format(motor.get_position())) 65 | 66 | # move by a relative amount of -5000 67 | print('Moving by -5000...') 68 | motor.move_relative(-5000) 69 | wait() 70 | print('Moving done. At position {} [device units]'.format(motor.get_position())) 71 | 72 | # jog forwards 73 | print('Jogging forwards by {} [device units]'.format(motor.get_jog_step_size())) 74 | motor.move_jog('Forwards') 75 | wait() 76 | print('Jogging done. At position {} [device units]'.format(motor.get_position())) 77 | 78 | # stop polling and close the connection 79 | motor.stop_polling() 80 | motor.disconnect() 81 | 82 | # you can access the default settings for the motor to pass to the set_*() methods 83 | print('\nThe default motor settings are:') 84 | pprint(motor.settings) 85 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/kst101.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to communicate with Thorlabs 3 | KST101, KCube Stepper Motor. 4 | """ 5 | import os 6 | from pprint import pprint 7 | 8 | from msl.equipment import ( 9 | EquipmentRecord, 10 | ConnectionRecord, 11 | Backend, 12 | ) 13 | from msl.equipment.resources.thorlabs import MotionControl 14 | 15 | # ensure that the Kinesis folder is available on PATH 16 | os.environ['PATH'] += os.pathsep + 'C:/Program Files/Thorlabs/Kinesis' 17 | 18 | record = EquipmentRecord( 19 | manufacturer='Thorlabs', 20 | model='KST101', 21 | serial='26000908', # update for your device 22 | connection=ConnectionRecord( 23 | backend=Backend.MSL, 24 | address='SDK::Thorlabs.MotionControl.KCube.StepperMotor.dll', 25 | ), 26 | ) 27 | 28 | 29 | def wait(): 30 | motor.clear_message_queue() 31 | while True: 32 | status = motor.convert_message(*motor.wait_for_message())['id'] 33 | if status == 'Homed' or status == 'Moved': 34 | break 35 | position = motor.get_position() 36 | real = motor.get_real_value_from_device_unit(position, 'DISTANCE') 37 | print(' at position {} [device units] {:.3f} [real-world units]'.format(position, real)) 38 | 39 | 40 | # avoid the FT_DeviceNotFound error 41 | MotionControl.build_device_list() 42 | 43 | # connect to the KCube Stepper Motor 44 | motor = record.connect() 45 | print('Connected to {}'.format(motor)) 46 | 47 | # load the configuration settings, so that we can call 48 | # the get_real_value_from_device_unit() method 49 | motor.load_settings() 50 | 51 | # start polling at 200 ms 52 | motor.start_polling(200) 53 | 54 | # home the device 55 | print('Homing...') 56 | motor.home() 57 | wait() 58 | print('Homing done. At position {} [device units]'.format(motor.get_position())) 59 | 60 | # move to position 100000 61 | print('Moving to 100000...') 62 | motor.move_to_position(100000) 63 | wait() 64 | print('Moving done. At position {} [device units]'.format(motor.get_position())) 65 | 66 | # move by a relative amount of -5000 67 | print('Moving by -5000...') 68 | motor.move_relative(-5000) 69 | wait() 70 | print('Moving done. At position {} [device units]'.format(motor.get_position())) 71 | 72 | # jog forwards 73 | print('Jogging forwards by {} [device units]'.format(motor.get_jog_step_size())) 74 | motor.move_jog('Forwards') 75 | wait() 76 | print('Jogging done. At position {} [device units]'.format(motor.get_position())) 77 | 78 | # stop polling and close the connection 79 | motor.stop_polling() 80 | motor.disconnect() 81 | 82 | # you can access the default settings for the motor to pass to the set_*() methods 83 | print('\nThe default motor settings are:') 84 | pprint(motor.settings) 85 | -------------------------------------------------------------------------------- /docs/schema/file.md: -------------------------------------------------------------------------------- 1 | # File 2 | 3 | 13 | 14 | Suppose you have a variable named `file` (which is an instance of [File][msl.equipment.schema.File]) that represents the following information in an equipment register for data that is stored in a Spreadsheet 15 | 16 | ```xml 17 | 18 | tests\resources\irradiance.xlsx 19 | 7a91267cfb529388a99762b891ee4b7a12463e83b5d55809f76a0c8e76c71886 20 | 21 | ``` 22 | 23 | You can access *sha256* and *comment* as attributes of `file` 24 | 25 | ```pycon 26 | >>> file.sha256 27 | '7a91267cfb529388a99762b891ee4b7a12463e83b5d55809f76a0c8e76c71886' 28 | >>> file.comment 29 | 'FEL T647' 30 | 31 | ``` 32 | 33 | The *url* and *attributes* attributes of `file` can be used with the [read_table][msl.io.tables.read_table]{:target="_blank"} function of [msl-io](https://mslnz.github.io/msl-io/latest/){:target="_blank"} to read the Spreadsheet data 34 | 35 | ```pycon 36 | >>> from msl.io import read_table 37 | >>> table = read_table(file.url, **file.attributes) 38 | >>> print(table.metadata.header) 39 | ['Wavelength' 'Irradiance' 'u(Irradiance)'] 40 | >>> table 41 | 42 | >>> print(table) 43 | array([[2.500000e+02, 1.818000e-02, 2.033000e-02], 44 | [3.000000e+02, 1.847800e-01, 1.755000e-02], 45 | [3.500000e+02, 8.084500e-01, 1.606000e-02], 46 | [4.000000e+02, 2.213550e+00, 1.405000e-02], 47 | [4.500000e+02, 4.490040e+00, 1.250000e-02], 48 | [5.000000e+02, 7.451350e+00, 1.200000e-02], 49 | [5.500000e+02, 1.075753e+01, 1.152000e-02], 50 | [6.000000e+02, 1.403809e+01, 1.102000e-02], 51 | [6.500000e+02, 1.699469e+01, 1.103000e-02], 52 | [7.000000e+02, 1.944093e+01, 1.077000e-02]]) 53 | 54 | ``` 55 | 56 | !!! note 57 | Passing `**file.attributes` to [read_table][msl.io.tables.read_table]{:target="_blank"} works as expected provided that the XML attributes of the `` element are valid keyword arguments to [read_table][msl.io.tables.read_table]{:target="_blank"}. See [Read a table](https://mslnz.github.io/msl-io/latest/#read-a-table){:target="_blank"} for more examples from [msl-io](https://mslnz.github.io/msl-io/latest/){:target="_blank"}, in particular, specifying `dtype="header"` will return a structured dataset which would behave similar to the [Table][table] example in `msl-equipment` (i.e., accessing columns by header name). 58 | 59 | ::: msl.equipment.schema.File 60 | options: 61 | show_root_full_path: false 62 | show_root_heading: true 63 | -------------------------------------------------------------------------------- /src/msl/equipment/__init__.py: -------------------------------------------------------------------------------- 1 | """Manage and interface with equipment in the laboratory.""" 2 | 3 | from __future__ import annotations 4 | 5 | from .__about__ import __version__, version_tuple 6 | from .config import Config 7 | from .enumerations import Backend, DataBits, Parity, StopBits 8 | from .interfaces import ( 9 | GPIB, 10 | NIDAQ, 11 | SDK, 12 | VXI11, 13 | HiSLIP, 14 | MessageBased, 15 | MSLConnectionError, 16 | MSLTimeoutError, 17 | Prologix, 18 | PyVISA, 19 | Serial, 20 | Socket, 21 | ) 22 | from .readings import Readings 23 | from .record_types import ConnectionRecord, EquipmentRecord 24 | from .schema import ( 25 | AcceptanceCriteria, 26 | Accessories, 27 | Adjustment, 28 | Alteration, 29 | CapitalExpenditure, 30 | Competency, 31 | CompletedTask, 32 | Component, 33 | Conditions, 34 | Connection, 35 | CVDEquation, 36 | Deserialised, 37 | DigitalFormat, 38 | DigitalReport, 39 | Equation, 40 | Equipment, 41 | Evaluable, 42 | File, 43 | Financial, 44 | Firmware, 45 | Interface, 46 | IssuingLaboratory, 47 | Maintenance, 48 | Measurand, 49 | PerformanceCheck, 50 | PlannedTask, 51 | QualityManual, 52 | Range, 53 | ReferenceMaterials, 54 | Register, 55 | Report, 56 | Specifications, 57 | SpecifiedRequirements, 58 | Status, 59 | Table, 60 | ) 61 | 62 | __all__: list[str] = [ 63 | "GPIB", 64 | "NIDAQ", 65 | "SDK", 66 | "VXI11", 67 | "AcceptanceCriteria", 68 | "Accessories", 69 | "Adjustment", 70 | "Alteration", 71 | "Backend", 72 | "CVDEquation", 73 | "CapitalExpenditure", 74 | "Competency", 75 | "CompletedTask", 76 | "Component", 77 | "Conditions", 78 | "Config", 79 | "Connection", 80 | "ConnectionRecord", 81 | "DataBits", 82 | "Deserialised", 83 | "DigitalFormat", 84 | "DigitalReport", 85 | "Equation", 86 | "Equipment", 87 | "EquipmentRecord", 88 | "Evaluable", 89 | "File", 90 | "Financial", 91 | "Firmware", 92 | "HiSLIP", 93 | "Interface", 94 | "IssuingLaboratory", 95 | "MSLConnectionError", 96 | "MSLTimeoutError", 97 | "Maintenance", 98 | "Measurand", 99 | "MessageBased", 100 | "Parity", 101 | "PerformanceCheck", 102 | "PlannedTask", 103 | "Prologix", 104 | "PyVISA", 105 | "QualityManual", 106 | "Range", 107 | "Readings", 108 | "ReferenceMaterials", 109 | "Register", 110 | "Report", 111 | "Serial", 112 | "Socket", 113 | "Specifications", 114 | "SpecifiedRequirements", 115 | "Status", 116 | "StopBits", 117 | "Table", 118 | "__version__", 119 | "version_tuple", 120 | ] 121 | 122 | from . import resources as resources 123 | -------------------------------------------------------------------------------- /tests/test_record_types.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from msl.equipment import Backend, ConnectionRecord, EquipmentRecord 6 | from msl.equipment.record_types import _Warn # pyright: ignore[reportPrivateUsage] 7 | 8 | if TYPE_CHECKING: 9 | import pytest 10 | 11 | 12 | def test_warning_connection_record(recwarn: pytest.WarningsRecorder) -> None: 13 | _Warn.show = True 14 | 15 | equipment = EquipmentRecord( 16 | manufacturer="A", 17 | model="B", 18 | serial="C", 19 | connection=ConnectionRecord( 20 | address="COM1", 21 | backend=Backend.MSL, 22 | manufacturer="A", 23 | model="B", 24 | serial="C", 25 | timeout=10, 26 | ), 27 | ) 28 | 29 | assert equipment.manufacturer == "A" 30 | assert equipment.model == "B" 31 | assert equipment.serial == "C" 32 | assert equipment.connection is not None 33 | assert equipment.connection.address == "COM1" 34 | assert equipment.connection.backend == Backend.MSL 35 | assert equipment.connection.manufacturer == "A" 36 | assert equipment.connection.model == "B" 37 | assert equipment.connection.serial == "C" 38 | assert equipment.connection.properties == {"timeout": 10} 39 | 40 | # Warnings issued once 41 | _ = EquipmentRecord(connection=ConnectionRecord(address="A", backend="MSL")) 42 | _ = EquipmentRecord(connection=ConnectionRecord(address="A", backend="PyVISA")) 43 | _ = EquipmentRecord(connection=ConnectionRecord(address="A", backend="NIDAQ")) 44 | 45 | assert len(recwarn) == 1 46 | w = recwarn.pop(FutureWarning) 47 | assert issubclass(w.category, FutureWarning) 48 | assert w.lineno == 19 49 | assert w.filename == __file__ 50 | assert str(w.message).endswith( 51 | "Replace `EquipmentRecord` with `Equipment` and replace `ConnectionRecord` with `Connection`." 52 | ) 53 | 54 | 55 | def test_warning_equipment_record(recwarn: pytest.WarningsRecorder) -> None: 56 | _Warn.show = True 57 | 58 | equipment = EquipmentRecord(manufacturer="A", model="B", serial="C") 59 | 60 | assert equipment.manufacturer == "A" 61 | assert equipment.model == "B" 62 | assert equipment.serial == "C" 63 | assert equipment.connection is None 64 | 65 | # Warnings issued once 66 | _ = EquipmentRecord(manufacturer="D", model="E", serial="F") 67 | _ = EquipmentRecord(manufacturer="G", model="H", serial="I") 68 | _ = EquipmentRecord(manufacturer="J", model="K", serial="L") 69 | 70 | assert len(recwarn) == 1 71 | w = recwarn.pop(FutureWarning) 72 | assert issubclass(w.category, FutureWarning) 73 | assert w.lineno == 58 74 | assert w.filename == __file__ 75 | assert str(w.message).endswith( 76 | "Replace `EquipmentRecord` with `Equipment` and replace `ConnectionRecord` with `Connection`." 77 | ) 78 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/ps5000a_AWG_builtin.py: -------------------------------------------------------------------------------- 1 | """This example samples a sine wave that is created by the Arbitrary Waveform Generator (AWG). 2 | 3 | The output of the AWG must be connected to Channel A. 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | import os 9 | from typing import TYPE_CHECKING 10 | 11 | import numpy as np 12 | 13 | from msl.equipment import Connection 14 | 15 | if TYPE_CHECKING: 16 | from msl.equipment.resources import PicoScope 17 | 18 | connection = Connection( 19 | "SDK::ps5000a", # Alternatively, specify the full path to the SDK, "SDK::path/to/lib/ps5000a" 20 | manufacturer="Pico Technology", 21 | model="5244B", # Update for your PicoScope 22 | serial="DY135/055", # Update for your PicoScope 23 | # resolution="16bit", # Optional: Specify the device resolution (bit depth) 24 | ) 25 | 26 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 27 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 28 | 29 | print("Example :: Builtin AWG waveform") 30 | 31 | # Connect to the PicoScope 32 | scope: PicoScope = connection.connect() 33 | 34 | # Enable Channel A and set the voltage range to be +/- 10V 35 | scope.set_channel("A", range="10V") 36 | 37 | # Request to sample voltage every 1 us, for 200 us 38 | # Returns the sampling interval and the number of samples that will be acquired 39 | actual_dt, num_samples = scope.set_timebase(1e-6, 200e-6) 40 | print(f"The actual time between samples is {actual_dt} seconds and there will be {num_samples} samples") 41 | 42 | # Use Channel A as the trigger source at 1V and wait forever for a trigger event 43 | scope.set_trigger("A", threshold=1.0, timeout=None) 44 | 45 | # Create a sine wave 46 | scope.set_sig_gen_builtin_v2(start_frequency=10e3, peak_to_peak=2.0, offset_voltage=0.4) 47 | 48 | # Start acquisition 49 | _ = scope.run_block() 50 | 51 | # Wait until all requested samples are collected 52 | scope.wait_until_ready() 53 | 54 | # Set the data buffer for Channel A 55 | scope.set_data_buffer("A") 56 | 57 | # Fill the data buffer of Channel A with the values saved in the PicoScope's internal memory 58 | num_acquired, overflow_mask = scope.get_values() 59 | print(f"Number of samples acquired is {num_acquired}") 60 | print(f"Overflow bit mask => {overflow_mask}") 61 | 62 | # Stop the oscilloscope from sampling data 63 | scope.stop() 64 | 65 | # Calculate the timestamps. 66 | # In this example pre_trigger=0 since it was not specified when run_block() was called 67 | # so adjusting the times by `pre_trigger` seconds is not necessary. 68 | t0 = -scope.pre_trigger 69 | t1 = (actual_dt * num_samples) - scope.pre_trigger 70 | times = np.arange(t0, t1, actual_dt) 71 | 72 | volts = scope.channel["A"].volts 73 | 74 | print("The AWG output:") 75 | for t, v in zip(times, volts): 76 | print(f"{t:.2e} {v:f}") 77 | 78 | # Disconnect from the scope 79 | scope.disconnect() 80 | -------------------------------------------------------------------------------- /tests/resources/light/register.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MSLE.O.231 5 | MSL 6 | 3458A 7 | 0123456789 8 | A digital multimeter 9 | 10 | Spectrophotometer 11 | Active 12 | false 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | MSLE.O.103 24 | MSL 25 | Single 26 | B02 27 | Single element photodiode 28 | 29 | Spectrophotometer 30 | Active 31 | false 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | MSLE.O.061 43 | MSL 44 | Mono 45 | 123 46 | Monochromator f=500mm 47 | 48 | Spectrophotometer 49 | Active 50 | false 51 | true 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | MSLE.O.023 62 | MSL 63 | Model 64 | abc 65 | Temperature probe 66 | 67 | Spectrophotometer 68 | Active 69 | true 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /packages/resources/examples/thorlabs/lts150.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to communicate with Thorlabs LTS150, 3 | 150-mm Translation Stage with Stepper Motor. 4 | 5 | By changing the value of the `model` number (see below), 6 | this script can be used to control: 7 | 8 | * Long Travel Stages (LTS150 and LTS300) 9 | * Lab Jack (MLJ050, MLJ150) 10 | * Cage Rotator (K10CR1) 11 | """ 12 | import os 13 | from pprint import pprint 14 | 15 | from msl.equipment import ( 16 | EquipmentRecord, 17 | ConnectionRecord, 18 | Backend, 19 | ) 20 | from msl.equipment.resources.thorlabs import MotionControl 21 | 22 | # ensure that the Kinesis folder is available on PATH 23 | os.environ['PATH'] += os.pathsep + 'C:/Program Files/Thorlabs/Kinesis' 24 | 25 | record = EquipmentRecord( 26 | manufacturer='Thorlabs', 27 | model='LTS150/M', # update for your device 28 | serial='45870601', # update for your device 29 | connection=ConnectionRecord( 30 | backend=Backend.MSL, 31 | address='SDK::Thorlabs.MotionControl.IntegratedStepperMotors.dll', 32 | ), 33 | ) 34 | 35 | 36 | def wait(): 37 | motor.clear_message_queue() 38 | while True: 39 | status = motor.convert_message(*motor.wait_for_message())['id'] 40 | if status == 'Homed' or status == 'Moved': 41 | break 42 | position = motor.get_position() 43 | real = motor.get_real_value_from_device_unit(position, 'DISTANCE') 44 | print(' at position {} [device units] {:.3f} [real-world units]'.format(position, real)) 45 | 46 | 47 | # Build the device list before connecting to the Integrated Stepper Motor 48 | MotionControl.build_device_list() 49 | 50 | # connect to the Integrated Stepper Motor 51 | motor = record.connect() 52 | print('Connected to {}'.format(motor)) 53 | 54 | # initialize 55 | motor.enable_channel() 56 | motor.load_settings() 57 | 58 | # start polling at 200 ms 59 | motor.start_polling(200) 60 | 61 | # home the device 62 | print('Homing...') 63 | motor.home() 64 | wait() 65 | print('Homing done. At position {} [device units]'.format(motor.get_position())) 66 | 67 | # move to position 100000 68 | print('Moving to 100000...') 69 | motor.move_to_position(100000) 70 | wait() 71 | print('Moving done. At position {} [device units]'.format(motor.get_position())) 72 | 73 | # move by a relative amount of -5000 74 | print('Moving by -5000...') 75 | motor.move_relative(-5000) 76 | wait() 77 | print('Moving done. At position {} [device units]'.format(motor.get_position())) 78 | 79 | # jog forwards 80 | print('Jogging forwards by {} [device units]'.format(motor.get_jog_step_size())) 81 | motor.move_jog('Forwards') 82 | wait() 83 | print('Jogging done. At position {} [device units]'.format(motor.get_position())) 84 | 85 | # stop polling and close the connection 86 | motor.stop_polling() 87 | motor.disconnect() 88 | 89 | # you can access the default settings for the motor to pass to the set_*() methods 90 | print('\nThe default motor settings are:') 91 | pprint(motor.settings) 92 | -------------------------------------------------------------------------------- /packages/resources/examples/picotech/ps5000a_block_ready_callback.py: -------------------------------------------------------------------------------- 1 | """Acquire PicoScope data in Block-Ready Mode using a callback function. 2 | 3 | The callback function is notified when the data block has been acquired. 4 | """ 5 | 6 | from __future__ import annotations 7 | 8 | import os 9 | import time 10 | from typing import TYPE_CHECKING 11 | 12 | from msl.equipment import Connection 13 | from msl.equipment.resources import picoscope as ps 14 | 15 | if TYPE_CHECKING: 16 | from msl.equipment.resources import PicoScope 17 | 18 | connection = Connection( 19 | "SDK::ps5000a", # Alternatively, specify the full path to the SDK, "SDK::path/to/lib/ps5000a" 20 | manufacturer="Pico Technology", 21 | model="5244B", # Update for your PicoScope 22 | serial="DY135/055", # Update for your PicoScope 23 | # resolution="16bit", # Optional: Specify the device resolution (bit depth) 24 | ) 25 | 26 | # Optional: Ensure that the Pico Technology SDK directory is available on PATH (if not already) 27 | os.environ["PATH"] += os.pathsep + r"C:\Program Files\Pico Technology\SDK\lib" 28 | 29 | 30 | @ps.block_ready 31 | def run_done(handle: int, status: int, _: None) -> None: 32 | """Called when all samples have been acquired.""" 33 | print(f"Callback: Data acquisition is done! {handle=}, {status=}") 34 | 35 | # Set the data buffer for Channel A 36 | scope.set_data_buffer("A") 37 | 38 | # Fill the data buffer of Channel A with the values saved in the PicoScope's internal memory 39 | num_acquired, overflow_mask = scope.get_values() 40 | print(f"Number of samples acquired {num_acquired}") 41 | print(f"Overflow bit mask => {overflow_mask}") 42 | 43 | print(f"The time between samples is {scope.dt} seconds") 44 | print("The voltages are:") 45 | print(scope.channel["A"].volts) 46 | 47 | 48 | print("Example :: Using block-ready mode with a callback function") 49 | 50 | # Connect to the PicoScope 51 | scope: PicoScope = connection.connect() 52 | 53 | # Enable Channel A and set the voltage range to be +/- 1V 54 | scope.set_channel(ps.Channel.A, range=ps.Range.R_1V) 55 | 56 | # Request to sample the voltage every 1 ms, for 20 ms 57 | actual_dt, num_samples = scope.set_timebase(1e-3, 20e-3) 58 | print(f"The actual time between samples is {actual_dt} seconds and there will be {num_samples} samples") 59 | 60 | # Channel A is the trigger source with a trigger threshold value of 0.0 V and a timeout of 0.1 second 61 | scope.set_trigger(ps.Channel.A, threshold=0.0, timeout=0.1) 62 | 63 | print("Start data acquisition...") 64 | 65 | # Pass in our callback function to be notified when data acquisition is finished 66 | wait_time = scope.run_block(callback=run_done) 67 | print(f"Acquiring the samples should take approximately {wait_time} seconds") 68 | 69 | # Sleep to make sure the callback function gets called before this script terminates 70 | time.sleep(wait_time * 1.5) 71 | 72 | print("Stopping the PicoScope") 73 | scope.stop() 74 | 75 | # Disconnect from the scope 76 | scope.disconnect() 77 | -------------------------------------------------------------------------------- /packages/resources/src/msl/equipment/resources/thorlabs/kinesis/messages.py: -------------------------------------------------------------------------------- 1 | """ 2 | Device Message Queue defined in Thorlabs Kinesis v1.14.18 3 | 4 | The device message queue allows the internal events raised by the device to be 5 | monitored by the DLLs owner. 6 | 7 | The device raises many different events, usually associated with a change of state. 8 | 9 | These messages are temporarily stored in the DLL and can be accessed using the 10 | appropriate message functions. 11 | 12 | The message consists of 3 components, a messageType, a messageID and messageData:: 13 | 14 | WORD messageType 15 | WORD messageID 16 | WORD messageData 17 | 18 | """ 19 | from __future__ import annotations 20 | 21 | #: MessageTypes 22 | MessageTypes = { 23 | 0: 'GenericDevice', 24 | 1: 'GenericPiezo', 25 | 2: 'GenericMotor', 26 | 3: 'GenericDCMotor', 27 | 4: 'GenericSimpleMotor', 28 | 5: 'RackDevice', 29 | 6: 'Laser', 30 | 7: 'TECCtlr', 31 | 8: 'Quad', 32 | 9: 'NanoTrak', 33 | 10: 'Specialized', 34 | 11: 'Solenoid', 35 | } 36 | 37 | #: GenericDevice 38 | GenericDevice = { 39 | 0: 'settingsInitialized', 40 | 1: 'settingsUpdated', 41 | 2: 'settingsExtern', 42 | 3: 'error', 43 | 4: 'close', 44 | 5: 'settingsReset', 45 | } 46 | 47 | #: GenericMotor 48 | GenericMotor = { 49 | 0: 'Homed', 50 | 1: 'Moved', 51 | 2: 'Stopped', 52 | 3: 'LimitUpdated', 53 | } 54 | 55 | #: GenericDCMotor 56 | GenericDCMotor = { 57 | 0: 'error', 58 | 1: 'status', 59 | } 60 | 61 | #: GenericPiezo 62 | GenericPiezo = { 63 | 0: 'maxVoltageChanged', 64 | 1: 'controlModeChanged', 65 | 2: 'statusChanged', 66 | 3: 'maxTravelChanged', 67 | 4: 'TSG_Status', 68 | 5: 'TSG_DisplayModeChanged', 69 | } 70 | 71 | #: RackDevice 72 | RackDevice = { 73 | 0: 'RackCountEstablished', 74 | 1: 'RackBayState', 75 | } 76 | 77 | #: Quad 78 | Quad = { 79 | 0: 'statusChanged', 80 | } 81 | 82 | #: TECCtlr 83 | TECCtlr = { 84 | 0: 'statusChanged', 85 | 2: 'displaySettingsChanged', 86 | 3: 'feedbackParamsChanged', 87 | } 88 | 89 | #: Laser 90 | Laser = { 91 | 0: 'statusChanged', 92 | 1: 'controlSourceChanged', 93 | 2: 'displayModeChanged', 94 | } 95 | 96 | #: Solenoid 97 | Solenoid = { 98 | 0: 'statusChanged', 99 | } 100 | 101 | #: NanoTrak 102 | NanoTrak = { 103 | 0: 'statusChanged', 104 | } 105 | 106 | #: Specialized 107 | Specialized = {} 108 | 109 | #: GenericSimpleMotor 110 | GenericSimpleMotor = {} 111 | 112 | #: MessageID 113 | MessageID = { 114 | 'GenericDevice': GenericDevice, 115 | 'GenericPiezo': GenericPiezo, 116 | 'GenericMotor': GenericMotor, 117 | 'GenericDCMotor': GenericDCMotor, 118 | 'GenericSimpleMotor': GenericSimpleMotor, 119 | 'RackDevice': RackDevice, 120 | 'Laser': Laser, 121 | 'TECCtlr': TECCtlr, 122 | 'Quad': Quad, 123 | 'NanoTrak': NanoTrak, 124 | 'Specialized': Specialized, 125 | 'Solenoid': Solenoid, 126 | } 127 | --------------------------------------------------------------------------------