-
Notifications
You must be signed in to change notification settings - Fork 5
Fix register bit_names mismatches and FastHall JSON parsing #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,17 +2,20 @@ | |||||
|
|
||||||
| import json | ||||||
| from .xip_instrument import XIPInstrument, RegisterBase, StatusByteRegister, StandardEventRegister | ||||||
| from .generic_instrument import InstrumentException | ||||||
|
|
||||||
|
|
||||||
| class FastHallOperationRegister(RegisterBase): | ||||||
| """Class object representing the operation status register.""" | ||||||
|
|
||||||
| bit_names = [ | ||||||
| "", | ||||||
| "", | ||||||
| "", | ||||||
| "", | ||||||
| "measuring_Done" | ||||||
| "settling", | ||||||
| "ranging", | ||||||
| "measurement_complete", | ||||||
| "waiting_for_trigger", | ||||||
| "field_control_ramping", | ||||||
| "field_measurement_enabled", | ||||||
| "transient" | ||||||
| ] | ||||||
|
|
||||||
| def __init__(self, | ||||||
|
|
@@ -37,20 +40,20 @@ class FastHallQuestionableRegister(RegisterBase): | |||||
|
|
||||||
| bit_names = [ | ||||||
| "source_in_compliance_or_at_current_limit", | ||||||
| "negative_resistivity", | ||||||
| "", | ||||||
| "field_control_slew_rate_limit", | ||||||
| "field_control_at_voltage_limit", | ||||||
| "", | ||||||
| "", | ||||||
| "current_measurement_overload", | ||||||
| "voltage_measurement_overload", | ||||||
| "", | ||||||
| "", | ||||||
| "invalid_probe", | ||||||
| "invalid_calibration", | ||||||
| "inter_processor_communication_error", | ||||||
| "", | ||||||
| "", | ||||||
| "field_measurement_communication_error", | ||||||
| "probe_eeprom_read_error", | ||||||
| "r2_less_than_minimum_allowable", | ||||||
| "f_value_out_of_acceptable_range", | ||||||
| "geometry_out_of_acceptable_range" | ||||||
| "", | ||||||
| "" | ||||||
| ] | ||||||
|
|
||||||
| def __init__(self, | ||||||
|
|
@@ -90,7 +93,7 @@ def __init__(self, | |||||
| measurement_range='AUTO', | ||||||
| min_r_squared=0.9999, | ||||||
| blanking_time=2e-3): | ||||||
| """The constructor for ContackCheckManualParameters class. | ||||||
| """The constructor for ContactCheckManualParameters class. | ||||||
|
|
||||||
| Args: | ||||||
| excitation_type (str): | ||||||
|
|
@@ -378,7 +381,7 @@ def __init__(self, | |||||
| self.blanking_time = blanking_time | ||||||
| self.max_samples = max_samples | ||||||
| self.min_snr = min_snr | ||||||
| self.excitation_reversal = str(int(excitation_reversal)) | ||||||
| self.excitation_reversal = excitation_reversal | ||||||
|
|
||||||
|
|
||||||
| class DCHallParameters: | ||||||
|
|
@@ -450,7 +453,7 @@ def __init__(self, | |||||
| self.compliance_limit = compliance_limit | ||||||
| self.averaging_samples = averaging_samples | ||||||
| self.user_defined_field = user_defined_field | ||||||
| self.with_field_reversal = str(int(with_field_reversal)) | ||||||
| self.with_field_reversal = with_field_reversal | ||||||
| self.resistivity = resistivity | ||||||
| self.blanking_time = blanking_time | ||||||
| self.sample_thickness = sample_thickness | ||||||
|
|
@@ -538,7 +541,7 @@ def __init__(self, | |||||
|
|
||||||
|
|
||||||
| class ResistivityLinkParameters: | ||||||
| """Class object representing parameters used for running manual Resistivity measurements.""" | ||||||
| """Class object representing parameters used for running Resistivity Link measurements.""" | ||||||
| def __init__(self, | ||||||
| measurement_range='AUTO', | ||||||
| sample_thickness=0, | ||||||
|
|
@@ -594,6 +597,15 @@ def __init__(self, | |||||
| self.operation_register = FastHallOperationRegister | ||||||
| self.questionable_register = FastHallQuestionableRegister | ||||||
|
|
||||||
| def _parse_json_response(self, response, context=""): | ||||||
| """Parse a JSON response from the instrument with error handling.""" | ||||||
| try: | ||||||
| return json.loads(response) | ||||||
| except json.JSONDecodeError as ex: | ||||||
| raise InstrumentException( | ||||||
| f"Failed to parse JSON response{' for ' + context if context else ''}: {ex}" | ||||||
| ) from ex | ||||||
|
|
||||||
| # Status Methods | ||||||
| def get_contact_check_running_status(self): | ||||||
| """Indicates if the contact check measurement is running.""" | ||||||
|
|
@@ -616,7 +628,7 @@ def get_dc_hall_running_status(self): | |||||
| return bool(int(self.query("HALL:DC:RUNNING?"))) | ||||||
|
|
||||||
| def get_dc_hall_waiting_status(self): | ||||||
| """Indicates if the DC hall measurement is running.""" | ||||||
| """Indicates if the DC hall measurement is waiting.""" | ||||||
| return bool(int(self.query("HALL:DC:WAITING?"))) | ||||||
|
|
||||||
| def continue_dc_hall(self): | ||||||
|
|
@@ -737,7 +749,7 @@ def start_four_wire(self, settings): | |||||
| f"{str(settings.blanking_time)}," + | ||||||
| f"{str(settings.max_samples)}," + | ||||||
| f"{str(settings.min_snr)}," + | ||||||
| f"{str(settings.excitation_reversal)}") | ||||||
| f"{str(int(settings.excitation_reversal))}") | ||||||
| self.command(command_string) | ||||||
|
|
||||||
| def start_dc_hall_vdp(self, settings): | ||||||
|
|
@@ -757,7 +769,7 @@ def start_dc_hall_vdp(self, settings): | |||||
| f"{str(settings.compliance_limit)}," + | ||||||
| f"{str(settings.averaging_samples)}," + | ||||||
| f"{str(settings.user_defined_field)}," + | ||||||
| f"{str(settings.with_field_reversal)}," + | ||||||
| f"{str(int(settings.with_field_reversal))}," + | ||||||
| f"{str(settings.resistivity)}," + | ||||||
| f"{str(settings.blanking_time)}," + | ||||||
| f"{str(settings.sample_thickness)}") | ||||||
|
|
@@ -775,10 +787,10 @@ def start_dc_hall_hbar(self, settings): | |||||
| f"{str(settings.excitation_range)}," + | ||||||
| f"{str(settings.excitation_measurement_range)}," + | ||||||
| f"{str(settings.measurement_range)}," + | ||||||
| f"{str(settings.compliance_limit)}," + \ | ||||||
| f"{str(settings.compliance_limit)}," + | ||||||
| f"{str(settings.averaging_samples)}," + | ||||||
| f"{str(settings.user_defined_field)}," + | ||||||
| f"{str(settings.with_field_reversal)}," + | ||||||
| f"{str(int(settings.with_field_reversal))}," + | ||||||
| f"{str(settings.resistivity)}," + | ||||||
| f"{str(settings.blanking_time)}," + | ||||||
| f"{str(settings.sample_thickness)}") | ||||||
|
|
@@ -847,7 +859,7 @@ def get_contact_check_setup_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary with only the setup results | ||||||
| json_results = self.query('CCHECK:RESULT:JSON? 0') | ||||||
| setup_results = json.loads(json_results).get('Setup') | ||||||
| setup_results = self._parse_json_response(json_results, 'contact check setup').get('Setup', {}) | ||||||
|
|
||||||
| # Generate a Contact Check settings object using the setup result values as the initialization parameters | ||||||
| settings = ContactCheckManualParameters(excitation_type=setup_results.get('ExcitationType'), | ||||||
|
|
@@ -866,12 +878,12 @@ def get_contact_check_measurement_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary | ||||||
| json_results = self.query('CCHECK:RESULT:JSON? 0') | ||||||
| measurement_results = json.loads(json_results) | ||||||
| measurement_results = self._parse_json_response(json_results, 'contact check measurement') | ||||||
|
|
||||||
| # Remove the setup data from the results dictionary | ||||||
| measurement_results.pop('Setup') | ||||||
| measurement_results.pop('OptimizationSetup') | ||||||
| measurement_results.pop('OptimizationDiagnostics') | ||||||
| measurement_results.pop('Setup', None) | ||||||
| measurement_results.pop('OptimizationSetup', None) | ||||||
| measurement_results.pop('OptimizationDiagnostics', None) | ||||||
|
|
||||||
| return measurement_results | ||||||
|
|
||||||
|
|
@@ -880,22 +892,20 @@ def get_fasthall_setup_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary with only the setup results | ||||||
| json_results = self.query('FASTHALL:RESULT:JSON? 0') | ||||||
| setup_results = json.loads(json_results).get('Setup') | ||||||
| setup_results = self._parse_json_response(json_results, 'FastHall setup').get('Setup', {}) | ||||||
|
|
||||||
| # Generate a FastHall settings object using the setup result values as the initialization parameters | ||||||
| settings = FastHallManualParameters(excitation_type=setup_results.get('ExcitationType'), | ||||||
| excitation_value=setup_results.get('ExcitationValue'), | ||||||
| excitation_range=setup_results.get('ExcitationRange'), | ||||||
| excitation_measurement_range=setup_results.get('ExcitationMeasurementRange' | ||||||
| ), | ||||||
| excitation_measurement_range=setup_results.get('ExcitationMeasurementRange'), | ||||||
| measurement_range=setup_results.get('MeasurementRange'), | ||||||
| compliance_limit=setup_results.get('ComplianceLimit'), | ||||||
| max_samples=setup_results.get('MeasurementRange'), | ||||||
| max_samples=setup_results.get('MaximumNumberOfSamples'), | ||||||
| user_defined_field=setup_results.get('UserDefinedFieldReadingInTesla'), | ||||||
| resistivity=setup_results.get('Resistivity'), | ||||||
| blanking_time=setup_results.get('BlankingTimeInSeconds'), | ||||||
| averaging_samples=setup_results.get('NumberOfVoltageCompensationSamplesTo\ | ||||||
| Average'), | ||||||
| averaging_samples=setup_results.get('NumberOfVoltageCompensationSamplesToAverage'), | ||||||
| sample_thickness=setup_results.get('SampleThicknessInMeters'), | ||||||
| min_hall_voltage_snr=setup_results.get('HallVoltageSnr')) | ||||||
| return settings | ||||||
|
|
@@ -905,10 +915,10 @@ def get_fasthall_measurement_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary | ||||||
| json_results = self.query('FASTHALL:RESULT:JSON? 0') | ||||||
| measurement_results = json.loads(json_results) | ||||||
| measurement_results = self._parse_json_response(json_results, 'FastHall measurement') | ||||||
|
|
||||||
| # Remove the setup data from the results dictionary | ||||||
| measurement_results.pop('Setup') | ||||||
| measurement_results.pop('Setup', None) | ||||||
|
|
||||||
| return measurement_results | ||||||
|
|
||||||
|
|
@@ -917,13 +927,15 @@ def get_four_wire_setup_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary with only the setup results | ||||||
| json_results = self.query('FWIRE:RESULT:JSON? 0') | ||||||
| setup_results = json.loads(json_results).get('Setup') | ||||||
| setup_results = self._parse_json_response(json_results, 'four wire setup').get('Setup', {}) | ||||||
|
|
||||||
| # Generate a Four Wire settings object using the setup result values as the initialization parameters | ||||||
| settings = FourWireParameters(contact_point1=setup_results.get('ContactPairExcitation').get('Point1'), | ||||||
| contact_point2=setup_results.get('ContactPairExcitation').get('Point2'), | ||||||
| contact_point3=setup_results.get('ContactPairSense').get('Point1'), | ||||||
| contact_point4=setup_results.get('ContactPairSense').get('Point2'), | ||||||
| contact_pair_excitation = setup_results.get('ContactPairExcitation', {}) | ||||||
| contact_pair_sense = setup_results.get('ContactPairSense', {}) | ||||||
| settings = FourWireParameters(contact_point1=contact_pair_excitation.get('Point1'), | ||||||
| contact_point2=contact_pair_excitation.get('Point2'), | ||||||
| contact_point3=contact_pair_sense.get('Point1'), | ||||||
| contact_point4=contact_pair_sense.get('Point2'), | ||||||
| excitation_type=setup_results.get('ExcitationType'), | ||||||
| excitation_value=setup_results.get('ExcitationValue'), | ||||||
| excitation_range=setup_results.get('ExcitationRange'), | ||||||
|
|
@@ -941,10 +953,10 @@ def get_four_wire_measurement_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary | ||||||
| json_results = self.query('FWIRE:RESULT:JSON? 0') | ||||||
| measurement_results = json.loads(json_results) | ||||||
| measurement_results = self._parse_json_response(json_results, 'four wire measurement') | ||||||
|
|
||||||
| # Remove the setup data from the results dictionary | ||||||
| measurement_results.pop('Setup') | ||||||
| measurement_results.pop('Setup', None) | ||||||
|
|
||||||
| return measurement_results | ||||||
|
|
||||||
|
|
@@ -953,7 +965,7 @@ def get_dc_hall_setup_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary with only the setup results | ||||||
| json_results = self.query('HALL:DC:RESULT:JSON? 0') | ||||||
| setup_results = json.loads(json_results).get('Setup') | ||||||
| setup_results = self._parse_json_response(json_results, 'DC Hall setup').get('Setup', {}) | ||||||
|
|
||||||
| # Generate a DC Hall settings object using the setup result values as the initialization parameters | ||||||
| settings = DCHallParameters(excitation_type=setup_results.get('ExcitationType'), | ||||||
|
|
@@ -975,10 +987,10 @@ def get_dc_hall_measurement_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary | ||||||
| json_results = self.query('HALL:DC:RESULT:JSON? 0') | ||||||
| measurement_results = json.loads(json_results) | ||||||
| measurement_results = self._parse_json_response(json_results, 'DC Hall measurement') | ||||||
|
|
||||||
| # Remove the setup data from the results dictionary | ||||||
| measurement_results.pop('Setup') | ||||||
| measurement_results.pop('Setup', None) | ||||||
|
|
||||||
| return measurement_results | ||||||
|
|
||||||
|
|
@@ -987,19 +999,18 @@ def get_resistivity_setup_results(self): | |||||
|
|
||||||
| # Parse the JSON query string into a dictionary with only the setup results | ||||||
| json_results = self.query('RESISTIVITY:RESULT:JSON? 0') | ||||||
| setup_results = json.loads(json_results).get('Setup') | ||||||
| setup_results = self._parse_json_response(json_results, 'resistivity setup').get('Setup', {}) | ||||||
|
|
||||||
| # Generate a Resistivity settings object using the setup result values as the initialization parameters | ||||||
| settings = ResistivityManualParameters(setup_results.get('ExcitationType'), | ||||||
| settings = ResistivityManualParameters(excitation_type=setup_results.get('ExcitationType'), | ||||||
| excitation_value=setup_results.get('ExcitationValue'), | ||||||
| excitation_range=setup_results.get('ExcitationRange'), | ||||||
| excitation_measurement_range=setup_results.get('Excitation\ | ||||||
| MeasurementRange'), | ||||||
| excitation_measurement_range=setup_results.get('ExcitationMeasurementRange'), | ||||||
| measurement_range=setup_results.get('MeasurementRange'), | ||||||
| compliance_limit=setup_results.get('ComplianceLimit'), | ||||||
| width=setup_results.get('SampleWidthInMeters'), | ||||||
| separation=setup_results.get('SampleArmSeparationInMeters'), | ||||||
| max_samples=setup_results.get('MaxNumberOfSamples'), | ||||||
| max_samples=setup_results.get('MaxNumberOfSamples'), # TODO: verify key from M91 manual (other methods use 'MaximumNumberOfSamples') | ||||||
|
||||||
| max_samples=setup_results.get('MaxNumberOfSamples'), # TODO: verify key from M91 manual (other methods use 'MaximumNumberOfSamples') | |
| max_samples=setup_results.get('MaxNumberOfSamples', setup_results.get('MaximumNumberOfSamples')), |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -147,8 +147,8 @@ class Model335(Model335Enums, TemperatureController): | |||||
| """A class object representing the Lake Shore Model 335 cryogenic temperature controller.""" | ||||||
|
|
||||||
| # Initiate instrument specific registers | ||||||
| _status_byte_register = Model335StatusByteRegister | ||||||
| _service_request_enable = Model335ServiceRequestEnable | ||||||
| status_byte_register = Model335StatusByteRegister | ||||||
| service_request_enable = Model335ServiceRequestEnable | ||||||
|
||||||
| service_request_enable = Model335ServiceRequestEnable | |
| service_request_enable_register = Model335ServiceRequestEnable |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -330,8 +330,8 @@ class Model372(Model372Enums, TemperatureController): | |
| vid_pid = [(0x1FB9, 0x0305)] | ||
|
|
||
| # Initialize registers | ||
| _status_byte_register = Model372StatusByteRegister | ||
| _service_request_enable = Model372ServiceRequestEnable | ||
| status_byte_register = Model372StatusByteRegister | ||
| service_request_enable = Model372ServiceRequestEnable | ||
|
Comment on lines
332
to
+334
|
||
|
|
||
| def __init__(self, | ||
| baud_rate, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new JSON parsing/error-wrapping behavior isn’t covered by unit tests. Please add tests that (a) exercise one of the
get_*_setup_results/get_*_measurement_resultsmethods with a representative JSON payload, and (b) verify malformed JSON raisesInstrumentExceptionvia_parse_json_response()(to prevent regressions in the parsing/key fixes).