def retrieveVariables(self):
        self.systemControllerProfilometerRoutineStart = profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStart)
        profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStart,False)

        self.systemControllerProfilometerRoutineRunning = profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning)
        self.systemControllerProfilometerRoutineDirection = profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineDirection)
        self.systemControllerProfilometerRoutineStepSize = profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStepSize)
        self.systemControllerProfilometerRoutineTravelDirection = profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineTravelDistance)
 def run(self):
     # Initializes the data and equipment
     self.initializeData()
     self.initializeEquipment()
     self.retrieveVariables()
     while (True):
         # if self.systemControllerProfilometerRoutineStart: # True - start profilometer routine # Commented out to see if we can skip getVaraibles
         if profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStart): # True - start profilometer routine
             # self.profilometerRoutine(self.systemControllerProfilometerRoutineDirection,self.systemControllerProfilometerRoutineTravelDirection,self.systemControllerProfilometerRoutineStepSize)
             self.profilometerRoutine(profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineDirection), profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineTravelDistance), profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStepSize))
    def buttonClickedStartStop(self):

        ## If statement that cycles through the start/stop functionality of the button
        # First if statement that checks for routine running = True and then stops the run
        if profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning) == True:
            # Update the profilometer routine running to False when start/stop button clicked
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning,False)
            self.updateMovementButtonsState(True)
            # Updates the start/stop button to green and start
            self.buttonStartStop.setText('Start')
            self.buttonStartStop.setStyleSheet('background-color: green;border:0px;border-radius:10')
            print('Profilometer Routine Stopped')

        # Else if statement that checks for routine running = False and then starts the run
        elif profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning) == False:
            # Updates the profilometer routine running to True when start/stop button clicked
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning,True)
            # Updates the profilometer start flag to True when start/stop button clicked
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStart,True)
            # Updates the profilometer routine direction based on the radio button selected
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineDirection,self.retrieveProfilometerRoutineDirection())
            # Updates the profilometer routine step size based on the value entered into the entry box
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStepSize,self.entryBoxStepSize.text())
            # Updates the profilometer routine travel distance based on the value entered into the entry box
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineTravelDistance,self.entryBoxTravelDistance.text())
            self.updateMovementButtonsState(False)
            # Updates the start/stop button to red and stop
            self.buttonStartStop.setText('STOP')
            self.buttonStartStop.setStyleSheet('background-color: red;border:0px;border-radius:10')
            print('Profilometer Routine Started')

            ## Routine to test realtime plotting
            # Runs a while loop that checks to see if the routine is running
            while profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning):
                # Asks the GUI to process any events manually
                QtGui.QApplication.processEvents()

                try:
                    # If statement that checks to see if a new data point has been added
                    if profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_newDataPoint):
                        # Calls the plot data routine
                        self.buttonClickedPlotData()
                        # print('plot')

                        # Acquires the data thread lock
                        profilometerParameters.dataThreadLock.acquire()
                        # print('dataThreadLock acquired (UI)')
                        # Sets the new data point to false
                        profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_newDataPoint,False)
                        # Releases the data thread lock
                        profilometerParameters.dataThreadLock.release()
                        # print('dataThreadLock released (UI)')
                except:
                    pass
    def retrieveData(self):
        # Creates lists that will be appended to with the desired data
        _dataDirection_X = []
        _dataDirection_Y = []
        _dataDirection_Z = []
        _dataVolts = []
        _dataHeight = []

        # # Generates fake data for testing
        # profilometerParameters.clearDataStorageInstances()
        # for i in range(75):
        #     profilometerDataClass.profilometerData(i*1.0,i*1.0,i*1.0,math.sin(i/math.pi*180/100)*math.exp(i/100))

        # Loops through each data class instance and appends the data to the lists
        # Also pulls out the data to return
        for _dataSet in profilometerParameters.retrieveDataStorageInstances():
            _dataDirection_X.append(_dataSet.x)
            _dataDirection_Y.append(_dataSet.y)
            _dataDirection_Z.append(_dataSet.z)
            _dataVolts.append(_dataSet.volts)
            #Calculates the height of the sample by multiplying it by the correction factor
            _dataHeight.append(_dataSet.volts * profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_calibrationRatio))

        # Returns the direction and volts data
        return _dataDirection_X, _dataDirection_Y, _dataDirection_Z, _dataVolts, _dataHeight
    def retrieveVoltage(self):
        # profilometerParameters.agilent34461a.query("DIAG:REMOTE")

        # Sets a sample size
        multimeterReadingsSampleSize = 1
        # Sets a varaible that will hold the total value of all multimeter readings for finding the average
        multimeterReadingsTotals = 0.0
        for i in range(multimeterReadingsSampleSize):
            # Checks to see if the profilometer routine has been manually stopped by the user
            if not profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning):
                # Returns the multimeter back to local so that the display updates
                # profilometerParameters.agilent34461a.query("DIAG:LOCAL")
                break
            # Takes the running total and adds the current reading
            multimeterReadingsTotals = multimeterReadingsTotals + float(profilometerParameters.agilent34461a.query("MEASure:VOLTage:DC?"))

        # Finds the average multimeter reading
        multimeterReadingsAverage = multimeterReadingsTotals/multimeterReadingsSampleSize

        # Returns the multimeter back to local so that the display updates
        # profilometerParameters.agilent34461a.query("DIAG:LOCAL") # Command does not work for this device (no known command)
        return multimeterReadingsAverage
    def profilometerRoutine(self, direction, travelDistance, stepSize):
        # Converts the travel distance and step size to a float
        travelDistance = float(travelDistance)
        stepSize = float(stepSize)

        # Changes profilometer start to false so that the routine only runs once
        profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineStart,False)

        # Clears the data from any previous runs
        profilometerParameters.clearDataStorageInstances()

        # Creates an instance of the stages
        _stagesInstance = profilometerXYZStages.XYZStages()
        _stagesInstance.XYZStagesInitialize()

        # If statement that checks to make sure a valid direction has been entered and changes direction to
        # a value recognized by the stages class
        if direction == 'X':
            _movementDirection = _stagesInstance.positioner_X

        elif direction == 'Y':
            _movementDirection = _stagesInstance.positioner_Y

        else:
            print('Please select a direction')
            return

        # If statement that checks the sign of the travel distance
        if travelDistance < 0:
            stepSize = -stepSize

        i = 0
        # While loop that starts at 0 and moves the stage by step size until travel distance has been reached
        # Flow is: Scan > Move > Iterate - This allows us to scan the first and last points
        while i <= abs(float(travelDistance)):
            # Checks to see if the user clicked the stop button mid print and stops the print if so
            if not profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning):
                _stagesInstance.moveStageAbort()
                print('MID PRINTING STOP')
                break

            # Gets a data reading from the multimeter
            multimeterData = self.Agilent34461a.retrieveVoltage()
            # Gets the current x,y,z stage locations
            [x,y,z] = _stagesInstance.retrieveStagePostion()

            # Creates an instance of the data class with the current data
            profilometerDataClass.profilometerData(x,y,z,multimeterData)

            # Acquires the data thread lock
            profilometerParameters.dataThreadLock.acquire()
            # print('dataThreadLock acquired (SC)')
            # Updates the new data point to true
            profilometerParameters.updateDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_newDataPoint,True)
            # Releases the data thread lock
            profilometerParameters.dataThreadLock.release()
            # print('dataThreadLock released (SC)')

            # Moves the stages by creating a stage thread and then running that thread for the movement amount and direction
            _stagesInstanceThread = threading.Thread(target=_stagesInstance.moveStageRelative,args=(_movementDirection,[stepSize/1000]))
            _stagesInstanceThread.start()

            # For loop that runs during the stage movement and aborts the movement if the user clicks the stop button
            motionStatus = _stagesInstance.checkMotionStatus()

            while (motionStatus != 0):
                motionStatus = _stagesInstance.checkMotionStatus()
                # Checks to see if the user has clicked the stop button and aborts the stage movement if they have
                if not profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_routineRunning):
                    _stagesInstance.moveStageAbort()
                    print('MID PRINTING STOP')
                    break

            # Increases i by the step size for the next iteration
            i = i + abs(stepSize)/1000

        print('Profilometer Routine Complete')
    def buttonClickedSaveData(self):
        # While loop that checks for widgets within the plot layout and then deletes them
        # This is used to clear the plot each time a new plot is added to the plot layout
        while self.layoutPlot.count() > 0:
            item = self.layoutPlot.takeAt(0)
            if not item:
                continue
            w = item.widget()
            if w:
                w.deleteLater()

        # Retrieves the direction and millivolts data from the system controller
        [data_X, data_Y, data_Z, data_volts, data_height] = self.systemController.retrieveData()

        # Checks to see if the desired default path doesn't exists on the machine
        if not os.path.exists(profilometerParameters.profilometerDefaultSavePath):
            # Tries to create the desired default path if it doesn't exist
            try:
                os.makedirs(profilometerParameters.profilometerDefaultSavePath)
            except:
                pass

        # Opens a save as dialog directed towards the users' Documents/Data/Profilometer folder
        _saveFileName, saveButtonClicked = QtGui.QFileDialog.getSaveFileNameAndFilter(self, "Save Profilometer Data", os.path.expanduser('~/Documents/Data/Profilometer'))

        # If the user clicks the save button the data is saved as a csv
        if saveButtonClicked:
            # Opens the CSV file to save the data too
            _dataFile = open(str(_saveFileName) + '.csv','wt')

            # Creates a writer that will write the data to the csv file
            _dataWriter = csv.writer(_dataFile)

            # Finds the number of blocks that the user has entered (new block when user hits enter)
            numberOfBlocks = self.entryBoxHeader.blockCount()
            # Runs through each block and saves it as a new row in the CSV file
            for block in range(numberOfBlocks):
                _dataWriter.writerow(('# ' + str(self.entryBoxHeader.document().findBlockByNumber(block).text()),'')) # '' is needed to keep each line together

            # Includes the calibration ratio used below the header data
            _dataWriter.writerow(('# Calibration ratio used: ' + str(profilometerParameters.retrieveDictionaryParameter(profilometerParameters.kHNSystemControllerProfilometer_calibrationRatio)),''))

            # Includes the direction of the scan
            _dataWriter.writerow(('# Scan direction: ' + str(self.retrieveProfilometerRoutineDirection())))

            # Includes the date and time of the save
            _dataWriter.writerow(('Date and time: ' + str(datetime.datetime.now()),''))

            # Writes the column headers into the file
            _dataWriter.writerow(('X','Y','Z','Volts','Height (mm)'))

            # Loops through each element of the data lists and writes them to a row in the csv
            for i in range(len(data_X)):
                _dataWriter.writerow((data_X[i],data_Y[i],data_Z[i],data_volts[i],data_height[i]))

            # Closes the data file
            _dataFile.close()
        # If the cancel button is clicked nothing happens for now
        else:
            pass

        # Displays the plot of the data that was also saved
        graphicsLayoutWidget = pg.GraphicsLayoutWidget()
        graphicsLayout = pg.GraphicsLayout(border=(100,100,100))
        graphicsLayoutWidget.addItem(graphicsLayout)
        plot1 = graphicsLayout.addPlot(title='Profile')
        plot1.plot(x = data_X, y = data_height)
        plot1.setLabel('bottom','Distance (mm)')
        plot1.setLabel('left','Height (mm)')
        # plot1.setXRange(0,(float(self.entryBoxTravelDistance.text()) + 2.0))
        # plot1.setYRange(-1.0,1.0)
        plot1.showGrid(True, True, 0.75)
        self.layoutPlot.addWidget(graphicsLayoutWidget)