import sys import logging from enum import Enum from typing import Optional logging.basicConfig( # format='%(asctime)s § %(levelname)s § %(filename)s(%(lineno)d) § %(message)s', format='%(message)s', stream=sys.stdout, level=logging.DEBUG ) # from MeineModule import KeithleyDMM6500SCPI ### unsere erste eigene Exception! class UnknownFunctionError(Exception): pass ### "pass" macht gar nichts -- nein, nicht wie NOP in Assembler, das ### immerhin einen CPU-Tick verbrät und den Instruction Pointer um 1 ### erhöht. Daher erzeugen wir nur eine Exception mit einem eigenen, ### selbstgewählten Namen. Mehr ist möglich, aber selten nötig. class Keithley_SCPI: ################################################################################# _modes: dict[str, tuple[Optional[str], str]] = { "DCV": ("V", "VOLTage:DC"), "DCI": ("A", "CURRent:DC"), "ACV": ("V", "VOLTage:AC"), "ACI": ("A", "CURRent:AC"), "2W": ("Ω", "RESistance"), "4W": ("Ω", "FRESistance"), "Freq": ("Hz", "FREQuency"), "Period": (None, "PERiod"), "Diode": ("V", "DIODe"), "Temp": ("°C", "TEMPerature"), "Cap": ("F", "CAPacitance"), "Digi V": ("V", "VOLTage"), "Digi I": ("A", "CURRent") } ################################################################################# # erweiterbare Funktionsliste, mittels Namen wird der hinterlegte SCPI Syntax ausgelesen _syntax_table: dict[str, str] = { "getTime": ":SYSTem:TIME? 1", # Reference Manual Seite 12-158 "setTime": ":SYSTem:TIME ", # Reference Manual Seite 12-158 "setFunctionON": ':SENSe:FUNCtion:ON "{messmode}"', "setDigitizeFunctionON": ':SENSe:DIGItize:FUNCtion:ON "{messmode}"', "measure": ":MEASure:{messmode}?", # Reference Manual Seite 12-137 "setMeasureCounts": ":SENSe:COUNt ", # Reference Manual Seite 12-134 "setMeasureDigitizeCounts": ":SENSe:DIGItize:COUNt ", # Reference Manual Seite 12-135 "setSampleRateDigitize": ":SENSe:{messmode}:SRATe ", # Reference Manual Seite 12-118 "read": ":READ?", # Reference Manual Seite 12-10 "lastBufferWriteIndex": ":TRACe:ACTual:END?", # Reference Manual Seite 12-160 "readBuffer": ":TRACe:DATA?", # Reference Manual Seite 12-165 "averageCount": ":SENSE:{messmode}:AVERage:COUNt ", "averageRepeat": ":SENSE:{messmode}:AVERage:TCONTrol REPeat", "averageMoving": ":SENSE:{messmode}:AVERage:TCONTrol MOVing", "averageHybrid": ":SENSE:{messmode}:AVERage:TCONTrol HYBRid", "averageON": ":SENSE:{messmode}:AVERage ON", "averageOFF": ":SENSE:{messmode}:AVERage OFF", "deleteBuffer": ":TRACe:CLEar", # Reference Manual Seite 12-164 "localMode": ":TRIGger:CONTinuous RESTart", "None": "None" ### WTF? } ################################################################################# # Konstruktor def __init__(self, model: str): ### wenn schon, denn schon :-) self._model: str = model self._unit: str = None self._function: str = None self._syntax_table_modified: dict = {} # Kopie von '_syntax_table' def _update_table (self, replacement: str): # Kopie erstellen und Platzhalter ersetzen # wird direkt in Kopie 'self._syntax_table_modified' geschrieben for key, value in self._syntax_table.items(): modify = value.format(messmode=replacement) ### rock me, Amadeus! self._syntax_table_modified[key] = modify ### ochnö ############################################################################### def setFunction(self, measure: str) -> str: try: mode = self._modes[measure] self._unit, self._function = mode ### JA! self._update_table(self._function) # Änderung in Kopie schreiben return f'function found → {measure}' except KeyError: self._unit = None self._function = None print (f'function unknown → {measure}') ### sys.exit("Abbruch") raise UnknownFunctionError(f'function unknown → {measure}') # finally: # print ("finally wird immer ausgeführt") def scpi_command_syntax (self, name: str) -> str: # "averageON" → ":SENSE:MESSMODE:AVERage ON" try: syntax = self._syntax_table_modified[name] ### siehe "ochnö" return syntax except KeyError: return f'command unknown → {name}' @property # Getter - Aufruf ohne () def function(self) -> str: return self._function @property # Getter - Aufruf ohne () def unit(self) -> str: return self._unit ### für Debug #### def debug_ausgabe_formatiert (self, obj: dict): print() max_key_len = max(len(key) for key in obj.keys()) for key, value in obj.items(): print(f"{key:<{max_key_len}} {value}") ### siehe "ochnö" if __name__ == '__main__': ### gehört hier nicht hin - nur für schnelle Tests im Modul ############################### k = Keithley_SCPI("Keithley DMM6500") logging.info(k.setFunction("2W")) logging.info(k.function) # Debug logging.info(k.unit) # Debug logging.info(k.scpi_command_syntax("measure")) # Debug #k.debug_ausgabe_formatiert(k._syntax_table_modified) # Debug logging.info(k.setFunction("Temp")) logging.info(k.function) # Debug logging.info(k.unit) # Debug logging.info(k.scpi_command_syntax("measure")) # Debug k.debug_ausgabe_formatiert(k._syntax_table_modified) # Debug