
'''
RDEC7-Test
'''
import time
import pyvisa as visa
import matplotlib.pyplot as plt


def OpenDevices(Rdec7Res, DmmRes):
  rm = ""
  Dmm = None
  Rdec7 = visa.ResourceManager(rm).open_resource(Rdec7Res)
  print(Rdec7.query("*idn?"))
  if DmmRes:
    while True:
      try:
        Dmm = visa.ResourceManager(rm).open_resource(DmmRes)
        Dmm.write("*cls")
        print(Dmm.query("*idn?"))
      except Exception:
        time.sleep(5)
        continue
      break
  return Rdec7, Dmm    


###########################

def QueryErrors(DUT, Dmm):
  err = DUT.query("syst:err:all?").strip()
  if int(err.replace('"', "").split(",")[0]):
    print(f"DUT: {err}")
  if Dmm:
    err = Dmm.query("syst:err?").strip()
    if int(err.replace('"', "").split(",")[0]):
      print(f"Dmm: {err}")

###########################

def Measure(Dmm):
  rmeas = 0    
  while(True):
    time.sleep(0.1)
    rmeas0 = float(Dmm.query("READ?"))
    time.sleep(0.1)
    rmeas = float(Dmm.query("READ?"))
    if abs(rmeas-rmeas0) / rmeas < 0.001:
      break

  return rmeas

###########################
def InitDmm(Dmm):
  Dmm.query("*RST;*OPC?")
  Dmm.write("CONF:FRES auto")

###########################

def TestDeviation(Rdec7Res, DmmRes):

  fromRset = False

  Rdec7, Dmm = OpenDevices(Rdec7Res, DmmRes)
  Rdec7.query("*RST;*OPC?")

  #Rdec7.write("ADJ:stage:cal:enable OFF")

  stagecal = int(Rdec7.query("ADJ:stage:cal?"))
  stagecalenable = int(Rdec7.query("ADJ:stage:cal:enable?"))
  usestagecal = "ON" if (stagecal and stagecalenable) else "OFF"

  print(f"Using stage calibration: {usestagecal}")

  InitDmm(Dmm)

  QueryErrors(Rdec7, Dmm)

  rstart= 0.1
  rstop= 1e7

  limitpercent = 0.1
  limitabsres = 0.06 if fromRset else 0.01 # ohm
  
  deviationpercent = []
  rRefvalues = []
  limitvalues = []
  ok = True
  granularity = 10
  rset = rstart
  muststop = False
  while (True):
    if rset < 1:
      rstep = 0.1
    elif rset < 50:
      rstep = 0.1 * granularity
    elif rset < 500:
      rstep = 1 * granularity
    elif rset < 5e3:
      rstep = 10*granularity
    elif rset < 5e4:
      rstep = 1e2*granularity
    elif rset < 5e5:
      rstep = 1e3*granularity
    elif rset < 5e6:
      rstep = 1e4*granularity
    else:
      rstep = 1e5*granularity
      
    Rdec7.query(f"SOUR:RES {rset};*OPC?")
    ract = float(Rdec7.query("SOUR:RES:ACT?"))


    time.sleep(0.3)
    rRef = rset if fromRset else ract
    rRefvalues.append(rRef)

    limitabs = limitabsres + limitpercent / 100 * rRef
    limitpct = 100*limitabs / rRef
    limitvalues.append(limitpct)

    for r in range(3):
      rmeas = Measure(Dmm)
      devabs = abs(rmeas - rRef)
      devperc = devabs / rRef * 100

      if r < 2 and devperc > limitpct:
        print("#", end = "")
        continue

      if rset < 1000:
        print(f"Rset: {rset:6.2f} , Ract: {ract:6.2f} , Rmeas: {rmeas:7.3f} ,   Dev: {devabs:7.3f} Ohm, {devperc:7.3f} %", end="")
      elif rset < 1e6:
        print(f"Rset: {rset/1e3:6.2f}k, Ract: {ract/1e3:6.2f}k, Rmeas: {rmeas/1e3:7.3f}k,   Dev: {devabs:7.3f} Ohm, {devperc:7.3f} %", end="")
      else:
        print(f"Rset: {rset/1e6:6.2f}M, Ract: {ract/1e6:6.2f}M, Rmeas: {rmeas/1e6:7.3f}M,   Dev: {devabs:7.3f} Ohm, {devperc:7.3f} %", end="")
      break

    if devperc > limitpct:
      print (" !!FAIL!!")
      ok = False
    else:
      print()


    deviationpercent.append(devperc)
    if muststop:
      break

    rset += rstep
    if rset >= rstop:
      rset = rstop
      muststop = True

  if ok:
    print("Pass\n")
  else:
    print("FAIL\n")  

  QueryErrors(Rdec7, Dmm)

  if fromRset:
    plt.title('Deviation from set value')
  else:
    plt.title('Deviation from indicated value')
    
  plt.xscale('log')
  plt.yscale('log')
  plt.xlabel('Ohm')
  plt.ylabel ('%')
  plt.plot(rRefvalues, deviationpercent, label='Deviation')
  plt.plot(rRefvalues, limitvalues, label= f"{limitabsres} Ohm+{limitpercent}%")
  plt.legend(loc='upper right', borderaxespad=0.)
  plt.show()

  Rdec7.close()
  Dmm.close()

####################################

def AdjustStageResistances(Rdec7Res, DmmRes):
 
  Rdec7, Dmm = OpenDevices(Rdec7Res, DmmRes)
  Rdec7.query("*RST;*OPC?")
  InitDmm(Dmm)
  QueryErrors(Rdec7, Dmm)

  print("Adjusting short loop")
# bypass = ON
  for stage in range(10):
    Rdec7.query(f"SOUR:RES:STAGe ON,{stage};*OPC?")
    time.sleep(0.6)
    rmeas = Measure(Dmm)
    print (f"{stage:5d}  {rmeas:7.3f} Ohm")
    Rdec7.write(f"ADJ:STAGE:RES ON,{stage},{rmeas}")

  
  print("Adjusting long loop")
# bypass = OFF
  adjstagecount = int(Rdec7.query("ADJustment:STAGe:COUNt?"))
  for stage in range(adjstagecount):
    Rdec7.query(f"SOUR:RES:STAGe OFF,{stage};*OPC?")
    time.sleep(0.6)
    rmeas = Measure(Dmm)
    print (f"{stage:5d}  {rmeas:7.3f} Ohm")
    Rdec7.write(f"ADJ:STAGE:RES OFF,{stage},{rmeas}")

  Rdec7.write("ADJ:SAVE")

  Rdec7.close()
  Dmm.close()

####################################

####################################


if __name__ == "__main__":

  Rdec7Res = "USB0::0x16D0::0x1356::895909::INSTR"
  DmmRes = "USB0::0xF4EC::0x1201::SDM35HBD904312::INSTR"

#AdjustStageResistances(Rdec7Res, DmmRes)
TestDeviation(Rdec7Res, DmmRes)





