fusaware-instruments 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. fusaware_instruments/__init__.py +0 -0
  2. fusaware_instruments/utils.py +108 -0
  3. fusaware_instruments/visa_instrument_configuration/__init__.py +0 -0
  4. fusaware_instruments/visa_instrument_configuration/analog_probe.py +441 -0
  5. fusaware_instruments/visa_instrument_configuration/analog_probe_rigol_mso5000.py +44 -0
  6. fusaware_instruments/visa_instrument_configuration/dc_voltage_dmm.py +75 -0
  7. fusaware_instruments/visa_instrument_configuration/dc_voltage_supply.py +205 -0
  8. fusaware_instruments/visa_instrument_configuration/dc_voltage_supply_rigol_dp800.py +38 -0
  9. fusaware_instruments/visa_instrument_configuration/dc_voltage_supply_simulator.py +165 -0
  10. fusaware_instruments/visa_instrument_configuration/oscilloscope.py +408 -0
  11. fusaware_instruments/visa_instrument_drivers/__init__.py +3 -0
  12. fusaware_instruments/visa_instrument_drivers/driver_dc_power_supply_simulator.py +151 -0
  13. fusaware_instruments/visa_instrument_drivers/driver_keysight_e36150.py +183 -0
  14. fusaware_instruments/visa_instrument_drivers/driver_lecroy_wavejet.py +41 -0
  15. fusaware_instruments/visa_instrument_drivers/driver_rigol_dm3000.py +134 -0
  16. fusaware_instruments/visa_instrument_drivers/driver_rigol_dp_base.py +192 -0
  17. fusaware_instruments/visa_instrument_drivers/driver_rigol_mso_base.py +256 -0
  18. fusaware_instruments/visa_instrument_drivers/driver_tektronix_mdo_3_series.py +1209 -0
  19. fusaware_instruments/visa_instrument_hal/__init__.py +0 -0
  20. fusaware_instruments/visa_instrument_hal/hal_dc_power_supply.py +113 -0
  21. fusaware_instruments/visa_instrument_hal/hal_dc_power_supply_rigol_dp.py +260 -0
  22. fusaware_instruments/visa_instrument_hal/hal_dc_power_supply_simulator.py +203 -0
  23. fusaware_instruments/visa_instrument_hal/hal_dmm.py +151 -0
  24. fusaware_instruments/visa_instrument_hal/hal_dmm_keithley_dmm_6500.py +226 -0
  25. fusaware_instruments/visa_instrument_hal/hal_dmm_rigol_dm3000.py +290 -0
  26. fusaware_instruments/visa_instrument_hal/hal_dmm_rigol_dm3000_v2.py +112 -0
  27. fusaware_instruments/visa_instrument_hal/hal_oscilloscope.py +344 -0
  28. fusaware_instruments/visa_instrument_hal/hal_oscilloscope_rigol_mso.py +653 -0
  29. fusaware_instruments/visa_instrument_hal/hal_oscilloscope_tektronix_mdo_3_series.py +907 -0
  30. fusaware_instruments-0.1.0.dist-info/METADATA +42 -0
  31. fusaware_instruments-0.1.0.dist-info/RECORD +33 -0
  32. fusaware_instruments-0.1.0.dist-info/WHEEL +4 -0
  33. fusaware_instruments-0.1.0.dist-info/licenses/LICENSE +1 -0
File without changes
@@ -0,0 +1,108 @@
1
+ # pyright: strict
2
+
3
+ from typing import Protocol
4
+ from dataclasses import dataclass
5
+ from enum import Enum
6
+ import logging
7
+
8
+ import pyvisa as pv
9
+
10
+
11
+ class VisaIO(Protocol):
12
+ def query(self, message: str) -> str: ...
13
+
14
+ def write(self, message: str) -> int: ...
15
+
16
+ def read(self) -> str: ...
17
+
18
+ def read_bytes(self, count: int) -> bytes: ...
19
+
20
+ def read_raw(self, size: int | None = None) -> bytes: ...
21
+
22
+
23
+ class PyvisaIO(VisaIO):
24
+ def __init__(self, resource: pv.resources.MessageBasedResource):
25
+ self._resource = resource
26
+
27
+ def query(self, message: str) -> str:
28
+ resp = self._resource.query(message)
29
+ logging.debug(
30
+ f"Query: '{message}' -> Response: '{resp[:20] if len(resp) > 20 else resp}'"
31
+ )
32
+ return resp
33
+
34
+ def write(self, message: str) -> int:
35
+ logging.debug(f"Write: '{message}'")
36
+ return self._resource.write(message)
37
+
38
+ def read(self) -> str:
39
+ resp = self._resource.read()
40
+ logging.debug(f"Read: '{resp}'")
41
+ return resp
42
+
43
+ def read_bytes(self, count: int) -> bytes:
44
+ resp = self._resource.read_bytes(count)
45
+ logging.debug(f"Read bytes: {resp[:20] if len(resp) > 20 else resp}")
46
+ return resp
47
+
48
+ def read_raw(self, size: int | None = None) -> bytes:
49
+ resp = self._resource.read_raw(size)
50
+ logging.debug(f"Read raw: {resp[:20] if len(resp) > 20 else resp}")
51
+ return resp
52
+
53
+
54
+ @dataclass
55
+ class ScpiParseError(Exception):
56
+ response: str
57
+ query: str
58
+ message: str | None = None
59
+
60
+ def __str__(self):
61
+ if self.message is None:
62
+ return f"ScpiParseError: Could not parse response '{self.response}' for query '{self.query}'"
63
+ else:
64
+ return self.message
65
+
66
+
67
+ @dataclass
68
+ class ReconcileException[T](Exception):
69
+ param_name: str
70
+ expected: T
71
+ actual: T
72
+ message: str | None = None
73
+
74
+ def __str__(self):
75
+ if self.message is None:
76
+ return f"ReconcileException: Parameter '{self.param_name}' did not reconcile: expected '{self.expected}' but got '{self.actual}'"
77
+ else:
78
+ return self.message
79
+
80
+
81
+ class MappingDirection(Enum):
82
+ ConfigToHal = "CONFIG_TO_HAL"
83
+ HalToConfig = "HAL_TO_CONFIG"
84
+ HalToDriver = "HAL_TO_DRIVER"
85
+ DriverToHal = "DRIVER_TO_HAL"
86
+
87
+
88
+ @dataclass
89
+ class MappingException[T](Exception):
90
+ direction: MappingDirection
91
+ from_type: type
92
+ to_type: type
93
+ value: T
94
+
95
+ def __str__(self) -> str:
96
+ match self.direction:
97
+ case MappingDirection.ConfigToHal:
98
+ return f"Value '{self.value}' of type {self.from_type} cannot be mapped to HAL representation of type {self.to_type}."
99
+ case MappingDirection.HalToConfig:
100
+ return f"Value '{self.value}' of type {self.to_type} cannot be mapped to config representation of type {self.from_type}."
101
+ case MappingDirection.HalToDriver:
102
+ return f"Value '{self.value}' of type {self.to_type} cannot be mapped to driver representation of type {self.from_type}."
103
+ case MappingDirection.DriverToHal:
104
+ return f"Value '{self.value}' of type {self.from_type} cannot be mapped to HAL representation of type {self.to_type}."
105
+
106
+
107
+ def compare_floats(a: float, b: float, tolerance: float = 1e-9) -> bool:
108
+ return abs(a - b) <= tolerance
@@ -0,0 +1,441 @@
1
+ # pyright: strict
2
+
3
+ import math
4
+ from abc import ABC, abstractmethod
5
+ from enum import Enum
6
+ from typing import Tuple
7
+ import logging
8
+
9
+ from pydantic import BaseModel, validate_call
10
+
11
+ from fusaware_instruments.visa_instrument_hal.hal_oscilloscope import (
12
+ Attenuation,
13
+ HALOscilloscope,
14
+ ProbeAttenuation,
15
+ ProbeId,
16
+ UnknownProbe,
17
+ )
18
+ from fusaware_instruments.visa_instrument_hal.hal_oscilloscope import (
19
+ ProbeCoupling as HALCoupling,
20
+ )
21
+ from fusaware_instruments.visa_instrument_hal.hal_oscilloscope import Units as HALUnits
22
+
23
+
24
+ class Coupling(Enum):
25
+ AC = "ac"
26
+ DC = "dc"
27
+ Ground = "ground"
28
+
29
+
30
+ class State(Enum):
31
+ Disabled = "disabled"
32
+ Enabled = "enabled"
33
+
34
+
35
+ class Units(str, Enum):
36
+ Amps = "amps"
37
+ Volts = "volts"
38
+ Other = "other"
39
+
40
+
41
+ class AnalogProbeState(BaseModel):
42
+ attenuation: float
43
+ bandwidth_limit: float | int | str
44
+ coupling: Coupling
45
+ offset: float
46
+ scale: float
47
+ state: State
48
+ units: Units
49
+
50
+
51
+ class AnalogProbe(ABC):
52
+ @abstractmethod
53
+ def configure_analog_probe(
54
+ self,
55
+ attenuation: float,
56
+ bandwidth_limit: float | int | str,
57
+ coupling: Coupling,
58
+ offset: float | int,
59
+ scale: float | int,
60
+ state: State,
61
+ units: Units,
62
+ ) -> AnalogProbeState:
63
+ pass
64
+
65
+
66
+ @validate_call
67
+ def configure_analog_probe(
68
+ op: HALOscilloscope,
69
+ attenuation: float | int,
70
+ bandwidth_limit: float | int | str,
71
+ coupling: Coupling,
72
+ scale: float | int,
73
+ offset: float | int,
74
+ state: State,
75
+ units: Units,
76
+ ) -> tuple[AnalogProbeState, list[str]]:
77
+ desired_attenuation = Attenuation(attenuation=attenuation)
78
+ desired_bandwidth_limit = bandwidth_limit
79
+ desired_coupling = Coupling(coupling)
80
+ desired_scale = scale
81
+ desired_offset = offset
82
+ desired_state = State(state)
83
+ desired_units = Units(units)
84
+
85
+ probe_id = op.get_probe_id()
86
+
87
+ initial_state = get_state(op)
88
+ initial_units = get_units(op)
89
+ initial_bandwidth_limit = get_bandwidth_limit(op)
90
+ initial_coupling = get_coupling(op)
91
+ initial_attenuation = get_attenuation(op)
92
+ initial_scale = get_scale(op)
93
+ initial_offset = get_offset(op)
94
+
95
+ if not _is_state_equal(initial_state, desired_state):
96
+ set_state(op, desired_state)
97
+
98
+ if not _is_units_equal(desired_units, initial_units):
99
+ set_units(op, desired_units)
100
+
101
+ if not _is_attenuation_equal(desired_attenuation, initial_attenuation):
102
+ set_attenuation(op, desired_attenuation)
103
+
104
+ if not _is_scale_equal(desired_scale, initial_scale):
105
+ set_scale(op, desired_scale)
106
+
107
+ if not _is_offset_equal(desired_offset, initial_offset):
108
+ set_offset(op, desired_offset)
109
+
110
+ if not _is_bandwidth_limit_equal(desired_bandwidth_limit, initial_bandwidth_limit):
111
+ set_bandwidth_limit(op, desired_bandwidth_limit)
112
+
113
+ if not _is_coupling_equal(desired_coupling, initial_coupling):
114
+ set_coupling(op, desired_coupling)
115
+
116
+ final_state = get_state(op)
117
+ final_units = get_units(op)
118
+ final_attenuation = get_attenuation(op)
119
+ final_scale = get_scale(op)
120
+ final_offset = get_offset(op)
121
+ final_coupling = get_coupling(op)
122
+ final_bandwidth_limit = get_bandwidth_limit(op)
123
+
124
+ errors: list[str] = []
125
+
126
+ # TODO make these errors a type or something
127
+ if not _is_state_equal(final_state, desired_state):
128
+ errors.append(f"State mismatch: expected {desired_state}, got {final_state}")
129
+
130
+ if not _is_units_equal(final_units, desired_units):
131
+ match probe_id:
132
+ case ProbeId() | UnknownProbe():
133
+ errors.append(
134
+ f"Probe '{probe_id.name()}' does not support units '{desired_units.value}', final units: '{final_units.value}'"
135
+ )
136
+ case None:
137
+ errors.append(
138
+ f"Units mismatch: expected {desired_units}, got {final_units}"
139
+ )
140
+
141
+ # For future use
142
+
143
+ # match probe_id:
144
+ # case ProbeId():
145
+ # valid_units = [unit.value for unit in probe_id.valid_units()]
146
+ # errors.append(
147
+ # f"""
148
+ # Probe '{probe_id.name()}' does not support units '{desired_units.value}'
149
+ # Supported units: {",".join(valid_units)}
150
+ # """
151
+ # )
152
+ # case UnknownProbe():
153
+ # errors.append(
154
+ # f"Probe '{probe_id.name()}' does not support units '{desired_units.value}', check its documentation for more information"
155
+ # )
156
+ # case None:
157
+ # errors.append(
158
+ # f"Units mismatch: expected {desired_units}, got {final_units}"
159
+ # )
160
+
161
+ if not _is_attenuation_equal(desired_attenuation, final_attenuation):
162
+ match probe_id:
163
+ case ProbeId() | UnknownProbe():
164
+ errors.append(
165
+ f"Probe '{probe_id.name()}' does not support attenuation '{desired_attenuation.attenuation}', final attenuation: '{final_attenuation.attenuation}'"
166
+ )
167
+ case None:
168
+ errors.append(
169
+ f"Attenuation mismatch: expected {desired_attenuation.attenuation}, got {final_attenuation.attenuation}"
170
+ )
171
+
172
+ if not _is_scale_equal(desired_scale, final_scale):
173
+ match probe_id:
174
+ case ProbeId() | UnknownProbe():
175
+ errors.append(
176
+ f"Probe '{probe_id.name()}' does not support scale '{desired_scale}', final scale: '{final_scale}'"
177
+ )
178
+ case None:
179
+ errors.append(
180
+ f"Scale mismatch: expected {desired_scale}, got {final_scale}"
181
+ )
182
+
183
+ if not _is_offset_equal(desired_offset, final_offset):
184
+ match probe_id:
185
+ case ProbeId() | UnknownProbe():
186
+ errors.append(
187
+ f"Probe '{probe_id.name()}' does not support offset '{desired_offset}', final offset: '{final_offset}'"
188
+ )
189
+ case None:
190
+ errors.append(
191
+ f"Offset mismatch: expected {desired_offset}, got {final_offset}"
192
+ )
193
+
194
+ if not _is_coupling_equal(desired_coupling, final_coupling):
195
+ match probe_id:
196
+ case ProbeId() | UnknownProbe():
197
+ logging.warning(
198
+ f"Probe '{probe_id.name()}' does not support coupling '{desired_coupling.value}', final coupling: '{final_coupling.value}'"
199
+ )
200
+ case None:
201
+ errors.append(
202
+ f"Coupling mismatch: expected {desired_coupling.value}, got {final_coupling.value}"
203
+ )
204
+
205
+ if not _is_bandwidth_limit_equal(desired_bandwidth_limit, final_bandwidth_limit):
206
+ match probe_id:
207
+ case ProbeId() | UnknownProbe():
208
+ logging.warning(
209
+ f"Probe '{probe_id.name()}' does not support bandwidth limit '{desired_bandwidth_limit}', final bandwidth limit: '{final_bandwidth_limit}'"
210
+ )
211
+ case None:
212
+ errors.append(
213
+ f"Bandwidth limit mismatch: expected {desired_bandwidth_limit}, got {final_bandwidth_limit}"
214
+ )
215
+
216
+ return AnalogProbeState(
217
+ attenuation=final_attenuation.attenuation,
218
+ bandwidth_limit=final_bandwidth_limit,
219
+ coupling=final_coupling,
220
+ scale=final_scale,
221
+ offset=final_offset,
222
+ state=final_state,
223
+ units=final_units,
224
+ ), errors
225
+
226
+
227
+ def _is_attenuation_equal(expected: ProbeAttenuation, actual: ProbeAttenuation) -> bool:
228
+ return math.isclose(
229
+ expected.attenuation, actual.attenuation, rel_tol=1e-4, abs_tol=1e-6
230
+ )
231
+
232
+
233
+ def get_attenuation(op: HALOscilloscope) -> ProbeAttenuation:
234
+ attenuation = op.get_probe_attenuation()
235
+ return attenuation
236
+
237
+
238
+ def set_attenuation(op: HALOscilloscope, attenuation: ProbeAttenuation) -> None:
239
+ op.set_probe_attenuation(attenuation.attenuation)
240
+
241
+
242
+ def _map_bandwidth_limit_to_hal_bandwidth_limit(
243
+ bandwidth_limit: float | int | str,
244
+ ) -> Tuple[bool, float | int]:
245
+ if isinstance(bandwidth_limit, str) and bandwidth_limit == "none":
246
+ hal_enable = False
247
+ hal_bandwidth_limit = 0.0
248
+ elif isinstance(bandwidth_limit, (float, int)):
249
+ hal_enable = True
250
+ hal_bandwidth_limit = bandwidth_limit
251
+ else:
252
+ raise ValueError(f"Invalid bandwidth limit {bandwidth_limit}")
253
+
254
+ return hal_enable, hal_bandwidth_limit
255
+
256
+
257
+ def _is_bandwidth_limit_equal(
258
+ expected: float | int | str, actual: float | int | str
259
+ ) -> bool:
260
+ match expected, actual:
261
+ case str(), str():
262
+ return expected == actual
263
+ case float() | int(), float() | int():
264
+ return math.isclose(
265
+ expected,
266
+ actual,
267
+ rel_tol=1e-4,
268
+ abs_tol=1e-6,
269
+ )
270
+ case _:
271
+ return False
272
+
273
+
274
+ def get_bandwidth_limit(op: HALOscilloscope) -> float | int | str:
275
+ enable, bandwidth = op.get_probe_bandwidth_limit()
276
+
277
+ if enable:
278
+ return bandwidth
279
+ else:
280
+ return "none"
281
+
282
+
283
+ def set_bandwidth_limit(
284
+ op: HALOscilloscope, bandwidth_limit: float | int | str
285
+ ) -> None:
286
+ hal_enable, hal_bandwidth_limit = _map_bandwidth_limit_to_hal_bandwidth_limit(
287
+ bandwidth_limit
288
+ )
289
+ op.set_probe_bandwidth_limit(hal_enable, hal_bandwidth_limit)
290
+
291
+
292
+ def _map_hal_units_to_units(units: HALUnits) -> Units:
293
+ if units == HALUnits.AMPS:
294
+ return Units.Amps
295
+ elif units == HALUnits.CUSTOM:
296
+ return Units.Other
297
+ elif units == HALUnits.VOLTS:
298
+ return Units.Volts
299
+ raise ValueError(f"Invalid hal units: {units}")
300
+
301
+
302
+ def _map_units_to_hal_units(units: Units) -> HALUnits:
303
+ if units == Units.Amps:
304
+ return HALUnits.AMPS
305
+ elif units == Units.Other:
306
+ return HALUnits.CUSTOM
307
+ elif units == Units.Volts:
308
+ return HALUnits.VOLTS
309
+ raise ValueError(f"Invalid units: {units}")
310
+
311
+
312
+ def _is_units_equal(first: Units, second: Units) -> bool:
313
+ return first == second
314
+
315
+
316
+ def get_units(op: HALOscilloscope) -> Units:
317
+ hal_units = op.get_probe_units()
318
+ units = _map_hal_units_to_units(hal_units)
319
+ return units
320
+
321
+
322
+ def set_units(op: HALOscilloscope, units: Units):
323
+ hal_units = _map_units_to_hal_units(units)
324
+ op.set_probe_units(hal_units)
325
+ return
326
+
327
+
328
+ def _map_hal_coupling_to_coupling(coupling: HALCoupling) -> Coupling:
329
+ if coupling == HALCoupling.AC:
330
+ return Coupling.AC
331
+ elif coupling == HALCoupling.DC:
332
+ return Coupling.DC
333
+ elif coupling == HALCoupling.GROUND:
334
+ return Coupling.Ground
335
+ raise ValueError(f"Invalid hal coupling: {coupling}")
336
+
337
+
338
+ def _map_coupling_to_hal_coupling(coupling: Coupling) -> HALCoupling:
339
+ if coupling == Coupling.AC:
340
+ return HALCoupling.AC
341
+ elif coupling == Coupling.DC:
342
+ return HALCoupling.DC
343
+ elif coupling == Coupling.Ground:
344
+ return HALCoupling.GROUND
345
+ raise ValueError(f"Invalid coupling: {coupling}")
346
+
347
+
348
+ def _is_coupling_equal(first: Coupling, second: Coupling) -> bool:
349
+ return first == second
350
+
351
+
352
+ def get_coupling(op: HALOscilloscope) -> Coupling:
353
+ coupling_param = op.get_probe_coupling()
354
+ coupling = _map_hal_coupling_to_coupling(coupling_param)
355
+ return coupling
356
+
357
+
358
+ def set_coupling(op: HALOscilloscope, coupling: Coupling) -> None:
359
+ coupling_param = _map_coupling_to_hal_coupling(coupling)
360
+ op.set_probe_coupling(coupling_param)
361
+
362
+
363
+ def _map_hal_scale_to_scale(hal_scale: float | int) -> float | int:
364
+ scale = hal_scale
365
+ return scale
366
+
367
+
368
+ def _map_scale_to_scale_param(scale: float | int) -> float | int:
369
+ scale_param = scale
370
+ return scale_param
371
+
372
+
373
+ def _is_scale_equal(first: float | int, second: float | int) -> bool:
374
+ return math.isclose(first, second, rel_tol=1e-4, abs_tol=1e-6)
375
+
376
+
377
+ def get_scale(op: HALOscilloscope) -> float | int:
378
+ scale_param = op.get_probe_scale()
379
+ scale = _map_hal_scale_to_scale(scale_param)
380
+ return scale
381
+
382
+
383
+ def set_scale(op: HALOscilloscope, scale: float | int) -> None:
384
+ scale_param = _map_scale_to_scale_param(scale)
385
+ op.set_probe_scale(scale_param)
386
+
387
+
388
+ def _map_offset_param_to_offset(hal_offset: float | int) -> float | int:
389
+ offset = hal_offset
390
+ return offset
391
+
392
+
393
+ def _map_offset_to_hal_offset(offset: float | int) -> float | int:
394
+ hal_offset = offset
395
+ return hal_offset
396
+
397
+
398
+ def _is_offset_equal(first: float | int, second: float | int) -> bool:
399
+ return math.isclose(first, second, rel_tol=1e-4, abs_tol=1e-6)
400
+
401
+
402
+ def get_offset(op: HALOscilloscope) -> float | int:
403
+ offset_param = op.get_probe_offset()
404
+ offset = _map_offset_param_to_offset(offset_param)
405
+ return offset
406
+
407
+
408
+ def set_offset(op: HALOscilloscope, offset: float | int) -> None:
409
+ offset_param = _map_offset_to_hal_offset(offset)
410
+ op.set_probe_offset(offset_param)
411
+
412
+
413
+ def _map_hal_display_to_state(display_param: bool) -> State:
414
+ if display_param:
415
+ return State.Enabled
416
+ elif not display_param:
417
+ return State.Disabled
418
+ raise Exception(f"Invalid display param {display_param}")
419
+
420
+
421
+ def _map_state_to_hal_display(state: State) -> bool:
422
+ if state == State.Disabled:
423
+ return False
424
+ elif state == State.Enabled:
425
+ return True
426
+ raise Exception(f"Invalid state {state}")
427
+
428
+
429
+ def _is_state_equal(first: State, second: State) -> bool:
430
+ return first == second
431
+
432
+
433
+ def get_state(op: HALOscilloscope) -> State:
434
+ display = op.get_probe_display()
435
+ state = _map_hal_display_to_state(display)
436
+ return state
437
+
438
+
439
+ def set_state(op: HALOscilloscope, state: State) -> None:
440
+ display = _map_state_to_hal_display(state)
441
+ op.set_probe_display(display)
@@ -0,0 +1,44 @@
1
+ from fusaware_instruments.visa_instrument_configuration.analog_probe import (
2
+ AnalogProbe,
3
+ AnalogProbeState,
4
+ configure_analog_probe,
5
+ Coupling,
6
+ State,
7
+ Units,
8
+ )
9
+ from fusaware_instruments.visa_instrument_hal.hal_oscilloscope_rigol_mso import (
10
+ HALOscilloscopeProbeRigolMSOBase,
11
+ )
12
+
13
+
14
+ class AnalogVoltageProbeRigolMSO5000(AnalogProbe):
15
+ def __init__(self, address: str, channel_name: str):
16
+ self._address = address
17
+ self._channel_name: str = channel_name
18
+ self._channel_number: int = int(channel_name[-1])
19
+ self._op = HALOscilloscopeProbeRigolMSOBase(
20
+ self._address, self._channel_number, ""
21
+ )
22
+
23
+ def configure_analog_probe(
24
+ self,
25
+ attenuation: float,
26
+ bandwidth_limit: float | int | str,
27
+ coupling: Coupling,
28
+ offset: float | int,
29
+ scale: float | int,
30
+ state: State,
31
+ units: Units,
32
+ ) -> AnalogProbeState:
33
+ probe_state, _ = configure_analog_probe(
34
+ self._op,
35
+ attenuation,
36
+ bandwidth_limit,
37
+ coupling,
38
+ offset,
39
+ scale,
40
+ state,
41
+ units,
42
+ )
43
+
44
+ return probe_state
@@ -0,0 +1,75 @@
1
+ from typing import Tuple
2
+
3
+ from fusaware_instruments.visa_instrument_hal.hal_dmm import HALDigitalMultimeter
4
+
5
+
6
+ # Function stubs for conversions
7
+ def is_range_equal(desired: float, actual: float) -> bool: ...
8
+ def is_resolution_equal(desired: float, actual: float) -> bool: ...
9
+ def is_digits_equal(desired: float, actual: float) -> bool: ...
10
+ def is_time_aperture_equal(desired: float, actual: float) -> bool: ...
11
+
12
+
13
+ def configure_dc_voltage_meter(
14
+ dmm: HALDigitalMultimeter,
15
+ range: float,
16
+ resolution: float,
17
+ digits: float,
18
+ time_aperture: float,
19
+ error: object | None,
20
+ ) -> Tuple[float, float, float, float, object | None]:
21
+ desired_range = range
22
+ desired_resolution = resolution
23
+ desired_digits = digits
24
+ desired_time_aperture = time_aperture
25
+
26
+ dmm.connect()
27
+
28
+ initial_range = dmm.get_range()
29
+ initial_resolution = dmm.get_resolution()
30
+ initial_digits = dmm.get_digits()
31
+ initial_time_aperture = dmm.get_time_aperture()
32
+
33
+ if not is_range_equal(desired_range, initial_range):
34
+ dmm.set_range(desired_range)
35
+
36
+ if not is_resolution_equal(desired_resolution, initial_resolution):
37
+ dmm.set_resolution(desired_resolution)
38
+
39
+ if not is_digits_equal(desired_digits, initial_digits):
40
+ dmm.set_digits(desired_digits)
41
+
42
+ if not is_time_aperture_equal(desired_time_aperture, initial_time_aperture):
43
+ dmm.set_time_aperture(desired_time_aperture)
44
+
45
+ final_range = dmm.get_range()
46
+ final_resolution = dmm.get_resolution()
47
+ final_digits = dmm.get_digits()
48
+ final_time_aperture = dmm.get_time_aperture()
49
+
50
+ dmm.disconnect()
51
+
52
+ err = None
53
+
54
+ if not is_range_equal(final_range, desired_range):
55
+ err = {
56
+ "type": "ValueError",
57
+ "message": f"range: expected {desired_range}, got {final_range}.",
58
+ }
59
+
60
+ if not is_resolution_equal(final_resolution, desired_resolution):
61
+ err = {
62
+ "type": "ValueError",
63
+ "message": f"resolution: expected {desired_resolution}, got {final_resolution}.",
64
+ }
65
+
66
+ if not is_digits_equal(final_digits, desired_digits):
67
+ err = {
68
+ "type": "ValueError",
69
+ "message": f"digits: expected {desired_digits}, got {final_digits}.",
70
+ }
71
+
72
+ if not is_time_aperture_equal(final_time_aperture, desired_time_aperture):
73
+ ...
74
+
75
+ return final_range, final_resolution, final_digits, final_time_aperture, err