def __init__(self, testName, hasChannelData):
     self.Data = []
     self.columns = columns[testName]
     self.testName = testName
     self.hasChannelData = hasChannelData
     self.config = ReadConfig.GetMostRecentConfig(configFolder)
     self.params = ReadParams.GetMostRecentParams(paramsFolder)
def LatchTest(output, load, PowerUnitID):
    # Config params
    config = ReadConfig.GetMostRecentConfig('/home/its/Desktop/PB-production/PB-production/scripts/LargeScaleTest/QualificationConfig/')
    minrc = config["LatchTest_minrc"]		
    maxrc = config["LatchTest_maxrc"]		


    OpenFtdi() # Starts communication with RDO board

    ConfigurePowerADC(PowerUnitID) # To be able to read out voltages and currents
    ConfigureBiasADC(PowerUnitID) # To be able to read out voltages and currents

    passed = True

    # Recording states of channels before enabling them
    poweronStates   = GetPowerLatchStatus(PowerUnitID)
    poweronVoltages = ReadPowerChannelVoltages(PowerUnitID)
    poweronCurrents = ReadPowerChannelCurrents(PowerUnitID)

    ponBiasCurrent = 0.
    ponBiasVoltage = 0.
    ponCurrents = [0. for x in range(16)]
    ponVoltages = [0. for x in range(16)]
    for i in range(10):
        poweronBiasCurrent, poweronBiasVoltage = ReadBiasADC(PowerUnitID) 
        ponBiasCurrent  = ponBiasCurrent + poweronBiasCurrent 
        ponBiasVoltage  = ponBiasVoltage + poweronBiasVoltage
        ponCurrents = [x + y for x,y in zip(ponCurrents, ReadPowerChannelCurrents(PowerUnitID))]
        ponVoltages = [x + y for x,y in zip(ponVoltages, ReadPowerChannelVoltages(PowerUnitID))]
    ponCurrents.append(ponBiasCurrent)
    ponVoltages.append(ponBiasVoltage)
    ponCurrents = [('%.3f' % (x*100)) for x in ponCurrents]
    ponVoltages = [('%.4f' % (x*100)) for x in ponVoltages]
    # Check positive voltages at power on
    if any([float(x) > 10. for x in ponVoltages[0:16]]):
        print "Power on voltage for positive voltages is not ~0V"
        sys.exit()
    # Check positive currents at power on
    if any([(float(x) > 7. or x < -7.) for x in ponCurrents[0:16]]):
        print "Power on current for positive voltages is not ~0A"
        sys.exit()
    # Check negative regulator voltage at power on
    if (float(ponVoltages[16]) > -4500 or float(ponVoltages[16]) < -5000):
        print ponVoltages
        print "Power on voltage for negative voltage regulator is not ~-5V"
        sys.exit()
    # Check negative regulator current at power on
    if (float(ponCurrents[16]) > 70 or float(ponCurrents[16]) < 30):
        print ponCurrents[16]
        print "Power on current for negative voltage regulator is not ~50mA"
        sys.exit()

    lines = []
    lines.append(" ")
    lines.append("Power on Voltages and currents:")
    lines.append("Channel:              0      1      2      3      4      5      6      7      8      9     10     11     12     13     14     15     NREG")
    lines.append("Voltage (e-3) [V]: " + " ".join(str(x) for x in ponVoltages))
    lines.append("Current (e-3) [I]: " + " ".join(str(x) for x in ponCurrents))
    lines.append(" ")
    for line in lines:
        print line
        with open(output,"ab") as f:
	    f.write(str(line) + "\n")

    # Latching all channels and setting threshold to max value
    LowerThresholdsToMin(PowerUnitID) 
    time.sleep(1.)

    header = 'CH#   After PB powering  /  After Enabling  /  After Disabling  /  After Power not latched  /  After Power Latched  /  All checks passed?'
    with open(output,"ab") as f:
	f.write(str(header) + "\n")

    print " "
    print 'Printing state results:'
    print 'CH#   After PB powering  /  After Enabling  /  After Disabling  /  After Power not latched  /  After Power Latched  /  All checks passed?'

    # Setting Power voltages to midscale
    SetPowerVoltageAll(0xFF, PowerUnitID)

    # Loop over channels
    for channel in range(16):
        # Setting threshold low, enabling channel and setting threshold high after 10ms (short time)
        if (channel % 2):
            SetThreshold(channel, 0x370, PowerUnitID) # Lowering digital thresholds so the channels will latch at poweron (however threshold will be raised so it won't happen)
        else:
            SetThreshold(channel, 0x24E, PowerUnitID) # Lowering analog thresholds so the channels will latch at poweron (however threshold will be raised so it won't happen)
	time.sleep(0.010)  # Setting time of the threshold
        ListOfCommands = []
        LinkType       = IOExpanderPowerLink
        I2CAddress     = IOExpanderPowerAddress[channel/8]
        I2CData   = [0xFF & (1 << channel%8)]
        AppendWriteToDevice(ListOfCommands, I2CLink(PowerUnitID, LinkType), I2CAddress, *I2CData)
        AppendSleep(ListOfCommands, minrc * 1000) # 7 ms (10 ms RC is nominal, 8ms is -20%, taking 1ms lower margin)
        LinkType       = ThresPowerLink 
        I2CAddress     = ThresPowerAddress[channel/4]
        I2CData   = [0x3F, 0xFF, 0xF0]
        AppendWriteToDevice(ListOfCommands, I2CLink(PowerUnitID, LinkType), I2CAddress, *I2CData)
        SendPacket(ListOfCommands, [])
        time.sleep(0.05)
        afterPowerNotLatchedStates = GetPowerLatchStatus(PowerUnitID)
	time.sleep(0.12)  # ADC conversion time (15ms per ADC channel * # channels)
        afterPowerNotLatchedVoltages = ReadPowerChannelVoltages(PowerUnitID)

        # Setting threshold low, enabling channel and setting threshold high after 10ms (short time)
        if (channel % 2):
            SetThreshold(channel, 0x300, PowerUnitID) # Lowering digital thresholds so the channels will latch at poweron (however threshold will be raised so it won't happen)
        else:
            SetThreshold(channel, 0x200, PowerUnitID) # Lowering analog thresholds so the channels will latch at poweron (however threshold will be raised so it won't happen)
	time.sleep(0.010)  # Setting time of the threshold
        ListOfCommands = []
        LinkType       = IOExpanderPowerLink
        I2CAddress     = IOExpanderPowerAddress[channel/8]
        I2CData   = [0xFF & (1 << channel%8)]
        AppendWriteToDevice(ListOfCommands, I2CLink(PowerUnitID, LinkType), I2CAddress, *I2CData)
        AppendSleep(ListOfCommands, maxrc * 1000) # 13 ms (10 ms RC is nominal, 12ms is +20%, taking 1ms higher margin)
        LinkType       = ThresPowerLink 
        I2CAddress     = ThresPowerAddress[channel/4]
        I2CData   = [0x3F, 0xFF, 0xF0]
        AppendWriteToDevice(ListOfCommands, I2CLink(PowerUnitID, LinkType), I2CAddress, *I2CData)
        SendPacket(ListOfCommands, [])
        time.sleep(0.05)
        afterPowerLatchedStates = GetPowerLatchStatus(PowerUnitID)
	time.sleep(0.12)  # ADC conversion time (15ms per ADC channel * # channels)
        afterPowerLatchedVoltages = ReadPowerChannelVoltages(PowerUnitID)

        # Raising threshold to max, enabling channels and checking states and voltages
        SetThreshold(channel, 0xFFF, PowerUnitID)
	time.sleep(0.003)  # Setting time of the threshold
        UnlatchPower(channel, PowerUnitID) # Enable channel 
	time.sleep(0.001)  # Turn on time of the regulators (< 1ms)
        afterEnablingStates   = GetPowerLatchStatus(PowerUnitID) # Read status
	time.sleep(0.12) # Conversion time of the ADCs
        afterEnablingVoltages = ReadPowerChannelVoltages(PowerUnitID)
        # Disabling channels and checking states and voltages
        DisablePowerAll(PowerUnitID)
	time.sleep(0.001)  # Turn off time of the regulators
        afterDisablingStates = GetPowerLatchStatus(PowerUnitID) # Read status
	time.sleep(0.12) # Conversion time of the ADCs
        afterDisablingVoltages = ReadPowerChannelVoltages(PowerUnitID)
        if (poweronStates == 0 and afterPowerNotLatchedStates == (1 << channel) and afterPowerLatchedStates == 0 \
            and afterEnablingStates == (1 << channel) and afterDisablingStates == 0 \
            and not any([(voltage > 0.001) for voltage in poweronVoltages]) \
            and (afterPowerNotLatchedVoltages[channel] > 2.0) \
            and not any([(afterPowerNotLatchedVoltages[i] > 0.001) for i in range(len(afterPowerNotLatchedVoltages)) if i != channel]) \
            and not any([(voltage > 0.001) for voltage in afterPowerLatchedVoltages]) \
            and (afterEnablingVoltages[channel] > 2.0) \
            and not any([(afterEnablingVoltages[i] > 0.001) for i in range(len(afterEnablingVoltages)) if i != channel]) \
            and not any([(voltage > 0.001) for voltage in afterDisablingVoltages])):
            line = "%2d %10d %23d %18d %23d %24d %21s" %(channel, poweronStates, afterEnablingStates, afterDisablingStates, afterPowerNotLatchedStates, afterPowerLatchedStates, 'YES')
	else:
            line = "%2d %10d %23d %18d %23d %24d %21s" %(channel, poweronStates, afterEnablingStates, afterDisablingStates, afterPowerNotLatchedStates, afterPowerLatchedStates, 'NO')
            passed = False

	print line
        with open(output,"ab") as f:
            f.write(str(line) + "\n")
  
    print " "
    LowerThresholdsToMin(PowerUnitID) # To latch everything and erase whatever previous state
    RaiseThresholdsToMax(PowerUnitID)

    # Starting test of the bias circuitry
    print " "
    SetBiasVoltage(0x50, PowerUnitID)
    time.sleep(1.)
    poweronStates = 0xFF - int(GetBiasLatchStatus(PowerUnitID), 2)
    
    print 'Printing results:'
    print 'CH#   After PB powering  /  After Enabling  /  After Disabling  /                                                      All checks passed?'
    #DisableBiasAll(PowerUnitID)
    biasRes = {"Low": 1000., "Nominal": 1000., "High": 330.}
    offset = 0.
    for biasOutput in range(0, 3):
        idleCurrent, voltage = ReadBiasADC(PowerUnitID) 
        UnlatchBiasWithMask(0x7, PowerUnitID)
        time.sleep(0.1)  # Enable time
        afterEnablingThreeStates = 0xFF - int(GetBiasLatchStatus(PowerUnitID), 2)
        time.sleep(0.25) # ADC conversion time
        currentThree, voltageThree = ReadBiasADC(PowerUnitID) 
        if biasOutput == 0:
            offset = currentThree - abs(voltageThree)*(3./biasRes[load] + 1./100.)
        UnlatchBiasWithMask(0x7 - 2**biasOutput, PowerUnitID)
        time.sleep(0.1)  # Enable time
        afterEnablingStates = 0xFF - int(GetBiasLatchStatus(PowerUnitID), 2)
        time.sleep(0.25) # ADC conversion time
        current, voltage = ReadBiasADC(PowerUnitID) 
        DisableBiasAll(PowerUnitID)
        time.sleep(0.1)  # Enable time
        afterDisablingStates = 0xFF - int(GetBiasLatchStatus(PowerUnitID), 2)
        time.sleep(0.25) # ADC conversion time
        finalCurrent, finalVoltage = ReadBiasADC(PowerUnitID) 
        if not (poweronStates == 0 and afterEnablingThreeStates == 0x7 and afterEnablingStates == (0x7 - 2**biasOutput) and afterDisablingStates == 0):
            print "Bias channel states are wrong!"            
            line = "%2s %10d %23d %18d %70s" %("B" + str(biasOutput), poweronStates, 0x7 - afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        elif not (abs(finalCurrent - idleCurrent) < 0.0002 and voltage > -3.5 and voltage < -2.5):
            print abs(finalCurrent - idleCurrent), voltage
            print "Mismatch between idle current and current after all channel disable, or voltage not in the expected range"
            line = "%2s %10d %23d %18d %70s" %("B" + str(biasOutput), poweronStates, 0x7 - afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        elif not ((abs(abs(voltage)/(currentThree - current) - biasRes[load])/biasRes[load]) < 0.1):
            print "Measured load resistance does not match actual load"
            line = "%2s %10d %23d %18d %70s" %("B" + str(biasOutput), poweronStates, 0x7 - afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        else:
            line = "%2s %10d %23d %18d %70s" %("B" + str(biasOutput), poweronStates, 0x7 - afterEnablingStates, afterDisablingStates, 'YES')

	print line
        with open(output,"ab") as f:
            f.write(str(line) + "\n")

    SetBiasVoltage(0x80, PowerUnitID)
    time.sleep(1.)  # Wait before sampling

    idleCurrent, voltage = ReadBiasADC(PowerUnitID) 
    UnlatchBias(3, PowerUnitID)
    time.sleep(0.1)  # Enable time
    afterEnablingStates = 0xFF - int(GetBiasLatchStatus(PowerUnitID), 2)
    time.sleep(0.25) # ADC conversion time
    current, voltage = ReadBiasADC(PowerUnitID) 
    DisableBiasAll(PowerUnitID)
    time.sleep(0.1)  # Enable time
    afterDisablingStates = 0xFF - int(GetBiasLatchStatus(PowerUnitID), 2)
    time.sleep(0.25) # ADC conversion time
    finalCurrent, finalVoltage = ReadBiasADC(PowerUnitID) 
    currentLimit = current - offset
    if load == "Low":
        if not (poweronStates == 0 and afterEnablingStates == (1 << 3) and afterDisablingStates == 0):
            print "Bias channel states are wrong!"            
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        elif not ((currentLimit < 0.120 and currentLimit > 0.073) and (voltage < -1.5 and voltage > -2.5)):
            print "Current limit outside boundaries (73mA - 105mA) or voltage outside boundaries (-1.5, -2.5)"            
            print currentLimit, offset
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        elif not ((abs(finalCurrent - idleCurrent) < 0.0002) and ((abs(voltage)/currentLimit) - 28.)/28. < 0.1) :
            print "Mismatch between idle current and current after all channel disabled or wrong load measurement" 
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        else:
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'YES')
    else:
        if not (poweronStates == 0 and afterEnablingStates == (1 << 3) and afterDisablingStates == 0):
            print "Bias channel states are wrong!"            
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        elif not (abs(finalCurrent - idleCurrent) < 0.0002 and voltage < -4.5):
            print "Mismatch between idle current and current after all channel disable, or voltage is higher than -4.5V"
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        elif not ((abs(abs(voltage)/(current - idleCurrent) - biasRes[load])/biasRes[load]) < 0.1):
            print "Measured load resistance does not match actual load"
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'NO')
            passed = False
        else:
            line = "%2s %10d %23d %18d %70s" %("B3", poweronStates, afterEnablingStates, afterDisablingStates, 'YES')

    print line
    with open(output,"ab") as f:
        f.write(str(line) + "\n")

    if load == "Low":
        with open(output,"ab") as f:
            f.write(" " + "\n")
            f.write("Negative voltage regulator hardware current limit measured with Low current loads: %f\n" % currentLimit)


    CloseFtdi() # Ends communication with RDO board

    return passed
예제 #3
0
def PowerVoltageScan(output, load, PowerUnitID):
    # Config params
    config = ReadConfig.GetMostRecentConfig(
        '/home/its/Desktop/PB-production/PB-production/scripts/LargeScaleTest/QualificationConfig/'
    )
    step = config["PowerScan_Vstep"]
    start = config["PowerScan_start"]
    end = config["PowerScan_end"]
    Nsamples = config["PowerScan_nsamples"]

    header = "CH# Vset[DAC]   V[V]    dVRMS[mV] dVpp[mV]    I[A]  dIRMS[mA] dIpp[mA]   R[ohm]   T[C]   State                Timestamp"
    with open(output, "ab") as f:
        f.write(str(header) + "\n")

    OpenFtdi()  # Starts communication with RDO board

    ConfigureRTD(PowerUnitID)  # To monitor temperature on the power board

    # Setting threshold to max value
    LowerThresholdsToMin(
        PowerUnitID)  # To latch everything and erase whatever previous state
    RaiseThresholdsToMax(PowerUnitID)

    # Switching on the channels in sequence to avoid sensing issues on the TDK supply
    UnlatchPowerWithMask(PowerUnitID, 0x000F)
    time.sleep(0.2)
    UnlatchPowerWithMask(PowerUnitID, 0x00FF)
    time.sleep(0.2)
    UnlatchPowerWithMask(PowerUnitID, 0x0FFF)
    time.sleep(0.2)
    UnlatchPowerWithMask(PowerUnitID, 0xFFFF)
    time.sleep(0.2)

    # This is necessary to be able to read ADCs that read the power channels
    ConfigurePowerADC(PowerUnitID)

    #print "#ch Vset [DAC] V [V] VRMS [mV] dV[mV] I [A] IRMS [mA] dI [mA] R [ohm] T[C]"
    for voltage in range(start, end, -1 * step):  #loop over voltages
        print ' '
        print 'Setting voltage of all channels to %f [V]' % (voltage)
        SetPowerVoltageAll(voltage, PowerUnitID)
        time.sleep(0.5)
        LUstate = GetPowerLatchStatus(PowerUnitID)
        if LUstate == 0x00: break
        Imatrix = np.zeros((Nsamples, 16))
        Vmatrix = np.zeros((Nsamples, 16))

        for n in range(Nsamples):
            Itemp, Vtemp, I_ADC, V_ADC = ReadPowerADC(PowerUnitID)
            Imatrix[n] = Itemp
            Vmatrix[n] = Vtemp

        T = ReadRTD(PowerUnitID, 1)
        print "Printing results:"
        print "CH# Vset[DAC]   V[V]    dVRMS[mV] dVpp[mV]    I[A]  dIRMS[mA] dIpp[mA]   R[ohm]   T[C]   State                 Timestamp"
        for ch in range(16):  #loop over
            Ipoints = np.array([x[ch] for x in Imatrix])
            Vpoints = np.array([x[ch] for x in Vmatrix])
            Iread = Ipoints.mean()
            IRMS = 1000 * Ipoints.std()
            Vread = Vpoints.mean()
            VRMS = 1000 * Vpoints.std()
            DeltaI = 1000 * (Ipoints.max() - Ipoints.min())
            DeltaV = 1000 * (Vpoints.max() - Vpoints.min())
            rload = -666
            if (Iread > 0.): rload = Vread / Iread
            line = "%2d %7d %10.4f %8.1f %9.1f %10.4f %8.1f %6.1f %11.3f %6.1f %20s %24s" \
                   % (ch, voltage, Vread, VRMS, DeltaV, Iread, IRMS, DeltaI, rload, T, str(bin(LUstate)), str(datetime.now().strftime("%Y%m%dT%H%M%S%f")))
            print line
            with open(output, "ab") as f:
                f.write(str(line) + "\n")

    # Set the thresholds low to latch all unlatched channels (this should not be necessary if the board works properly), and then re-raise the thresholds for next test
    print ' '
    LowerThresholdsToMin(PowerUnitID)
    RaiseThresholdsToMax(PowerUnitID)

    CloseFtdi()  # Ends communication with RDO board
예제 #4
0
def BiasVoltageScan(output, load, PowerUnitID, testType="standard"):
    # Config params
    config = ReadConfig.GetMostRecentConfig(
        '/home/its/Desktop/PB-production/PB-production/scripts/LargeScaleTest/QualificationConfig/'
    )
    step = config["BiasScan_Vstep"]
    start = config["BiasScan_start"]
    end = config["BiasScan_end"]
    Nsamples = config["BiasScan_nsamples"]
    header = "Vset[DAC]   V[V]      dVRMS[mV]   dVpp[mV]   I[A]     dIRMS[mA]   dIpp[mA]   R[ohm]   T[C]     State      Timestamp"
    with open(output, "ab") as f:
        f.write(str(header) + "\n")

    # Starts communication with RDO board
    OpenFtdi()

    # To monitor temperature on the power board
    ConfigureRTD(PowerUnitID)

    print 'Setting Bias Voltage '
    SetBiasVoltage(0, PowerUnitID)
    biasMask = 0
    if (testType == "calibration"):
        biasMask = 0x0
    elif (load == "Low"):
        biasMask = 0x7
    elif (load == "High"):
        biasMask = 0x9
    else:
        biasMask = 0xF
    UnlatchBiasWithMask(biasMask, PowerUnitID)

    ConfigureBiasADC(PowerUnitID)  # this is necessary to be able to read ADCs
    time.sleep(0.2)
    print " "
    print "Scanning voltages and printing results:"
    print "Vset[DAC]   V[V]      dVRMS[mV]   dVpp[mV]   I[A]     dIRMS[mA]   dIpp[mA]   R[ohm]   T[C]     State      Timestamp"
    for voltage in range(start, end, -1 * step):
        SetBiasVoltage(voltage, PowerUnitID)
        time.sleep(0.2)

        Ipoints = np.array([])
        Vpoints = np.array([])
        for n in range(Nsamples):
            Itemp, Vtemp = ReadBiasADC(
                PowerUnitID
            )  #read current and voltage from ADCs (before setting new threshold)
            Ipoints = np.append(Ipoints, Itemp)
            Vpoints = np.append(Vpoints, Vtemp)

        Iread = Ipoints.mean()
        IRMS = 1000 * Ipoints.std()
        Vread = Vpoints.mean()
        VRMS = 1000 * Vpoints.std()
        DeltaI = 1000 * (Ipoints.max() - Ipoints.min())
        DeltaV = 1000 * (Vpoints.max() - Vpoints.min())
        rload = -1
        if (Iread > 0.): rload = Vread / Iread

        T = ReadRTD(PowerUnitID, 1)
        state = bin(0xFF -
                    int(GetBiasLatchStatus(PowerUnitID),
                        2))  # bitwise not because all bits are active low
        line = "%5d %12.4f %9.2f %11.2f %11.6f %9.3f %9.3f %9.3f %9.3f %9s %24s" \
               % (voltage, Vread, VRMS, DeltaV, Iread, IRMS, DeltaI, abs(rload), T, state, str(datetime.now().strftime("%Y%m%dT%H%M%S%f")))
        print line

        with open(output, "ab") as f:
            f.write(str(line) + "\n")

    print ' '
    DisableBiasAll(PowerUnitID)

    # Ends communication with RDO board
    CloseFtdi()
def ThresholdScan(output, Vset, PowerUnitID):
    # Config params
    config = ReadConfig.GetMostRecentConfig('/home/its/Desktop/PB-production/PB-production/scripts/LargeScaleTest/QualificationConfig/')
    step  = config["ThresholdScan_Thstep"]
    start = config["ThresholdScan_start"]
    end   = config["ThresholdScan_end"]
    voltages  = config["ThresholdScan_Vpoints"]

    header = "CH# Threshold[DAC] Vset[DAC]     V[V]     I[A]     R[ohm]     T[C]           LUstate          Timestamp"
    with open(output,"ab") as f:
        f.write(str(header) + "\n")

    OpenFtdi() # Starts communication with RDO board

    # To monitor temperature on the power board
    ConfigureRTD(PowerUnitID) 
    # This is necessary to be able to read ADCs 
    ConfigurePowerADC(PowerUnitID) 

    for Vset in voltages:
	    # Setting voltage of all positive voltage channels
	    SetPowerVoltageAll(Vset, PowerUnitID)

	    # Setting threshold to max value
	    LowerThresholdsToMin(PowerUnitID)
	    RaiseThresholdsToMax(PowerUnitID)
	    
	    # Switching on the channels in sequence to avoid sensing issues on the TDK supply
	    UnlatchPowerWithMask(PowerUnitID, 0x000F)
	    time.sleep(0.2)
	    UnlatchPowerWithMask(PowerUnitID, 0x00FF)
	    time.sleep(0.2)
	    UnlatchPowerWithMask(PowerUnitID, 0x0FFF)
	    time.sleep(0.2)
	    UnlatchPowerWithMask(PowerUnitID, 0xFFFF)
	    time.sleep(1)  

	    LUstate = 0          
	    print " "
	    print 'Threshold scan loop. Vset set to ' + str(Vset)
	    print "Printing results:"
	    #print "CH# Th[DAC] Vset[DAC] V[V] I[A]  R[ohm] T[C]"

	    flags = np.ones(16)
	    ListOfCommands       = []
	    DataBuffer           = []
	    ThresholdData        = [] # Contains all databytes read during the scan (encoded)
	    DecodedThresholdData = [] # Contains the state of the channels vs the various threshold settings

            ifloat = [0. for i in xrange(16)]
            vfloat = [0. for i in xrange(16)]
            for i in range(10):
                ifl, vfl, idi, vd = ReadPowerADC(PowerUnitID)
                ifloat = [ifloat[i] + ifl[i] for i in xrange(len(ifl))]
                vfloat = [vfloat[i] + vfl[i] for i in xrange(len(vfl))]
            ifloat = [ifloat[i]/10. for i in xrange(len(ifloat))]
            vfloat = [vfloat[i]/10. for i in xrange(len(vfloat))]
            
	    # Scan thresholds and check when channels latch
            thresholdList = []
	    for j in range (0, 4096, step):
		LinkType  = ThresPowerLink
		threshold = (4095 - j)
                if (j % 64 == 0) or IsNearThreshold(threshold, ifloat[0]) or IsNearThreshold(threshold, ifloat[1]):
                    thresholdList.append(threshold)
                else:
                    continue
                    
		I2CData   = [0x3F, threshold/16, (threshold%16)<<4]
		## Set thresholds
		for I2CAddress in ThresPowerAddress: 
		    AppendWriteToDevice(ListOfCommands, I2CLink(PowerUnitID, LinkType), I2CAddress, *I2CData)
		AppendSleep(ListOfCommands, 20000) # 100 ms sleep default
		## Get channels status
		for I2CAddress in IOExpanderPowerAddress:
		    LinkType     = IOExpanderPowerLink
		    AppendReadFromDevice(ListOfCommands, DataBuffer, I2CLink(PowerUnitID, LinkType), I2CAddress, 1)    

		if (j % 250 == 0 and j != 0):
		    SendPacket(ListOfCommands, DataBuffer)
		    ThresholdData.extend(DataBuffer)
		    DataBuffer     = [] 
		    ListOfCommands = []

	    # Sending last commands and collecting data
	    SendPacket(ListOfCommands, DataBuffer)
	    ThresholdData.extend(DataBuffer)
	    
	    # Reformatting data
	    LUstatus = 0
	   
	    # Decoding channel state
	    for i in range (0, len(ThresholdData)):
		if (i%6 == 1 or i%6 == 4):
		    if i%6 == 4:
			LUstatus = LUstatus | (ThresholdData[i] << 8)
			DecodedThresholdData.append(LUstatus & 0xFFFF)
			LUstatus = 0
		    else:
			LUstatus = ThresholdData[i]

	    Rload = [0. for i in xrange(16)]
	    for channel in range(0,16):
		itrigger = -666
		lastLUstate = -999
		for i in range(len(thresholdList)):
		    LUstate = DecodedThresholdData[i]
		    if (not (int(LUstate) & 2**channel)):
			print 'Channel %i latched at threshold %i' %(channel, thresholdList[i])
			itrigger = thresholdList[i]
			lastLUstate = LUstate
			break

		Rload[channel] = vfloat[channel]/ifloat[channel]

		T = ReadRTD(PowerUnitID, 1)
                line = "%2d %10d %9d %13.4f %9.4f %8.4f %10.4f %022s %24s" \
                       % (channel, itrigger, Vset, vfloat[channel], ifloat[channel], Rload[channel], T, format(int(LUstate), '#016b'), str(datetime.now().strftime("%Y%m%dT%H%M%S%f")))
                with open(output,"ab") as f:
		    f.write(str(line) + "\n")
	    
    print " "
    # Making sure that channels are latched
    LowerThresholdsToMin(PowerUnitID)

    # Ends communication with RDO board
    CloseFtdi()