diff --git a/hp4155/memristor (Version 4.1)/help.py b/hp4155/memristor (Version 4.1)/help.py
new file mode 100644
index 0000000000000000000000000000000000000000..18e87e7012d41c453ced6e91a69d4791ce27ab5f
--- /dev/null
+++ b/hp4155/memristor (Version 4.1)/help.py	
@@ -0,0 +1,559 @@
+"""
+This is a python file containing all the important functions for memristor measurement
+
+Available Functions
+
+measurements in the HP4155a
+plot results
+create data frame 
+ini file decoder
+enabing and disabling widgets for jupyter(lists)
+"""
+
+import sys
+sys.path.insert(0, '..') #append parent directory
+
+import hp4155a
+import matplotlib.pyplot as plt
+
+import tkinter as tk
+from tkinter import filedialog
+import tkinter.messagebox
+
+import numpy as np
+from IPython.display import display, clear_output
+import pandas as pd
+from datetime import datetime
+import ipywidgets as widgets
+import time
+import os
+
+
+#contact check between two SMUs (i,j)
+def contact_check(i,j,device):
+    smu = [1,2,3,4]
+    device.measurement_mode('SAMP')
+    parameters ={
+        'mode' : 'LIN',
+        'hold': 0,
+        'interval':2e-3,
+        'points': 1,
+        'filter': 'OFF',
+        'value':0.01, #voltage value
+        'comp':0.1 #compliance value
+    }
+    
+    device.setup_sampling(parameters)
+    
+    device.auto_sampling_time('ON')
+    device.integration_time('MED')
+
+    smu_v = device.smu_dict()
+    smu_v.update(
+        vname = f'V{i}',
+        iname = f'I{i}',
+        mode = 'V',
+        func = 'CONS'
+    )
+    device.setup_smu(i,smu_v)
+
+    smu_ground = device.smu_dict()
+    smu_ground.update(
+        vname =f'V{j}',
+        iname = f'I{j}',
+        mode = 'COMM',
+        func='CONS'
+    )
+    device.setup_smu(j,smu_ground)
+                                                        
+    #one smu is measuring
+    #one smu is ground
+
+    #set voltage and compliance
+    device.setup_smu_sampling(i,parameters)
+
+    #smus to remove
+    smu_disable = smu.copy()
+    smu_disable.remove(i)
+    smu_disable.remove(j)
+
+    for number in smu_disable:
+         device.smu_disable(number)
+
+    device.user_function(f'R{i}{j}','OHM',f'V{i}/I{i}')
+    device.display_variable('X','@TIME')
+    device.display_variable('Y1',f'R{i}{j}')
+    device.single_measurement()
+    while device.operation_completed() == False:
+        time.sleep(2)
+   
+    R = device.return_values(f'R{i}{j}')[0] #only the first value
+    print(f"R{i}{j}:{'{:.2e}'.format(R)} Ohm")
+    device.del_user_functions()
+    device.autoscaling()
+    return R
+    
+    
+#these are all the  sampling checks 
+def regular_contact_check(device):
+    resistances = {}
+    for i in range(1,4): # iterate through smus 1-4
+        for j in range(4,i,-1): 
+            """ 
+            We have the following pairs in order
+            1-4,1-3,1-2,2-4,2-3,3-4
+            """
+            R=contact_check(i,j,device)
+            resistances[f"{i}-{j}"] = R
+
+    #convert dictionary to df
+    df = pd.DataFrame(resistances.items(), columns=['SMU pair', 'Resistance (Ohm)'])
+    return df
+
+def EBL(device):
+    # EBL are SMUs 1-4 and 2-3
+    resistances = {}
+    for i,j in zip(range(1,3),range(4,2,-1)): #loop simultaneously 1-4,2-3 pairs
+        R = contact_check(i,j,device)
+        resistances[f"{i}-{j}"] = R
+    
+    #convert dictionary to df
+    df = pd.DataFrame(resistances.items(), columns=['SMU pair', 'Resistance (Ohm)'])
+    return df
+            
+def OL(device):
+    # OL smu 3-4,1-2
+    resistances= {}
+    for i,j in zip(range(3,0,-2),range(4,1,-2)): #loop simultaneously 3-4 , 1-2 pairs
+        R = contact_check(i,j,device)
+        resistances[f"{i}-{j}"] = R
+
+    #convert dictionary to df
+    df = pd.DataFrame(resistances.items(), columns=['SMU pair', 'Resistance (Ohm)'])
+    return df
+
+#double sweep from start to stop and then from start to stop
+def sweep(start,stop,step,comp,integration,device): #step cannot be negative
+    if start < stop and step < 0 :
+        step = -step
+    elif start > stop and step > 0 :
+        step = -step
+
+    smu_v = device.smu_dict()
+    smu_ground = device.smu_dict()
+    parameters = device.var1_dict()
+
+    smu_v.update(
+        iname = 'I2',
+        vname = 'V2',
+        mode = 'V',
+        func = 'VAR1'
+    )
+    smu_ground.update(
+        iname ='I4',
+        vname = 'V4',
+        mode = 'COMM',
+        func = 'CONS'
+    )
+    parameters.update(
+        mode ='DOUB',
+        start = start,
+        stop = stop,
+        step = step,
+        comp = comp,
+        pcomp = 0
+    )
+
+    #disable smus 1 and 3
+    device.measurement_mode('SWE')
+    device.smu_disable(1)
+    device.smu_disable(3)
+
+    device.setup_smu(2,smu_v)
+    device.setup_smu(4,smu_ground)
+    device.setup_var1(parameters)
+    device.integration_time(integration)
+    
+    #display variables
+    device.display_variable('X','V2')
+    device.display_variable('Y1','I2')
+
+    #execute measurement
+    device.single_measurement()
+    while device.operation_completed()==False:
+        time.sleep(2)
+        
+    device.autoscaling()
+
+    #return values
+    V=device.return_values('V2')
+    I=device.return_values('I2')
+
+    #convert the list to np.array to return the absolute values for the logarithmic scale
+    V = np.array(V)
+    I = np.array(I)
+
+    #return all values to the function
+    return V, I
+
+#sampling check
+def sampling_check(voltage,device):
+    
+    parameters ={
+        'mode' : 'LIN',
+        'hold': 0,
+        'interval':2e-3,
+        'points': 5,
+        'filter': 'OFF',
+        'value':voltage, #voltage value
+        'comp':0.1 #compliance value
+    }
+    smu_v = device.smu_dict()
+    smu_ground = device.smu_dict()
+
+
+    smu_v.update(
+        iname = 'I2',
+        vname = 'V2',
+        mode = 'V',
+        func = 'CONS'
+    )
+    smu_ground.update(
+        iname ='I4',
+        vname = 'V4',
+        mode = 'COMM',
+        func = 'CONS'
+    )
+    
+    device.measurement_mode('SAMP')
+    device.smu_disable(1)
+    device.smu_disable(3)
+    device.setup_smu(2,smu_v)
+    device.setup_smu(4,smu_ground)
+
+    device.setup_smu_sampling(2,parameters)
+    device.setup_sampling(parameters)
+
+    device.integration_time('LONG')
+    
+    #remove total sampling time
+    device.auto_sampling_time('ON')
+
+    device.user_function('R','OHM','V2/I2')
+
+    device.display_variable('X','@INDEX')
+    device.display_variable('Y1','R')
+    device.single_measurement()
+    while device.operation_completed() == False:
+        time.sleep(2)
+       
+    index = np.array(device.return_values('@INDEX'))
+    R = np.array(device.return_values('R'))
+    R_mean = np.average(R)
+    device.del_user_functions()
+    device.autoscaling()
+
+    # Plot the results
+    fig,ax = plt.subplots()
+    
+    ax.set_title(f"Average Resistance(Sampling Check):{'{:.2e}'.format(R_mean)} Ohm")
+    ax.set_yscale('log')
+    ax.set_ylabel('Resistance (Ohm)')
+    ax.set_xlabel('Sampling Index')
+    ax.set_xticks(index)
+    ax.scatter(index,np.absolute(R),label = f"Voltage={voltage}V")
+    ax.legend()
+    display(fig)
+    
+    return R_mean
+
+#new (retention)
+def retention(voltage,period,duration,device):
+    parameters ={
+        'mode' : 'LIN',
+        'hold': 0,
+        'interval':2e-3,
+        'points': 0,
+        'filter': 'OFF',
+        'value':voltage, #voltage value
+        'comp':0.1 #compliance value
+    }
+    smu_v = device.smu_dict()
+    smu_ground = device.smu_dict()
+
+    smu_v.update(
+        iname = 'I2',
+        vname = 'V2',
+        mode = 'V',
+        func = 'CONS'
+    )
+    smu_ground.update(
+        iname ='I4',
+        vname = 'V4',
+        mode = 'COMM',
+        func = 'CONS'
+    )
+    
+    device.measurement_mode('SAMP')
+    device.smu_disable(1)
+    device.smu_disable(3)
+    device.setup_smu(2,smu_v)
+    device.setup_smu(4,smu_ground)
+
+    device.setup_smu_sampling(2,parameters)
+
+    device.integration_time('LONG')
+    device.total_sampling_time(duration)
+
+    if int(duration/period)+1<=10001:
+        parameters.update(points=int(duration/period)+1)
+    else:
+        parameters.update(points = 'MAX')
+    device.setup_sampling(parameters)    
+    
+    device.integration_time('MED')
+    device.user_function('R','OHM','V2/I2')
+    device.user_function('ABSR','OHM', 'ABS(R)')
+    
+    
+    device.display_variable('X','@TIME')
+    device.display_variable('Y1','ABSR')
+    device.axis_scale('Y1','LOG')
+    device.display_variable_min_max('Y1','MIN',10)
+    device.display_variable_min_max('Y1','MAX',10**8)
+    
+    device.single_measurement()
+    while device.operation_completed() == False:
+        time.sleep(2)
+
+    
+    TIME = device.return_values('@TIME')
+    R = device.return_values('R')
+    TIME = np.array(TIME)
+    R = np.array(R)
+    device.del_user_functions()
+    device.autoscaling()
+    return TIME,R
+    
+
+#plot sweep results
+def plot_sweep(x,y,title):
+    #plot results
+    fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis 
+    fig.suptitle(title)
+    ax1.set_title('Linear I')
+    ax1.set(xlabel='Voltage(V)',ylabel='Current(A)')
+    ax2.set_title('Logarithmic I')
+    ax2.set(xlabel='Voltage(V)',ylabel='Current(A)')
+    ax2.set_yscale('log')
+
+    ax1.plot(x,y)
+    ax2.plot(x,np.absolute(y))
+    fig.tight_layout()
+    display(fig)
+
+def plot_retention(x,y):
+    fig, ax = plt.subplots() 
+    fig.suptitle('Retention')
+    ax.set(xlabel='time(s)',ylabel='Resistance(Ohm)')
+    ax.set_yscale('log')
+    ax.set_xscale('linear')
+    ax.plot(x,y)
+    display(fig)
+    
+
+def create_data_frame(x,y):
+    header = ['V(V)','ABSV(V)',"I(A)",'ABSI(A)',"R(Ohm)"]
+    data = {header[0]:x,header[1]:np.absolute(x),header[2]:y,header[3]:np.absolute(y),header[4]:np.divide(x,y)}
+    df = pd.DataFrame(data)
+    return df
+
+def create_retention_data_frame(x,y):
+    header = ['Time(s)','R(Ohm)']
+    data = {header[0]:x,header[1]:y}
+    df =  pd.DataFrame(data)
+    return df
+
+
+#write results to file
+def write_to_file(file,title:list,df):
+    #append escape character after each element
+    index = 1
+    while index <= len(title):
+        title.insert(index,"\n")
+        index = index+2
+
+    #write to file
+    with open(file,'a') as f:    
+        f.writelines(title)
+        f.write("\n")
+        f.write(df.to_string())
+        f.write("\n\n")
+
+#### new functions ##############
+def disable_widgets(widgets_list):
+    for widget in widgets_list:
+        widget.disabled = True
+
+def change_state(widgets_list):
+    for widget in widgets_list:
+        widget.disabled = not widget.disabled
+
+def enable_widgets(widgets_list):
+    for widget in widgets_list:
+        widget.disabled = False
+
+#a check values function
+def check_values(step,set_voltage,reset_voltage):
+    valid = True
+
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    if step > abs(set_voltage) or step > abs(reset_voltage) or step==0:#invalid parameter setting 
+        valid = False
+        tkinter.messagebox.showerror(message="Invalid parameter setting!")
+
+    #now if the set-reset voltages have the same polarity show a warning
+    elif set_voltage*reset_voltage>0:
+        valid = tk.messagebox.askokcancel(message="Set-Reset voltages have the same polarity. Continue?")
+
+    else:
+        pass
+        
+    root.destroy()
+    return valid
+        
+
+def information_box(information):
+    #open dialog and hide the main window
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    #display meaagebox
+    tkinter.messagebox.showinfo(message=information)
+    root.destroy()
+
+#choose directory to save measurement results
+#and check if you have access
+def check_writable(folder):
+    filename = "test.txt"
+    file = os.path.join(folder,filename)
+
+    #protection against removing existing file in python
+    i=1
+    while os.path.exists(file):
+        filename=f"test{i}.txt"
+        file = os.path.join(folder,filename)
+    try:
+        with open(file,'a'):
+            writable = True
+        os.remove(file)
+    except:
+        writable = False
+        information_box(f"{folder} is not writable!")
+    
+    return writable  
+    
+def choose_folder():
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    #choose nonemty folder
+    folder = tk.filedialog.askdirectory()
+    
+    while folder == '':
+        folder = tk.filedialog.askdirectory()
+
+    #check if writable in a while loop
+    writable=check_writable(folder)
+
+    while writable == False:
+        #choose a correct folder
+        folder = tk.filedialog.askdirectory()
+    
+        while folder == '':
+            folder = tk.filedialog.askdirectory()
+        
+        #check writable if not repeat
+        writable=check_writable(folder)
+        
+    root.destroy()
+    return folder
+
+
+def upload_results(source_file,target_file,target_file_dir):
+    """
+    New function (UPLOAD RESULTS) 
+    IMPORTANT FOR ALL MEASUREMENTS
+    THE RESULTS ARE MOVED FROM SOURCE FILE TO TARGET FILE EVEN LOCALLY
+    """
+    while True:
+        try:
+            with (open(source_file,'r') as source,open(target_file,'a') as target):
+                target.write(source.read())
+            os.remove(source_file)
+            return source_file,target_file,target_file_dir
+        except:
+            information_box(f"{target_file} is no longer accessible. Please change directory")
+            target_file_dir = choose_folder()
+            filename = os.path.basename(target_file)
+            target_file =os.path.join(target_file_dir,filename)
+            #and then try again
+
+
+#ini file functions
+def save_as_ini(default_filename):
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    file = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("Ini files","*.ini")],title = "save as ini",initialfile =default_filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".ini") == False:
+        #open again filedialog with error message box
+        answer=tk.messagebox.askyesno(message='Do you want to cancel the ini file Save?')
+        if answer == True:
+            raise Exception("Ini File Operation aborted!")
+        else:
+            file = filedialog.asksaveasfilename(defaultextension=".ini", filetypes=[("Ini files","*.ini")],title = "save as ini",initialfile =default_filename)
+    root.destroy()
+    return file
+
+def load_ini():
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
+
+    root.attributes("-topmost", True)#window stays above all other applications
+
+    
+    file = filedialog.askopenfilename(filetypes=[("Ini files","*.ini")],title ='Select ini file')
+    while file.endswith(".ini") == False:
+        #open again filedialog with error message box
+        answer=tk.messagebox.askyesno(message='Do you want to cancel the ini file load?')
+        if answer == True:
+            raise Exception("Ini File Operation aborted!")
+        else:
+            file = filedialog.askopenfilename(filetypes=[("Ini files","*.ini")],title = "Select ini file")
+    root.destroy()
+    return file
+
+
+        
+
+        
+        
+    
\ No newline at end of file
diff --git a/hp4155/memristor (Version 4.1)/help_pulse.py b/hp4155/memristor (Version 4.1)/help_pulse.py
new file mode 100644
index 0000000000000000000000000000000000000000..a5195597a879a8520133f809c25e500d4346c8e3
--- /dev/null
+++ b/hp4155/memristor (Version 4.1)/help_pulse.py	
@@ -0,0 +1,463 @@
+import sys
+sys.path.insert(0, '..') #append parent directory
+
+import ipywidgets as widgets
+import tkinter as tk
+from tkinter import filedialog
+import tkinter.messagebox
+import os
+from datetime import datetime
+import matplotlib.pyplot as plt
+import numpy as np
+import module
+import time
+import pandas as pd
+from IPython.display import display, clear_output
+
+#widgets interactivity
+
+def add_widgets_to_list(source_dictionary,target_list):
+    for widget in source_dictionary.values():
+        target_list.append(widget)
+
+
+def check_pulse(dictionary):
+    #check if number of pulses is ok
+    if dictionary['pulses'].value < 0:
+        dictionary['pulses'].value = -dictionary['pulses'].value
+    elif dictionary['pulses'].value==0:
+        dictionary['pulses'].value = 1
+    else:
+        pass
+
+    # Restriction: pulse period ≥ pulse width + 4 ms
+    if dictionary['period'].value < dictionary['width'].value+4e-3:
+        dictionary['period'].value = dictionary['width'].value+4e-3
+
+
+#sweep pulse measurement
+def sweep_meas(dictionary,device):
+    smu_v = device.smu_dict()
+    smu_ground = device.smu_dict()
+    parameters = device.var1_dict()
+
+    smu_v.update(
+        iname = 'I2',
+        vname = 'V2',
+        mode = 'VPULSE',
+        func = 'VAR1'
+    )
+    smu_ground.update(
+        iname ='I4',
+        vname = 'V4',
+        mode = 'COMM',
+        func = 'CONS'
+    )
+    parameters.update(
+        mode ='SING',
+        start = dictionary['start'].value,
+        stop = dictionary['stop'].value,
+        step = (dictionary["stop"].value-dictionary["start"].value)/(dictionary["pulses"].value-1), #define the number of steps given specific pulses
+        comp = dictionary['comp'].value,
+        pcomp = 0,
+        base = dictionary["base"].value,
+        width = dictionary["width"].value,
+        period= dictionary["period"].value
+    )
+    device.smu_disable(1)
+    device.smu_disable(3)
+
+    
+    device.measurement_mode("SWE")
+    device.setup_smu(2,smu_v)
+    device.setup_smu(4,smu_ground)
+    device.setup_var1(parameters)
+    
+    device.display_variable("X","V2")
+    device.display_variable("Y1",'I2')
+
+    device.range_mode(4,"AUTO")
+    device.range_mode(2,"AUTO")
+
+    device.setup_pulse(parameters)
+
+    device.integration_time(dictionary["integration"].value)
+
+    t0 = time.time()
+    device.single_measurement()
+    while device.operation_completed()== False:
+        pass
+    
+    t1 = time.time()
+    # get the execution time
+    elapsed_time = t1 - t0
+    device.autoscaling()
+
+    I_i=device.return_values("I2")
+    V_i=device.return_values("V2")
+    R_i = np.divide(V_i,I_i)
+    
+    
+    expected_time = dictionary["period"].value*dictionary["pulses"].value
+
+    times = (elapsed_time,expected_time)
+    values = (V_i,I_i,R_i)
+
+    del device
+
+    return times,values
+
+def plot_sweep_pulse(values):    
+    fig, ax1 = plt.subplots() 
+    color = 'tab:red'
+
+    ax1.set_xlabel("V(V)")
+    ax1.set_ylabel("I(A)",color=color)
+    ax1.set_yscale('log')
+
+    ax1.plot(values[0],np.abs(values[1]),color=color)
+    ax1.tick_params(axis ='y', labelcolor = color,which = 'both') 
+
+    # Adding Twin Axes 
+    ax2 = ax1.twinx() 
+    color = 'tab:green'
+
+    ax2.set_ylabel("R(Ohm)",color = color)
+    ax2.plot(values[0],np.abs(values[2]),color = color)
+
+    ax2.tick_params(axis ='y', labelcolor = color,which = 'both')
+    ax2.set_yscale('log')
+
+    fig.suptitle("Sweep Pulse Measurement Results")
+
+    display(fig)
+
+def save_sweep(folder,sample_dict,values,times,sweep_dict):
+    filename = f"{sample_dict['series'].value}_{sample_dict['field'].value}_{sample_dict['dut'].value}.txt"
+
+    file = os.path.join(folder,filename)
+
+    with open(file,"a") as f: 
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Sweep Pulse Measurement at {date}"+"\n")
+        f.write(f"period(s):{sweep_dict['period'].value}"+"\n")
+        f.write(f"width(s):{sweep_dict['width'].value}"+"\n")
+        f.write(f"base value(V):{sweep_dict['base'].value}"+"\n")
+        f.write(f"execution time(s):{times[0]}"+"\n")
+        f.write(f"expected time(s):{times[1]}"+"\n")
+        f.write(f"number of pulses:{sweep_dict['pulses'].value}"+"\n")
+        f.write(f"current compliance(A):{sweep_dict['comp'].value}"+"\n")
+        f.write(f"voltage:{sweep_dict['start'].value}V to {sweep_dict['stop'].value}V"+"\n")
+        f.write(f"integration time:{sweep_dict['integration'].value}"+"\n\n")
+
+        zipped = list(zip(values[0],values[1], values[2]))
+        df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)'])
+
+        f.write("Results Sweep Pulse:\n")
+        f.write(df.to_string())
+        f.write("\n\n\n")
+
+def constant_meas(dictionary,device):
+    smu_v = device.smu_dict()
+    smu_ground = device.smu_dict()
+    sweep_params = device.var1_dict()
+    smu_help = device.smu_dict() #this is the uncontacted smu
+
+    smu_v.update(
+        iname = 'I2',
+        vname = 'V2',
+        mode = 'V',
+        func = 'CONS'
+    )
+    smu_help.update(
+        iname = 'I3',
+        vname = 'V3',
+        mode = 'VPULSE',
+        func = 'VAR1'
+    )
+    smu_ground.update(
+        iname ='I4',
+        vname = 'V4',
+        mode = 'COMM',
+        func = 'CONS'
+    )
+    sweep_params.update(
+        mode ='SING',
+        start = 0,
+        stop = 10,
+        step = 10/(dictionary["pulses"].value-1), #define the number of steps given specific pulses
+        comp = 0.1,
+        pcomp = 0,
+        base = dictionary["base"].value,
+        width = dictionary["width"].value,
+        period= dictionary["period"].value
+    )
+    #the constant smu
+    cons = {
+        'value':dictionary["voltage"].value,
+        'comp':dictionary["comp"].value
+    }
+    
+    device.measurement_mode("SWE")
+    device.smu_disable(1)
+    device.setup_smu(2,smu_v)
+    device.setup_smu(3,smu_help)
+    device.setup_smu(4,smu_ground)
+    device.setup_var1(sweep_params)
+    device.setup_pulse(sweep_params)
+    device.setup_cons_smu(2,cons)
+    
+    device.user_function('R','OHM','V2/I2')
+    
+    device.display_variable("X","@INDEX")
+    device.display_variable("Y1",'R')
+
+    device.range_mode(4,"AUTO")
+    device.range_mode(2,"AUTO")
+    device.range_mode(3,"AUTO")
+
+    
+    device.integration_time(dictionary["integration"].value)
+
+    device.variables_to_save(['@INDEX','V2','I2','R'])
+
+    t0 = time.time()
+    device.single_measurement()
+    while device.operation_completed()== False:
+        pass
+    
+    t1 = time.time()
+    # get the execution time
+    elapsed_time = t1 - t0
+    
+
+    I_i=device.return_values("I2")
+    V_i=device.return_values("V2")
+    R_i = device.return_values('R')
+
+    
+    expected_time = dictionary["period"].value*dictionary["pulses"].value
+
+    times = (elapsed_time,expected_time)
+    values = (V_i,I_i,R_i)
+
+    device.del_user_functions()
+    device.autoscaling()
+
+    return times,values
+
+def plot_constant_pulse(values):
+    index =[]
+    for i in range(len(values[0])):
+        index.append(i+1)
+    
+    fig, ax1 = plt.subplots() 
+    color = 'tab:red'
+
+    ax1.set_xlabel("Index(Pulse number)")
+    ax1.set_ylabel("I(A)",color=color)
+    ax1.set_yscale('log')
+
+    ax1.plot(index,np.abs(values[1]),color=color,label = "Voltage(V):"+str(min(values[0])))
+    ax1.tick_params(axis ='y', labelcolor = color,which = 'both') 
+
+    # Adding Twin Axes 
+    ax2 = ax1.twinx() 
+    color = 'tab:green'
+
+    ax2.set_ylabel("R(Ohm)",color = color)
+    ax2.plot(index,np.abs(values[2]),color=color)
+    ax2.set_yscale('log')
+
+    ax2.tick_params(axis ='y', labelcolor = color,which = 'both') 
+
+    fig.suptitle("Constant Pulse Measurement Results")
+    ax1.set_title("Voltage:"+str(min(values[0]))+"V")
+
+    display(fig)
+
+def save_constant(folder,sample_dict,values,times,cons_dict):
+    filename = f"{sample_dict['series'].value}_{sample_dict['field'].value}_{sample_dict['dut'].value}.txt"
+
+    file = os.path.join(folder,filename)
+
+    with open(file,"a") as f: 
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Constant Pulse Measurement at {date}"+"\n")
+        f.write(f"period(s):{cons_dict['period'].value}"+"\n")
+        f.write(f"width(s):{cons_dict['width'].value}"+"\n")
+        f.write(f"base value(V):{cons_dict['base'].value}"+"\n")
+        f.write(f"execution time(s):{times[0]}"+"\n")
+        f.write(f"expected time(s):{times[1]}"+"\n")
+        f.write(f"number of pulses:{cons_dict['pulses'].value}"+"\n")
+        f.write(f"current compliance(A):{cons_dict['comp'].value}"+"\n")
+        f.write(f"constant voltage:{cons_dict['voltage'].value}V"+"\n")
+        f.write(f"integration time:{cons_dict['integration'].value}"+"\n\n")
+
+        zipped = list(zip(values[0],values[1], values[2]))
+        df = pd.DataFrame(zipped, columns=['VPULSE(V)', 'IPULSE(A)', 'RPULSE(Ohm)'])
+
+        f.write("Results Constant Pulse:\n")
+        f.write(df.to_string())
+        f.write("\n\n\n")
+
+import ipywidgets as widgets
+
+#sample interface
+
+style = {'description_width': 'initial'}
+
+def constant_pulse():
+    voltage = widgets.BoundedFloatText(
+        value = 10,
+        min = -100,
+        max = 100,
+        step = 1,
+        description = 'Constant Voltage(V):',
+        style=style,
+    )
+
+    comp = widgets.BoundedFloatText(
+        value = 0.1,
+        min = -0.1,
+        max = 0.1,
+        step = 0.01,
+        description = 'Compliance(A):',
+        style=style,
+    )
+    
+    pulses = widgets.IntText(
+        value = 100,
+        description = 'Number of Pulses:',
+        style=style,                    
+    )
+    period = widgets.BoundedFloatText(
+        value = 5e-3,
+        min = 5e-3,
+        max = 1,
+        step = 5e-3,
+        description ='Pulse Period(s):',
+        style=style,
+
+    )
+    width = widgets.BoundedFloatText(
+        value = 5e-4,
+        min = 5e-4,
+        max = 1e-1,
+        step= 5e-4,
+        description ='Pulse Width(s):',
+        style=style,
+    )
+    base = widgets.BoundedFloatText(
+        value = 0,
+        min = -100,
+        max = 100,
+        step = 1,
+        description = 'Base Voltage(V):',
+        style=style
+    )
+
+    integration =widgets.Dropdown(
+        options=['SHORt', 'MEDium', 'LONG'],
+        value='MEDium',
+        description='Integration:',
+        style=style
+    )
+
+    pulse_parameters = widgets.VBox([pulses,period,width,base])
+    smu_parameters = widgets.VBox([voltage,comp,integration])
+
+    constant_pulse_widgets = widgets.HBox([smu_parameters,pulse_parameters])
+    constant_pulse_dict = {
+        'voltage': voltage,
+        'comp':comp,
+        'pulses':pulses,
+        'period':period,
+        'width':width,
+        'base':base,
+        'integration':integration
+    }
+    return constant_pulse_widgets,constant_pulse_dict
+
+def sweep_pulse():
+    start_voltage = widgets.BoundedFloatText(
+        value = 0,
+        min = -100,
+        max = 100,
+        step = 1,
+        description = 'Start Voltage(V):',
+        style=style,
+    )
+    stop_voltage = widgets.BoundedFloatText(
+        value = 15,
+        min = -100,
+        max = 100,
+        step = 1,
+        description = 'Stop Voltage(V):',
+        style=style,
+    )
+
+    comp = widgets.BoundedFloatText(
+        value = 0.1,
+        min = -0.1,
+        max = 0.1,
+        step = 0.01,
+        description = 'Compliance(A):',
+        style=style,
+    )
+    
+    pulses = widgets.IntText(
+        value = 100,
+        description = 'Number of Pulses:',
+        style=style,                    
+    )
+    period = widgets.BoundedFloatText(
+        value = 5e-3,
+        min = 5e-3,
+        max = 1,
+        step = 5e-3,
+        description ='Pulse Period(s):',
+        style=style,
+
+    )
+    width = widgets.BoundedFloatText(
+        value = 5e-4,
+        min = 5e-4,
+        max = 1e-1,
+        step= 5e-4,
+        description ='Pulse Width(s):',
+        style=style,
+    )
+    base = widgets.BoundedFloatText(
+        value = 0,
+        min = -100,
+        max = 100,
+        step = 1,
+        description = 'Base Voltage(V):',
+        style=style
+    )
+
+    integration =widgets.Dropdown(
+        options=['SHORt', 'MEDium', 'LONG'],
+        value='MEDium',
+        description='Integration:',
+        style=style
+    )
+
+    pulse_parameters = widgets.VBox([pulses,period,width,base])
+    smu_parameters = widgets.VBox([start_voltage,stop_voltage,comp,integration])
+
+    sweep_pulse_widgets = widgets.HBox([smu_parameters,pulse_parameters])
+    sweep_pulse_dict = {
+        'start': start_voltage,
+        'stop':stop_voltage,
+        'comp':comp,
+        'pulses':pulses,
+        'period':period,
+        'width':width,
+        'base':base,
+        'integration':integration
+    }
+    return sweep_pulse_widgets,sweep_pulse_dict
+
+
diff --git a/hp4155/memristor (Version 4.1)/memristor.py b/hp4155/memristor (Version 4.1)/memristor.py
new file mode 100644
index 0000000000000000000000000000000000000000..a42a905898506903fc6655e8024a966a10651247
--- /dev/null
+++ b/hp4155/memristor (Version 4.1)/memristor.py	
@@ -0,0 +1,692 @@
+### this is the new memrstor measurement (set and reset as many times as the user wants and full sweeps with a button)
+from help import *
+import ipywidgets as widgets
+from keyboard import add_hotkey,remove_hotkey
+import configparser
+
+# pulsed libraries
+from help_pulse import *
+
+#create temporary file to store the results localy
+temp_file= os.path.join(os.getcwd(),'tempfile.txt')
+
+# the three naming fields
+
+sample_series= widgets.Text(
+    value= '',
+    placeholder ='Enter text here:',
+    description = 'sample series:',
+    style = {'description_width': 'initial'}
+    )
+
+field = widgets.Text(
+    value= '',
+    placeholder ='Enter text here:',
+    description = 'Field:',
+    style = {'description_width': 'initial'},
+    )
+
+DUT = widgets.Text(
+    value= '',
+    placeholder ='Enter text here:',
+    description = 'DUT:',
+    style = {'description_width': 'initial'},
+    )
+
+
+#choose a new folder button
+new_folder = widgets.Button(description='change folder')
+
+image = widgets.Image(
+    value=open("schematic.png", "rb").read(),
+    format='png',
+    width=300,
+    height=100,
+)
+
+contact_check =  widgets.Button(description = 'CONTACT CHECK')
+qcc = widgets.Button(description = 'QUICK CONTACT CHECK',layout=widgets.Layout(width='80%'),style={"button_width": "auto"})
+qcc_select = widgets.RadioButtons(description = 'QCC type:',options = ['EBL','OL'])
+
+vertical1 = widgets.VBox([sample_series,field,DUT,new_folder,contact_check,qcc,qcc_select])
+vertical2 = widgets.VBox([image])
+all_text_boxes = widgets.HBox([vertical1,vertical2])
+
+
+
+#first series of parameters
+step = widgets.BoundedFloatText(
+    value=0.01,
+    min=0,
+    max=100,
+    step=0.01,
+    description='Step(V):',
+)
+
+integration_time=widgets.Dropdown(
+    options=['SHORt', 'MEDium', 'LONG'],
+    value='MEDium',
+    description='Integration:',
+    #style = {'description_width': 'initial'},
+)
+
+sampling=widgets.Checkbox(description='sampling check')
+
+auto_qcc = widgets.Checkbox(
+    description = 'Auto QCC after Reset',
+    style = {'description_width': 'initial'},
+    value = True
+)
+
+# THE BUTTONS 
+#create buttons as it shown in the how_buttons_look 
+set=widgets.Button(description='SET')
+reset=widgets.Button(description='RESET')
+full=widgets.Button(description='FULL SWEEP')
+number = widgets.BoundedIntText(value=1,min=1,max=sys.maxsize,step=1,description='full sweeps:',disabled=False) #number of measuremts for the full sweep
+retention_button=widgets.Button(description='RETENTION')
+export_ini_button = widgets.Button(description = 'Export as ini')
+import_ini_button = widgets.Button(description='Import from ini')
+
+
+
+#parameter boxes
+Vset=widgets.BoundedFloatText(
+    value=1,
+    min=-100,
+    max=100,
+    step=0.1,
+    description='Voltage(V):',
+)
+
+#parameter buttons
+CC_vset=widgets.BoundedFloatText(
+    value=1e-3,
+    min=-0.1,
+    max=0.1,
+    step=0.01,
+    description= 'Comp(A):',
+)
+
+#parameter buttons
+Vreset=widgets.BoundedFloatText(
+    value=-1,
+    min=-100,
+    max=100,
+    step=0.1,
+    description='Voltage(V):',
+)
+
+#parameter buttons
+CC_vreset=widgets.BoundedFloatText(
+    value=1e-3,
+    min=-0.1,
+    max=0.1,
+    step=0.01,
+    description='Comp(A):',
+)
+
+Vretention=widgets.BoundedFloatText(
+    value=1,
+    min=-100,
+    max=100,
+    step=1,
+    description='Voltage(V):',
+)
+
+period=widgets.BoundedFloatText(
+    value=1,
+    min=2e-3,
+    max=65.535,
+    step=1,
+    description='Period(s):',
+)
+
+duration=widgets.BoundedFloatText(
+    value=60,
+    min=60e-6,
+    max=1e11,
+    step=1,
+    description='Duration(s):',
+)
+
+# for automatic stop of endurance
+auto_stop = widgets.Checkbox(
+    description = 'Auto QCC after Reset',
+    style = {'description_width': 'initial'},
+    value = False
+)
+
+threshold = widgets.FloatText(
+    description = "Stop Condition: R(HRS)/R(LRS)<",
+    style = {'description_width': 'initial'}
+    value = 1000
+)
+
+#align a button with a checkbox or integer bounded texts horizontaly
+line0 = widgets.HBox([step,integration_time,sampling,auto_qcc])
+line1 = widgets.HBox([set,Vset,CC_vset])
+line2 = widgets.HBox([reset,Vreset,CC_vreset])
+line3 = widgets.HBox([full,number,auto_stop,threshold])
+line4 = widgets.HBox([retention_button,Vretention,period,duration])
+
+#pack them into a single vertical box
+all = widgets.VBox([line0,line1,line2,line3,line4])
+output = widgets.Output()
+
+
+#display all at the end
+display(all_text_boxes)
+
+cons_widgets,cons_dict = constant_pulse()
+sweep_widgets,sweep_dict = sweep_pulse()
+
+sweep_button = widgets.Button(description = "SWEEP PULSE")
+cons_button = widgets.Button(description = "CONSTANT PULSE")
+
+
+children = [all,widgets.VBox([sweep_widgets,sweep_button]),widgets.VBox([cons_widgets,cons_button])]
+titles = ["Regular","Sweep Pulse","Constant Pulse"]
+tab = widgets.Tab()
+tab.children = children
+tab.titles = titles
+
+display(tab)
+display(widgets.HBox([import_ini,button,export_ini_button]))
+display(output)
+
+all_widgets=[sweep_button,cons_button,sample_series,field,DUT,set,reset,full,new_folder,retention_button,contact_check,qcc,qcc_select,Vset,CC_vset,Vreset,CC_vreset,step,integration_time,number,sampling,Vretention,period,duration,auto_qcc,auto_stop,threshold,export_ini_button,import_ini_button]
+add_widgets_to_list(cons_dict,all_widgets)
+add_widgets_to_list(sweep_dict,all_widgets)
+
+# The regular dictionary for ini
+regular_parameters={
+    'step': step,
+    'integration': integration,
+    'set_voltage': Vset,
+    'set_compliance': CC_vset,
+    'reset_voltage': Vreset,
+    'reset_compliance':CC_vreset,
+    'number_of_cycles': number,
+    'threshold':threshold,
+    'retention_voltage':Vretention,
+    'retention_period': period,
+    'retention_duration':duration
+}
+
+device = hp4155a.HP4155a('GPIB0::17::INSTR')
+device.reset()
+device.disable_not_smu()
+
+#choose folder directory
+folder=choose_folder() #here buttons dont work yet!
+
+def on_contact_check_clicked(b):
+    global folder,temp_file
+    with output:
+        clear_output()
+        change_state(all_widgets)
+        device.inst.lock_excl()
+
+        filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt"
+        file = os.path.join(folder,filename)
+
+        R = regular_contact_check(device)
+        date = str(datetime.today().replace(microsecond=0))
+        title = [f"Full Contact Check at {date}"]
+
+        write_to_file(temp_file,title,R)
+
+        #upload results
+        temp_file,file,folder=upload_results(temp_file,file,folder)
+
+        information_box("Contact Check Completed")
+        device.inst.unlock()
+
+        change_state(all_widgets)
+
+def on_qcc_clicked(b):
+    global folder,temp_file
+    with output:
+        clear_output()
+        change_state(all_widgets)
+        device.inst.lock_excl()
+
+        filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt"
+        file = os.path.join(folder,filename)
+        device.inst.lock_excl()
+        
+        if qcc_select.value == 'EBL':
+            R = EBL(device)
+        else: # OL
+            R = OL(device) #df
+
+        date = str(datetime.today().replace(microsecond=0))
+        title = [f"Quick Contact Check ({qcc_select.value}) at {date}"]
+
+        write_to_file(temp_file,title,R)
+
+        #upload results
+        temp_file,file,folder=upload_results(temp_file,file,folder)
+
+        information_box("Quick Contact Check Completed")
+
+        device.inst.unlock()
+
+        change_state(all_widgets)
+    
+        
+def on_set_button_clicked(b):
+    global folder,temp_file
+    with output:
+        #disable buttons
+        change_state(all_widgets)
+
+        filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt"
+        file = os.path.join(folder,filename)
+
+        #lock the  device
+        device.inst.lock_excl()
+
+        clear_output()
+
+        #check values
+        valid = check_values(step.value,Vset.value,Vreset.value)
+
+
+        if valid == True:
+            if sampling.value == True: #do sampling set before set process(100mV)
+                R_mean_before= sampling_check(-0.01,device)
+                 
+               
+            #execute measurement,plot results and save them
+            V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device)
+            plot_sweep(V12,I12,'SET')
+            df = create_data_frame(V12,I12)
+            display(df)
+            
+
+            if sampling.value == True: #do sampling set after set process(10mV)
+                R_mean_after = sampling_check(0.01,device)
+            
+            date = str(datetime.today().replace(microsecond=0))
+            title = [f"SET Memristor at {date}",f"Set Voltage={Vset.value}V",f"current compliance={CC_vset.value}A"]
+            if sampling.value == True:
+                title.extend([f"R(Ohm)  Before/After",f"{R_mean_before}  {R_mean_after}"])
+            write_to_file(temp_file,title,df)
+
+            #upload results
+            temp_file,file,folder=upload_results(temp_file,file,folder)
+        
+        #show messagebox
+        information_box("Measurement finished!")
+
+        #unlock device
+        device.inst.unlock()
+        
+        change_state(all_widgets)
+ 
+def on_reset_button_clicked(b):
+    global folder,temp_file
+    with output:
+        change_state(all_widgets)
+
+        filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt"
+        file = os.path.join(folder,filename)
+
+        #lock device
+        device.inst.lock_excl()
+
+        clear_output()
+
+        #check values
+        valid = check_values(step.value,Vset.value,Vreset.value)
+
+
+        if valid == True:
+            if sampling.value == True: #do sampling set before reset process(10mV)
+                R_mean_before = sampling_check(0.01,device)
+            
+            #execute measurement,plot results and save them
+            V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device)
+            plot_sweep(V34,I34,'RESET')
+            df = create_data_frame(V34,I34)
+            display(df)
+            
+            if sampling.value == True: #do sampling set after reset process(100mV)
+                R_mean_after = sampling_check(-0.01,device)
+
+            date = str(datetime.today().replace(microsecond=0))
+            title =[f"RESET Memristor at {date}",f"Reset Voltage={Vreset.value}V",f"current compliance={CC_vreset.value}A"]
+            if sampling.value == True:
+                title.extend([f"R(Ohm)  Before/After",f"{R_mean_before}  {R_mean_after}"])
+            write_to_file(temp_file,title,df)
+
+            #Quick Contact Check after reset Process 
+            if auto_qcc.value == True:
+                if qcc_select.value == 'EBL':
+                    R=EBL(device)
+                else: # OL
+                    R=OL(device)
+
+                title = [f"Automatic Quick Contact Check({qcc_select.value}) after Reset"]
+                write_to_file(temp_file,title,R)
+            
+            #upload results
+            temp_file,file,folder=upload_results(temp_file,file,folder)
+
+        #show messagebox
+        information_box("Measurement finished!")
+
+        #unlock device
+        device.inst.unlock()
+
+        change_state(all_widgets)
+
+def on_full_button_clicked(b):
+    global folder,temp_file
+    with output:
+        change_state(all_widgets)
+
+        filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt"
+        file = os.path.join(folder,filename)
+
+        # lock device
+        device.inst.lock_excl()
+        
+        clear_output()
+
+        #check values
+        valid = check_values(step.value,Vset.value,Vreset.value)
+        date = str(datetime.today().replace(microsecond=0))
+        
+        if valid == True:
+            with open(temp_file,'a') as f:
+                header =[f"{number.value} full sweeps with parameters:",f"Set Voltage = {Vset.value}V",f"Current compliance set = {CC_vset.value}A",f"Reset Voltage = {Vreset.value}V",f"Current compliance reset = {CC_vreset.value}A"]
+                
+                fig, (ax1, ax2) = plt.subplots(2,sharex=True,figsize=(8,6)) #the plots share the same x axis 
+                fig.suptitle('FULL SWEEP')
+                ax1.set_title('Linear I')
+                ax1.set(xlabel='Voltage(V)',ylabel='Current(A)')
+                ax2.set_title('Logarithmic I')
+                ax2.set(xlabel='Voltage(V)',ylabel='Current(A)')
+                ax2.set_yscale('log')
+
+                stop = False
+
+                def break_loop():
+                    nonlocal stop
+                    stop = True
+                #help list with the resistances
+                resistances = []    
+                        
+                add_hotkey("esc",break_loop)
+                #execute number of measurements
+                for i in range(number.value):#here it is easier to implement the sampling checks
+                    clear_output(wait = True)
+                    if i>0:
+                        display(fig)
+                    if sampling.value == True: #before set(100mv)
+                        R_mean_init = sampling_check(-0.01,device)
+                        resistances.append(R_mean_init)
+                        
+                    V12,I12 = sweep(0,Vset.value,step.value,CC_vset.value,integration_time.value,device) #set
+                    plot_sweep(V12,I12,f"SET Iteration {i+1}")
+                    
+                    #after set/before reset
+                    if sampling.value == True: #before set(10mv)
+                        R_mean_set = sampling_check(0.01,device) # Here HRS
+                        resistances.append(R_mean_set)
+                        if auto_stop.value == True and abs(R_mean_set/R_mean_init)< abs(threshold).value:
+                            stop = True
+                    
+                    V34,I34 = sweep(0,Vreset.value,step.value,CC_vreset.value,integration_time.value,device) #reset
+                    plot_sweep(V34,I34,f"RESET Iteration {i+1}")
+
+
+                    #after reset
+                    if sampling.value == True:#-0.1V
+                        R_mean_reset = sampling_check(-0.01,device) #here LRS
+                        resistances.append(R_mean_reset)
+                        if auto_stop.value == True and abs(R_mean_set/R_mean_reset)< abs(threshold).value:
+                            stop = True
+
+                    #Quick Contact Check after reset Process 
+                    if auto_qcc.value == True:
+                        if qcc_select.value == 'EBL':
+                            R = EBL(device)
+                        else: # OL
+                            R = OL(device)
+
+                    #butterfly curve
+                    V=np.concatenate((V12,V34))
+                    I=np.concatenate((I12,I34))
+
+                    #create data frame and save to file
+                    df = create_data_frame(V,I)
+                    display(df)
+                    if i == 0 :
+                        header.extend([f"{i+1} Iteration"])
+                        title = header.copy()
+                    else:
+                        title = [f"{i+1} Iteration"]
+                    if sampling.value == True:
+                        title.extend([f"R(Ohm)  INIT/SET/RESET",f"{R_mean_init}  {R_mean_set} {R_mean_reset}"])
+
+                    write_to_file(temp_file,title,df)
+    
+                    if auto_qcc.value == True:
+                        title= [f"Quick Contact Check({qcc_select.value}) after Reset"]
+                        write_to_file(temp_file,title,R)
+
+                    #plot results
+                    ax1.plot(V,I)
+                    ax2.plot(V,np.absolute(I))
+                    fig.tight_layout()
+                    
+                    #check for loop termination
+                    if stop == True:
+                        clear_output(wait= True)
+                        time.sleep(2)
+                        display(fig)
+                        information_box("Endurance stopped after esc (manually) or automatically!")
+                        f.write("endurance stopped!\n\n")
+                        break
+                else:
+                    clear_output(wait = True)
+                    time.sleep(2)
+                    display(fig)
+                    information_box("Endurance completed!")
+                    f.write("endurance completed!\n\n")
+                        
+                remove_hotkey('esc')
+                stop = False
+
+                #plot resistances if sampling value == True or len(resistances) !=0
+                if len(resistances)!=0:
+                    indexes = np.arange(1,len(resistances)+1)
+                    resistances = np.absolute(resistances)
+                
+                    fig, ax = plt.subplots()
+                    
+                    fig.suptitle('Average Resistances from sampling checks')
+                    ax.set(xlabel='Index',ylabel='Resistance(Ohm)',yscale='log')
+                    ax.scatter(indexes,resistances)
+                    display(fig)
+
+
+            #upload results
+            temp_file,file,folder=upload_results(temp_file,file,folder)
+        
+        #unlock the device
+        device.inst.unlock()
+        change_state(all_widgets)
+
+
+#new_folder clicked
+def on_new_folder_button_clicked(b):
+    global folder
+    with output:
+        change_state(all_widgets)
+        
+        folder = choose_folder() #choose new folder
+    
+        change_state(all_widgets)
+
+def on_retention_button_clicked(b):
+    global folder,temp_file
+    with output:
+        
+        change_state(all_widgets)
+
+
+        device.inst.lock_excl()
+        
+        clear_output()
+
+        filename=f"{sample_series.value}_{field.value}_{DUT.value}.txt"
+        file = os.path.join(folder,filename)
+
+        #execute measurement
+        t,R=retention(Vretention.value,period.value,duration.value,device)
+        plot_retention(t,R)
+        df=create_retention_data_frame(t,R)
+        date = str(datetime.today().replace(microsecond=0))
+        title =[f"Retention Memristor at {date}",f"Voltage={Vretention.value}V",f"period={period.value}s",f"duration={duration.value}s"]
+
+        write_to_file(temp_file,title,df)
+        #upload results
+        temp_file,file,folder=upload_results(temp_file,file,folder)
+        #show messagebox
+        information_box("Measurement finished!")
+
+        device.inst.unlock()
+    
+        change_state(all_widgets)
+
+
+def on_sweep_button_clicked(b):
+    with output:
+        clear_output()
+        change_state(all_widgets)
+        check_pulse(sweep_dict)
+
+        sample_dict= {
+            'series':sample_series,
+            'field':field,
+            'dut':DUT
+        }
+
+        times,values = sweep_meas(sweep_dict,device)
+        plot_sweep_pulse(values)
+        save_sweep(folder,sample_dict,values,times,sweep_dict)
+        change_state(all_widgets)
+
+
+def on_constant_button_clicked(b):
+    with output:
+        global first
+        clear_output()
+        change_state(all_widgets)
+        
+        check_pulse(sweep_dict)
+
+        sample_dict= {
+            'series':sample_series,
+            'field':field,
+            'dut':DUT
+        }
+
+        times,values = constant_meas(cons_dict,device)
+        plot_constant_pulse(values)
+        save_constant(folder,sample_dict,values,times,cons_dict)
+        change_state(all_widgets)
+
+def on_export_ini_clicked(b):
+    with output:
+        change_state(all_widgets)
+        config = configparser.ConfigParser()
+        default_filename = 'memristor.ini'
+        try:
+            file = save_as_ini(default_filename)
+            with open(file,'w') as configfile:
+                config.add_section('ALL VALUES ARE IN SI-UNITS!')
+                config.add_section('IT IS RECOMMENDED TO CHANGE THE INI FILE FROM THE INTERFACE AND DO NOT CHANGE ANY VALUES MANUALLY')
+
+                #Regular Parameters
+                config.add_section('Set-Reset-Endurance-Retention')
+                for parameter,widget in regular_parameters.items():
+                    config.set('Set-Reset-Endurance-Retention',parameter,str(widget.value))
+                
+                # Sweep_pulse
+                config.add_section('Sweep Pulse')
+                for parameter,widget in sweep_dict.items():
+                    config.set('Sweep Pulse',parameter,str(widget.value))
+
+                # Constant Pulse
+                config.add_section('Constant Pulse')
+                for parameter,widget in cons_dict.items():
+                    config.set('Constant Pulse',parameter,str(widget.value))
+
+                config.write(configfile)
+        except Exception as e:
+            information_box(e)
+        
+        change_state(all_widgets)
+    
+def on_import_ini_clicked(b):
+    with output:
+        disable_widgets(all_widgets)
+        #load values to the interface
+        config = configparser.ConfigParser()
+        try:
+            file = load_ini()
+        except Exception as e:
+            information_box(e)
+            enable_widgets(all_widgets)
+            return
+
+        try:    
+            #read the values from each section
+            config.read(file)
+
+            #Regular
+            for parameter,widget in regular_parameters.items():
+                widget.value = config.get('Set-Reset-Endurance-Retention',parameter)
+            
+            #Sweep Pulse
+            for parameter,widget in sweep_dict.items():
+                widget.value = config.get('Sweep Pulse',parameter)
+            for parameter,widget in cons_dict.items():
+                widget.value = config.get('Constant Pulse',parameter)
+
+            information_box("all parameters loaded succesfully")
+        except Exception as error:
+            if type(error).__name__ =='NoSectionError':
+                information_box(f"{error}.Explanation: Section(header) [section] does not exist. Create a new ini file or compare it with functional ini files!")
+            elif type(error).__name__=='NoOptionError':
+                information_box(f'{error}.Explanation: The variable name before the equal sign is not recognized. Create a new ini file or compare it with functional ini files!')
+            elif type(error).__name__ == 'TraitError':
+                information_box(f'{error}.Explanation: Invalid Parameter Setting. Check if you set an invalid value!')
+            elif type(error).__name__ =="DuplicateOptionError":
+                information_box(f"{error}. Explaination: The section contains the setted parameter more than once!")
+            else:
+                information_box(f"A {type(error).__name__} has occurred. Create A new ini file")
+        change_state(all_widgets)
+            
+
+#link buttons to widgets (pulsed)
+sweep_button.on_click(on_sweep_button_clicked)
+cons_button.on_click(on_constant_button_clicked)
+
+#link buttons with functions
+set.on_click(on_set_button_clicked)
+reset.on_click(on_reset_button_clicked)
+full.on_click(on_full_button_clicked)
+new_folder.on_click(on_new_folder_button_clicked)
+retention_button.on_click(on_retention_button_clicked)
+contact_check.on_click(on_contact_check_clicked)
+qcc.on_click(on_qcc_clicked)
+
+import_ini_button.on_click(on_import_ini_clicked)
+export_ini_button.on_click(on_export_ini_clicked)
diff --git a/hp4155/memristor (Version 4.1)/memristor_buttons.ipynb b/hp4155/memristor (Version 4.1)/memristor_buttons.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..c9aa7e1d764af70e814dd3f28e2a6ef48ee6801e
--- /dev/null
+++ b/hp4155/memristor (Version 4.1)/memristor_buttons.ipynb	
@@ -0,0 +1,86 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "b913930d-b120-4e59-8a42-d9eecb526a61",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "04df3def923445eb95f28afa67430db0",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "HBox(children=(VBox(children=(Text(value='', description='sample series:', placeholder='Enter text here:', sty…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "0eeebb7ea7f64c97814087e1c195f32b",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Tab(children=(VBox(children=(HBox(children=(BoundedFloatText(value=0.01, description='Step(V):', step=0.01), D…"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "ff84a98e2896443cbf3470c994e9b383",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%run memristor.py"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1047e606-d5cb-420b-892f-766226339854",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.11.4"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/hp4155/memristor (Version 4.1)/schematic.png b/hp4155/memristor (Version 4.1)/schematic.png
new file mode 100644
index 0000000000000000000000000000000000000000..7a3a144bfd6c17374838b2d9222e57173fe2fcd8
Binary files /dev/null and b/hp4155/memristor (Version 4.1)/schematic.png differ