# -*- coding: utf-8 -*-
"""
Created on Wed Dec 13 13:40:47 2017
Base VISA driver
@author: mbuel
"""

import visa
import time
 
# StartVoltage = 10
global rm
rm = visa.ResourceManager()
global rmList
rmList = rm.list_resources()

#Find all VISA resources
#Private - completed by class
#def _GetResourceList():
#    global rmList
#    try:
#        #raise Exception('Test Resource fault') #used for test purposes
#        rmList = rm.list_resources()
#        return rmList
#    except:
#        return rmList
    
# Used for Fluke45 (possibly 8845A) should probably be moved to that object
# In process of deprecating   
#def __SerialReadLoop(resource, termChar):
#    returnString = ""
#    while (termChar not in returnString):
#        returnString += resource.read()
#    return returnString

#generic reader
#resource - VISA resource being written/read from
#command - only required if you are iterating - command to send to resource
#iterations=1 - if not sent, one measurement is taken and sent back (single)
#iteration > 1 - if set to greater than 1, it will return an array of data points
#prompt="" - default, don't look or wait for prompt
#prompt="=>" - if set, it writes to the resource, then waits for the prompt
#return data - for single point
#return dataSet - for array of points
def ReadData(resource, command="", iterations=1, prompt=""):
    '''Generic visa reader function.
    resource: VISA resource being read from instrument.
    command: required only if iterations (looped measurement).
    iterations: defaults to 1, if more than 1 command is required.
    prompt: required with certain instruments to stop read loop.'''
    try:
            
        data = ""
        dataSet = []
    #    print ("Before Counter")
    #    print ("iterations: " + str(iterations))
    #    print ("Command: " + command)
        if iterations > 1 and len(command)>1:
            
            while (iterations >= 1):
        #        print ("Inside for loop")
                WriteData(resource, command)
                if len(prompt)>1:
                    #WriteData(resource, command)
                    while prompt not in data:
                        WriteData(resource,command)
                        data += resource.read()
                    data = data.split("/r/n")[1]
                else:
                    WriteData(resource, command)
                    data = resource.read()
                dataSet.append(data)
                iterations = iterations - 1
        else:
            if len(prompt)>1:
            #WriteData(resource, command)
                data += resource.read()
                data = data.split("/r/n")[1]
            else:
                data = resource.read()
            dataSet.append(data)
                
    #        print data
        
    except:
        dataSet = None
        #VISA TIMEOUT ERROR

    return dataSet

#generic writer
#resource - VISA resource being written to
#command - command to write to VISA port
#no return        
def WriteData(resource, command):
    '''Generic VISA writer.
    resource: VISA resource.
    command: command to send.'''
    try:
        resource.write(command)
        time.sleep(0.2)
    except:
        print("Unable to write to specified resource.")
    
# Used to connect to resource from global filtering on instrument identifier
# instIdentifier - string to compare to device output, makes sure you are grabbing the correct resource
# command - command sent to device to return data
# instFilter - is used to make sure you don't connect to the same instrument twice. Used for Dmm1, Dmm2 most frequently
# prompt - if the device communicates slower, using this to loop until prompt is received can make sure correct data is returned.
# test coverage completed
# returns resource that is used to connect to the device       
def GetInstrument(instIdentifier, command, instFilter="Z", prompt=""):
    '''Used to connect to resource from global rmList defined.
    instIdentifier: Instrument string to filter on.
    command: command to query instrument with.
    instFilter: defaults to "Z" to skip, if you have two of the same types of isntruments this is used.
    prompt: used to end readLoop on older instruments.'''
    global rmList
    resource = None
    if instIdentifier == "" or command == "":
        print("Cannot continue without proper instIdentifier or iDcommand")
        return resource
    else:
        for resource in rmList:
            #print (resource)
            
            instString = ""        
            try:
                newResource = OpenInstrument(resource)
                if ("ASRL" not in resource):
                    WriteData(newResource, command)
                    instString = ReadData(newResource)
                else:
                    if prompt is not "":
                        WriteData(newResource, command)
                        instString = ReadData(newResource, 1, prompt)
    
                print instString
                if instIdentifier in str(instString[0]):
                    if str(instFilter) in str(newResource ):
                        continue
                    else:
                        return resource
                        
            except Exception as e:
                #Handle error?
                print ("exception: " + str(e))
                resource = ""
            finally:
                CloseInstrument(resource)
    print resource
    return resource
    

def OpenInstrument(resource):
    '''Open VISA resource.'''
    internalResource = ""
    if str(resource) is not "":
        
        internalResource = rm.open_resource(resource, send_end=True)
        internalResource.write_termination = '\r\n'
        
#        if "ASRL" in resource:
#            internalResource = rm.open_resource(resource, send_end=True)
#            internalResource.write_termination = '\r'
#        else:
#            internalResource = rm.open_resource(resource, send_end=False)
        return internalResource
    else:
        return internalResource


def CloseInstrument(resource):
    '''CloseInstrument - closes the VISA resource'''
    try:
        if "Instrument" in str(resource):
            rm.close
            return True
        else:
            return False
    except:
        return False

#TEST FUNCTIONS
#Error handler returns false, if IDN fails for any reason
#May Deprecate this function        
def VerifyInstrument(resource, command):
    '''VerifyInstrument - verifies communications on VISA resource.'''
    try:
        #print (Instrument)
        #print (Instrument.query("*IDN?"))
        return len(resource.query(command)) > 0
    except:
        return False

#Used for internal system testing
def InternalTest():
    '''Used for internal system testing.'''

    if (True):
        PowerSupplyResource = GetInstrument("SPD","*IDN?")
        print PowerSupplyResource
        PowerSupply = OpenInstrument(PowerSupplyResource)
        #if (VerifyInstrument(PowerSupply)):
        #    print(PowerSupply.query_ascii_values('*IDN?'))
        #    PowerSupply ("INST CH1")   #Select on Ch 1
        #    SetVoltage = "CH1:VOLT %f" %StartVoltage
        
        Dmm1Resource = GetInstrument("DM3R","*IDN?")
#        print(Dmm1Resource)
        Dmm1 = OpenInstrument(Dmm1Resource)
        #if (VerifyInstrument(Dmm1)):
            #Dmm1.query(':measure:voltage:dc:measure:auto;')
            #time.sleep(0.2)
            #print(Dmm1.read())
        
        Dmm2Resource = GetInstrument("DM3R","*IDN?", Dmm1)
#       print(Dmm2Resource)
        
        
        
        #print (str(PowerSupply))

        SetVoltage = "CH1:VOLT 15.0"
        SetCurrent = "CH1:CURRENT 0.2"
        #print(PowerSupply)
        try:
#            print(PowerSupply)
            WriteData(PowerSupply, SetVoltage)
            #time.sleep(0.2)
            print("Wrote Supply Voltage.") #debug line
            
            WriteData(PowerSupply, SetCurrent)
            #time.sleep(0.2)
            print("Wrote Supply Current.") #debug line
            
            EnableSupply = "OUTPUT CH1,ON"
            WriteData(PowerSupply, EnableSupply)  #Turn on Ch1
            #time.sleep(0.2)    
            WriteData(PowerSupply,"*IDN?")
            print(ReadData(PowerSupply))
            CloseInstrument(PowerSupply)
        except:
            print("Problem with Power Supply.")
        ##
        #PowerSupply.write(SetVoltage)   #Set voltage to 'SetVoltage'
        #PowerSupply.write("*IDN?")
        #print(PowerSupply.readline())
        #PowerSupply.write("MEAS:VOLT? CH1")
        ##print(PowerSupply. ())
        #print(CloseInstrumentResource(PowerSupply))
        #
        #
        print Dmm1
        #Dmm1.write_termination = '\r'
        #Dmm1.write("MEAS?")
        #print (SerialReadLoop(Dmm1,"=>"))
       #CloseInstrument(Dmm1)
    else:
        print("cannot capture list of resources.")
    #print (CloseInstrumentResource(Dmm1))
        
#initialize the class
#_GetResourceList()

    
#InternalTest()