diff --git a/Test1.csv b/Test cases/Test1.csv similarity index 100% rename from Test1.csv rename to Test cases/Test1.csv diff --git a/Test2.csv b/Test cases/Test2.csv similarity index 100% rename from Test2.csv rename to Test cases/Test2.csv diff --git a/Test2_slow.csv b/Test cases/Test2_slow.csv similarity index 100% rename from Test2_slow.csv rename to Test cases/Test2_slow.csv diff --git a/out of bounds.csv b/Test cases/out of bounds.csv similarity index 91% rename from out of bounds.csv rename to Test cases/out of bounds.csv index d3c377e..3e10ebc 100644 --- a/out of bounds.csv +++ b/Test cases/out of bounds.csv @@ -4,7 +4,7 @@ Time (s);xField (T);yField (T);zField (T); 2;0,00018;-0,00018;0,00002;180 3;0,00019;-0,00019;0,00002;190 4;0,0002;-0,0002;0,00002;200 -5;0,00021;-0,00021;0,00002;210 +5;0,00021;0,00021;0,00002;210 6;0,00022;-0,00022;0,00002;220 7;0,0002;-0,0002;0,00002;200 8;0,00018;-0,00018;0,00002;180 diff --git a/User_Interface.py b/User_Interface.py index 07eddd1..10705d4 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -420,7 +420,8 @@ class Configuration(Frame): self.update_fields() def restore_defaults(self): # restore all default settings - config.reset_config_to_default(config.CONFIG_FILE) # overwrite config file with default + config.reset_config_to_default() # overwrite config file with default + ui_print("\nReinitializing devices...") func.setup_all() # setup everything with the defaults self.update_fields() # update fields in config window @@ -500,6 +501,7 @@ class Configuration(Frame): def implement(self): # executed on button press self.write_values() # write current values from entry fields to config object + ui_print("\nReinitializing devices...") func.setup_all() # reinitialize devices and program with new values self.update_fields() # update entry fields to show new values @@ -511,8 +513,9 @@ class Configuration(Frame): if exists(filename): # does the file exist? config.CONFIG_FILE = filename # set global config file to the new file config.CONFIG_OBJECT = config.get_config_from_file(filename) # load from config file to config object - config.check_config( - config.CONFIG_OBJECT) # check the values and display warnings if values are out of bounds + config.check_config(config.CONFIG_OBJECT) # check and display warnings if values are out of bounds + + ui_print("\nReinitializing devices...") func.setup_all() # reinitialize devices and program with new values self.update_fields() # update entry fields to show new values elif filename == '': # this happens when file selection window is closed without selecting a file @@ -642,10 +645,14 @@ class ExecuteCSVMode(Frame): ui_print("Error while opening file:", e) messagebox.showerror("Error!", "Error while opening file: \n%s" % e) - csv.check_array_ok(self.sequence_array) # check for values exceeding limits - self.display_plot() # plot data and display - - self.execute_button["state"] = "normal" # activate run button + try: + csv.check_array_ok(self.sequence_array) # check for values exceeding limits + self.display_plot() # plot data and display + except BaseException as e: + ui_print("Error while processing data from file:", e) + messagebox.showerror("Error!", "Error while processing data from file: \n%s" % e) + else: + self.execute_button["state"] = "normal" # activate run button elif filename == '': # this happens when file selection window is closed without selecting a file ui_print("No file selected, could not load.") else: diff --git a/cage_func.py b/cage_func.py index f0f64e3..b2ac41f 100644 --- a/cage_func.py +++ b/cage_func.py @@ -1,5 +1,5 @@ -# this file contains all classes and functions directly related to the operation of the helmholtz test stand -# the two main classes are Axis and ArduinoCtrl, see their definitions for details +# This file contains all classes and functions directly related to the operation of the helmholtz test stand. +# The two main classes are Axis and ArduinoCtrl, see their definitions for details. import numpy as np import serial diff --git a/config_handling.py b/config_handling.py index 5651efe..0fbfea9 100644 --- a/config_handling.py +++ b/config_handling.py @@ -1,3 +1,6 @@ +# This file contains functions and variables related to reading and writing configuration files. +# The configparser module is used for processing. Config files are of type .ini + from configparser import ConfigParser from tkinter import messagebox @@ -6,11 +9,13 @@ import cage_func as func # noinspection PyPep8Naming import User_Interface as ui -global CONFIG_FILE # variable storing the path of the used config file +global CONFIG_FILE # string storing the path of the used config file global CONFIG_OBJECT # object of type ConfigParser(), storing all configuration information +# CONFIG_OBJECT is what is mostly read/written by the program +# CONFIG_FILE is only used to export/import to/from a file -def get_config_from_file(file): +def get_config_from_file(file): # read a config file to a config_object config_object = ConfigParser() # initialize config parser config_object.read(file) # open config file return config_object # return config object, that contains all info from the file @@ -21,62 +26,70 @@ def write_config_to_file(config_object): # write contents of config object to a config_object.write(conf) -def read_from_config(section, key, config_object): # read specific value from config object +def read_from_config(section, key, config_object): # read a specific value from a config object try: section_obj = config_object[section] # get relevant section value = section_obj[key] # get relevant value in the section return value - except KeyError as e: + except KeyError as e: # a section or key was used, that does not exist ui.ui_print("Error while reading config file:", e) raise KeyError("Could not find key", key, "in config file.") -def edit_config(section, key, value, override=False): # edit specific value in config file - config_object = CONFIG_OBJECT - # ToDo: add check for data types, e.g. int for arduino ports +def edit_config(section, key, value, override=False): # edit a specific value in the CONFIG_OBJECT + # section: Section of the config, e.g. "X-Axis" or "PORTS" + # key: name of the value in the section, e.g. max_amps + # value: new value to be written into the config + # override: Bool to allow user to force writing a value into the config, even if it exceeds the safe limit - # Check if value to write is within acceptable limits (set in globals.py) + global CONFIG_OBJECT # get the global config object to edit it + + # ToDo (optional): add check for data types, e.g. int for arduino ports + # Check if value to write is within acceptable limits (set in dictionary in globals.py): try: value_ok = 'OK' - if section in g.AXIS_NAMES and not override: # only check numerical values and not if overridden by user + if section in g.AXIS_NAMES and not override: # only check values in axis sections and not if check overridden value_ok = func.value_in_limits(section, key, value) # check if value is ok, too high or too low - max_value = g.default_arrays[key][1][g.AXIS_NAMES.index(section)] # get max value - min_value = g.default_arrays[key][2][g.AXIS_NAMES.index(section)] # get min value - if value_ok == 'HIGH': + + if value_ok == 'HIGH': # value is too high + max_value = g.default_arrays[key][1][g.AXIS_NAMES.index(section)] # get max value for message printing message = "Prevented writing too high value for {s} {k} to config file:\n" \ "{v}, max. {mv} allowed. Erroneous values may damage equipment!" \ .format(s=section, k=key, v=value, mv=max_value) - raise ValueError(message) - elif value_ok == 'LOW': + raise ValueError(message) # return an error with the message attached + + elif value_ok == 'LOW': # value is too low + min_value = g.default_arrays[key][2][g.AXIS_NAMES.index(section)] # get min value for message printing message = "Prevented writing too low value for {s} {k} to config file:\n" \ "{v}, max. {mv} allowed. Erroneous values may damage equipment!" \ .format(s=section, k=key, v=value, mv=min_value) - raise ValueError(message) + raise ValueError(message) # return an error with the message attached - if value_ok == 'OK' or override: # value is within limits or user has overridden + if value_ok == 'OK' or override: # value is within limits or user has overridden the checks try: - section_obj = config_object[section] # get relevant section - except KeyError: + section_obj = CONFIG_OBJECT[section] # get relevant section in the config + except KeyError: # there is no such section ui.ui_print("Could not find section", section, "in config file, creating new.") - config_object.add_section(section) - section_obj = config_object[section] + CONFIG_OBJECT.add_section(section) # create the missing section + section_obj = CONFIG_OBJECT[section] # get the object of the section try: - section_obj[key] = str(value) # set relevant value in the section - except KeyError: + section_obj[key] = str(value) # set value for correct entry in the section + except KeyError: # there is no entry with this key ui.ui_print("Could not find key", key, "in config file, creating new.") - config_object.set(section, key, str(value)) + CONFIG_OBJECT.set(section, key, str(value)) # create the entry and set the value - except KeyError as e: + except KeyError as e: # key for section or specific value does not exist in the dictionary for max/min values ui.ui_print("Error while editing config file:", e) - raise KeyError("Could not find key", key, "in config file.") + raise KeyError("Could not find key", key, "in config file.") # return an error def check_config(config_object): # check all numeric values in the config and see if they are within safe limits ui.ui_print("Checking config file for values exceeding limits:") - i = 0 + concerns = {} # initialize dictionary for found problems - problem_counter = 0 - for axis in g.AXIS_NAMES: + problem_counter = 0 # count the number of values that exceed limits + i = 0 + for axis in g.AXIS_NAMES: # go through all 3 axes concerns[axis] = [] # create dictionary entry for this axis for key in g.default_arrays.keys(): # go over entries in this axis value = float(read_from_config(axis, key, config_object)) # read value to check from config file @@ -87,30 +100,30 @@ def check_config(config_object): # check all numeric values in the config and s concerns[axis].append(key) # add this entry to the problem dictionary problem_counter += 1 - if len(concerns[axis]) == 0: + if len(concerns[axis]) == 0: # no problems were found for this axis concerns[axis].append("No problems detected.") ui.ui_print(axis, ":", *concerns[axis]) # print out results for this axis i += 1 if problem_counter > 0: # some values are not ok # shop pup-up warning message: - messagebox.showwarning("Warning!", "Found values exceeding limits in config file. Check values " - "to ensure correct operation and avoid equipment damage!") + messagebox.showwarning("Warning!", "Found %i value(s) exceeding limits in config file. Check values " + "to ensure correct operation and avoid equipment damage!" % problem_counter) g.app.show_frame(ui.Configuration) # open configuration window so user can check values -def reset_config_to_default(file): # reset values in config object to defaults (stored in globals.py) - config = ConfigParser() # initialize global config object - global CONFIG_OBJECT - CONFIG_OBJECT = config +def reset_config_to_default(): # reset values in config object to defaults (set in globals.py) + config = ConfigParser() # reinitialize empty config object + global CONFIG_OBJECT # get the global config object + CONFIG_OBJECT = config # reset it to the empty object i = 0 for axis_name in g.AXIS_NAMES: # go through axes config.add_section(axis_name) # add section for this axis for key in g.default_arrays.keys(): # go through dictionary with default values - config.set(axis_name, key, str(g.default_arrays[key][0][i])) # set value + config.set(axis_name, key, str(g.default_arrays[key][0][i])) # set values i += 1 config.add_section("PORTS") # add section for PSU serial ports - for key in g.default_ports.keys(): - config.set("PORTS", key, str(g.default_ports[key])) \ No newline at end of file + for key in g.default_ports.keys(): # go through dictionary of default serial ports + config.set("PORTS", key, str(g.default_ports[key])) # set the value for each axis diff --git a/csv_logging.py b/csv_logging.py index 881b437..41c1cdc 100644 --- a/csv_logging.py +++ b/csv_logging.py @@ -1,5 +1,5 @@ -# This file contains functions related to logging data from the program to a CSV file -# They are mainly but not only called by the ConfigureLogging class in User_Interface.py +# This file contains functions related to logging data from the program to a CSV file. +# They are mainly but not only called by the ConfigureLogging class in User_Interface.py. import pandas as pd import globals as g diff --git a/csv_threading.py b/csv_threading.py index cf57adb..a6963c0 100644 --- a/csv_threading.py +++ b/csv_threading.py @@ -1,5 +1,5 @@ -# this file contains code for executing a sequence of magnetic fields from a csv file -# to do this without crashing the UI it has to run in a separate thread using the threading module +# tThis file contains code for executing a sequence of magnetic fields from a csv file. +# To do this without crashing the UI it has to run in a separate thread using the threading module. import time import pandas diff --git a/main.py b/main.py index 58dd69a..5fb229d 100644 --- a/main.py +++ b/main.py @@ -35,7 +35,7 @@ try: # start normal operations # ToDo: remember what the last config file was if not exists(config.CONFIG_FILE): print("Config file not found, creating new from defaults.") - config.reset_config_to_default(config.CONFIG_FILE) + config.reset_config_to_default() config.write_config_to_file(config.CONFIG_OBJECT) config.CONFIG_OBJECT = config.get_config_from_file(config.CONFIG_FILE) diff --git a/example.py b/zz old test files etc/example.py similarity index 100% rename from example.py rename to zz old test files etc/example.py diff --git a/example2.py b/zz old test files etc/example2.py similarity index 100% rename from example2.py rename to zz old test files etc/example2.py