diff --git a/README.md b/README.md
index 23ec5e0a9d302f8159fd7b5fadf5bc64cd5faf19..8d3049d04c269813aeaaec2c14ac75a224bba56a 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 # PyPCC
 Python OPC-UA server to control the I2C devices in the LTS. 
 
-+ opcuserv.py: OPC-UA server that expose (visible) variables and methods.
++ pypcc2.py: OPC-UA server that expose (visible) variables and methods.
 
 # Prerequisites
 
@@ -34,7 +34,7 @@ python3 -m pip install -r requirements.txt
 
 # Execute it
 
-The software can be simply executed with Python3:  `python3 opcuaserv.py`
+The software can be simply executed with Python3:  `python3 pypcc2.py -c RCY,CLK,UNB2`
 
 Optional parameters are explained when the `-h` or `--help` parameter is supplied:
 
@@ -47,7 +47,8 @@ usage: pypcc2.py [-h] [-s] [--no-lib-hack] [-p PORT]
 optional arguments:
   -h, --help            show this help message and exit
   -s, --simulator       Do not connect to I2c, but simulate behaviour.
-  --no-lib-hack         Do not require a hacked opcua library. Breaks behaviour.
   -p PORT, --port PORT  Port number to listen on [4842].
+  -c ..
+  -t ...
 ```
 
diff --git a/clk/CLK.py b/clk/CLK.py
deleted file mode 100644
index 37d9b6f4565e64896914a1c52758965a2dd08be6..0000000000000000000000000000000000000000
--- a/clk/CLK.py
+++ /dev/null
@@ -1,414 +0,0 @@
-from . import Vars
-import numpy as np
-import logging
-from .spibitbang2 import *
-import threading
-
-
-def ApplyMask(value,width=8,bitoffset=0,previous=0):
-    mask=(1<<width)-1
-    if bitoffset>0:
-      value<<=bitoffset;
-      mask<<=bitoffset;
-    return (value & mask) + (previous - (previous & mask));
-def UnMask(value,width=8,bitoffset=0):
-    mask=(1<<width)-1
-    if bitoffset>0:
-      value>>=bitoffset;
-    value=value&mask;
-    return value;
-
-def bytes2int(bts):
-   x=0;
-   for b in bts:
-     x=x*256+b;
-   return x;
-def int2bytes(i):
-   b=[];
-   while i>255: 
-        b=[i%256]+b;
-        i>>=8;
-   return [i]+b;
-
-def strs2bytes(var):
-#    print("str2bytes",var)
-    if len(var)==0: return var;
-    if isinstance(var[0],str): #make string a byte array
-#            return [ord(c.encode('utf-8')[0]) for s in var for c in s]
-            return [c.encode('utf-8')[0] for s in var for c in s]
-    return var
-
-def bytes2strs(var,step,dtype):
-    if not(dtype==Vars.datatype.dstring): return var
-    cnt=int(len(var)/step)
-    print(var)
-    return [(bytearray(var[i*step:(i+1)*step]).decode("utf-8")) for i in range(cnt)]
-
-class RCU1():
-    def __init__(self,number,I2Ccallback,Switchcallback):
-        self.N=number;
-        self.I2Ccallback=I2Ccallback
-        self.SWcallback=Switchcallback
-        self.previous   =np.zeros([number,Vars.RCU_storeReg],dtype='int')
-        self.previousHBA=np.zeros([number,3,32],dtype='int')
-
-    def load(self):
-        Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_init,0,[])  #Read the current status of GPIO IOs
-        self.SetVar(Inst1)
-#Vars.RCU_mask.OPCW.get_data_value().Value.Value=[1,1,0,0]
-#Vars.Ant_mask.OPCW.get_data_value().Value.Value=[1,1,0,0,0,0,0,0,0,0,1,0]
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_init,0,[])  #Read the current status of GPIO IOs
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Var,Vars.RCU_att,12,[0,1,2,3,4,5,6,7,8,9,11])
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_off,0,[])
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_on,0,[])
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.ADC1_on,0,[])
-#RCU.SetVar(Inst1)
-
-#print(Vars.RCU)
-
-    def SetVar(self,Instr,Mask=[]):
-#        Instr.value=strs2bytes(Instr.value) #Alwast be an array of bytes
-        if (self.N==1): Mask=[True]
-        if Instr.type==Vars.DevType.Instr:
-              #Execute instructions
-              Iset=Instr.dev;
-              if len(Mask)==0:  Mask=Vars.RCU_mask.OPCW.get_value()
-              for i in Iset.instr:
-                  logging.debug(str(("Inst",i)))
-                  self.SetVar(i,Mask=Mask)
-              return;
-        if Instr.type in [Vars.DevType.I2C,Vars.DevType.SPIbb,Vars.DevType.I2Cbb]:
-            if len(Mask)==0:  Mask=Vars.RCU_mask.OPCW.get_value()
-            mask=0;
-            RCU0=-1;
-            for RCUi in range(self.N):
-                 if (Mask[RCUi]): 
-                      mask|=1<<Vars.RCU_MPaddr.Switch[RCUi]
-                      if RCU0<0: RCU0=RCUi;
-            if RCU0<0: return; #Mask all zero
-            self.SWcallback(mask)
-            if Instr.type==Vars.DevType.I2C:
-              logging.info(str(('** Set I2C:',Instr.dev,Instr.value)))
-              self.SetI2C(RCU0,Instr.dev,8,0,strs2bytes(Instr.value))
-              return;
-            elif Instr.type==Vars.DevType.SPIbb:
-              logging.debug(str(('** Set SPIbb:',Instr.dev,Instr.value)))
-              SetSPIbb(self.SetI2C,RCU0,Instr.dev,strs2bytes(Instr.value))
-              return;
-            elif Instr.type==Vars.DevType.I2Cbb:
-              logging.info(str(('** Set I2Cbb:',Instr.dev,Instr.value)))
-#              self.SetI2C(RCUi,Instr.dev,8,0,strs2bytes(Instr.value))
-              return;
-        V1=Instr.dev
-        if not((Instr.nvalue==V1.nVars) and (Instr.type==Vars.DevType.VarUpdate)) and not(Instr.nvalue==V1.size*self.N):
-             logging.error("Wrong size of value")
-             return False
-        if V1.Vars[0].type==Vars.DevType.Internal:
-          Instr.dev.OPCW.set_value(Instr.value)
-          logging.debug("Update internal variable")
-          return
-#        if V1.Vars[0].type==Vars.DevType.Internal: return;
-        Step=V1.nVars
-        Step2=int(V1.size/V1.nVars)
-        if (self.N>1):
-           Mask=(Vars.RCU_mask if Step==1 else Vars.Ant_mask)
-           Mask=Mask.OPCW.get_value()
-        value1=strs2bytes(Instr.value) if V1.OPCR is None else strs2bytes(V1.OPCR.get_value())
-        if (len(value1)==V1.nVars) and (self.N>1):  value1=(value1*self.N);
-        if (Instr.type==Vars.DevType.Var):
-          logging.info(str(('** Set Var:',V1.name,value1)))
-          for RCUi in range(self.N):
-            for Vari in range(Step):
-                if not(Mask[RCUi*Step+Vari]): continue
-                i0=(RCUi*Step+    Vari)*Step2
-                i1=(RCUi*Step+(Vari+1))*Step2
-                self.SetVarValue(RCUi,V1.Vars[Vari],Instr.value[i0:i1])
-                value2=value1[i0:i1]
-                self.GetVarValue(RCUi,V1.Vars[Vari],value2)
-                value1[i0:i1]=value2
-          if not(V1.OPCR is None): V1.OPCR.set_value(bytes2strs(value1,Step2,V1.type))
-
-        elif Instr.type==Vars.DevType.VarUpdate:
-          if self.N==1:
-             for Vari in range(Step):
-                i0=(Vari)*Step2
-                i1=(Vari+1)*Step2
-                value2=value1[i0:i1]
-                self.GetVarValue(0,V1.Vars[Vari],value2)
-                value1[i0:i1]=value2
-             if not(V1.OPCR is None): V1.OPCR.set_value(bytes2strs(value1,Step2,V1.type))
-          else:
-             self.GetVarValueAll(V1,value1)
-#            if not(V1.OPCR is None): V1.OPCR.get_data_value().Value.Value=bytes2strs(value1,Step2,V1.type)
-             if not(V1.OPCR is None): V1.OPCR.set_value(bytes2strs(value1,Step2,V1.type))
-#            V1.OPCR.get_data_value().Value.Value=value1
-
-        logging.info(str(('** Readback:',V1.name,value1)))
-
-    def GetVarValue(self,RCUi,var,value):
-            logging.info(str(("RCU1 Get ",RCUi,var,value)))
-            if var.type==Vars.DevType.I2C:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.GetI2C(RCUi,var.devreg,var.width,var.bitoffset,value)
-            elif var.type==Vars.DevType.HBA1:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.GetI2CHBA1(RCUi,var.devreg,var.width,var.bitoffset,value)
-            elif var.type==Vars.DevType.I2Cbb:
-                logging.error("I2Cbb Implemented")
-            elif var.type==Vars.DevType.SPIbb:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                GetSPIbb(self.SetI2C,self.GetI2C,RCUi,var.devreg,value)
-            else:
-                logging.error("Not Implemented")
-
-    def GetVarValueAll(self,V1,value1):
-            mask=0;
-            for RCUi in range(self.N):
-                mask|=1<<Vars.RCU_MPaddr.Switch[RCUi]
-            Step=V1.nVars
-            Step2=int(V1.size/V1.nVars)
-            if V1.Vars[0].type==Vars.DevType.I2C:
-              for Vari in range(Step):  
-                DevReg=V1.Vars[Vari].devreg
-                self.SWcallback(mask)
-                self.SetI2CAddr(self,DevReg)
-                if DevReg.Register_R>255: self.I2Ccallback(DevReg.Addr,[250],read=3) #Wait for ADC
-                for RCUi in range(self.N):
-                    self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                    i0=(RCUi*Step+    Vari)*Step2
-                    i1=(RCUi*Step+(Vari+1))*Step2
-                    value2=value1[i0:i1]
-                    var=V1.Vars[Vari]
-#                    print(Step,Step2,i0,i1,value2,len(value1))
-                    self.GetI2Cnoreg(RCUi,var.devreg,var.width,var.bitoffset,value2)
-#                    print(value2)
-                    if (var.Scale!=0): value2[0]*=var.Scale;
-                    value1[i0:i1]=value2
-            elif V1.Vars[0].type==Vars.DevType.SPIbb:
-              self.GetBBValueAll(V1,value1,mask)
-#              logging.info("SPIbb all not implemented yet")
-            elif V1.Vars[0].type==Vars.DevType.HBA1:
-              for Vari in range(Step):  
-                var=V1.Vars[Vari]
-                for RCUi in range(self.N):
-                    self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-#                    print(Step,Step2,len(value1),V1.size)
-                    i0=(RCUi*Step+    Vari)*Step2
-                    i1=(RCUi*Step+(Vari+1))*Step2
-                    value2=value1[i0:i1]
-                    self.GetI2CHBA1(RCUi,var.devreg,var.width,var.bitoffset,value2)
-                    value1[i0:i1]=value2
-#                    i0=(RCUi*Step+    Vari)*Step2+16
-#                    i1=(RCUi*Step+(Vari+1))*Step2
-#                    value2=value1[i0:i1]
-#                    self.GetI2Cnoreg(RCUi,var.devreg,var.width,var.bitoffset,value2)
-#                    value1[i0:i1]=value2
-            else:
-               logging.error("Type not implemented")
-#            print(value1)
-    def GetBBValueAll(self,V1,value1,mask):
-        def SetBit(RCUi,dev,width,bitoffset,value,buffer=False):
-            if not(buffer): self.SWcallback(mask)
-            self.SetI2C(RCUi,dev,width,bitoffset,value,buffer=buffer)
-        def GetBit(RCUixx,dev,width,bitoffset,buffer=False):
-            value=[0 for RCUi in range(self.N)]
-            value2=[0]
-            if buffer: 
-                for RCUi in range(self.N):
-                  self.GetI2Cbuffer(RCUi,dev,width,bitoffset,value2)
-                  value[RCUi]=value2[0]
-                return value
-            self.SWcallback(mask)
-            self.SetI2CAddr(self,dev)
-            for RCUi in range(self.N):
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                #for i in range(len(value2)): value2[i]*=0;
-                value2[0]=0
-                self.GetI2Cnoreg(RCUi,dev,width,bitoffset,value2)
-                value[RCUi]=value2[0]
-            return value;
-        devs=[V1.Vars[Vari].devreg for Vari in range(V1.nVars)]
-        GetSPIbb2(SetBit,GetBit,0,devs,value1)
-
-
-    def SetVarValue(self,RCUi,var,value):
-            if var.devreg.Register_W==-1: return True; #We can not set it, only read it e.g. temperature
-            logging.debug(str(("RCU1 Set ",RCUi,var,value)))
-            if var.type==Vars.DevType.I2C:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.SetI2C(RCUi,var.devreg,var.width,var.bitoffset,value)
-            elif var.type==Vars.DevType.HBA1:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.SetHBA1I2C(RCUi,var.devreg,var.width,var.bitoffset,value)
-#                 print("RCU1 Set",RCUi,var,value)
-            elif var.type==Vars.DevType.I2Cbb:
-                logging.error("I2Cbb Implemented")
-            elif var.type==Vars.DevType.SPIbb:
-                logging.error("SPIbb Implemented")
-            else:
-                logging.error("Not Implemented")
-
-    def SetI2C(self,RCUi,dev,width,bitoffset,value,buffer=False):
-        if dev.store>0:
-            previous=self.previous[RCUi,dev.store-1];
-            value[0]=ApplyMask(value[0],width,bitoffset,previous);
-            self.previous[RCUi,dev.store-1]=value[0]
-#            logging.debug(str(('masked to',value)))
-#            logging.debug(str(("Store buffer",RCUi,dev.store,value[0])))
-        if buffer: return True;
-        return self.I2Ccallback(dev.Addr,value,reg=dev.Register_W)
-
-    def SetHBA1I2C(self,RCUi,dev,width,bitoffset,value,buffer=False):
-#        if dev.store>0:
-        previous=self.previousHBA[RCUi,dev.store-1];
-        L=len(value)
-        for i in range(L):
-          value[i]=ApplyMask(value[i],width,bitoffset,previous[i]);
-        self.previousHBA[RCUi,dev.store-1]=value
-#        if buffer: return True;
-        self.I2Ccallback(dev.Addr,value[:16],reg=dev.Register_W)
-        if L>16: self.I2Ccallback(dev.Addr,value[16:],reg=dev.Register_W+16)
-        self.I2Ccallback(dev.Addr,[500],reg=dev.Register_W,read=3) #Wait 500ms
-        return True
-#        return self.I2Ccallback(dev.Addr,value,reg=dev.Register_W)
-
-    def GetI2Cbuffer(self,RCUi,dev,width,bitoffset,value):
-        if not(dev.store>0): return False;
-        value[0]=self.previous[RCUi,dev.store-1];
-#        logging.debug(str(("GetI2Cbuffer",RCUi,dev.store,value)))
-        l1=int(np.floor((width+bitoffset+7)/8))
-        if (width!=l1*8) or (bitoffset>0): 
-          for i in range(len(value)):
-             value[i]=UnMask(value[i],width,bitoffset)      
-        return True
-
-    def GetI2C(self,RCUi,dev,width,bitoffset,value):
-#        if dev.store>0:
-#            value[0]=self.previous[RCUi,dev.store-1]
-#        return True          
-        l1=int(np.floor((width+bitoffset+7)/8))
-#        print(width,bitoffset,l1)
-        makesinglevalue=((len(value)==1) and (l1>1));
-        if makesinglevalue: value2=[0 for x in range(l1)]
-        else: value2=value
-        reg=dev.Register_R
-        if reg>255: #This is for the monitor ADC
-          if not(self.I2Ccallback(dev.Addr,int2bytes(reg),read=2)): return False;
-          I2Ccallback(Addr,[250],read=3)
-          if not(self.I2Ccallback(dev.Addr,value2,read=1)): return False;
-        else:
-          if not(self.I2Ccallback(dev.Addr,value2,reg=reg,read=1)): return False;
-        if value2[0] is None:  return False
-        if makesinglevalue: value[0]=bytes2int(value2)
-        else: value[:]=value2[:];
-        if dev.store>0:
-            self.previous[RCUi,dev.store-1]=value[0]
-#            logging.debug(str(("Store buffer",RCUi,dev.store,value[0])))
-        if (width!=l1*8) or (bitoffset>0): 
-            for i in range(len(value)):
-              value[i]=UnMask(value[i],width,bitoffset)      
-        else: value[0]=value2[0]
-        return True;
-    def GetI2Cbit(self,RCUi,dev,pin):
-           value2=[value]
-           self.I2CGet(RCUi,dev,1,1<<pin,value2)
-           return value2[0]
-
-
-    def SetI2CAddr(self,RCUi,dev):
-        return self.I2Ccallback(dev.Addr,int2bytes(dev.Register_R),read=2)
-
-
-
-    def GetI2Cnoreg(self,RCUi,dev,width,bitoffset,value):
-        #print(width,len(value))
-        l1=int(np.floor((width+bitoffset+7)/8))
-        makesinglevalue=((len(value)==1) and (l1>1));
-        if makesinglevalue: value2=[0 for x in range(l1)]
-        else: value2=value
-        reg=dev.Register_R
-        if not(self.I2Ccallback(dev.Addr,value2,read=1)): return False;
-        if value2[0] is None:  return False
-        if makesinglevalue: value[0]=bytes2int(value2)
-        else: value[:]=value2[:];
-        if dev.store>0:
-            self.previous[RCUi,dev.store-1]=value[0]
-#            logging.debug(str(("Store buffer",RCUi,dev.store,value[0])))
-#        if width<8:
-        if (width!=l1*8) or (bitoffset>0):
-            for i in range(len(value)): 
-              value[i]=UnMask(value[i],width,bitoffset)      
-#              value[0]=UnMask(value[0],width,bitoffset)      
-        #else: value[0]=value2[0]
-        #if (len(value)>1) and (width<8): print value
-        return True;
-
-    def GetI2CHBA1(self,RCUi,dev,width,bitoffset,value):
-        #print(width,len(value))
-        value2=value
-        reg=dev.Register_R
-        if not(self.I2Ccallback(dev.Addr,value2,read=1)): return False;
-        if value2[0] is None:  return False
-        value[:]=value2[:];
-        if dev.store>0:
-            self.previousHBA[RCUi,dev.store-1]=value
-        for i in range(len(value)): 
-              value[i]=UnMask(value[i],width,bitoffset)      
-        return True;
-
-
-    def start(self,Q1):
-      def RCUthread(Q1):
-         while True:
-           item = Q1.get()
-           if item is None: break;
-           self.SetVar(item)
-         logging.info("End RCU thread")
-
-      RCUthread1 = threading.Thread(target=RCUthread, args=(Q1,))
-      RCUthread1.start()
-      
-      return RCUthread1 
- 
-    def Queue_Monitor(self,Q1,NRCU):
-          Inst1=Vars.Instr(Vars.DevType.VarUpdate,Vars.CLK_Stat1,NRCU,[0]*NRCU)
-          Q1.put(Inst1)
-#         Inst1=Vars.Instr(Vars.DevType.VarUpdate,Vars.RCU_ADC_lock,96,[0]*96)
-#         Q1.put(Inst1)
-          return 
-    def AddVars(self,Q1,AddVarR,AddVarW):
-     for v in Vars.OPC_devvars:
-        dim1=Vars.RCU_MPaddr.nI2C*Vars.RCU_MPaddr.nSwitch*v.nVars
-        dim2=Vars.RCU_MPaddr.nI2C*Vars.RCU_MPaddr.nSwitch*v.size
-        dim3=int(v.size/v.nVars)
-        #print(v.name,dim)
-        varvalue2=0
-        if   v.type==Vars.datatype.dInt:    varvalue2=dim2*[0]
-        elif v.type==Vars.datatype.dbool:   varvalue2=dim2*[False]
-        elif v.type==Vars.datatype.dfloat:  varvalue2=dim2*[0.0] 
-        elif v.type==Vars.datatype.dstring: varvalue2=dim1*[" "*dim3]
-        print(len(varvalue2),varvalue2)
-        if v.RW in [Vars.RW.ReadOnly,Vars.RW.ReadWrite]:
-            var1=AddVarR(v.name+"_R",varvalue2,v)
-#            print(len(varvalue1),len(varvalue2),v.size,dim2)
-            v.OPCR=var1
-            Inst=Vars.Instr(Vars.DevType.VarUpdate,v,dim2,varvalue2)
-            Q1.put(Inst)
-
-        if v.RW in [Vars.RW.WriteOnly,Vars.RW.ReadWrite]:
-            var1=AddVarW(v.name+"_RW",varvalue2,v,Q1)
-            v.OPCW=var1
-
-    def AddMethod(self,Q1,Addmethod):
-      for v in Vars.OPC_methods:
-        Inst1=Vars.Instr(Vars.DevType.Instr,v,0,[])
-        Addmethod(v.name,Inst1,Q1)
diff --git a/clk/HWconf.py b/clk/HWconf.py
deleted file mode 100644
index e6f2f6f3195f22279433b96ff6c92465bd453104..0000000000000000000000000000000000000000
--- a/clk/HWconf.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#from collections import namedtuple
-#from enum import Enum
-from pcctypes import *
-
-#Mid plane address
-RCU_MPaddr=MPaddr(1,[1],1,[7])
-
-CLK_IO3_OUT1=DevReg(0x20,0,2,1)
-CLK_IO3_OUT2=DevReg(0x20,1,3,2)
-CLK_IO3_CONF1=DevReg(0x20,6,6,3)
-CLK_IO3_CONF2=DevReg(0x20,7,7,4)
-
-RCU_storeReg=4; #Number of stored registers
-
-
-
-SPIBB_PLL=BBdev(4,[CLK_IO3_OUT1,CLK_IO3_OUT1,CLK_IO3_OUT1,CLK_IO3_OUT1],[4,7,5,6],0) #CLK,SDI,SDO,CS
-
-CLK_PLL_lock =DevReg(SPIBB_PLL,0X00,0X00,0) # PLL locked status
-CLK_PLL_div  =DevReg(SPIBB_PLL,0X0D,0X0D,0) # PLL divide
-CLK_PLL_pwr  =DevReg(SPIBB_PLL,0X03,0X03,0) # PLL divide
-CLK_PLL_5  =DevReg(SPIBB_PLL,0X05,0X05,0) # PLL divide
-CLK_PLL_6  =DevReg(SPIBB_PLL,0X06,0X06,0) # PLL divide
-CLK_PLL_7  =DevReg(SPIBB_PLL,0X07,0X07,0) # PLL divide
-CLK_PLL_8  =DevReg(SPIBB_PLL,0X08,0X08,0) # PLL divide
-CLK_PLL_9  =DevReg(SPIBB_PLL,0X09,0X09,0) # PLL divide
-CLK_PLL_A  =DevReg(SPIBB_PLL,0X0A,0X0A,0) # PLL divide
-CLK_PLL_D  =DevReg(SPIBB_PLL,0X0D,0X0D,0) # PLL divide
-CLK_PLL_F  =DevReg(SPIBB_PLL,0X0F,0X0F,0) # PLL divide
-CLK_PLL_11  =DevReg(SPIBB_PLL,0X11,0X11,0) # PLL divide
-CLK_PLL_13  =DevReg(SPIBB_PLL,0X13,0X13,0) # PLL divide
diff --git a/clk/Vars.py b/clk/Vars.py
deleted file mode 100644
index 75c45b19b9158ad60b35a85b38132a0ade42ea03..0000000000000000000000000000000000000000
--- a/clk/Vars.py
+++ /dev/null
@@ -1,74 +0,0 @@
-from .HWconf import *
-
-CLKmod=I2Cmodules.CLK
-
-
-CLK_IGNORE_PPS= VarArray("CLK_Ignore_PPS",1,[Var2dev("",CLKmod,DevType.I2C,CLK_IO3_OUT1,1 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_Enable_PWR= VarArray("CLK_Enable_PWR",1,[Var2dev("",CLKmod,DevType.I2C,CLK_IO3_OUT1,1 ,1,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_Stat1     = VarArray("CLK_Stat"      ,1,[Var2dev("",CLKmod,DevType.I2C,CLK_IO3_OUT1,2 ,2,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_lock1      = VarArray("CLK_Lock"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_lock,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_div1       = VarArray("CLK_Div"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_div,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_pwr1       = VarArray("CLK_Pwr"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_pwr,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_5       = VarArray("CLK_PLL_5"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_5,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_6       = VarArray("CLK_PLL_6"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_6,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_7       = VarArray("CLK_PLL_7"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_7,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_8       = VarArray("CLK_PLL_8"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_8,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_9       = VarArray("CLK_PLL_9"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_9,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_A       = VarArray("CLK_PLL_A"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_A,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_D       = VarArray("CLK_PLL_D"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_D,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_F       = VarArray("CLK_PLL_F"      ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_F,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_11      = VarArray("CLK_PLL_11"     ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_11,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-CLK_13      = VarArray("CLK_PLL_13"     ,1,[Var2dev("",CLKmod,DevType.SPIbb,CLK_PLL_13,8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-
-
-#OPC_devvars=[CLK_Enable_PWR,CLK_Stat1,CLK_5,CLK_6,CLK_7,CLK_8,CLK_9,CLK_A,CLK_D,CLK_F,CLK_11,CLK_13] #,CLK_lock1,CLK_Stat1,CLK_div1,CLK_pwr1,CLK_IGNORE_PPS]
-OPC_devvars=[CLK_Enable_PWR,CLK_Stat1] #,CLK_lock1,CLK_Stat1,CLK_div1,CLK_pwr1,CLK_IGNORE_PPS]
-
-RCU_init=Instrs("CLK_update",2,[
-#   Instr(DevType.VarUpdate,CLK_IGNORE_PPS,1,[0]),
-   Instr(DevType.VarUpdate,CLK_Enable_PWR,1,[0]),
-   Instr(DevType.VarUpdate,CLK_Stat1,1,[0])
-])
-
-CLK_on=Instrs("CLK_on",3,[
-   Instr(DevType.I2C,CLK_IO3_CONF1,1,[0x2C]),#0010 1100 PPS/PWR output, SCLK,CS,SDI
-   Instr(DevType.I2C,CLK_IO3_OUT1 ,1,[0x42]),#0100 0010 high:PWR enable, CS
-#   Instr(DevType.VarUpdate,CLK_lock1,1,[0]),
-   Instr(DevType.VarUpdate,CLK_Stat1,1,[0]),
-   Instr(DevType.VarUpdate,CLK_Enable_PWR,1,[0])
-])
-
-CLK_off=Instrs("CLK_off",3,[
-   Instr(DevType.I2C,CLK_IO3_CONF1,1,[0x2C]),
-   Instr(DevType.I2C,CLK_IO3_OUT1 ,1,[0x40]),
-   Instr(DevType.VarUpdate,CLK_Enable_PWR,1,[0])
-])
-
-def SPIinst(reg,value):
-  return Instr(DevType.SPIbb,DevReg(SPIBB_PLL,0,reg,0),1,[value])
-
-CLK_PLL_setup=Instrs("CLK_PLL_setup",15,[
-#   SPIinst(0x03,0x08),
-#   Instr(DevType.I2C,CLK_IO3_CONF1,1,[0x2C]),
-   SPIinst(0x05,0x17),#was 97
-   SPIinst(0x06,0x10),
-
-   SPIinst(0x07,0x04),
-   SPIinst(0x08,0x01),
-   SPIinst(0x07,0x00),
-
-   SPIinst(0x09,0x10),
-   SPIinst(0x0A,0x14),
-   SPIinst(0x09,0x00),
-
-   SPIinst(0x0D,0x01),#was 2
-   SPIinst(0x0F,0x01),
-   SPIinst(0x11,0x01),
-   SPIinst(0x13,0x01),
- #  Instr(DevType.VarUpdate,CLK_lock1,1,[0]),
- #  Instr(DevType.VarUpdate,CLK_div1,1,[0]),
-   Instr(DevType.VarUpdate,CLK_Stat1,1,[0])
-])
-
-
-OPC_methods=[CLK_on,CLK_off,CLK_PLL_setup,RCU_init]
diff --git a/clk/spibitbang2.py b/clk/spibitbang2.py
deleted file mode 100644
index d312d5b6560f7bfaaaa75a9cef2773bc9b636f71..0000000000000000000000000000000000000000
--- a/clk/spibitbang2.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from enum import Enum
-import logging
-import numpy as np
-
-class SPIBB_pins(Enum):
-    CLK = 0  
-    SDI = 1  
-    SDO = 2 
-    CS = 3  
-
-def SetSPIbb(SetI2C,RCUi,dev,value):
-        ADC_address=dev.Register_W
-        CSdev=dev.Addr.devs[SPIBB_pins.CS.value]
-        CSpin=dev.Addr.pins[SPIBB_pins.CS.value]
-        SDOdev=dev.Addr.devs[SPIBB_pins.SDO.value]
-        SDOpin=dev.Addr.pins[SPIBB_pins.SDO.value]
-        SDIdev=dev.Addr.devs[SPIBB_pins.SDI.value]
-        SDIpin=dev.Addr.pins[SPIBB_pins.SDI.value]
-        CLKdev=dev.Addr.devs[SPIBB_pins.CLK.value]
-        CLKpin=dev.Addr.pins[SPIBB_pins.CLK.value]
-
-        logging.info(str(("SPIbb set",ADC_address,value)))
-
-#          dev_rw    = 0x00 # 0 for write, 1 for read
-#          data2 =  ( reg_address << 9 ) + ( dev_rw << 8 ) + value[0]
-        data2 = (  ADC_address << 9 ) + value[0]
-          
-        bit_array = "{0:{fill}16b}".format(data2, fill='0')
-      #    print(bit_array)
-        SetI2C(RCUi,CSdev,1,CSpin,[1]) #disable
-        SetI2C(RCUi,CSdev,1,CSpin,[0]) #enable
-        for bit in bit_array:
-              SetI2C(RCUi,CLKdev,1,CLKpin,[0]) 
-              SetI2C(RCUi,SDIdev,1,SDIpin,[int(bit)]) 
-              SetI2C(RCUi,CLKdev,1,CLKpin,[1]) 
-        SetI2C(RCUi,CLKdev,1,CLKpin,[0])#Why? 
-        SetI2C(RCUi,CLKdev,1,CLKpin,[1]) 
-        SetI2C(RCUi,CSdev,1,CSpin,[1]) #disable
-     #   SetI2C(RCUi,SDIdev,1,SDIpin,[1]) #high when finished
-        return True;
-
-def GetSPIbb(SetI2C,GetI2C,RCUi,dev,value):
-        ADC_reg_address=dev.Register_R
-        CSdev=dev.Addr.devs[SPIBB_pins.CS.value]
-        CSpin=dev.Addr.pins[SPIBB_pins.CS.value]
-        SDOdev=dev.Addr.devs[SPIBB_pins.SDO.value]
-        SDOpin=dev.Addr.pins[SPIBB_pins.SDO.value]
-        SDIdev=dev.Addr.devs[SPIBB_pins.SDI.value]
-        SDIpin=dev.Addr.pins[SPIBB_pins.SDI.value]
-        CLKdev=dev.Addr.devs[SPIBB_pins.CLK.value]
-        CLKpin=dev.Addr.pins[SPIBB_pins.CLK.value]
-
-        logging.info(str(("SPIbb get",ADC_reg_address)))
-        ADC_bytes = 0x00
-        #          ADC_rw    = 0x01 # 0 for write, 1 for read
-        data =  (ADC_reg_address << 1) + 1 #was 7??
-          
-        SetI2C(RCUi,CSdev,1,CSpin,[1]) #disable
-        SetI2C(RCUi,CSdev,1,CSpin,[0]) #enable
-
-
-        bit_array = "{0:{fill}8b}".format(data, fill='0')
-        for bit in bit_array:
-              SetI2C(RCUi,SDIdev,1,SDIpin,[int(bit)]) 
-              SetI2C(RCUi,CLKdev,1,CLKpin,[0]) 
-              SetI2C(RCUi,CLKdev,1,CLKpin,[1]) 
-
-     #   SetI2C(RCUi,SDIdev,1,SDIpin,[1]) #high when finished
-
-          #    print("read byte")
-        a=[0]
-        N=1 #len(value)
-        ret_value=[0]
-        for i in range(N): value[i]=0
-        for cnt in range(8*(ADC_bytes+1)):
-              SetI2C(RCUi,CLKdev,1,CLKpin,[0]) 
-              SetI2C(RCUi,CLKdev,1,CLKpin,[1])  #read after rising
-              GetI2C(RCUi,SDOdev,1,SDOpin,ret_value) 
-              for i in range(N): value[i]=(value[i]<<1)+ ret_value[i]
-        SetI2C(RCUi,CLKdev,1,CLKpin,[0]) 
-        SetI2C(RCUi,CSdev,1,CSpin,[1]) #disable
-        return True;
-
-
diff --git a/config/CLK.yaml b/config/CLK.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5bd902124c20314573e3759649cc728fb6ff2b78
--- /dev/null
+++ b/config/CLK.yaml
@@ -0,0 +1,167 @@
+version: "1.0"
+description: "1234"
+
+drivers:
+ - name: I2C
+   type: i2c
+   parameters: [4] #I2C port number
+ - name: I2C_CLK
+   type: i2c_dev #I2C devices
+   parent: I2C
+   status: CLK_I2C_STATUS
+ - name: SPIbb1 
+   type: spibitbang2 #SPI bitbang via GPIO expander: CLK, SDI,SDO,CS
+   parent: I2C_CLK
+   devreg: [IO1.GPIO1,IO1.GPIO1,IO1.GPIO1,IO1.GPIO1]
+   parameters: [4,7,5,6]
+
+#This is the I2C devices in the RCU
+device_registers:
+ - name: IO1
+   description: IO-Expander
+   address: 0x20
+   driver: I2C_CLK
+   registers:
+   - name: CONF1
+     description: Direction of port1
+     address: 6
+     store: True
+   - name: GPIO1
+     description: Input/Ouput port 1
+     address: [0,2]  #Read / Write address different
+     store: True
+
+ - name: PLL
+   driver: SPIbb1
+   registers:
+    - name: PLL_stat
+      description: PLL locked status
+      address: 0x0
+    - {name: r3, address: 0x03}
+    - {name: r5, address: 0x05}
+    - {name: r6, address: 0x06}
+
+
+variables:
+  - name: CLK_I2C_STATUS
+    driver: I2C_CLK
+    rw:  ro #server RW variable, not linked to IO
+    dtype: uint8
+
+  - name: CLK_translator_busy
+    description: False when idle
+    rw:  ro #server variable, not linked to IO
+    dtype: boolean
+    dim: 1
+
+  - name: CLK_Enable_PWR
+    description: Power enabled
+    rw:  ro
+    dtype: boolean
+    driver: I2C_CLK
+    devreg:  IO1.GPIO1
+    bitoffset: 1
+    width: 1
+
+
+  - name: CLK_PLL_locked
+    description: First status pin give lock status
+    rw:  ro
+    dtype: boolean
+    monitor: true
+    driver: I2C_CLK
+    devreg:  IO1.GPIO1
+    bitoffset: 2
+    width: 1
+
+  - name: CLK_PLL_error
+    description: Second status pin give error
+    rw:  ro
+    dtype: boolean
+    monitor: true
+    driver: I2C_CLK
+    devreg:  IO1.GPIO1
+    bitoffset: 3
+    width: 1
+
+  - name: CLK_PLL_locked_SPI
+    description: 0x81=locked
+    driver: I2C_CLK
+    devreg:  PLL.PLL_stat
+    width: 8
+    rw:  ro
+    dtype: uint8
+    debug: True
+
+  - name: [CLK_PLL_r3,CLK_PLL_r5,CLK_PLL_r6]
+    driver: I2C_CLK
+    devreg:  [PLL.r3,PLL.r5,PLL.r6]
+    width: 8
+    rw:  ro
+    dtype: uint8
+    debug: True
+
+  - name: RCU_IO1_GPIO1
+    driver: I2C_CLK
+    devreg:  IO1.GPIO1
+    width: 8
+    rw:  ro
+    dtype: uint8
+    mask: RCU_mask
+    debug: True
+
+methods:
+  - name: CLK_Init #Called after startup to load. Should have all stored registers  
+    driver: I2C_CLK
+    debug: True
+    instructions:   
+      - CLK_I2C_STATUS : 0
+      - RCU_IO1_GPIO1 : Update
+      - IO1.CONF1: Update
+      - CLK_Enable_PWR: Update
+      - CLK_PLL_locked: Update
+      - CLK_PLL_error: Update
+
+  - name: CLK_on  
+    driver: I2C_CLK
+    instructions:   
+     - CLK_I2C_STATUS : 0
+     - IO1.CONF1: 0x2C #0010 1100 PPS/PWR output, SCLK,CS,SDI
+     - IO1.GPIO1: 0x42 #0100 0010 high:PWR enable, CS
+     - CLK_Enable_PWR: Update
+     - WAIT: 200         #ms to wait before checking lock
+     - CLK_PLL_setup: 0
+     - WAIT: 100         #ms to wait before checking lock
+     - CLK_PLL_locked: Update
+
+  - name: CLK_off  
+    driver: I2C_CLK
+    instructions:   
+     - CLK_I2C_STATUS : 0
+     - IO1.CONF1: 0x2C #0010 1100 PPS/PWR output, SCLK,CS,SDI
+     - IO1.GPIO1: 0x00 #all low
+     - CLK_Enable_PWR: Update
+     - CLK_PLL_locked: Update
+
+  - name: CLK_PLL_setup  
+    driver: I2C_CLK
+    debug: true
+    instructions:   
+#   - PLL.0x03: 0x08 #Set power, this is default
+    - PLL.0x05: 0x17 #was 97, set lock time
+    - PLL.0x06: 0x10
+
+    - PLL.0x07: 0x04 #Stop R divider
+    - PLL.0x08: 0x01 #Set R divider
+    - PLL.0x07: 0x00 #Start R divider
+
+    - PLL.0x09: 0x10 #Stop N divider
+    - PLL.0x0A: 0x14 #Set N divider=20, 200MHz/20=10MHz = input clock
+    - PLL.0x09: 0x00 #Start N divider
+
+    - PLL.0x0D: 0x01 #Divider output 1=1 
+    - PLL.0x0F: 0x01 #Divider output 2=1
+    - PLL.0x11: 0x01 #Divider output 3=1
+    - PLL.0x13: 0x01 #Divider output 4=1
+
+ 
diff --git a/config/RCU.yaml b/config/RCU.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f1c28ddb334ea76076ff2cc4a94904b2d4b26531
--- /dev/null
+++ b/config/RCU.yaml
@@ -0,0 +1,488 @@
+version: "1.0"
+description: "1234"
+
+drivers:
+ - name: I2C1 #TCA9548
+   type: i2c_switch
+   devreg: [0x70]
+   parameters: [1] #I2C port number
+ - name: I2C_RCU 
+   type: i2c_array #An array of similar devices connected to an I2C switch
+   parent: I2C1
+   parameters: [0,31] #start,number of RCUs
+   status: RCU_I2C_STATUS
+ - name: I2C_HBAT
+   type: hba1 #Special driver to manage HBAT1s.
+   parent: I2C_RCU
+ - name: I2Cbb1 
+   type: i2cbitbang1 #I2C bitbang via GPIO expander
+   devreg: [IO1.GPIO1,IO2.GPIO2,IO2.CONF2]
+   parameters: [6,3,3] #pins
+   parent: I2C_RCU
+ - name: I2Cbb2
+   type: i2cbitbang1
+   devreg: [IO1.GPIO2,IO2.GPIO1,IO1.CONF1]
+   parameters: [7,7,7]
+   parent: I2C_RCU
+ - name: I2Cbb3
+   type: i2cbitbang1
+   devreg: [IO1.GPIO2,IO2.GPIO1,IO1.CONF1]
+   parameters: [7,7,7]
+   parent: I2C_RCU
+ - name: SPIbb1 
+   type: spibitbang1 #SPI bitbang via GPIO expander: CLK, SDIO, SDIOdir,CS
+   devreg: [IO3.GPIO1,IO3.GPIO1,IO3.CONF1,IO3.GPIO2]
+   parameters: [1,0,0,0]
+   parent: I2C_RCU
+ - name: SPIbb2
+   type: spibitbang1
+   devreg: [IO3.GPIO1,IO3.GPIO1,IO3.CONF1,IO3.GPIO2]
+   parameters: [3,2,2,1]
+   parent: I2C_RCU
+ - name: SPIbb3
+   type: spibitbang1
+   devreg: [IO3.GPIO1,IO3.GPIO1,IO3.CONF1,IO3.GPIO2]
+   parameters: [5,4,4,2]
+   parent: I2C_RCU
+ - name: HBA_trigger
+   type: gpio_hba_trigger
+   devreg: [0x40.0x10] #I2C broadcast register
+   parameters: [15] #PPS GPIO pin
+   parent: I2C_RCU
+
+#This is the I2C devices in the RCU
+device_registers:
+ - name: IO
+   dim: 3
+   description: [IO-Expander for filter selection,IO-Expander for ON/OFF, Band, BUFx2,IO-Expander for ADC control]
+   address: [0x75,0x76,0x20]
+   device: [TCA9539,TCA9539,TCA6416]
+   driver: I2C1
+   registers:
+   - name: CONF1
+     description: Direction of port1
+     address: 6
+     store: True
+   - name: CONF2
+     description: Direction of port2
+     address: 7
+     store: True
+   - name: GPIO1
+     description: Input/Ouput port 1
+     address: [0,2]  #Read / Write address different
+     store: True
+   - name: GPIO2
+     description: Input/Ouput port 2
+     address: [1,3]
+     store: True
+
+ - name: ROM
+   description: IO-Expander for filter selection
+   address: 0x50
+   driver: I2C1
+   registers:
+   - name: ID
+     description: Random
+     address: 0xfc
+   - name: Version
+     description: Set in production
+     address: 0
+ 
+ - name: AN
+   description: Monitor ADC on RCU
+   address: 0x14
+   device: LTC2495
+   driver: I2C1
+   registers:
+   - name: V_1v8
+     address: 0xB080
+   - name: V_2v5
+     address: 0xB880
+   - name: V_3v3
+     address: 0xB180
+   - name: I_Ant0
+     address: 0xB980
+   - name: I_Ant1
+     address: 0xB280
+   - name: I_Ant2
+     address: 0xBA80
+   - name: V_Ant0
+     address: 0xB380
+   - name: V_Ant1
+     address: 0xBB80
+   - name: Temp
+     address: 0xA0C0
+
+#This 'special' devices that uses I2C
+
+ - name: HB_UC
+   description: RCU microcontroller 
+   address: 0x40
+   driver: I2C1
+   registers:
+   - name: ID
+     description: Device ID
+     address: 0
+
+ - name: HB_UC_update
+   description: RCU microcontroller 
+   address: 0x40
+   driver: HBA_trigger
+   registers:
+   - name: wait_pps
+     address: 10
+
+ - name: HBAT
+   dim: 3
+   address: [0x41,0x42,0x43]
+   description: Virtual HBAT0 interface
+   driver: I2C_HBAT
+   registers:
+   - name: XY
+     address: 0x10
+     description: XY delay register
+     store: True
+   - name: Version
+     address: 127
+     description: HBAT server version
+
+ - name: ADC
+   dim: 3
+   description:  ADC SPI control
+   device: AD9683
+   driver: [SPIbb1,SPIbb2,SPIbb3]
+   registers:
+    - name: PLL_stat
+      description: PLL locked status
+      address: 0x0A
+    - name: JESD_control1
+      description: JESD link control
+      address: 0x5F
+    - name: SYNC_control
+      address: 0x3A
+    - name: CML_level
+      description: CML output adjust
+      address: 0x15
+    - name: Update
+      description: Global device uptate
+      address: 0xFF
+
+ - name: DTH
+   dim: 3
+   description: CW dither source
+   device: SI4012
+   driver: [I2Cbb1,I2Cbb1,I2Cbb1]
+   address: 0x70
+   registers:
+    - name: Freq
+      description: Frequency
+      address: [0x1140,0x1141]
+    - name: Property
+      description: Properties
+      address: [0x11,0x11]
+    - name: Start
+      description: Start CW
+      address: [0x62,0x62]
+    - name: Stop
+      description: Stop CW
+      address: [0x67,0x67]
+
+variables:
+   - name: Ant_mask
+     description: Only masked RF chains are updated
+     driver: I2C_RCU
+     rw:  variable #server RW variable, not linked to IO
+     dtype: boolean
+     dim: 96
+
+   - name: RCU_mask
+     description: Only masked RCUs are updated
+     driver: I2C_RCU
+     rw:  variable #server RW variable, not linked to IO
+     dtype: boolean
+     dim: 32
+
+   - name: RCU_I2C_STATUS
+     description: 0=Good, 1=No communication, 2=error
+     driver: I2C_RCU
+     rw:  ro #server RW variable, not linked to IO
+     dtype: uint8
+     mask: RCU_mask
+     dim: 32
+
+#   - name: RCU_state
+#     description: State of RCUs 0=unknown, 1=ready, 2=busy, 3= wait PPS, 4=error
+#     driver: I2C_RCU
+#     rw:  ro #server variable, not linked to IO
+#     dtype: uint8
+#     dim: 1
+
+   - name: RCU_translator_busy
+     description: False when idle
+     rw:  ro #server variable, not linked to IO
+     dtype: boolean
+     dim: 1
+
+   - name: RCU_attenuator
+     description: Attenuator before ADC
+     driver: I2C_RCU
+     devreg:  [IO1.GPIO1,IO1.GPIO2,IO2.GPIO1]
+     bitoffset: [0,0,0]
+     width: 5
+     rw:  rw
+     dtype: uint8
+     dim: 96
+     mask: Ant_mask
+
+   - name: RCU_band
+     description: Band select switch 1=10MHz,2=30MHz
+     driver: I2C_RCU
+     devreg:  [IO2.GPIO2,IO2.GPIO2,IO2.GPIO2]
+     bitoffset: [0,2,4]
+     width: 2
+     rw:  rw
+     dtype: uint8
+     dim: 96
+     mask: Ant_mask
+
+   - name: [RCU_IO1_GPIO1,RCU_IO1_GPIO2,RCU_IO2_GPIO1,RCU_IO2_GPIO2,RCU_IO3_GPIO1,RCU_IO3_GPIO2]
+     driver: I2C_RCU
+     devreg:  [IO1.GPIO1,IO1.GPIO2,IO2.GPIO1,IO2.GPIO2,IO3.GPIO1,IO3.GPIO2]
+     width: 8
+     rw:  ro
+     dtype: uint8
+     dim: 32
+     mask: RCU_mask
+     debug: True
+
+   - name: RCU_LED0
+     driver: I2C_RCU
+     description: LED on RCU
+     devreg:  IO2.GPIO2
+     bitoffset: 6
+     width: 1
+     rw:  rw
+     dtype: boolean
+     dim: 32
+     mask: RCU_mask
+
+   - name: RCU_LED1
+     driver: I2C_RCU
+     description: LED on RCU
+     devreg:  IO2.GPIO2
+     bitoffset: 7
+     width: 1
+     rw:  rw
+     dtype: boolean
+     dim: 32
+     mask: RCU_mask
+
+   - name: RCU_temperature
+     description: Temperature sensor on RCU
+     driver: I2C_RCU
+     devreg:  AN.Temp
+     width: 23
+     scale: 4.21e-3
+     rw:  ro
+     dtype: double
+     dim: 32
+     monitor: true
+     mask: RCU_I2C_STATUS
+
+   - name: RCU_Pwr_dig
+     description: Enable LDOs
+     driver: I2C_RCU
+     devreg:  IO2.GPIO1
+     width: 1
+     bitoffset: 6
+     rw:  ro
+     dtype: boolean
+     dim: 32
+     mask: RCU_mask
+
+   - name: HBA_element_beamformer_delays
+     description: Delays of each frontend
+     driver: I2C_HBAT
+     devreg:  [HBAT1.XY,HBAT2.XY,HBAT3.XY]
+     bitoffset: [2,2,2]
+     width: 5
+     rw:  rw
+     dtype: uint8
+     dim: 3072
+     mask: Ant_mask
+     wait: 100 #ms
+
+   - name: [HBA_element_led,HBA_element_pwr,HBA_element_LNA_pwr]
+     description: LED, power, frontend power of each frontend
+     driver: I2C_HBAT
+     devreg:  [HBAT1.XY,HBAT2.XY,HBAT3.XY]
+     bitoffset: [0,7,1]
+     width: 1
+     rw:  rw
+     dtype: boolean
+     dim: 3072
+     mask: Ant_mask
+     wait: 100 #ms
+
+   - name: RCU_ID
+     description: Unique RCU ID
+     driver: I2C_RCU
+     devreg:  ROM.ID
+     width: 32
+     rw:  ro
+     dtype: uint32
+     dim: 32
+     mask: RCU_mask
+
+   - name: RCU_version
+     description: RCU version number
+     driver: I2C_RCU
+     devreg:  ROM.Version
+     width: 80  #10 characters
+     rw:  ro
+     dtype: string
+     dim: 32
+     mask: RCU_mask
+     
+   - name: RCU_ADC_lock
+     description: 0x81=locked
+     driver: I2C_RCU
+     devreg:  [ADC1.PLL_stat,ADC2.PLL_stat,ADC3.PLL_stat]
+     width: 8
+     rw:  ro
+     dtype: uint8
+     dim: 96
+     monitor: true
+
+   - name: RCU_ADC_sync
+     description: 0x81=locked
+     driver: I2C_RCU
+     devreg:  [ADC1.SYNC_control,ADC2.SYNC_control,ADC3.SYNC_control]
+     width: 8
+     rw:  ro
+     dtype: uint8
+     dim: 96
+     debug: true
+
+#   - name: RCU_dth1_freq
+#     driver: I2C_RCU
+#     devreg:  [DTH1.Freq,DTH2.Freq,DTH3.Freq]
+#     width: 32
+#     rw:  rw
+#     dtype: uint32
+#     dim: 96
+#     mask: Ant_mask
+
+methods:
+  - name: RCU_Init #Called after startup to load. Should have all stored registers  
+    driver: I2C_RCU
+    debug: True
+    instructions:   
+    - RCU_IO1_GPIO1: Update
+    - RCU_IO1_GPIO2: Update
+    - RCU_IO2_GPIO1: Update
+    - RCU_IO2_GPIO2: Update
+    - RCU_IO3_GPIO1: Update
+    - RCU_IO3_GPIO2: Update
+#    - IO1.GPIO2: Update
+#    - IO2.GPIO1: Update
+#    - IO2.GPIO2: Update
+#    - IO3.GPIO1: Update
+#    - IO3.GPIO2: Update
+    - IO3.CONF1: Update
+    - RCU_update: 0
+
+  - name: RCU_on
+    driver: I2C_RCU
+    mask: RCU_mask
+    instructions:
+     - IO2.CONF1: 0    #Set device register, can also specify a register adress direction e.g. OIO2.0: 0
+     - IO2.GPIO1: 0x4A
+     - IO2.GPIO2: 0x55
+     - IO3.GPIO1: 0x15
+     - IO3.GPIO2: 0x47
+     - IO1.GPIO1: 0xCA
+     - IO1.GPIO2: 0xCA
+     - IO2.CONF2: 0
+     - IO3.CONF1: 0
+     - IO3.CONF2: 0
+     - IO1.CONF1: 0
+     - IO1.CONF1: 0
+#     - RCU_GPIO1: Update
+#     - RCU_GPIO2: Update
+#     - RCU_attenuator: [10,10,10]  #Set OPC-UA variable
+     - WAIT: 500         #ms to wait
+     - ADC1_on: 0        #call another opc-ua method
+     - ADC2_on: 0
+     - ADC3_on: 0
+     - WAIT: 500         #ms to wait
+     - RCU_update: 0
+
+  - name: RCU_update
+    driver: I2C_RCU
+    mask: RCU_mask
+    debug: True
+    instructions:
+      - RCU_Pwr_dig: Update  #Read value and update the OPC-UA variable
+      - RCU_ID: Update
+      - RCU_version: Update
+      - RCU_LED0: Update
+      - RCU_attenuator: Update
+      - RCU_band: Update
+      - RCU_ADC_lock: Update
+      - RCU_ADC_sync: Update
+
+
+  - name: ADC1_on
+    driver: I2C_RCU
+    debug: True
+#    rw: hidden
+    instructions:
+     - ADC1.JESD_control1 : 0x14
+     - ADC1.SYNC_control: 1  #Setup ADCs
+     - ADC1.CML_level: 0x7
+     - ADC1.Update: 1       #Needed to update ADC registers
+     
+  - name: ADC2_on
+    driver: I2C_RCU
+    debug: True
+#    rw: hidden
+    instructions:
+     - ADC2.JESD_control1 : 0x14
+     - ADC2.SYNC_control: 1  #Setup ADCs
+     - ADC2.CML_level: 0x7
+     - ADC2.Update: 1       #Needed to update ADC registers
+
+  - name: ADC3_on
+    driver: I2C_RCU
+    debug: True
+#    rw: hidden
+    instructions:
+     - ADC3.JESD_control1 : 0x14
+     - ADC3.SYNC_control: 1  #Setup ADCs
+     - ADC3.CML_level: 0x7
+     - ADC3.Update: 1       #Needed to update ADC registers
+
+  - name: RCU_off
+    driver: I2C_RCU
+    mask: RCU_mask
+    instructions:
+     - RCU_Pwr_dig: 0 #Switch power off
+     - IO2.GPIO1: 0
+     - IO2.GPIO2: 0
+     - IO3.GPIO1: 0
+     - IO3.GPIO2: 0
+     - IO1.GPIO1: 0
+     - IO1.GPIO2: 0
+     - RCU_update: 0
+     #todo, also make all GPIO pins (except power enables) inputs to remove all power from devices.
+
+  - name: RCU_HBAT_WAIT_PPS
+    driver: I2C_RCU
+    mask: RCU_mask
+    debug: True
+    instructions:
+     - RCU_state: 3
+     - HB_UC_update.wait_pps : 1
+     - RCU_state: 1
+
diff --git a/config/UNB2.yaml b/config/UNB2.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5ac65152df724826fc6d31bd083adf5d8d630d2f
--- /dev/null
+++ b/config/UNB2.yaml
@@ -0,0 +1,296 @@
+version: "0.0"
+description: "UNB2 DTS first draft" 
+
+drivers:
+ - name: I2C1
+   type: i2c_switch2 
+   devreg: [APSCT_SWITCH.MASK,UB2_SWITCH1.MASK,UB2_SWITCH2.MASK] 
+   parameters: [3,0,0,0] #I2C port number, 3x switch reset pins 
+
+ - name: switch_UNB2
+   type: i2c_array
+   parent: I2C1
+   parameters: [0,1] 
+   status: UNB2_I2C_bus_STATUS
+
+ - name: switch_PS
+   type: i2c_array2 
+   parent: I2C1
+   parameters: [0,1,  4,4] 
+   status: UNB2_I2C_bus_PS_STATUS
+
+ - name: switch_FP
+   type: i2c_array2 
+   parent: I2C1
+   parameters: [0,1,  5,5] 
+   status: UNB2_I2C_bus_FP_STATUS
+
+ - name: switch_QSFP 
+   type: i2c_array2 #An array of similar devices connected to an I2C switch
+   parent: I2C1
+   parameters: [0,1,  0,3,  0,3, 6,7] #Parameters: APSCT_Switch, main switch, 2nd switch, 2nd switch
+   status: UNB2_I2C_bus_QSFP_STATUS
+
+ - name: switch_DDR4
+   type: i2c_array2 
+   parent: I2C1
+   parameters: [0,1,  0,3,  4,4]
+   status: UNB2_I2C_bus_DDR4_STATUS
+
+ - name: switch_FPGA_PS
+   type: i2c_array2 
+   parent: I2C1
+   parameters: [0,1,  0,3,  5,5] 
+   status: UNB2_I2C_bus_FPGA_PS_STATUS
+
+ - name: GPIO
+   type: gpio
+
+  
+#This is the I2C devices in the RCU
+device_registers:
+- name: APSCT_SWITCH #not in LTS
+  description: Uniboard select switch on APSCT
+  address: 0x70
+  device: TCA9548
+  driver: I2C1
+  registers:
+  - name: MASK
+- name: UB2_SWITCH1
+  description: UNB2 primary switch
+  address: 0x71
+  device: TCA9548
+  driver: I2C1
+  registers:
+  - name: MASK
+- name: UB2_SWITCH2
+  description: UNB2 secondary switch
+  address: 0x72
+  device: TCA9548
+  driver: I2C1
+  registers:
+  - name: MASK
+
+- name: FP_IO
+  description: IO-Expander for front panel
+  address: 0x41
+  device: PCA9536
+  driver: d_front_panel
+  registers:
+  - name: CONF #default 0xff = all input
+    description: Direction of GPIO
+    address: 3
+  - name: GPIO
+    description: Input/Ouput port 
+    address: [0,1]  #Read / Write address different
+    store: True
+
+
+variables:
+
+#When I2C bus timeout, bus_STATUS set to False.  Can we set to True again to retry.
+   - name: UNB2_I2C_bus_STATUS
+     driver: switch_UNB2
+     rw:  ro
+     dtype: uint8
+     dim: 2
+   - name: UNB2_I2C_bus_FP_STATUS
+     driver: switch_UNB2
+     rw:  hidden
+     dtype: uint8
+     dim: 2
+   - name: UNB2_I2C_bus_QSFP_STATUS
+     driver: switch_QSFP
+     rw:  ro
+     dtype: uint8
+     dim: 48
+   - name: UNB2_I2C_bus_DDR4_STATUS
+     driver: switch_QSFP
+     rw:  ro
+     dtype: uint8
+     dim: 8
+   - name: UNB2_I2C_bus_FPGA_PS_STATUS
+     driver: switch_FPGA_PS
+     rw:  ro
+     dtype: uint8
+     dim: 8
+   - name: UNB2_I2C_bus_PS_STATUS
+     driver: switch_PS
+     rw:  ro
+     dtype: uint8
+     dim: 2
+
+   - name: UNB2_translator_busy
+     description: False when idle
+     rw:  ro #server variable, not linked to IO
+     dtype: boolean
+     dim: 1
+
+##Central MP for whole Uniboard2
+   - name: UNB2_mask
+     rw:  variable #translator variable
+     dtype: boolean
+     dim: 2
+
+   - name: UNB2_Power_ON_OFF
+     driver: GPIO
+     mask: UNB2_mask
+     width: 1
+     rw:  ro
+     dtype: boolean
+     dim: 2
+
+   - name: UNB2_Front_Panel_LED
+     description: bit 0=Red, 1=Blue, 2=Green
+     mask: UNB2_mask
+     driver: switch_FP
+     devreg: FP_IO.GPIO
+     bitoffset: 4
+     width: 3
+     rw:  rw
+     dtype: uint8
+     dim: 2
+
+   - name: UNB2_EEPROM_Serial_Number
+     driver: switch_UNB2
+     devreg: 0x50.0
+     width: 80  #10 characters
+     rw:  ro
+     dtype: string
+     dim: 2
+
+   - name: UNB2_EEPROM_Unique_ID
+     driver: switch_UNB2
+     devreg: 0x50.0xFC
+     width: 32
+     rw:  ro
+     dtype: uint32
+     dim: 2
+
+   - name: [UNB2_DC_DC_48V_12V_VIN,UNB2_DC_DC_48V_12V_VOUT,UNB2_DC_DC_48V_12V_IOUT,UNB2_DC_DC_48V_12V_TEMP]
+     driver: switch_PS
+     devreg:  [0x2C.0x88,0x2C.0x8B,0x2C.0x8C,0x2C.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 2
+     monitor: true
+
+   - name: [UNB2_POL_QSFP_N01_VOUT,UNB2_POL_QSFP_N01_IOUT,UNB2_POL_QSFP_N01_TEMP,UNB2_POL_QSFP_N23_VOUT,UNB2_POL_QSFP_N23_IOUT,UNB2_POL_QSFP_N23_TEMP]
+     driver: switch_PS
+     devreg:  [0x2.0x8B,0x2.0x8C,0x2.0x8D,0x1.0x8B,0x1.0x8C,0x1.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 2
+     monitor: true
+
+   - name: [UNB2_POL_SWITCH_1V2_VOUT,UNB2_POL_SWITCH_1V2_IOUT,UNB2_POL_SWITCH_1V2_TEMP,UNB2_POL_SWITCH_PHY_VOUT,UNB2_POL_SWITCH_PHY_IOUT,UNB2_POL_SWITCH_PHY_TEMP]
+     driver: switch_PS
+     devreg:  [0xF.0x8B,0xF.0x8C,0xF.0x8D,0xE.0x8B,0xE.0x8C,0xE.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 2
+     monitor: true
+
+   - name: [UNB2_POL_CLOCK_VOUT,UNB2_POL_CLOCK_IOUT,UNB2_POL_CLOCK_TEMP]
+     driver: switch_PS
+     devreg:  [0xD.0x8B,0xD.0x8C,0xD.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 2
+     monitor: true
+
+##Local MP per FPGA node
+   - name: UNB2_FPGA_DDR4_SLOT_TEMP
+     description: Signed I2C!
+     driver: switch_DDR4
+     devreg:  [0x18.0x5,0x19.0x5]
+     width: 13
+     rw:  ro
+     dtype: double
+     scale: 0.0625 
+     dim: 16
+     monitor: true
+
+   - name: UNB2_FPGA_DDR4_SLOT_PART_NUMBER
+     driver: switch_DDR4
+     devreg:  [0x18.0x149,0x19.0x149]
+     width: 160
+     rw:  ro
+     dtype: string
+     dim: 16
+     monitor: true
+
+   - name: [UNB2_POL_FPGA_CORE_VOUT,UNB2_FPGA_POL_CORE_IOUT,UNB2_FPGA_POL_CORE_TEMP,UNB2_FPGA_POL_ERAM_VOUT,UNB2_FPGA_POL_ERAM_IOUT,UNB2_FPGA_POL_ERAM_TEMP]
+     driver: switch_FPGA_PS
+     devreg:  [0x1.0x8B,0x1.0x8C,0x1.0x8D,0xD.0x8B,0xD.0x8C,0xD.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 8
+     monitor: true
+
+   - name: [UNB2_FPGA_POL_RXGXB_VOUT,UNB2_FPGA_POL_RXGXB_IOUT,UNB2_FPGA_POL_RXGXB_TEMP,UNB2_FPGA_POL_TXGXB_VOUT,UNB2_FPGA_POL_TXGXB_IOUT,UNB2_POL_FPGA_TXGXB_TEMP]
+     driver: switch_FPGA_PS
+     devreg:  [0xE.0x8B,0xE.0x8C,0xE.0x8D,0xF.0x8B,0xF.0x8C,0xF.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 8
+     monitor: true
+
+   - name: [UNB2_FPGA_POL_HGXB_VOUT,UNB2_FPGA_POL_HGXB_IOUT,UNB2_FPGA_POL_HGXB_TEMP,UNB2_FPGA_POL_PGM_VOUT,UNB2_FPGA_POL_PGM_IOUT,UNB2_FPGA_POL_PGM_TEMP]
+     driver: switch_FPGA_PS
+     devreg:  [0x10.0x8B,0x10.0x8C,0x10.0x8D,0x11.0x8B,0x11.0x8C,0x11.0x8D]
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 8
+     monitor: true
+
+
+
+##Local MP per FPGA node, QSFP cage
+   - name: UNB2_FPGA_QSFP_CAGE_TEMP
+     description: Signed I2C!
+     driver: switch_QSFP
+     devreg:  0x50.0x16
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 0.0625 #TBC
+     dim: 48
+     monitor: true
+
+   - name: UNB2_FPGA_QSFP_CAGE_LOS
+     description: Bits for 4 TX, 4 RX channels
+     driver: switch_QSFP
+     devreg:  0x50.0x03
+     width: 8
+     rw:  ro
+     dtype: uint8
+     dim: 48
+     monitor: true
+
+
+methods:
+  - name: UNB2_on
+    mask: UNB2_mask
+    instructions:
+     - FP_IO.CONF: 0xff    #TODO: setup correctly
+     - UNB2_Front_Panel_LED: 1
+
+  - name: UNB2_off
+    mask: UNB2_mask
+    instructions:
+     - UNB2_Front_Panel_LED: 2
diff --git a/config/apsctl.schema.json b/config/apsctl.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..07c6b82a4866a48c4d4f4b3166af321404950a95
--- /dev/null
+++ b/config/apsctl.schema.json
@@ -0,0 +1,83 @@
+{
+    "$id": "http://git.astron.nl/lofar2.0/pypcc/apsctl.schema.json",
+    "$schema": "http://json-schema.org/draft-07/schema",
+    "title": "apsctl",
+    "description": "APSCTL yaml schema",
+    "type" : "object",
+    "properties": {
+        "version": {"type":"string"},
+        "description":{"type":"string"},
+        "drivers":         { "type":"array",  "items": { "$ref": "#/$defs/drivers"}},
+        "device_registers":{ "type":"array",  "items": { "$ref": "#/$defs/dev_regs"}},
+        "variables":{ "type":"array",  "items": { "$ref": "#/$defs/variables"}},
+        "methods":{ "type":"array",  "items": { "$ref": "#/$defs/methods"}}
+    },
+    "additionalProperties" : false,
+    "$defs":{
+        "drivers" : {
+            "type" : "object",
+            "properties": {
+                "name" : {"type":"string"},
+                "type" : {"enum":["i2c","RCU_switch","UNB2_switch","i2c_devs","i2c_array","i2c_array2","hba1","i2cbitbang1","spibitbang1","spibitbang2"]},
+                "parent" : {"type":"string"},
+                "parameters" : {"type":"array","items":{"type":"integer"}} ,
+                "devreg" : {"type":"array","items":{"type":"string"}}
+                },
+                "additionalProperties" : false
+            },
+        "dev_regs" : {
+            "type" : "object",
+            "properties": {
+                "name" : {"type":"string"},
+                "dim" : {"type":"integer"},
+                "description" : {},
+                "address" : {"anyOf":[{"type":"integer"},{"type":"array","items":{"type":"integer"}}]},
+                "device" : {},
+                "driver" : {},
+                "registers":{ "type":"array",  "items": { "$ref": "#/$defs/registers"}}
+            },
+            "additionalProperties" : false
+        },
+        "registers" : {
+            "type" : "object",
+            "properties": {
+                "name" : {"type":"string"},
+                "description" : {"type":"string"},
+                "address" : {},
+                "store" : {"type":"boolean"}
+            },
+            "additionalProperties" : false
+        },
+        "variables" : {
+            "type" : "object",
+            "properties": {
+                "name" : {"type":"string"},
+                "description" : {"type":"string"},
+                "dim" : {"type":"integer"},
+                "dtype" : {"enum":["uint64","uint32","uint16","uint8","double","boolean","string"]},
+                "driver" : {"type":"string"},
+                "rw" : {"enum":["variable","rw","ro","hidden"]},
+                "scale" : {"type":"number"},
+                "bitoffset" : {},
+                "width" : {"type":"integer"},
+                "devreg" : {},
+                "mask" : {"type":"string"}
+            },
+            "additionalProperties" : false
+        },
+        "methods" : {
+            "type" : "object",
+            "properties": {
+                "name" : {"type":"string"},
+                "mask" : {"type":"string"},
+                "instructions" : {"type":"array"},
+                "rw" : {"enum":["visible","hidden"]}
+            },
+            "additionalProperties" : false
+        }
+
+    }
+
+}
+
+
diff --git a/i2c/I2C.py b/i2c/I2C.py
deleted file mode 100644
index 10eddc5245bd9025c220b178d007402d9058eca2..0000000000000000000000000000000000000000
--- a/i2c/I2C.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#import os
-#if os.sys.platform is 'linux':
-import pylibi2c;
-import time
-import logging
-#bus = pylibi2c.I2CDevice('/dev/i2c-1'
-#read=0: write to register
-#read=1: read from register
-#read=2: write to register (common in group)
-#read=3: wait ms second
-I2Ccounter=0;
-
-def I2C1server(addr,data,reg=None,read=0):
-#  print("I2C",addr,reg,data,read)
-  try:
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       logging.debug(str(("I2C",addr,reg,data,read)))
-
-#       return True;
-       bus=pylibi2c.I2CDevice('/dev/i2c-1',addr)
-       if read==1:
-         length=len(data)
-         bus.iaddr_bytes=0
-         if not(reg is None):
-             bus.ioctl_write(0,str(bytearray([reg])))
-         data[:]=[int(x) for x in bus.ioctl_read(0,length)]
-#         print("I2C read",addr,reg,data,read)
-       else:
-            if reg is None: 
-               bus.iaddr_bytes=0
-               reg=0;
-            bus.ioctl_write(reg,str(bytearray(data)))
-       bus.close()
-       return True;
-  except:
-       if bus: bus.close()
-#       data[0]=0xff
-       return False;
-
-def I2C4server(addr,data,reg=None,read=0):
-#  print("I2C4",addr,reg,data,read)
-  try:
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       logging.debug(str(("I2C",addr,reg,data,read)))
-
-#       print("I2C",addr,reg,data,read)
-#       return True;
-       bus=pylibi2c.I2CDevice('/dev/i2c-4',addr)
-       if read==1:
-         length=len(data)
-         bus.iaddr_bytes=0
-         if not(reg is None):
-             bus.ioctl_write(0,str(bytearray([reg])))
-         data[:]=[int(x) for x in bus.ioctl_read(0,length)]
-#         print(data)
-       else:
-            if reg is None:
-               bus.iaddr_bytes=0
-               reg=0;
-            bus.ioctl_write(reg,str(bytearray(data)))
-       bus.close()
-       return True;
-  except:
-       if bus: bus.close()
-#       data[0]=0
-       return False;
-
diff --git a/i2c/I2C.py.old b/i2c/I2C.py.old
deleted file mode 100644
index 1982b43c9c0e13bf33d61d4bf48e8c2b940b5d06..0000000000000000000000000000000000000000
--- a/i2c/I2C.py.old
+++ /dev/null
@@ -1,70 +0,0 @@
-import pylibi2c;
-import time
-import logging
-#bus = pylibi2c.I2CDevice('/dev/i2c-1'
-#read=0: write to register
-#read=1: read from register
-#read=2: write to register (common in group)
-#read=3: wait ms second
-I2Ccounter=0;
-
-def I2C1server(addr,data,reg=None,read=0):
-#  print("I2C",addr,reg,data,read)
-  try:
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       logging.debug(str(("I2C",addr,reg,data,read)))
-
-#       return True;
-       bus=pylibi2c.I2CDevice('/dev/i2c-1',addr)
-       if read==1:
-         length=len(data)
-         bus.iaddr_bytes=0
-         if not(reg is None):
-             bus.ioctl_write(0,str(bytearray([reg])))
-         data[:]=[int(x) for x in bus.ioctl_read(0,length)]
-#         print("I2C read",addr,reg,data,read)
-       else:
-            if reg is None: 
-               bus.iaddr_bytes=0
-               reg=0;
-            bus.ioctl_write(reg,str(bytearray(data)))
-       bus.close()
-       return True;
-  except:
-       if bus: bus.close()
-#       data[0]=0xff
-       return False;
-
-def I2C4server(addr,data,reg=None,read=0):
-#  print("I2C4",addr,reg,data,read)
-  try:
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       logging.debug(str(("I2C",addr,reg,data,read)))
-
-#       print("I2C",addr,reg,data,read)
-#       return True;
-       bus=pylibi2c.I2CDevice('/dev/i2c-4',addr)
-       if read==1:
-         length=len(data)
-         bus.iaddr_bytes=0
-         if not(reg is None):
-             bus.ioctl_write(0,str(bytearray([reg])))
-         data[:]=[int(x) for x in bus.ioctl_read(0,length)]
-#         print(data)
-       else:
-            if reg is None: 
-               bus.iaddr_bytes=0
-               reg=0;
-            bus.ioctl_write(reg,str(bytearray(data)))
-       bus.close()
-       return True;
-  except:
-       if bus: bus.close()
-       print("I2C4 error")
-#       data[0]=0xff
-       return False;
-
diff --git a/i2c/I2C_dummy.py b/i2c/I2C_dummy.py
deleted file mode 100644
index ba39c1a5d6e1df962bc6f5e1eab79140cd5ec122..0000000000000000000000000000000000000000
--- a/i2c/I2C_dummy.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#import pylibi2c;
-import time
-import logging
-#bus = pylibi2c.I2CDevice('/dev/i2c-1'
-#read=0: write to register
-#read=1: read from register
-#read=2: write to register (common in group)
-#read=3: wait ms second
-I2Ccounter=0;
-def I2C1server(addr,data,reg=None,read=0):
-       global I2Ccounter;
-       logging.debug(str(("I2C",addr,reg,data,read)))
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       if read==1:
-           data[0]=0
-       if reg: I2Ccounter+=1;
-       I2Ccounter+=len(data)
-#       logging.debug(str(("I2C",addr,reg,data,read)))
-       return True
-
-def I2C4server(addr,data,reg=None,read=0):
-       global I2Ccounter;
-       logging.debug(str(("I2C4",addr,reg,data,read)))
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       if read==1:
-           data[0]=0
-       if reg: I2Ccounter+=1;
-       I2Ccounter+=len(data)
-#       logging.debug(str(("I2C",addr,reg,data,read)))
-       return True
diff --git a/i2c/I2Cswitch1.py b/i2c/I2Cswitch1.py
deleted file mode 100644
index 187456b1d6cc9eb2d15330d216ff89e72fe42a18..0000000000000000000000000000000000000000
--- a/i2c/I2Cswitch1.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import numpy as np
-import logging
-#import HWconf
-SWaddr=0x70
-class I2Cswitch1():
-    def __init__(self,callback1):
-        self.callback1=callback1;
-        self.CurrentChannel=0;
-
-    def SetChannel(self,channel):
-        if (channel)==self.CurrentChannel: return True;
-        logging.debug(str(("SetChannel",channel,self.CurrentChannel)))
-        self.CurrentChannel=channel
-        return self.callback1(SWaddr,[channel])
-
-    def I2Ccallback(self,RCU,addr,data,reg=None,read=0):
-        self.callback1(addr,data,reg,read)    
-        
-class I2Cswitch0():
-    def __init__(self,callback1):
-       return
-   
-    def SetChannel(self,channel):
-        return True
-
-    def I2Ccallback(self,RCU,addr,data,reg=None,read=0):
-        return
\ No newline at end of file
diff --git a/i2c/I2Cv2.py b/i2c/I2Cv2.py
deleted file mode 100644
index 1627b362488d3a250654c41856f4ecfe1baa41ad..0000000000000000000000000000000000000000
--- a/i2c/I2Cv2.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#import pylibi2c;
-#import 
-from periphery import I2C;
-
-import time
-import logging
-#bus = pylibi2c.I2CDevice('/dev/i2c-1'
-#read=0: write to register
-#read=1: read from register
-#read=2: write to register (common in group)
-#read=3: wait ms second
-I2Ccounter=0;
-
-
-i2c1=I2C("/dev/i2c-1")
-
-def I2C1server(addr,data,reg=None,read=0):
-#  print("I2C",addr,reg,data,read)
-  try:
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       logging.debug(str(("I2C",addr,reg,data,read)))
-       if read==1:
-          if not(reg is None):  i2c1.transfer(addr,[I2C.Message([reg])])
-          msgs=[I2C.Message(data,read=True)]
-          i2c1.transfer(addr,msgs)
-          data[:]=msgs[0].data
-       else:
-            if reg is None: 
-               msgs=[I2C.Message(data)]
-            else:
-               msgs=[I2C.Message([reg]+data)]
-            i2c1.transfer(addr,msgs)
-       return True;
-  except:
-       return False;
-
-i2c4=I2C("/dev/i2c-4")
-
-def I2C4server(addr,data,reg=None,read=0):
-#  print("I2C",addr,reg,data,read)
-  try:
-       if read==3:
-           time.sleep(data[0]/1000.)
-           return True
-       logging.debug(str(("I2C",addr,reg,data,read)))
-
-       if read==1:
-          if not(reg is None):  i2c4.transfer(addr,[I2C.Message([reg])])
-          msgs=[I2C.Message(data,read=True)]
-          i2c4.transfer(addr,msgs)
-          data[:]=msgs[0].data
-       else:
-            if reg is None: 
-               msgs=[I2C.Message(data)]
-            else:
-               msgs=[I2C.Message([reg]+data)]
-            i2c4.transfer(addr,msgs)
-       return True;
-  except:
-       return False;
diff --git a/i2c/setRCUversion.py b/i2c/setRCUversion.py
deleted file mode 100644
index 4771de66e197be6a9f94861bcf39c8c4b2baa3ce..0000000000000000000000000000000000000000
--- a/i2c/setRCUversion.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from I2C import *
-import time
-RCU=1
-Ver="RCU2H v0.2"
-R1=0
-ROM=0x50
-
-#Set switch
-print("Set switch")
-if not(I2C1server(0x70,[1<<RCU],reg=None,read=0)): exit() #select RCU
-#exit()
-#Get ID
-print("Get ID")
-ID=[0]*4
-if not(I2C1server(ROM,ID,reg=0xFC,read=1)): exit() #select RCU
-print(ID)
-exit()
-
-#Upload version
-Ver2=[(c.encode('utf-8')[0]) for c in Ver]
-print(len(Ver),Ver,Ver2)
-V2=[0]
-for i,v in enumerate(Ver2):
- time.sleep(0.1)
- I2C1server(ROM,[v],reg=R1+i,read=0) #select RCU
-# I2C1server(ROM,[v],reg=None,read=0) #select RCU
- time.sleep(0.1)
- I2C1server(ROM,V2,reg=R1+i,read=1) #select RCU
- print(i,v,V2)
-
-#Download version
-Ver2=[0]*10
-I2C1server(ROM,Ver2,reg=R1,read=1) #select RCU
-print(Ver2)
diff --git a/i2c/setswitch.py b/i2c/setswitch.py
deleted file mode 100644
index 45f43942a9b3dc1fc7cde1b4efa5a06b674bde92..0000000000000000000000000000000000000000
--- a/i2c/setswitch.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from I2C import *
-import time
-RCU=3
-Ver="RCU2H v0.2"
-R1=0
-ROM=0x50
-
-#Set switch
-print("Set switch")
-if not(I2C1server(0x70,[1<<RCU],reg=None,read=0)):
-   print("Error setting switch!")
-   exit() #select RCU
-exit()
-#Get ID
-print("Get ID")
-ID=[0]*4
-if not(I2C1server(ROM,ID,reg=0xFC,read=1)): exit() #select RCU
-print(ID)
-exit()
-
-#Upload version
-Ver2=[(c.encode('utf-8')[0]) for c in Ver]
-print(len(Ver),Ver,Ver2)
-V2=[0]
-for i,v in enumerate(Ver2):
- time.sleep(0.1)
- I2C1server(ROM,[v],reg=R1+i,read=0) #select RCU
-# I2C1server(ROM,[v],reg=None,read=0) #select RCU
- time.sleep(0.1)
- I2C1server(ROM,V2,reg=R1+i,read=1) #select RCU
- print(i,v,V2)
-
-#Download version
-Ver2=[0]*10
-I2C1server(ROM,Ver2,reg=R1,read=1) #select RCU
-print(Ver2)
diff --git a/i2c/test.py b/i2c/test.py
deleted file mode 100644
index 92ee093a8b833322558341cd664855f643f57dd1..0000000000000000000000000000000000000000
--- a/i2c/test.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from I2C import *
-import time
-RCU=1
-Ver="RCU2H v0.2"
-R1=0
-ROM=0x50
-
-ID=[0]*7
-I2C1server(0x20,ID,reg=2,read=1)
-print(ID)
-I2C1server(0x20,ID,reg=2,read=1)
-print(ID)
-exit()
-#0=0
-#1=0   #debug?
-#2=21  #spd1
-#3=7   #spd2
-#4=175 #TXspeed
-#5=0
-#6=0
-
-#Upload version
-Ver2=[(c.encode('utf-8')[0]) for c in Ver]
-print(len(Ver),Ver,Ver2)
-V2=[0]
-for i,v in enumerate(Ver2):
- time.sleep(0.1)
- I2C1server(ROM,[v],reg=R1+i,read=0) #select RCU
-# I2C1server(ROM,[v],reg=None,read=0) #select RCU
- time.sleep(0.1)
- I2C1server(ROM,V2,reg=R1+i,read=1) #select RCU
- print(i,v,V2)
-
-#Download version
-Ver2=[0]*10
-I2C1server(ROM,Ver2,reg=R1,read=1) #select RCU
-print(Ver2)
diff --git a/clk/__init__.py b/i2cserv/__init__.py
similarity index 100%
rename from clk/__init__.py
rename to i2cserv/__init__.py
diff --git a/i2cserv/gpio.py b/i2cserv/gpio.py
new file mode 100644
index 0000000000000000000000000000000000000000..20e38ab4a1161a435ee7c202bf5786a10510660a
--- /dev/null
+++ b/i2cserv/gpio.py
@@ -0,0 +1,7 @@
+#import numpy as np
+from .hwdev import hwdev;
+import logging
+class gpio(hwdev):
+  def __init__(self,config):
+    hwdev.__init__(self,config);
+    logging.info("gpio todo")
diff --git a/i2cserv/gpio_hba_trigger.py b/i2cserv/gpio_hba_trigger.py
new file mode 100644
index 0000000000000000000000000000000000000000..452f5630af6bde50e9e1f6daeba798e6fd22634e
--- /dev/null
+++ b/i2cserv/gpio_hba_trigger.py
@@ -0,0 +1,28 @@
+from .hwdev import hwdev;
+import logging
+import signal
+try:
+  import RPi.GPIO as GPIO
+except:
+  GPIO=False;
+  
+class gpio_hba_trigger(hwdev):
+  def __init__(self,config):
+    hwdev.__init__(self,config);
+    self.pin=config['parameters'][0];
+    logging.info("HBAT wait for PPS on pin %i",self.pin)
+    if GPIO:
+      GPIO.setmode(GPIO.BCM)
+      GPIO.setup(self.pin,GPIO.IN)
+    else:
+      logging.warn("RPi GPIO module not found, PPS input disable!")
+
+  def i2csetget(self,addr,data,reg=None,read=0):
+    if (read==0) and GPIO:
+      channel=GPIO.wait_for_edge(self.pin,GPIO.RISING,timeout=1500)
+      if channel is None:
+        logging.info("PPS not received!");
+        return False;
+    self.conf['parentcls'].i2csetget(addr,data,reg,read)
+    
+    
diff --git a/i2cserv/hba1.py b/i2cserv/hba1.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a0524b35767457a6b60a237ab7775bfcf3e2fb1
--- /dev/null
+++ b/i2cserv/hba1.py
@@ -0,0 +1,51 @@
+import numpy as np
+from .hwdev import hwdev
+import logging
+from .i2c_array import ApplyMask
+from time import sleep
+from queuetypes import *
+
+class hba1(hwdev):
+  def __init__(self,config):
+    hwdev.__init__(self,config);
+    logging.info("HBA1 driver loaded")
+#    self.previousHBA=np.zeros([32,3,32],dtype='int')
+
+  def OPCUASetVariable(self,varid,var1,data,mask):
+       logging.info(str(("HBA set Var",var1['name'],data[:32*3],mask[:12])))
+       self.conf['parentcls'].SetGetVarValueMask(var1,data,mask,getalso=False)
+       #Wait for PPS if required else wait a bit
+       if var1.get('wait'):
+         logging.debug("Wait %i ms",var1.get('wait')) 
+         sleep(var1['wait']/100.)
+       data,mask2=self.conf['parentcls'].GetVarValueMask(var1,mask)
+       Data=OPCUAset(varid,InstType.varSet,data.copy(),mask2.copy())
+       return [Data]
+
+  def i2csetget(self,addr,data,reg=None,read=0):
+    if read==0: return self.sethba(addr,reg,data)
+    elif read==1: return self.gethba(addr,reg,data)
+    else: logging.warn("Not implemented!")
+    return False;
+
+  def sethba(self,addr,reg,data):
+      logging.debug("SetHba addr=0x%x reg=0x%x",addr,reg)
+      I2Ccallback=self.conf['parentcls'].i2csetget
+      I2Ccallback(0x40,[0],read=1)#wakeup, do nothing
+      sleep(0.01) 
+      I2Ccallback(addr,data[:16],reg=reg)
+      if len(data)>16:
+        sleep(0.01) 
+        I2Ccallback(addr,data[16:],reg=reg+16)
+      sleep(0.01) 
+      return True
+
+  def gethba(self,addr,reg,data):
+      I2Ccallback=self.conf['parentcls'].i2csetget
+#      logging.debug("getHba addr=0x%x reg=0x%x",addr,reg)
+      if not(I2Ccallback(addr,data,read=1)): return False;
+#      I2Ccallback(addr,data,read=1);
+      logging.debug("getHba addr=0x%x reg=0x%x data=%s",addr,reg,str((data)))
+      if data is None:  return False
+#      data[:]=[255]*len(data)
+      return True;
\ No newline at end of file
diff --git a/i2cserv/hwdev.py b/i2cserv/hwdev.py
new file mode 100644
index 0000000000000000000000000000000000000000..a365a1c16a3508e729ef86f2d9101d338b78c4a8
--- /dev/null
+++ b/i2cserv/hwdev.py
@@ -0,0 +1,17 @@
+
+import logging
+class hwdev():
+  def __init__(self,config):
+        #print("Init",config['name'])  
+        self.conf=config
+
+  def OPCUASetVariable(self,varid,var1,data,mask):
+      logging.warn(self.conf['name']+" OPCUASetVariable Not implemented!")
+
+  def OPCUAReadVariable(self,varid,var1,mask):
+      logging.warn(self.conf['name']+" OPCUAReadVariable Not implemented!")
+      return []
+
+  def OPCUAcallMethod(self,var1,data,mask):
+      logging.warn(self.conf['name']+" OPCUAcallVariable Not implemented!")
+      return []
diff --git a/i2cserv/i2c.py b/i2cserv/i2c.py
new file mode 100644
index 0000000000000000000000000000000000000000..3eb98b2e5b2709666b647b370600ac8f6fc27a61
--- /dev/null
+++ b/i2cserv/i2c.py
@@ -0,0 +1,52 @@
+import os
+#if os.sys.platform is 'linux':
+import pylibi2c;
+import time
+import logging
+#read=0: write to register
+#read=1: read from register
+#read=2: write to register (common in group)
+#read=3: wait ms second
+from .hwdev import hwdev;
+
+class i2c(hwdev):
+    def __init__(self,config):
+       hwdev.__init__(self,config);
+       self.I2Cdev='/dev/i2c-'+str(config['parameters'][0]);
+       logging.info("i2c driver on port "+str(self.I2Cdev))
+       self.I2Ccounter=0
+
+    def i2csetget(self,addr,data,reg=None,read=0):
+#       logging.debug(str(("I2C",addr,reg,data,read)))
+       bus=None;
+       try:
+#       if True:
+              if read==3:
+                     time.sleep(data[0]/1000.)
+                     return True
+
+#       return True;
+              bus=pylibi2c.I2CDevice(self.I2Cdev,addr)
+              if read==1:
+                     length=len(data)
+                     bus.iaddr_bytes=0
+                     if not(reg is None):
+                            bus.ioctl_write(0,bytes(bytearray([reg])))
+                     data[:]=[int(x) for x in bus.ioctl_read(0,length)]
+                     logging.debug(str(("I2C get",addr,reg,data,read)))
+#         print("I2C read",addr,reg,data,read)
+              else:
+                     if reg is None: 
+                            bus.iaddr_bytes=0
+                            reg=0;
+                     logging.debug(str(("I2C set",addr,reg,bytes(bytearray(data)),read)))
+                     bus.ioctl_write(reg,bytes(bytearray(data)))
+              bus.close()
+              return True;
+       except:
+#       else:
+              if bus: bus.close()
+              logging.debug("I2C failed!")
+#       data[0]=0xff
+              return False;
+
diff --git a/i2cserv/i2c_array.py b/i2cserv/i2c_array.py
new file mode 100644
index 0000000000000000000000000000000000000000..60fed98e8b6247608a9c99ba03605d8a4e7c7696
--- /dev/null
+++ b/i2cserv/i2c_array.py
@@ -0,0 +1,216 @@
+import numpy as np
+import logging
+from .spibitbang1 import spibitbang1
+from queuetypes import *
+from .hwdev import hwdev
+from .i2c_dev import *
+
+def GetSteps(V1):
+              if isinstance(V1['devreg'],list): Step=len(V1['devreg']) 
+              else: Step=1; #V1.nVars
+              Step2=V1.get('dim',1)*((V1.get('width',8)+7)//8)//Step #int(V1.size/V1.nVars)
+              logging.debug(str(("GetStep",Step,Step2)));
+              return Step,Step2
+
+class i2c_array(i2c_dev):
+    def __init__(self,config):
+        i2c_dev.__init__(self,config);
+#        self.Qout=Qout;
+#        self.Qin=Qin;
+#        self.I2Ccallback=I2Ccallback
+#        self.SWcallback=Switchcallback
+#        self.previousHBA=np.zeros([number,3,32],dtype='int')
+        pars=config['parameters'];
+        self.RCU_Switch1=range(pars[0],pars[1]+1);
+        self.N=len(self.RCU_Switch1);
+        self.I2Cmask=[0]*self.N
+
+#        self.devregs,RCU_storeReg=DevRegList(yaml)
+#        print("Init",config['name'],'len=',len(self.RCU_Switch1),' stored reg=',RCU_storeReg)
+#        self.previous   =np.zeros([self.N,RCU_storeReg],dtype='int')
+
+    def OPCUAReadVariable(self,varid,var1,mask):
+      if len(mask)==0: mask=[True]*self.N; 
+      return i2c_dev.OPCUAReadVariable(self,varid,var1,mask)
+
+    def SetSwitch(self,RCUi):
+        self.conf['parentcls'].SetSW1(self.RCU_Switch1[RCUi]);
+
+    def SetSwitchMask(self,mask):
+        m=0;
+        for RCUi in range(self.N):
+           if (mask[RCUi]) and (self.I2Cmask[RCUi]==0): 
+               m|=1<<self.RCU_Switch1[RCUi];
+        self.conf['parentcls'].SetChannel(m);
+
+    def SetGetVarValueMask(self,var1,data,mask,getalso=True):
+        Step,Step2=GetSteps(var1);
+        value1=[0]*Step*Step2;
+        if len(data)==Step:
+           data=data*self.N;
+        if not(len(data)==Step*Step2):
+            print("Check data length!");
+            return;
+        Step2//=self.N
+        if (len(mask)==self.N):
+          mask=[m for m in mask for x in range(Step)]
+        if not(len(mask)==Step*self.N):
+            print("Check mask length!");
+            return;
+#        if (len(value1)==V1.nVars) and (self.N>1):  value1=(value1*self.N);
+#        logging.debug(str(("Step=",Step,"Mask=",mask)))
+        for RCUi in range(self.N):
+            for Vari in range(Step):
+                if not(mask[RCUi*Step+Vari]): continue
+                if not(self.I2Cmask[RCUi]==0):
+                  mask[RCUi*Step+Vari]=False;
+                  continue;
+                i0=(RCUi*Step+    Vari)*Step2
+                i1=(RCUi*Step+(Vari+1))*Step2
+                devreg=var1['devreg'][Vari];
+                width=var1.get('width',8)
+                bitoffset=GetField(var1,'bitoffset',Vari,0)
+                self.SetSwitch(RCUi);
+                self.RCUi=RCUi;
+                res=self.SetVarValue(devreg,width,bitoffset,data[i0:i1])
+                if not(res):
+                  self.I2Cmask[RCUi]=1;
+                  mask[RCUi*Step+Vari]=False;
+                  continue;
+                if getalso:
+                  value2=value1[i0:i1]
+                  res=self.GetVarValue(devreg,width,bitoffset,value2)
+                  if not(res):
+                    self.I2Cmask[RCUi]=1;
+                    mask[RCUi*Step+Vari]=False;
+                    continue;
+                  value1[i0:i1]=value2
+        return value1,mask
+
+
+    def GetVarValueMask(self,var1,mask):
+        Step,Step2=GetSteps(var1);
+        value1=[0]*Step*Step2;
+        Step2//=self.N
+        if (len(mask)==self.N):
+          mask=[m for m in mask for x in range(Step)]
+        if not(len(mask)==Step*self.N):
+            print("Check mask length!");
+            return;
+#        if (len(value1)==V1.nVars) and (self.N>1):  value1=(value1*self.N);
+        i2c=self.conf['parentcls'];
+#        logging.debug(str(("Step=",Step,"Mask=",mask)))
+        for RCUi in range(self.N):
+            for Vari in range(Step):
+                if not(mask[RCUi*Step+Vari]): continue
+                if not(self.I2Cmask[RCUi]==0):
+                  mask[RCUi*Step+Vari]=False;
+                  continue;
+                i0=(RCUi*Step+    Vari)*Step2
+                i1=(RCUi*Step+(Vari+1))*Step2
+                devreg=var1['devreg'][Vari];
+                width=var1.get('width',8)
+                bitoffset=GetField(var1,'bitoffset',Vari,0)
+                self.SetSwitch(RCUi);
+                value2=value1[i0:i1]
+                self.RCUi=RCUi;
+                res=self.GetVarValue(devreg,width,bitoffset,value2)
+                if not(res):
+                  self.I2Cmask[RCUi]=1;
+                  mask[RCUi*Step+Vari]=False;
+                  continue;
+                value1[i0:i1]=value2
+        return value1,mask
+
+    def getstorearray(self,devreg,N=1):
+          storearray=devreg.get('storearray')
+          if not(storearray):
+                devreg['storearray']=([0] if N==1 else [[0]*N])*self.N;
+                storearray=devreg.get('storearray');
+          return storearray;
+
+    def Setdevreg(self,devreg,value,mask=[]):
+#        if devreg.get('store'): logging.debug("Stored")
+#        print(devreg['store'])
+        self.SetSwitchMask(mask)
+        if not(self.SetVarValue(devreg,8,0,value)): return False;
+        if devreg.get('store'):
+                storearray=self.getstorearray(devreg);
+                for RCUi in range(self.N):
+                  if (mask[RCUi]) and (self.I2Cmask[RCUi]==0):   
+                      storearray[RCUi]=value[0]
+                      self.RCUi=RCUi;
+                logging.debug(str(("Stored values:",self.getstorearray(devreg))))
+        return True;
+        
+
+    def Getdevreg(self,devreg,mask=[]):
+        value1=[0]*self.N
+        mask=[True]*self.N
+        if devreg.get('store'):
+                storearray=self.getstorearray(devreg);
+        i2c=self.conf['parentcls'];
+        for RCUi in range(self.N):
+                if not(mask[RCUi]): continue
+                if not(self.I2Cmask[RCUi]==0): continue
+                self.SetSwitch(RCUi);
+                value2=[value1[RCUi]]
+                self.RCUi=RCUi;
+                res=self.GetVarValue(devreg,8,0,value2)
+                if not(res):
+                    self.I2Cmask[RCUi]=False;
+                value1[RCUi]=value2[0]
+                if devreg.get('store'):
+                  if mask[RCUi]:   
+                      storearray[RCUi]=value2[0]
+        logging.debug(str(("Stored values:",self.getstorearray(devreg))))
+        return True;
+
+    def SetVarValue(self,devreg,width,bitoffset,value):
+            if devreg['register_W']==-1: return True; #We can not set it, only read it e.g. temperature
+            logging.debug(str(("RCU1 Set ",self.RCUi,devreg['addr'],value)))
+            #self.parentcls.SetChannel(1<<RCU_Switch[RCUi]);
+            if devreg['store']:
+                storearray=self.getstorearray(devreg);
+                previous=storearray[self.RCUi];
+                for x in range(len(value)):
+                  value[x]=ApplyMask(value[x],width,bitoffset,previous);
+                storearray[self.RCUi]=(value[0] if len(value)==1 else value[:])
+                logging.debug("Stored value:"+str(storearray[self.RCUi]))
+            #  devreg['drivercls'].i2csetget
+            return devreg['drivercls'].i2csetget(devreg['addr'],value,reg=devreg['register_W'])
+
+    def GetVarValue(self,devreg,width,bitoffset,value):
+        logging.debug(str(("RCU1 Get ",self.RCUi,devreg['addr'],value)))
+#                self.GetI2C(RCUi,devreg,width,bitoffset,value)
+#        if dev.store>0:
+#            value[0]=self.previous[RCUi,dev.store-1]
+#        return True
+        callback=devreg['drivercls'].i2csetget;
+        l1=int(np.floor((width+bitoffset+7)/8))
+#        print(width,bitoffset,l1)
+        value2=value
+        reg=devreg['register_R']
+        if reg>255: #This is for the monitor ADC
+          if not(callback(devreg['addr'],int2bytes(reg),read=2)): return False;
+          callback(0,[250],read=3)
+          if not(callback(devreg['addr'],value2,read=1)): return False;
+        else:
+          if not(callback(devreg['addr'],value2,reg=reg,read=1)): return False;
+        if value2[0] is None:  return False
+        value[:]=value2[:];
+        if devreg['store']:
+             storearray=self.getstorearray(devreg,len(value));
+             storearray[self.RCUi]=(value[0] if len(value)==1 else value[:])
+             logging.debug(str(("Store buffer",self.RCUi,storearray[self.RCUi])))
+ #            print("Stored values:",self.getstorearray(devreg))
+        if (width!=l1*8) or (bitoffset>0):
+            if (width<8):
+              for i in range(len(value)):
+                value[i]=UnMask(value[i],width,bitoffset)
+            else:
+                value[0]=UnMask(value[0],width-(l1-1)*8,bitoffset)
+        else: value[0]=value2[0]
+        return True;
+
+
diff --git a/i2cserv/i2c_array2.py b/i2cserv/i2c_array2.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef71eb3661414a3d1683c74950bf9d82a83dbabf
--- /dev/null
+++ b/i2cserv/i2c_array2.py
@@ -0,0 +1,43 @@
+import logging
+from .i2c_array import i2c_array;
+from .hwdev import hwdev
+from .i2c_dev import i2c_dev
+
+
+class i2c_array2(i2c_array):
+    def __init__(self,config):
+        i2c_dev.__init__(self,config);
+
+#       Make array of switch states
+        pars=config['parameters'];
+        self.Nswitch=(len(pars)+1)//2;
+        sw1=list(range(pars[0],pars[1]+1));
+        sw2=([] if len(pars)<4 else list(range(pars[2],pars[3]+1)))
+        sw3=([] if len(pars)<6 else list(range(pars[4],pars[5]+1)))
+        sw4=([] if len(pars)<8 else list(range(pars[6],pars[7]+1)))
+        sw3=sw3+sw4
+        if self.Nswitch>3: self.Nswitch=3;
+        self.RCU_Switch1=range(pars[0],pars[1]+1);
+        self.N=len(sw1)
+        if len(sw2)>0: self.N*=len(sw2)
+        if len(sw3)>0: self.N*=len(sw3)
+        self.I2Cmask=[0]*self.N
+        self.sw1=[x for x in sw1 for i in range(self.N//len(sw1))]
+        self.sw2=[x for x in sw2 for i in range(self.N//len(sw1)//len(sw2))]*len(sw1)
+        self.sw3=[x for x in sw3]*len(sw1)*len(sw2)
+        logging.debug(str(("Init",config['name'],' len=',self.N,'Nswitch=',self.Nswitch,self.sw1,self.sw2,self.sw3)))
+
+    def SetSwitch(self,RCUi):
+        #print("Set switch element",RCUi,'=',self.sw1[RCUi],self.sw2[RCUi],(self.sw3[RCUi] if len(self.sw3)<0 else 'x'))
+        self.conf['parentcls'].SetSW1(self.sw1[RCUi]);
+        self.conf['parentcls'].SetSW2(self.sw2[RCUi]);
+        if len(self.sw3)>0:
+                self.conf['parentcls'].SetSW3(self.sw3[RCUi]);
+
+    def SetSwitchMask(self,mask):
+        logging.warn("Not implemented!!")
+#        m=0;
+#        for RCUi in range(self.N):
+#           if mask[RCUi]: m|=1<<self.RCU_Switch1[RCUi];
+#        self.conf['parentcls'].SetChannel(m);
+
diff --git a/i2cserv/i2c_dev.py b/i2cserv/i2c_dev.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f73afaad2f28220342175219b4b1ad2d80c8de4
--- /dev/null
+++ b/i2cserv/i2c_dev.py
@@ -0,0 +1,266 @@
+import numpy as np
+import logging
+from .spibitbang1 import spibitbang1
+from queuetypes import *
+from .hwdev import hwdev
+
+def ApplyMask(value,width=8,bitoffset=0,previous=0):
+    mask=(1<<width)-1
+    if bitoffset>0:
+      value<<=bitoffset;
+      mask<<=bitoffset;
+    return (value & mask) + (previous - (previous & mask));
+def UnMask(value,width=8,bitoffset=0):
+    mask=(1<<width)-1
+    if bitoffset>0:
+      value>>=bitoffset;
+    value=value&mask;
+    return value;
+
+def int2bytes(i):
+   b=[];
+   while i>255:
+        b=[i%256]+b;
+        i>>=8;
+   return [i]+b;
+
+def GetField(D,name,dev_number,default=None):
+    X=D.get(name,default)
+    return X[dev_number] if isinstance(X,list) else X;
+def Find(L,name,value):
+  for x in L:
+    if x[name]==value:
+        return x;
+  return False;
+
+class AttrDict(dict):
+  def __init__(self,*args,**kwargs):
+    super(AttrDict,self).__init__(*args,**kwargs)
+    self.__dict__=self
+
+def DevRegList(D):
+  #todo only count the drivers registers!!
+  for i,dev in enumerate(D.drivers):
+    dev['drv_id']=i;
+  devreglist={}
+  store=0;
+  for dev in D.device_registers:
+    N=dev.get('dim',1)
+    name=dev['name']    
+    for n in range(N):
+      addr=GetField(dev,'address',n,0)
+      devtype=GetField(dev,'driver',n)
+#      print(addr,devtype)
+      devid=0;
+      if devtype:
+        devid=Find(D.drivers,'name',devtype)['drv_id']
+        devtype=Find(D.drivers,'name',devtype)['type']
+      else: devtype=0;
+      if N>1: name2=name+str(n+1)
+      else:   name2=name;
+      for reg in dev['registers']:
+         regR=GetField(reg,'address',0,0)
+         regW=GetField(reg,'address',1,0)
+         if reg.get('store',False):
+            store+=1;
+            storex=store
+         else:
+            storex=0
+#         hf.write("const devreg %s {%i,%i,%i,%i,%i};\n" % (name2+'_'+reg['name'],addr,regR,regW,storex,devtype) )
+         devregname=name2+'.'+reg['name'];
+         devreglist[devregname]=AttrDict({"Addr":addr,"Register_R":regR,"Register_W":regW,"store":storex,"devtype":devtype,"devid":devid});
+#         print(devregname,devreglist[devregname]);
+#         hf.write("inline const t_devreg %s {.address=%i,.register_R=%i,.register_W=%i,.store=%i,.driver=%i};\n" % (devregname,addr,regR,regW,storex,devtype) )
+#hf.write("#define NumberStoreReg %i"%store)
+#  print(devreglist)
+  return devreglist,store
+
+def list_different(A,B):
+      if not(len(A)==len(B)): return True;
+      for i,m in enumerate(B): 
+          if not(m==A[i]): return True
+      return False
+
+class i2c_dev(hwdev):
+    def __init__(self,config):
+        hwdev.__init__(self,config);
+        self.I2Cmask=[0]
+        self.I2Cmaskid=config.get('maskid',None)
+        if self.I2Cmaskid is None: logging.warn(config['name']+" I2C mask not found!")
+
+    def OPCUASetVariable(self,varid,var1,data,mask):
+       logging.info(str(("Set Var",var1['name'],data,mask)))
+       if (var1['rw']=='variable') or not(var1.get('devreg')):
+          if varid==self.I2Cmaskid:
+              if len(mask)==0: mask=[True]*len(data);
+              if len(data)!=len(mask): 
+                logging.warn("Trying to set I2C OK with wrong mask length!")
+                return []
+              for x,m in enumerate(mask):
+                if m: self.I2Cmask[x]=data[x];
+                return [OPCUAset(self.I2Cmaskid,InstType.varSet,self.I2Cmask.copy(),[])]
+          return [OPCUAset(varid,InstType.varSet,data,mask)];
+       oldmask=self.I2Cmask.copy()
+       data,mask2=self.SetGetVarValueMask(var1,data,mask);
+#       if len(mask)==len(mask2): mask[:]=mask2[:];
+#       elif len(mask)==0: (mask.append(x) for x in mask2);
+       Data=OPCUAset(varid,InstType.varSet,data.copy(),mask2.copy())
+       if list_different(self.I2Cmask,oldmask):
+           Data=[Data,OPCUAset(self.I2Cmaskid,InstType.varSet,self.I2Cmask.copy(),[])]
+       else: Data=[Data] 
+       return Data
+
+    def OPCUAReadVariable(self,varid,var1,mask):
+      logging.info(str(("Read Var",var1['name'],mask)))
+      if not(var1.get('devreg')): return []
+      #data=self.GetVarValueAll(var1)
+      #else:             
+      oldmask=self.I2Cmask.copy()
+      data,mask2=self.GetVarValueMask(var1,mask);
+#      if len(mask)==len(mask2): mask[:]=mask2[:];
+#      elif len(mask)==0: (mask.append(x) for x in mask2);
+      Data=OPCUAset(varid,InstType.varSet,data.copy(),mask2.copy())
+      if list_different(self.I2Cmask,oldmask):
+           Data=[Data,OPCUAset(self.I2Cmaskid,InstType.varSet,self.I2Cmask.copy(),[])]
+      else: Data=[Data] 
+      return Data
+
+#    def OPCUAcallMethod(self,var1,data,mask):
+#       print("Call Method",var1)
+    
+    def i2csetget(self,*args,**kwargs):
+       return self.conf['parentcls'].i2csetget(*args,**kwargs)
+    
+    def SetGetVarValueMask(self,var1,data,mask):
+        Step=(len(var1['devreg']) if isinstance(var1['devreg'],list) else 1)
+        value1=[0]*Step
+        if not(len(data)==Step):
+            print("Check data length!");
+            return;
+        if (len(mask)==1):
+          mask=[mask[0] for x in range(Step)]
+        if (len(mask)==0):
+          mask=[True for x in range(Step)]
+        if not(len(mask)==Step):
+            print("Check mask length!");
+            return;
+        for Vari in range(Step):
+                if not(mask[Vari]): continue
+                if not(self.I2Cmask[0]==0):
+                  mask[Vari]=False;
+                  continue;
+                i0=(Vari)*Step
+                i1=(Vari+1)*Step
+                devreg=var1['devreg'][Vari];
+                width=var1.get('width',8)
+                bitoffset=GetField(var1,'bitoffset',Vari,0)
+                res=self.SetVarValue(devreg,width,bitoffset,data[i0:i1])
+                if not(res):
+                  self.I2Cmask[0]=1;
+                  mask[Vari]=False;
+                  continue;
+                value2=value1[i0:i1]
+                res=self.GetVarValue(devreg,width,bitoffset,value2)
+                if not(res):
+                  self.I2Cmask[0]=1;
+                  mask[Vari]=False;
+                  continue;
+                value1[i0:i1]=value2
+        return value1,mask
+
+
+    def GetVarValueMask(self,var1,mask):
+        Step=(len(var1['devreg']) if isinstance(var1['devreg'],list) else 1)
+        value1=[0]*Step;
+        if (len(mask)==1):
+          mask=[mask[0] for x in range(Step)]
+        if (len(mask)==0):
+          mask=[True for x in range(Step)]
+        if not(len(mask)==Step):
+            print("Check mask length!");
+            return;
+        for Vari in range(Step):
+                if not(mask[Vari]): continue
+                if not(self.I2Cmask[0]==0):
+                  mask[Vari]=False;
+                  continue;
+                i0=( Vari)*Step
+                i1=(Vari+1)*Step
+                devreg=var1['devreg'][Vari];
+                width=var1.get('width',8)
+                bitoffset=GetField(var1,'bitoffset',Vari,0)
+                value2=value1[i0:i1]
+                res=self.GetVarValue(devreg,width,bitoffset,value2)
+                if not(res):
+                  self.I2Cmask[0]=1;
+                  mask[Vari]=False;
+                  continue;
+                value1[i0:i1]=value2
+        return value1,mask
+
+
+    def getstoreval(self,devreg):
+          storeval=devreg.get('storeval')
+          if not(storeval):
+                devreg['storeval']=0;
+                storeval=devreg.get('storeval');
+          return storeval;
+
+    def Setdevreg(self,devreg,value,mask=[]):
+#        if devreg.get('store'): logging.debug("Stored")
+#        print(devreg['store'])
+        if not(self.I2Cmask[0]==0): return False;
+        res=self.SetVarValue(devreg,8,0,value)
+        if not(res):
+          self.I2Cmask[0]=1;
+          return False;
+        if devreg.get('store'):
+           devreg['storeval']=value[0];
+        return True;
+
+    def Getdevreg(self,devreg,mask=[]):
+        value=[0];
+        if not(self.I2Cmask[0]==0): return False;
+        res=self.GetVarValue(devreg,8,0,value)
+        if not(res):
+          self.I2Cmask[0]=1;
+          return False;
+        if devreg.get('store'):
+                devreg['storeval']=value[0];
+                logging.debug("Stored value:"+str(value[0]))
+        return True;        
+
+    def SetVarValue(self,devreg,width,bitoffset,value):
+            if devreg['register_W']==-1: return True; #We can not set it, only read it e.g. temperature
+            logging.debug(str(("I2C Set ",devreg['addr'],value)))
+            #self.parentcls.SetChannel(1<<RCU_Switch[RCUi]);
+            if devreg['store']:
+                previous=self.getstoreval(devreg);
+                for x in range(len(value)):
+                  value[x]=ApplyMask(value[x],width,bitoffset,previous);
+                devreg['storeval']=value[0];
+                logging.debug("Stored value:"+str(value[0]))
+            #  devreg['drivercls'].i2csetget
+            return devreg['drivercls'].i2csetget(devreg['addr'],value,reg=devreg['register_W'])
+
+    def GetVarValue(self,devreg,width,bitoffset,value):
+        logging.debug(str(("RCU1 Get ",devreg['addr'],value)))
+        callback=devreg['drivercls'].i2csetget;
+        value2=value
+        reg=devreg['register_R']
+        if not(callback(devreg['addr'],value2,reg=reg,read=1)): return False;
+        if value2[0] is None:  return False
+        value[:]=value2[:];
+        if devreg['store']:
+             devreg['storeval']=value[0];
+        l1=int(np.floor((width+bitoffset+7)/8))
+        #print(value[0],width,bitoffset,l1)
+        if (width!=l1*8) or (bitoffset>0):
+            if (width<8):
+              for i in range(len(value)):
+                value[i]=UnMask(value[i],width,bitoffset)
+            else:
+                value[0]=UnMask(value[0],width-(l1-1)*8,bitoffset)
+        else: value[0]=value2[0]
+        return True;
+
diff --git a/i2cserv/i2c_switch.py b/i2cserv/i2c_switch.py
new file mode 100644
index 0000000000000000000000000000000000000000..6863b5ad2688fc7aacb2d1898575cd200a191617
--- /dev/null
+++ b/i2cserv/i2c_switch.py
@@ -0,0 +1,28 @@
+import logging
+from .i2c import i2c
+
+#import HWconf
+#SWaddr=0x70
+class i2c_switch(i2c):
+    def __init__(self,config):
+        i2c.__init__(self,config)
+        self.SWaddr=config['devreg'][0]['addr']
+        self.CurrentChannel=0
+        logging.info("i2c switch at address "+str(self.SWaddr))
+
+    def SetSW1(self,channelbit):
+        channel=(0 if (channelbit>5) else 1<<(channelbit)) #LTS
+        if (channel)==self.CurrentChannel: return True;
+        logging.debug("SetChannelbit=%i" % channelbit)
+        self.CurrentChannel=channel
+        return self.i2csetget(self.SWaddr,[channel])
+
+    def SetChannel(self,channel):
+        channel&=0x3F;#LTS
+        if (channel)==self.CurrentChannel: return True;
+        logging.debug("SetChannel=%i" % channel)
+        self.CurrentChannel=channel
+        return self.i2csetget(self.SWaddr,[channel])
+
+#    def I2Ccallback(self,RCU,addr,data,reg=None,read=0):
+#        self.callback1(addr,data,reg,read)    
diff --git a/i2cserv/i2c_switch2.py b/i2cserv/i2c_switch2.py
new file mode 100644
index 0000000000000000000000000000000000000000..e86b47cff9fa12144433358100be54c006260fb0
--- /dev/null
+++ b/i2cserv/i2c_switch2.py
@@ -0,0 +1,39 @@
+#3 switches of UNB2
+import logging
+from .i2c import i2c
+
+class i2c_switch2(i2c):
+    def __init__(self,config):
+        i2c.__init__(self,config)
+        self.SWaddr1=config['devreg'][0]['addr']
+        self.SWaddr2=config['devreg'][1]['addr']
+        self.SWaddr3=config['devreg'][2]['addr']
+        self.channel1=0
+        self.channel2=0
+        self.channel3=0
+        logging.info("i2c switch2 at address %i,%i,%i" % (self.SWaddr1,self.SWaddr2,self.SWaddr3))
+
+    def SetSW1(self,channelbit):
+        channel=1<<(channelbit)
+        if (channel)==self.channel1: return True;
+        logging.debug("SetChannel1=%i" % channelbit)
+        self.channel1=channel
+        self.channel2=0
+        self.channel3=0
+        return self.i2csetget(self.SWaddr1,[channel])
+
+    def SetSW2(self,channelbit):
+        channel=1<<(channelbit)
+        if (channel)==self.channel2: return True;
+        logging.debug("SetChannel2=%i" % channelbit)
+        self.channel2=channel
+        self.channel3=0
+        return self.i2csetget(self.SWaddr2,[channel])
+
+    def SetSW3(self,channelbit):
+        channel=1<<(channelbit)
+        if (channel)==self.channel3: return True;
+        logging.debug("SetChannel3=%i" % channelbit)
+        self.channel3=channel
+        return self.i2csetget(self.SWaddr3,[channel])
+
diff --git a/rcu/spibitbang1.py b/i2cserv/i2cbitbang1.py
similarity index 80%
rename from rcu/spibitbang1.py
rename to i2cserv/i2cbitbang1.py
index ca8fd300bdb46cd1463318a9ea9b727d1c323580..8aacf743f7fe6f395dfdfb6ab6d1fc7238da1bbb 100644
--- a/rcu/spibitbang1.py
+++ b/i2cserv/i2cbitbang1.py
@@ -1,13 +1,24 @@
 from enum import Enum
 import logging
 import numpy as np
-
+from .hwdev import hwdev
+#This is copy of spibitbang. Need to be updated!!
 class SPIBB_pins(Enum):
     CLK = 0  
     SDIO = 1  
     SDIOdir = 2 
     CS = 3  
 
+class i2cbitbang1(hwdev):
+  def __init__(self,config):
+    hwdev.__init__(self,config)
+    logging.info("i2cbitbang todo")
+
+  def i2csetget(self,addr,data,reg=None,read=0):
+    logging.info("i2cbitbang todo")
+    return False;
+
+
 def SetSPIbb(SetI2C,RCUi,dev,value):
         ADC_address=dev.Register_W
         CSdev=dev.Addr.devs[SPIBB_pins.CS.value]
@@ -78,30 +89,26 @@ def GetSPIbb(SetI2C,GetI2C,RCUi,dev,value):
         SetI2C(RCUi,SDIOdirdev,1,SDIOdirpin,[0]) #output
         return True;
 
-def GetSPIbb2(SetI2C,GetI2C,RCUi,devs,value):
-        ADC_reg_address=devs[0].Register_R
+def GetSPIbb2(SetI2C,GetI2C,RCUi,SPIdev,I2Cdev,I2Cpins,value):
+#Read 3 SPI devices in parallel from same IOexpander
+        ADC_reg_address=SPIdev[0].Register_R
+        Nv=len(SPIdev)
         def Setbit(pintype,value):
-           for dev in devs:
-             dev1=dev.Addr.devs[pintype.value]
-             pin1=dev.Addr.pins[pintype.value]
-             SetI2C(RCUi,dev1,1,pin1,[value],buffer=True) 
-           SetI2C(RCUi,dev1,1,pin1,[value]) 
+           for i in range(1,Nv):
+             SetI2C(RCUi,I2Cdev[i][pintype],1,I2Cpins[i][pintype],[value],buffer=True) 
+           SetI2C(RCUi,I2Cdev[0][pintype],1,I2Cpins[0][pintype],[value]) 
         def Getbit(pintype):
+           print("N=",Nv,len(value))
            retvalue=np.zeros_like(value)
-           step=len(devs)
-           dev1=devs[0].Addr.devs[pintype.value]
-           pin1=devs[0].Addr.pins[pintype.value]
-           retvalue[0::step]=GetI2C(RCUi,dev1,1,pin1)
-           for i,dev in enumerate(devs[1:]):
-             dev1=dev.Addr.devs[pintype.value]
-             pin1=dev.Addr.pins[pintype.value]
-             retvalue[i+1::step]=GetI2C(RCUi,dev1,1,pin1,buffer=True)
+           retvalue[0::Nv]=GetI2C(RCUi,I2Cdev[0][pintype],1,I2Cpins[0][pintype])
+           for i in range(1,Nv):
+             retvalue[i::Nv]=GetI2C(RCUi,I2Cdev[i][pintype],1,I2Cpins[i][pintype],buffer=True)
            return retvalue
            
-        CS=SPIBB_pins.CS
-        SDIO=SPIBB_pins.SDIO
-        CLK=SPIBB_pins.CLK
-        SDIOdir=SPIBB_pins.SDIOdir
+        CLK=0
+        SDIO=1
+        SDIOdir=2
+        CS=3
 
         logging.debug(str(("SPIbb get",ADC_reg_address)))
           
diff --git a/i2cserv/i2cthread.py b/i2cserv/i2cthread.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4066a059f7ce397e2b2df10d6c91a4257749fcf
--- /dev/null
+++ b/i2cserv/i2cthread.py
@@ -0,0 +1,147 @@
+#Start the correct I2C server connect to the pipes on a new process
+import logging
+from multiprocessing import Process
+from queuetypes import *
+from time import sleep
+#from i2cserv import I2Cswitch1
+#from i2cserv import I2C_dummy as I2C
+
+#from i2cserv import RCU
+#from i2cserv import CLK
+
+import yamlconfig as yc
+
+import yaml
+class AttrDict(object):
+    def __init__(self, dct):
+        self.dict = dct
+
+    def __repr__(self):
+        return repr(self.dict)
+
+    def __getattr__(self, attr):
+        try:
+            val = self.dict[attr]
+            if isinstance(val, dict):
+                val = AttrDict(val)
+            return val
+        except KeyError:
+            raise AttributeError
+
+def runmethod(conf,Qout,methodid,mask):
+#    print("Run method",methodid,mask)
+    var1=conf.getmethod(methodid)
+    drv=var1.get('drivercls');
+    for inst in var1['instructions']:
+        for key,value in inst.items():
+            if not(isinstance(value,list)): value=[value]
+            logging.info(str(("Run instruction",key,value,mask)));
+            if mask is None: mask=[]
+            if (key=='WAIT'):
+                sleep(value[0]/1000.)
+                continue;
+            v1=conf.getvarid(key)
+            if not(v1 is None): 
+                if value[0]=='Update':
+                   #mask=
+                   getvar(conf,Qout,v1,mask)
+                else:
+                   #mask=
+                   setvar(conf,Qout,v1,value,mask)
+                continue;
+            v1=conf.getmethodid(key)
+            if v1: 
+                #mask=
+                runmethod(conf,Qout,v1,mask)
+                continue;
+            v1=conf.getdevreg(key)
+            if v1:
+                drv2=v1.get('drivercls')
+                if value[0]=='Update':
+                    if drv:  drv.Getdevreg(v1,mask)
+                    elif drv2: drv2.Getdevreg(v1,mask)
+                    else: logging.warn("Driver not specified for instruction"+key)
+                else:
+                    if drv:  drv.Setdevreg(v1,value,mask)
+                    elif drv2: drv2.Setdevreg(v1,value,mask)
+                    else: logging.warn("Driver not specified for instruction"+key)
+
+                continue;
+#    def Setdevreg(self,devreg,value,mask=[],width=8,bitoffset=0):
+            logging.warn("Unknown instruction "+key)
+#               drv=var1.get('drivercls');
+#               if not(drv): 
+#                   logging.warn(var1['name']+" driver not found!")
+#                   continue;
+#               for data in drv.OPCUAcallMethod(item.id,var1,item.data,item.mask):
+#                   Qout.put(data)
+    return mask
+
+def setvar(conf,Qout,varid,data,mask):
+    var1=conf.getvars()[varid]
+    drv=var1.get('drivercls');
+    if not(drv): 
+        logging.warn(var1['name']+" driver not found!")
+        return;
+    for data in drv.OPCUASetVariable(varid,var1,data,mask):
+        if len(mask)==len(data.mask): mask[:]=data.mask[:];
+        elif len(mask)==0: mask=data.mask.copy();
+        Qout.put(data)
+    return mask;
+
+def getvar(conf,Qout,varid,mask):
+    var1=conf.getvars()[varid]
+    drv=var1.get('drivercls');
+    if not(drv): 
+        logging.warn(var1['name']+" driver not found!")
+        return;
+    for data in drv.OPCUAReadVariable(varid,var1,mask):
+        if len(mask)==len(data.mask): mask[:]=data.mask[:];
+        elif len(mask)==0: mask=data.mask.copy();
+        Qout.put(data)
+    return mask;
+
+
+def I2Cserver(Qin,Qout,name):
+        logging.info("New i2c process "+name)
+        conf=yc.yamlconfig(name)
+        conf.linkdevices()
+        conf.loaddrivers()
+        conf.linkdrivers()
+        statusid=conf.getvarid(name+"_translator_busy");
+        while True:
+           item = Qin.get()
+           if item is None: break;
+#           print("TODO: Set busy")
+#           self.statevar.set_value("busy");
+           #print("SetVar",item)#,self.conf.variables[item.id])
+           if (item.type==InstType.varSet):
+               setvar(conf,Qout,item.id,item.data,item.mask)
+           #    self.OPCUASetVariable(item.id,var1,item.data,item.mask)
+           elif (item.type==InstType.varRead):
+               getvar(conf,Qout,item.id,item.mask)
+           #    var1=self.conf.variables[item.id]
+           #    self.OPCUAReadVariable(item.id,var1,item.data,item.mask)
+           elif (item.type==InstType.method): runmethod(conf,Qout,item.id,item.mask)
+           else: print("OPCUA call not implemented!");
+#           print("TODO: Set ready")
+           if (Qin.qsize()==0) and not(statusid is None): Qout.put(OPCUAset(statusid,InstType.varSet,[0],[]))
+        logging.info("End i2c process "+name)
+
+#        if name=='RCU':
+#          SW1=I2Cswitch1.I2Cswitch1(I2C.I2C1server)
+#          RCU1=RCU.RCU1(32,I2C.I2C1server,SW1.SetChannel,settings,Qin,Qout)
+#        elif name=='CLK':
+#          SW0=I2Cswitch1.I2Cswitch0(None) #Dummy switch as their is no switch on LTS
+#          RCU1=CLK.RCU1(1,I2C.I2C4server,SW0.SetChannel)
+#        else:
+#          logging.warn(str(("Unknown name",name," thread stopping")))
+#          return
+#        RCU1.load() #Load current register values from HW
+#        RCU1.RCUthread(Qin)
+
+def start(Qout,Qin,name):  
+        thread1 = Process(target=I2Cserver, args=(Qin,Qout,name))
+        thread1.start()
+        return thread1
+
diff --git a/i2cserv/spibitbang1.py b/i2cserv/spibitbang1.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bbfb01c0c31fc3cc548979dc9bac574c85e5ac6
--- /dev/null
+++ b/i2cserv/spibitbang1.py
@@ -0,0 +1,159 @@
+from enum import Enum
+import logging
+import numpy as np
+from .hwdev import hwdev
+
+class SPIBB_pins(Enum):
+    CLK = 0  
+    SDIO = 1  
+    SDIOdir = 2 
+    CS = 3  
+
+class spibitbang1(hwdev):
+  def __init__(self,config):
+    hwdev.__init__(self,config)
+#    logging.info("spibitbang todo")
+
+  def i2csetget(self,addr,data,reg=None,read=0):
+    if read==0: return self.SetSPIbb(reg,data)
+    elif read==1: return self.GetSPIbb(reg,data)
+    else: logging.warn("Not implemented!")
+    return False;
+
+  def SetSPIbb(self,ADC_address,value):
+         
+        CSdev=self.conf['devreg'][SPIBB_pins.CS.value]
+        CSpin=self.conf['parameters'][SPIBB_pins.CS.value]
+        SDOdev=self.conf['devreg'][SPIBB_pins.SDIO.value]
+        SDOpin=self.conf['parameters'][SPIBB_pins.SDIO.value]
+        CLKdev=self.conf['devreg'][SPIBB_pins.CLK.value]
+        CLKpin=self.conf['parameters'][SPIBB_pins.CLK.value]
+#        SDIOdirdev=self.conf['devreg'][SPIBB_pins.SDIOdir.value]
+#        SDIOdirpin=self.conf['parameters'][SPIBB_pins.SDIOdir.value]
+
+        logging.debug(str(("SPIbb set",ADC_address,value)))
+        SetI2C=self.conf['parentcls'].SetVarValue
+        ADC_bytes = 0x00
+        ADC_rw    = 0x00 # 0 for write, 1 for read
+        data2 = ( ADC_rw << 23 ) + ( ADC_bytes << 21 ) + ( ADC_address << 8 ) + value[0]
+          
+        bit_array = "{0:{fill}24b}".format(data2, fill='0')
+      #    print(bit_array)
+        if not(SetI2C(CSdev,1,CSpin,[0])): return False #enable
+        for bit in bit_array:
+              SetI2C(SDOdev,1,SDOpin,[int(bit)]) 
+              SetI2C(CLKdev,1,CLKpin,[1]) 
+              SetI2C(CLKdev,1,CLKpin,[0]) 
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+        SetI2C(SDOdev,1,SDOpin,[1]) #high when finished
+        return True;
+
+  def GetSPIbb(self,ADC_reg_address,value):
+        CSdev=self.conf['devreg'][SPIBB_pins.CS.value]
+        CSpin=self.conf['parameters'][SPIBB_pins.CS.value]
+        SDOdev=self.conf['devreg'][SPIBB_pins.SDIO.value]
+        SDOpin=self.conf['parameters'][SPIBB_pins.SDIO.value]
+        CLKdev=self.conf['devreg'][SPIBB_pins.CLK.value]
+        CLKpin=self.conf['parameters'][SPIBB_pins.CLK.value]
+        SDIOdirdev=self.conf['devreg'][SPIBB_pins.SDIOdir.value]
+        SDIOdirpin=self.conf['parameters'][SPIBB_pins.SDIOdir.value]
+#        print("SPI registers")
+#        print("CS",CSdev,CSpin)
+#        print("SDO",SDOdev,SDOpin)
+#        print("CLK",CLKdev,CLKpin)
+#        print("DIR",SDIOdirdev,SDIOdirpin)
+        logging.debug(str(("SPIbb get",ADC_reg_address)))
+          
+        ADC_bytes = 0x00
+        ADC_rw    = 0x01 # 0 for write, 1 for read
+        
+        data = ( ADC_rw << 15) + ( ADC_bytes << 13 ) + ADC_reg_address
+
+        SetI2C=self.conf['parentcls'].SetVarValue
+        GetI2C=self.conf['parentcls'].GetVarValue
+        if not(SetI2C(CSdev,1,CSpin,[0])): return False #enable
+
+
+        bit_array = "{0:{fill}16b}".format(data, fill='0')
+        #print("SPI TX bits",bit_array)
+        for bit in bit_array:
+              SetI2C(SDOdev,1,SDOpin,[int(bit)]) 
+              SetI2C(CLKdev,1,CLKpin,[1]) 
+              SetI2C(CLKdev,1,CLKpin,[0]) 
+
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+
+          #    print("read byte")
+        SetI2C(SDIOdirdev,1,SDIOdirpin,[1]) #input
+        SetI2C(CSdev,1,CSpin,[0]) #enable
+        a=[0]
+        N=1;#len(value)
+        ret_value=[0];
+        for i in range(N): value[i]=0
+        for cnt in range(8*(ADC_bytes+1)):
+              GetI2C(SDOdev,1,SDOpin,ret_value) #enable
+#              logging.debug("Got bit"+str((ret_value)))
+              for i in range(N): value[i]=(value[i]<<1)+ ret_value[i]
+              SetI2C(CLKdev,1,CLKpin,[1]) 
+              SetI2C(CLKdev,1,CLKpin,[0])  #read after falling edge
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+        SetI2C(SDIOdirdev,1,SDIOdirpin,[0]) #output
+#        logging.debug(str(("SPIbb got",value)))
+        return True;
+
+def GetSPIbb2(SetI2C,GetI2C,RCUi,SPIdev,I2Cdev,I2Cpins,value):
+#Read 3 SPI devices in parallel from same IOexpander
+        ADC_reg_address=SPIdev[0].Register_R
+        Nv=len(SPIdev)
+        def Setbit(pintype,value):
+           for i in range(1,Nv):
+             SetI2C(RCUi,I2Cdev[i][pintype],1,I2Cpins[i][pintype],[value],buffer=True) 
+           SetI2C(RCUi,I2Cdev[0][pintype],1,I2Cpins[0][pintype],[value]) 
+        def Getbit(pintype):
+           print("N=",Nv,len(value))
+           retvalue=np.zeros_like(value)
+           retvalue[0::Nv]=GetI2C(RCUi,I2Cdev[0][pintype],1,I2Cpins[0][pintype])
+           for i in range(1,Nv):
+             retvalue[i::Nv]=GetI2C(RCUi,I2Cdev[i][pintype],1,I2Cpins[i][pintype],buffer=True)
+           return retvalue
+           
+        CLK=0
+        SDIO=1
+        SDIOdir=2
+        CS=3
+
+        logging.debug(str(("SPIbb get",ADC_reg_address)))
+          
+        ADC_bytes = 0x00
+        ADC_rw    = 0x01 # 0 for write, 1 for read
+        
+        data = ( ADC_rw << 15) + ( ADC_bytes << 13 ) + ADC_reg_address
+        Setbit(CLK,0) 
+          
+        Setbit(CS,0) #enable
+
+        bit_array = "{0:{fill}16b}".format(data, fill='0')
+        logging.debug(str(("SPI TX",bit_array)))
+        for bit in bit_array:
+              Setbit(CLK,0) 
+              Setbit(SDIO,int(bit)) 
+              Setbit(CLK,1) 
+
+#        Setbit(CS,1) #disable
+        Setbit(SDIOdir,1) #input
+        Setbit(CLK,0) 
+
+          #    print("read byte")
+#        Setbit(CS,0) #enable
+        a=[0]
+        N=len(value)
+        for i in range(N): value[i]=0
+        for cnt in range(8*(ADC_bytes+1)):
+              ret_value=Getbit(SDIO)
+              for i in range(N): value[i]=(value[i]<<1)+ ret_value[i]
+              Setbit(CLK,1) 
+              Setbit(CLK,0)  #read after falling edge
+        Setbit(CS,1) #disable
+        Setbit(SDIO,1)#High when finished 
+        Setbit(SDIOdir,0) #output
+        return True;
\ No newline at end of file
diff --git a/i2cserv/spibitbang2.py b/i2cserv/spibitbang2.py
new file mode 100644
index 0000000000000000000000000000000000000000..0dedef82fcb86ed04e8e82420143ab22411878e3
--- /dev/null
+++ b/i2cserv/spibitbang2.py
@@ -0,0 +1,95 @@
+from enum import Enum
+import logging
+import numpy as np
+from .hwdev import hwdev
+
+class SPIBB_pins(Enum):
+    CLK = 0  
+    SDI = 1  
+    SDO = 2 
+    CS = 3  
+
+
+class spibitbang2(hwdev):
+  def __init__(self,config):
+    hwdev.__init__(self,config)
+
+  def i2csetget(self,addr,data,reg=None,read=0):
+    if read==0: return self.SetSPIbb(reg,data)
+    elif read==1: return self.GetSPIbb(reg,data)
+    else: logging.warn("Not implemented!")
+    return False;
+
+  def SetSPIbb(self,address,value):
+         
+        CSdev=self.conf['devreg'][SPIBB_pins.CS.value]
+        CSpin=self.conf['parameters'][SPIBB_pins.CS.value]
+        SDIdev=self.conf['devreg'][SPIBB_pins.SDI.value]
+        SDIpin=self.conf['parameters'][SPIBB_pins.SDI.value]
+        CLKdev=self.conf['devreg'][SPIBB_pins.CLK.value]
+        CLKpin=self.conf['parameters'][SPIBB_pins.CLK.value]
+
+        logging.info(str(("SPIbb2 set",address,value)))
+
+        data2 = (  address << 9 ) + value[0]
+        SetI2C=self.conf['parentcls'].SetVarValue
+
+        bit_array = "{0:{fill}16b}".format(data2, fill='0')
+      #    print(bit_array)
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+        SetI2C(CSdev,1,CSpin,[0]) #enable
+        for bit in bit_array:
+              SetI2C(CLKdev,1,CLKpin,[0]) 
+              SetI2C(SDIdev,1,SDIpin,[int(bit)]) 
+              SetI2C(CLKdev,1,CLKpin,[1]) 
+        SetI2C(CLKdev,1,CLKpin,[0])#Why? 
+        SetI2C(CLKdev,1,CLKpin,[1]) 
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+     #   SetI2C(RCUi,SDIdev,1,SDIpin,[1]) #high when finished
+        return True;
+  
+  def GetSPIbb(self,reg_address,value):
+        CSdev=self.conf['devreg'][SPIBB_pins.CS.value]
+        CSpin=self.conf['parameters'][SPIBB_pins.CS.value]
+        SDOdev=self.conf['devreg'][SPIBB_pins.SDO.value]
+        SDOpin=self.conf['parameters'][SPIBB_pins.SDO.value]
+        SDIdev=self.conf['devreg'][SPIBB_pins.SDI.value]
+        SDIpin=self.conf['parameters'][SPIBB_pins.SDI.value]
+        CLKdev=self.conf['devreg'][SPIBB_pins.CLK.value]
+        CLKpin=self.conf['parameters'][SPIBB_pins.CLK.value]
+
+
+        logging.info(str(("SPIbb2 get",reg_address)))
+        SetI2C=self.conf['parentcls'].SetVarValue
+        GetI2C=self.conf['parentcls'].GetVarValue
+
+        ADC_bytes = 0x00
+        #          ADC_rw    = 0x01 # 0 for write, 1 for read
+        data =  (reg_address << 1) + 1 #was 7??
+          
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+        SetI2C(CSdev,1,CSpin,[0]) #enable
+
+
+        bit_array = "{0:{fill}8b}".format(data, fill='0')
+        for bit in bit_array:
+              SetI2C(SDIdev,1,SDIpin,[int(bit)]) 
+              SetI2C(CLKdev,1,CLKpin,[0]) 
+              SetI2C(CLKdev,1,CLKpin,[1]) 
+
+
+          #    print("read byte")
+        a=[0]
+        N=1 #len(value)
+        ret_value=[0]
+        for i in range(N): value[i]=0
+        for cnt in range(8*(ADC_bytes+1)):
+              SetI2C(CLKdev,1,CLKpin,[0]) 
+              SetI2C(CLKdev,1,CLKpin,[1])  #read after rising
+              GetI2C(SDOdev,1,SDOpin,ret_value) 
+              for i in range(N): value[i]=(value[i]<<1)+ ret_value[i]
+        SetI2C(CLKdev,1,CLKpin,[0]) 
+        SetI2C(CSdev,1,CSpin,[1]) #disable
+        return True;
+
+
diff --git a/i2c/__init__.py b/opcuaserv/__init__.py
similarity index 100%
rename from i2c/__init__.py
rename to opcuaserv/__init__.py
diff --git a/opcuaserv/i2client.py b/opcuaserv/i2client.py
new file mode 100644
index 0000000000000000000000000000000000000000..b00d227a52297b16e43c29ff4962a926804b1427
--- /dev/null
+++ b/opcuaserv/i2client.py
@@ -0,0 +1,46 @@
+#This is the OPC-UA side of the pipes to I2Cserver
+
+from multiprocessing import Queue
+from queuetypes import *
+
+
+class i2client():
+    def __init__(self,name='RCU'):
+        self.Qin=Queue() 
+        self.Qout=Queue()
+        self.name=name;
+
+    def GetInfo(self):
+        return self.Qin,self.Qout,self.name
+
+    def stop(self):
+        self.Qout.put(None);
+        self.Qin.put(None);
+#        self.thread1.join();
+#        os.close(self.Output)
+#        self.Input.close()
+
+    def readvar(self,id1,mask=[]):
+        Data=OPCUAset(id1,InstType.varRead,[],mask)
+        self.Qout.put(Data);
+
+    def setvar(self,id1,data=[],mask=[]):
+        Data=OPCUAset(id1,InstType.varSet,data,mask)
+        self.Qout.put(Data);
+
+    def QoutLength(self):
+        return self.Qout.qsize()
+
+    def callmethod(self,id1,mask=[]):
+        Data=OPCUAset(id1,InstType.method,[],mask)
+        self.Qout.put(Data);
+
+    def data_waiting(self):
+        return (self.Qin.qsize()>0);
+
+    def readdata(self):
+        message=self.Qin.get()
+        if message is None: return None
+        return message.id,message.data,message.mask
+
+
diff --git a/opcuaserv.py b/opcuaserv/opcuaserv.py
similarity index 72%
rename from opcuaserv.py
rename to opcuaserv/opcuaserv.py
index f38b8acb5a4ced13f3e49bb6d45c1897de1de520..63763e875fbcf4c302c1a22dc2f9610d55b990cc 100644
--- a/opcuaserv.py
+++ b/opcuaserv/opcuaserv.py
@@ -8,7 +8,7 @@ from datetime import datetime;
 import logging
 #import Vars
 #import HWconf
-from pcctypes import *
+#from pcctypes import *
 
 Vars_R={}
 Vars_W={}
@@ -21,14 +21,15 @@ class SubHandler(object):
     def datachange_notification(self, node, val, data):
 #        print("Python: New data change event", node, val,data)
         if not(running): return
-        vname,myvar,VarD,Q1=Vars_W[node.nodeid.Identifier]
+        vname,myvar,v,reader=Vars_W[node.nodeid.Identifier]
 #        val=(val if isinstance(val, list) else [val] )
         logging.info(str(("Datachange callback",vname,val)))
 #        myvar2.Value.Value=val
 #        myvar2.SourceTimestamp = datetime.utcnow()
+        reader.setvar(v,val)
 
-        Inst=Instr(DevType.Var,VarD,len(val),val)
-        Q1.put(Inst)
+#        Inst=Instr(DevType.Var,VarD,len(val),val)
+#        Q1.put(Inst)
  #       P1.SetVarValue(vname,val)
         #readback
 #        if True:
@@ -46,7 +47,7 @@ class SubHandler(object):
 def CallMethod(ObjectID,name,Inst1,Q1):
         logging.info(str(("Callmethod",ObjectID,name)))
 #        Inst1=Vars.Instr(Vars.DevType.Instr,instrs,0,[])
-        Q1.put(Inst1)
+        Q1.callMethod(Inst1)
 
 #        P1.CallMethod(name,None)
 
@@ -55,29 +56,32 @@ def AddVar(name,value):
     myvar2.set_writable()
     return myvar2
 
-def AddVarR(vname,varvalue2,v):
-    myvar = PCCobj.add_variable(idx, vname, varvalue2)
-    logging.info(str(("Variable added: ",vname,len(varvalue2))))
-    Vars_R[myvar.nodeid.Identifier]=[v.name,myvar.get_data_value(),varvalue2,v]
+def AddVarR(vname,varvalue2,v,debug):
+    obj=(DEBUGobj if debug else PCCobj) 
+    myvar = obj.add_variable(idx, vname, varvalue2)
+    logging.info(str(("Variable added: ",vname,(len(varvalue2) if isinstance(varvalue2,list) else ''))))
+    Vars_R[myvar.nodeid.Identifier]=[vname,myvar.get_data_value(),varvalue2,v]
     return myvar
 
-def AddVarW(vname,varvalue2,v,Q1):
+def AddVarW(vname,varvalue2,v,Q1,debug):
     logging.info(str(("Variable added: ",vname)))#,'=',varvalue2)
-    myvar2 = PCCobj.add_variable(idx, vname, varvalue2)
+    obj=(DEBUGobj if debug else PCCobj) 
+    myvar2 = obj.add_variable(idx, vname, varvalue2)
     myvar2.set_writable()
-    Vars_W[myvar2.nodeid.Identifier]=[v.name,myvar2.get_data_value(),v,Q1]
-    handle = sub.subscribe_data_change(myvar2)
+    if v:
+        Vars_W[myvar2.nodeid.Identifier]=[vname,myvar2.get_data_value(),v,Q1]
+        handle = sub.subscribe_data_change(myvar2)
     return myvar2
 
-
-def Addmethod(vname,v,Q1):
-    myvar = PCCobj.add_method(idx, vname, lambda ObjectId,name=vname,inst=v,Q1=Q1 : CallMethod(ObjectId,name,inst,Q1), [],[] )
+def Addmethod(vname,v,Q1,debug):
+    obj=(DEBUGobj if debug else PCCobj) 
+    myvar = obj.add_method(idx, vname, lambda ObjectId,name=vname,inst=v,Q1=Q1 : CallMethod(ObjectId,name,inst,Q1), [],[] )
     logging.info(str(("AddMethod:",vname)))
 
 def InitServer(port=4840):
 
 # setup our server
-    global server,running,PCCobj,idx,sub;
+    global server,running,PCCobj,DEBUGobj,idx,sub;
     server = Server()
     server.set_endpoint("opc.tcp://0.0.0.0:{}/PCC/".format(port))
 
@@ -89,6 +93,7 @@ def InitServer(port=4840):
 
     # populating our address space
     PCCobj = objects.add_object(idx, "PCC")
+    DEBUGobj = PCCobj.add_object(idx, "DEBUG")
 #    self.PCCobj=PCCobj
     
     # starting!
diff --git a/opcuaserv/yamlreader.py b/opcuaserv/yamlreader.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0c3873729830e1d99f4322c022398b43a012c06
--- /dev/null
+++ b/opcuaserv/yamlreader.py
@@ -0,0 +1,225 @@
+import yaml
+import struct
+import time
+from yamlconfig import *
+import logging
+def bytes2int(bts):
+   x=0;
+   for b in bts:
+     x=x*256+b;
+   return x;
+
+def int2bytes(i):
+   b=[];
+   while i>255: 
+        b=[i%256]+b;
+        i>>=8;
+   return [i]+b;
+
+
+class yamlreader(yamlconfig):
+    def __init__(self,i2cserver,yamlfile='RCU'):
+        self.yamlfile=yamlfile;
+        yamlconfig.__init__(self,yamlfile)
+        self.server=i2cserver;
+        self.timecount=0;
+        self.monitorvarcnt=0;
+        self.statusid=self.getvarid(yamlfile+"_translator_busy");
+
+    def SetBusy(self):
+        if self.statusid is None: return
+        self.OPCset(self.statusid,[1],[])
+
+    def AddVars(self,AddVarR,AddVarW):
+     self.monitorvar=AddVarW(self.yamlfile+"_monitor_rate_RW",60,None,None,None)
+     for v in self.conf['variables']:
+#        print(v)
+        dim1=v.get('dim',1);
+        name=v.get('name');
+        datatype=v.get('dtype','integer')
+#        dim1=Vars.RCU_MPaddr.nI2C*Vars.RCU_MPaddr.nSwitch*v.nVars
+#        dim2=Vars.RCU_MPaddr.nI2C*Vars.RCU_MPaddr.nSwitch*v.size
+#        dim3=int(v.size/v.nVars)
+        #print(v.name,dim)
+        varvalue2=0
+        if   datatype in ['uint8','uint16','uint32','uint64']:  varvalue2=dim1*[0]
+        elif datatype=='double':    varvalue2=dim1*[0.0] 
+        elif datatype=='boolean':  varvalue2=dim1*[False] 
+        elif datatype=='string':   varvalue2=dim1*[""]
+        if len(varvalue2)==1: varvalue2=varvalue2[0];
+#        print(len(varvalue2),varvalue2)
+        if v.get('rw') in ['ro','rw']:
+            var1=AddVarR(name+"_R",varvalue2,v['id'],v.get('debug'))
+            v['OPCR']=var1
+            logging.debug("Var added:"+name+"_R")
+#            self.server.readvar(v['id'])
+#            time.sleep(0.1);
+#            Inst=Vars.Instr(Vars.DevType.VarUpdate,v,dim2,varvalue2)
+#            Q1.put(Inst)
+
+        if v.get('rw') in ['wo','rw','variable']:
+            var1=AddVarW(name+"_RW",varvalue2,v['id'],self,v.get('debug'))
+            v['OPCW']=var1
+            logging.debug("Var added:"+name+"_RW")
+     for v in self.conf['variables']:
+        mask=v.get('mask');
+        if not(mask): continue;
+        mask=Find(self.conf['variables'],'name',mask)
+        if not(mask): continue;
+        mask=mask.get('OPCW',None)
+        if (mask==None): continue;
+        v['maskOPC']=mask
+
+    def AddMethod(self,Addmethod):
+      for v in self.conf['methods']:
+          if v.get('hidden'): continue;
+#          print(v)
+#        Inst1=Vars.Instr(Vars.DevType.Instr,v,0,[])
+          Addmethod(v['name'],v['id'],self,v.get('debug'))
+          mask=v.get('mask');
+          if not(mask): continue;
+          mask=Find(self.conf['variables'],'name',mask)
+          if not(mask): continue;
+          mask=mask.get('OPCW',None)
+          if (mask==None): continue;
+          v['maskOPC']=mask
+
+    def callMethod(self,id1):
+        v=self.conf['methods'][id1];
+        logging.debug("Method called!"+v['name'])
+        mask=v.get('maskOPC',None);
+        mask=mask.get_value() if (mask!=None) else [];
+        self.SetBusy()
+        self.server.callmethod(id1,mask) 
+
+    def CallInit(self):
+        v=Find(self.conf['methods'],'name',self.yamlfile+'_Init');
+        if not(v):
+            logging.warn(self.yamlfile+"_Init method not found for initialisation!") 
+            return;
+        self.server.callmethod(v['id'],[]) 
+
+    def setvar(self,id1,data=[]):
+        v=self.conf['variables'][id1];
+        if v['rw']=='variable': return;
+        mask=v.get('maskOPC',None);
+        mask=mask.get_value() if (mask!=None) else [];
+#        print("M2:",mask)
+        dtype=v.get('dtype','integer');
+        width=(v.get('width',8)-1)//8+1
+        if not(isinstance(data,list)): data=[data];
+        if (dtype=="double"): 
+                scale=v.get('scale',1.)
+                data=[int(d/scale) for d in data]
+        if (dtype=="boolean"): 
+                data2=bytearray(data*1);
+        elif (dtype in ['uint8','uint16','uint32','uint64','double']): 
+            if width<=1: 
+                data2=bytearray(data)
+            elif width==2:
+                data2 = struct.pack('>%sH' % len(data), *data)
+            elif width==3:
+                data2=bytearray()
+                for a in data: data2.extend(struct.pack('>L',a)[1:])
+            elif width==4:
+                data2 = struct.pack('>%sL' % len(data), *data)
+            elif width==8:
+                data2 = struct.pack('>%sQ' % len(data), *data)
+            else:
+                logging.warn("setvar"+v['name']+" unsupported width!"+str(width))
+                return;
+        elif (dtype=="string"):
+                data2=bytearray() 
+                for s in data:
+                    data2.extend('{s:>{width}'.format(s=s[:width],width=width).encode('ascii'));
+        else:
+                logging.warn("setvar unsupported type");
+                return;
+        data2=[d for d in data2]
+        logging.debug(str(("setvar ",v['name'],data2,mask)));
+        self.SetBusy()
+        self.server.setvar(id1,data2,mask) 
+
+    def getvar(self):
+#        if not(self.server.data_waiting()): return;
+#        print("getvar ...")
+        while True:
+#         while (self.server.data_waiting()):
+#           try:
+            item=self.server.readdata()
+            if item is None: break;
+            id1,data,mask=item; 
+            logging.debug(str(("**getvar",id1,data,mask)));
+            if len(data)==0: continue;
+#           except:
+#              print('finished')
+#              return;
+            self.OPCset(id1,data,mask);
+ 
+    def OPCset(self,id1,data,mask):
+        v=self.conf['variables'][id1];
+        dtype=v.get('dtype','integer');
+        width=(v.get('width',8)-1)//8+1
+        logging.debug(str(("OPCset",width,data)))
+        if dtype=="boolean": 
+                data2=[d==1 for d in data];
+        elif (dtype in ['uint8','uint16','uint32','uint64','double']): 
+            data=bytearray(data)
+            if width<=1: 
+                data2=[d for d in data]
+            elif width==2:
+                data2 = struct.unpack('>%sH' % (len(data)//2), data)
+            elif width==3:
+                data2 = [struct.unpack('>L' ,bytearray([0])+data[x*3:x*3+3])[0] for x in range(len(data)//3)]
+            elif width==4:
+                data2 = struct.unpack('>%sL' % (len(data)//4), data)
+            elif width==8:
+                data2 = struct.unpack('>%sQ' % (len(data)//8), data)
+            else:
+                logging.warn("OPCset"+v['name']+" unsupported width!"+str(width))
+                return;
+        elif dtype=="string": 
+                cnt=int(len(data)/width)
+#                data2=[(bytearray(data[i*width:(i+1)*width]).decode("utf-8")) for i in range(cnt)]
+                data2=[bytearray(data)[i*width:(i+1)*width].decode("utf-8") for i in range(cnt)]
+        else:
+                logging.warn("OPCset unsupported type");
+                return;
+        if dtype=="double": 
+                scale=float(v.get('scale',1.))
+                data2=[(d*scale) for d in data2]
+        var1=v.get('OPCR')
+        if not(var1): var1=v.get('OPCW')
+        if not(var1):
+           logging.warn("OPC variable not found!!");
+           return;
+        data3=var1.get_value();
+        if not(isinstance(data3,list)): data3=[data3];
+#        print("OPCset",v['name'],data3,mask)
+        if mask: #Only update masked values
+            step=len(data2)//len(mask)
+            #print("mask step=",step)
+            for i in range(len(data2)):
+                if mask[i//step]: data3[i]=data2[i]
+        else:
+            data3=data2;
+        if len(data3)==1: data3=data3[0];
+        logging.info(str(("OPCset",v['name'],data3)))
+        var1.set_value(data3);
+
+    def Monitor(self):
+        T1=self.monitorvar.get_value()*10;
+        if T1<=0: return;
+        self.timecount+=1;
+        while self.timecount>=T1:
+          if self.server.QoutLength()>3: return;
+          v=self.conf['variables'][self.monitorvarcnt];
+          if v.get('monitor'):
+               mask=(v['maskOPC'].get_value() if v.get('maskOPC') else [])
+#               print("monitor",v['name'],mask)
+               self.server.readvar(self.monitorvarcnt,mask=mask)
+          self.monitorvarcnt+=1;
+          if self.monitorvarcnt>=len(self.conf['variables']): 
+                    self.monitorvarcnt=0;
+                    self.timecount=0;              
+
diff --git a/pcctypes.py b/pcctypes.py
deleted file mode 100644
index 56c4bc7da636ed670e6d4bfcfc69adda86a663d8..0000000000000000000000000000000000000000
--- a/pcctypes.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#For capnproto
-from collections import namedtuple
-from enum import Enum
-from recordclass import recordclass
-
-#I2C ports & Switch addresses of device
-MPaddr=namedtuple("MPaddr","nI2C I2C nSwitch Switch"); 
-
-#Device registers
-DevReg=namedtuple("DevReg","Addr Register_R Register_W store"); 
-#Addr: Byte (I2C) or *BBdev
-#Register_R/W: Byte (I2C register)
-#store: Byte 0=not stored else store index
-
-#Bitbang devices
-BBdev=namedtuple("BBdev","nPins devs pins addr")
-# devs: *DevReg[nPins]
-# pins:  Byte[nPins]
-# addr:  Byte (SPI device address)
-
-
-class I2Cmodules(Enum):
-   Switch = 0
-   RCU = 1
-   CLK = 2
-   UNB2 = 3
-
-class DevType(Enum):
-    Var = 0
-    I2C  = 1
-    SPIbb= 2
-    I2Cbb= 3
-    Instr =4
-    VarUpdate = 5
-    Internal = 6
-    HBA1 = 7
-    HBA2 = 8
-    Wait = 9
-
-class RW(Enum):
-    Hidden = 0  #Not an OPC_UA variable
-    ReadOnly = 1  #OPC_variable name_R
-    WriteOnly = 2 #OPC_variable name_RW
-    ReadWrite = 3  #both of above
-
-class datatype(Enum):
-   dInt = 0
-   dfloat = 1
-   dstring = 2
-   dbool = 3
-
-#Variable two device link
-Var2dev=namedtuple("Var2dev","name module type devreg width bitoffset Scale")
-#name: string (Currently unused!)
-#module: I2Cmodules
-#Type: DevType
-#DevReg: *DevReg
-#Width: Byte (# of bits)
-#Bitoffset: Byte
-#Scale: Float (=1 means no scaling i.e. integer)
-
-#OPC-UA variable: Array of similar variables
-VarArray=recordclass("VarArray","name nVars Vars RW type size OPCR OPCW") #OPCR and OPCW linked at runtime
-#name: string
-#Vars: *Var2dev[nVars]
-#RW: RW
-#type: datatype
-#size: =nVars (default), but x16/32 for HBA antennas
-#OPCR/W: pointer to variable in OPC-UA server (linked during runtime)
-
-#Instruction
-Instr=namedtuple("DevInstr","type dev nvalue value")
-#Type: DevType
-#dev: pointer to vararray / DevReg / etc depending on type
-#value: Bytes[nvalue]
-
-#List of instructions
-Instrs=namedtuple("Instr","name ninstr instr")
-#name: string
-#inst: Instr[ninstr]
-
diff --git a/pypcc2.py b/pypcc2.py
index b7b716828ce4778cc51c23b4322e85ea8bc4a9d4..0fb7bef0ac7814141f692a3933ef244c2c2ca388 100644
--- a/pypcc2.py
+++ b/pypcc2.py
@@ -1,25 +1,21 @@
-import opcuaserv
-try:
- import queue
-except ImportError:
- import Queue as queue;
-from rcu import RCU
-from clk import CLK
-from i2c import I2Cswitch1
-import threading
-import signal
-import sys
-import time
-#import Vars
 import logging
 import argparse
-
-NRCU=32
+from opcuaserv import opcuaserv
+from opcuaserv import i2client
+from opcuaserv import yamlreader
+#from opcuaserv import pypcc2
+from i2cserv import i2cthread
+import threading
+import time
+import sys
+import signal
 
 parser = argparse.ArgumentParser()
 parser.add_argument("-s", "--simulator", help="Do not connect to I2c, but simulate behaviour.", action="store_true")
+parser.add_argument("-t", "--test", help="Do not start OPC-UA server.", action="store_true")
 parser.add_argument("-p", "--port", help="Port number to listen on [%(default)s].", type=int, default=4842)
 parser.add_argument("-l", "--loglevel", help="Log level [%(default)s].", type=str, choices=["DEBUG","INFO","WARNING","ERROR"], default="INFO")
+parser.add_argument("-c", "--config", help="YAML config files, comma seperated [%(default)s]",type=str, default='RCU')
 args = parser.parse_args()
 
 # set log level
@@ -29,106 +25,66 @@ if not isinstance(loglevel_nr, int):
 #logging.basicConfig(level=loglevel_nr, format="%(asctime)s [%(levelname)8s] %(message)s")
 
 logging.basicConfig(level=loglevel_nr,format='%(asctime)s [%(levelname)-8s,%(filename)-20s:%(lineno)-3d] %(message)s')
-if args.simulator:
-    from i2c import I2C_dummy as I2C
-else:
-    from i2c import I2C
-#   from i2c import I2Cv2 as I2C
-
-#Queue used to pass instructions from opc-ua server to RCU
-Q1=queue.Queue() #RCUs
-Q2=queue.Queue() #CLK
-
-#Setup OPCUA server (running in its own thread)
-opcuaserv.InitServer(port=args.port)
-logging.info("OPC-UA Server started")   
-
-SW1=I2Cswitch1.I2Cswitch1(I2C.I2C1server)
-SW0=I2Cswitch1.I2Cswitch0(None) #Dummy switch as their is no switch on LTS
-
-RCU=RCU.RCU1(NRCU,I2C.I2C1server,SW1.SetChannel)
-RCU.AddVars(Q1,opcuaserv.AddVarR,opcuaserv.AddVarW,opcuaserv.AddVar)
-RCU.AddMethod(Q1,opcuaserv.Addmethod)
-RCU.load() #Load current register values from HW
-
-CLK=CLK.RCU1(1,I2C.I2C4server,SW0.SetChannel)
-CLK.AddVars(Q2,opcuaserv.AddVarR,opcuaserv.AddVarW)
-CLK.AddMethod(Q2,opcuaserv.Addmethod)
-CLK.load() #Load current register values from HW
-
-#logging.debug(str(("I2C bytes=",I2C.I2Ccounter)))
-
-if False:
-  opcuaserv.server.stop()
-  exit()
-
-RCUthread1=RCU.start(Q1)
-CLKthread1=CLK.start(Q2)
-
 RunTimer=True;
-
-def TimerThread(Q1,RCU):
-    V1=opcuaserv.AddVar("RCU_monitor_rate_RW",30)
-    cnt=0;#Count second ticks
-    while RunTimer:
-       time.sleep(1)
-       T1=V1.get_data_value().Value.Value
-       if T1==0:
-           continue;
-       cnt+=1;
-       if cnt>=T1:
-         if Q1.qsize()>3: continue;
-         cnt=0;
-         logging.debug(str(("I2C bytes=",I2C.I2Ccounter," Qlength=",Q1.qsize())))
-         RCU.Queue_Monitor(Q1,NRCU)
-
-    logging.info("End Timer thread")
-
-Timerthread1 = threading.Thread(target=TimerThread, args=(Q1,RCU))
-Timerthread1.start()
-
-
-def Timer2Thread(Q1,RCU):
-    V1=opcuaserv.AddVar("CLK_monitor_rate_RW",10)
-    cnt=0;#Count second ticks
-    while RunTimer:
-       time.sleep(1)
-       T1=V1.get_data_value().Value.Value
-       if T1==0:
-           continue;
-       cnt+=1;
-       if cnt>=T1:
-         if Q1.qsize()>3: continue;
-         cnt=0;
-         logging.debug(str(("I2C bytes=",I2C.I2Ccounter," Qlength=",Q1.qsize())))
-         RCU.Queue_Monitor(Q1,1)
-
-    logging.info("End Timer thread")
-
-Timerthread2 = threading.Thread(target=Timer2Thread, args=(Q2,CLK))
-Timerthread2.start()
-
-# on SIGINT: stop thread(s) by adding None to instruction queue(s)
 def signal_handler(sig, frame):
-    logging.info('Stop RCU thread')
-    Q1.put(None)
-    Q2.put(None)
-    logging.info('Stop timer thread')
+    logging.warn('Stop signal received!')
     global RunTimer; 
     RunTimer=False
 signal.signal(signal.SIGINT, signal_handler)
 
-time.sleep(1)
-opcuaserv.start()
+#Start i2c processes as soon as possible to have minimum duplication
+logging.info("Start I2C processes")   
+#I2Cports=['UNB2','RCU','CLK']
+#I2Cports=['RCU']
+I2Cports=[x for x in args.config.split(',')]
+threads=[]
+I2Cclients=[]
+for name in I2Cports:
+    RCU_I2C=i2client.i2client(name=name)
+    if not(args.simulator):  
+        thread1=i2cthread.start(*RCU_I2C.GetInfo())
+        threads.append(thread1)
+    I2Cclients.append(RCU_I2C)
+
+#Initialise OPCUA server and load variables
+logging.info("Initialised OPC-UA Server")   
+configs=[]
+if not(args.test):  
+    opcuaserv.InitServer(port=args.port)
+    logging.info("Load OPCUA variables & start i2c listing thread")   
+    for i,name in enumerate(I2Cports):
+        RCU_I2C=I2Cclients[i]
+        RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile=name)
+        RCU_conf.AddVars(opcuaserv.AddVarR,opcuaserv.AddVarW)
+        RCU_conf.AddMethod(opcuaserv.Addmethod)
+        RCU_conf.CallInit();
+        configs.append(RCU_conf);
+
+        thread2=threading.Thread(target=RCU_conf.getvar); #Thread on OPC-UA side of pipe
+        thread2.start()
+        threads.append(thread2)
+    time.sleep(1)
+    logging.info("Start OPC-UA server")
+    opcuaserv.start()
+logging.getLogger().setLevel("WARNING")
+
+if False:
+   opcuaserv.server.stop()
+   exit()
 
+ 
 try:
-#Do nothing.
  while RunTimer:
-    time.sleep(1)
+    time.sleep(0.1);
+    for c in configs:
+        c.Monitor();
 finally:
-        logging.info("Stop OPC-UA server")
-        opcuaserv.server.stop()
-        RCUthread1.join()
-        CLKthread1.join()
-        Timerthread1.join()
-        Timerthread2.join()
+   if not(args.test):
+       logging.info("Stop OPC-UA server")
+       opcuaserv.server.stop()
+
+logging.info("Stop threads")
+for i2c in I2Cclients:
+    i2c.stop()
+for thread1 in threads:
+    thread1.join()
diff --git a/queuetypes.py b/queuetypes.py
new file mode 100644
index 0000000000000000000000000000000000000000..f10f7b1a4b52e651b5c7af3be933c592a53cb096
--- /dev/null
+++ b/queuetypes.py
@@ -0,0 +1,9 @@
+from enum import Enum
+from recordclass import recordclass
+
+class InstType (Enum):
+    varSet  = 0
+    varRead = 1
+    method  = 2
+
+OPCUAset=recordclass("OPCUAset","id type data mask")
diff --git a/rcu/HWconf.py b/rcu/HWconf.py
deleted file mode 100644
index 44b75df15fe7bc8caef46d1986a452fe154e5703..0000000000000000000000000000000000000000
--- a/rcu/HWconf.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#from collections import namedtuple
-#from enum import Enum
-from pcctypes import *
-#Mid plane address
-#MPaddr=namedtuple("MPaddr","nI2C I2C nSwitch Switch"); 
-RCU_MPaddr=MPaddr(1,[1],32,[0,1,2,3,4,5,6,7,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5])
-#RCU_MPaddr=MPaddr(1,[1],2,[0,1])
-#RCU_MPaddr=MPaddr(1,[1],1,[0])
-#CLK_MPaddr=MPaddr(1,[1],1,[7])
-
-#DevReg=namedtuple("DevReg","Addr Register_R Register_W store"); 
-#I2C:Addr=I2C addr (int)
-#BBdev: Addr=BBdev (pointer)
-
-#Control board switch
-#dev: TCA9548
-SW1_ch=DevReg(0x70,0,0,0) 
-#I2C IO-Expanders
-#Device: TCA9539
-RCU_IO1_OUT1=DevReg(0x75,0,2,1)
-RCU_IO1_OUT2=DevReg(0x75,1,3,2)
-RCU_IO1_CONF1=DevReg(0x75,6,6,3)
-RCU_IO1_CONF2=DevReg(0x75,7,7,4)
-#Device: TCA9539
-RCU_IO2_OUT1=DevReg(0x76,0,2,5)
-RCU_IO2_OUT2=DevReg(0x76,1,3,6)
-RCU_IO2_CONF1=DevReg(0x76,6,6,7)
-RCU_IO2_CONF2=DevReg(0x76,7,7,8)
-#Device: TCA6416
-RCU_IO3_OUT1=DevReg(0x20,0,2,9)
-RCU_IO3_OUT2=DevReg(0x20,1,3,10)
-RCU_IO3_CONF1=DevReg(0x20,6,6,11)
-RCU_IO3_CONF2=DevReg(0x20,7,7,12)
-
-RCU_storeReg=13; #Number of stored registers
-
-#I2C monitor ADC
-RCU_AN_Ch0=DevReg(0x14,0xB080,-1,0)
-RCU_AN_Ch1=DevReg(0x14,0xB880,-1,0)
-RCU_AN_Ch2=DevReg(0x14,0xB180,-1,0)
-#etc
-RCU_AN_Temp=DevReg(0x14,0xA0C0,-1,0)
-
-#HBA1
-RCU_HBA1=DevReg(0x41,0x10,0x10,1)
-RCU_HBA2=DevReg(0x42,0x10,0x10,2)
-RCU_HBA3=DevReg(0x43,0x10,0x10,3)
-
-
-
-RCU_ROM_ID =DevReg(0x50,0xfc,0xfc,0) #32 bit ID=4 bytes
-RCU_ROM_Ver=DevReg(0x50,0,0,0) #String
-
-#Bitbang devices
-#BBdev=namedtuple("BBdev","nPins devs pins addr")
-I2CBB_dth3=BBdev(3,[RCU_IO1_OUT1,RCU_IO2_OUT2,RCU_IO2_CONF2],[6,3,3],0x70); #SCL,SDIO,SDIOdir
-I2CBB_dth2=BBdev(3,[RCU_IO1_OUT2,RCU_IO2_OUT1,RCU_IO1_CONF1],[7,7,7],0x70);
-I2CBB_dth1=BBdev(3,[RCU_IO1_OUT2,RCU_IO2_OUT1,RCU_IO1_CONF1],[7,7,7],0x70);
-SPIBB_ADC1=BBdev(4,[RCU_IO3_OUT1,RCU_IO3_OUT1,RCU_IO3_CONF1,RCU_IO3_OUT2],[1,0,0,0],0) #CLK,SDIO,SDIOdir,CS
-SPIBB_ADC2=BBdev(4,[RCU_IO3_OUT1,RCU_IO3_OUT1,RCU_IO3_CONF1,RCU_IO3_OUT2],[3,2,2,1],0) #CLK,SDIO,SDIOdir,CS
-SPIBB_ADC3=BBdev(4,[RCU_IO3_OUT1,RCU_IO3_OUT1,RCU_IO3_CONF1,RCU_IO3_OUT2],[5,4,4,2],0) #CLK,SDIO,SDIOdir,CS
-
-#SPI ADC 
-#Dev: AD9683 
-RCU_ADC1_PLL_stat =DevReg(SPIBB_ADC1,0X0A,0X0A,0) # PLL locked status
-RCU_ADC1_PLL_enc =DevReg(SPIBB_ADC1,0X21,0X21,0) # PLL low encode
-RCU_ADC1_JESD_ctr =DevReg(SPIBB_ADC1,0X5F,0X5F,0) #JESD link control, ILAS mode
-RCU_ADC1_CML_level=DevReg(SPIBB_ADC1,0X15,0X15,0) #CML output adjust
-RCU_ADC1_SYNC_ctr =DevReg(SPIBB_ADC1,0X3A,0X3A,0) #SYNC / SYSREF control
-RCU_ADC1_update   =DevReg(SPIBB_ADC1,0XFF,0xFF,0)    # Global device update
-
-RCU_ADC2_PLL_stat =DevReg(SPIBB_ADC2,0X0A,0X0A,0) # PLL locked status
-RCU_ADC2_PLL_enc =DevReg(SPIBB_ADC2,0X21,0X21,0) # PLL low encode
-RCU_ADC2_JESD_ctr =DevReg(SPIBB_ADC2,0X5F,0X5F,0) #JESD link control, ILAS mode
-RCU_ADC2_CML_level=DevReg(SPIBB_ADC2,0X15,0X15,0) #CML output adjust
-RCU_ADC2_SYNC_ctr =DevReg(SPIBB_ADC2,0X3A,0X3A,0) #SYNC / SYSREF control
-RCU_ADC2_update   =DevReg(SPIBB_ADC2,0XFF,0xFF,0)    # Global device update
-
-RCU_ADC3_PLL_stat =DevReg(SPIBB_ADC3,0X0A,0X0A,0) # PLL locked status
-RCU_ADC3_PLL_enc =DevReg(SPIBB_ADC3,0X21,0X21,0) # PLL low encode
-RCU_ADC3_JESD_ctr =DevReg(SPIBB_ADC3,0X5F,0X5F,0) #JESD link control, ILAS mode
-RCU_ADC3_CML_level=DevReg(SPIBB_ADC3,0X15,0X15,0) #CML output adjust
-RCU_ADC3_SYNC_ctr =DevReg(SPIBB_ADC3,0X3A,0X3A,0) #SYNC / SYSREF control
-RCU_ADC3_update   =DevReg(SPIBB_ADC3,0XFF,0xFF,0)    # Global device update
-
-#I2C_dither 
-#Dev: SI4010
-RCU_Dth1_Freq =DevReg(I2CBB_dth1,0x1140,0x1141,0) ##TBC
-RCU_Dth1_Prop =DevReg(I2CBB_dth1,0x11  ,0x11,0) 
-RCU_Dth1_Start=DevReg(I2CBB_dth1,0x62  ,0x62,0) 
-RCU_Dth1_Stop =DevReg(I2CBB_dth1,0x67  ,0x67,0) 
-RCU_Dth2_Freq =DevReg(I2CBB_dth2,0x1140,0x1141,0) ##TBC
-RCU_Dth2_Prop =DevReg(I2CBB_dth2,0x11  ,0x11,0) 
-RCU_Dth2_Start=DevReg(I2CBB_dth2,0x62  ,0x62,0) 
-RCU_Dth2_Stop =DevReg(I2CBB_dth2,0x67  ,0x67,0) 
-RCU_Dth3_Freq =DevReg(I2CBB_dth3,0x1140,0x1141,0) ##TBC
-RCU_Dth3_Prop =DevReg(I2CBB_dth3,0x11  ,0x11,0) 
-RCU_Dth3_Start=DevReg(I2CBB_dth3,0x62  ,0x62,0) 
-RCU_Dth3_Stop =DevReg(I2CBB_dth3,0x67  ,0x67,0) 
-
-#class DevType(Enum):
-#    Var = 0
-#    I2C  = 1
-#    SPIbb= 2
-#    I2Cbb= 3
-#    Instr =4
-#    VarUpdate = 5
-#    Internal = 6
diff --git a/rcu/RCU.py b/rcu/RCU.py
deleted file mode 100644
index 886790cf945f9dd559b906472e3aaaec535d5d70..0000000000000000000000000000000000000000
--- a/rcu/RCU.py
+++ /dev/null
@@ -1,424 +0,0 @@
-from . import Vars
-import numpy as np
-import logging
-from .spibitbang1 import *
-import threading
-import time
-
-
-def ApplyMask(value,width=8,bitoffset=0,previous=0):
-    mask=(1<<width)-1
-    if bitoffset>0:
-      value<<=bitoffset;
-      mask<<=bitoffset;
-    return (value & mask) + (previous - (previous & mask));
-def UnMask(value,width=8,bitoffset=0):
-    mask=(1<<width)-1
-    if bitoffset>0:
-      value>>=bitoffset;
-    value=value&mask;
-    return value;
-
-def bytes2int(bts):
-   x=0;
-   for b in bts:
-     x=x*256+b;
-   return x;
-def int2bytes(i):
-   b=[];
-   while i>255:
-        b=[i%256]+b;
-        i>>=8;
-   return [i]+b;
-
-def strs2bytes(var):
-#    print("str2bytes",var)
-    if len(var)==0: return var;
-    if isinstance(var[0],str): #make string a byte array
-#            return [ord(c.encode('utf-8')[0]) for s in var for c in s]
-            return [c.encode('utf-8')[0] for s in var for c in s]
-    return var
-
-def bytes2strs(var,step,dtype):
-    if not(dtype==Vars.datatype.dstring): return var
-    cnt=int(len(var)/step)
-    print(var)
-    return [(bytearray(var[i*step:(i+1)*step]).decode("utf-8")) for i in range(cnt)]
-
-class RCU1():
-    def __init__(self,number,I2Ccallback,Switchcallback):
-        self.N=number;
-        self.I2Ccallback=I2Ccallback
-        self.SWcallback=Switchcallback
-        self.previous   =np.zeros([number,Vars.RCU_storeReg],dtype='int')
-        self.previousHBA=np.zeros([number,3,32],dtype='int')
-
-    def load(self):
-        Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_init,0,[])  #Read the current status of GPIO IOs
-        self.SetVar(Inst1)
-#Vars.RCU_mask.OPCW.get_data_value().Value.Value=[1,1,0,0]
-#Vars.Ant_mask.OPCW.get_data_value().Value.Value=[1,1,0,0,0,0,0,0,0,0,1,0]
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_init,0,[])  #Read the current status of GPIO IOs
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Var,Vars.RCU_att,12,[0,1,2,3,4,5,6,7,8,9,11])
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_off,0,[])
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.RCU_on,0,[])
-#RCU.SetVar(Inst1)
-
-#Inst1=Vars.Instr(Vars.DevType.Instr,Vars.ADC1_on,0,[])
-#RCU.SetVar(Inst1)
-
-#print(Vars.RCU)
-
-    def SetVar(self,Instr,Mask=[]):
-#        Instr.value=strs2bytes(Instr.value) #Alwast be an array of bytes
-        if Instr.type==Vars.DevType.Wait:
-#            time.sleep(Instr.value[0]/1000.)
-            print("Sleep",Instr.value[0]/1000.,"s")
-            return;
-        if Instr.type==Vars.DevType.Instr:
-              #Execute instructions
-              Iset=Instr.dev;
-              if len(Mask)==0:  Mask=Vars.RCU_mask.OPCW.get_value()
-              for i in Iset.instr:
-                  logging.debug(str(("Inst",i)))
-                  self.SetVar(i,Mask=Mask)
-              return;
-        if Instr.type in [Vars.DevType.I2C,Vars.DevType.SPIbb,Vars.DevType.I2Cbb]:
-            if len(Mask)==0:  Mask=Vars.RCU_mask.OPCW.get_value()
-            mask=0;
-            RCU0=-1;
-            for RCUi in range(self.N):
-                 if (Mask[RCUi]):
-                      mask|=1<<Vars.RCU_MPaddr.Switch[RCUi]
-                      if RCU0<0: RCU0=RCUi;
-            if RCU0<0: return; #Mask all zero
-            self.SWcallback(mask)
-            if Instr.type==Vars.DevType.I2C:
-              logging.info(str(('** Set I2C:',Instr.dev,Instr.value)))
-              self.SetI2C(RCU0,Instr.dev,8,0,strs2bytes(Instr.value))
-              return;
-            elif Instr.type==Vars.DevType.SPIbb:
-              logging.debug(str(('** Set SPIbb:',Instr.dev,Instr.value)))
-              SetSPIbb(self.SetI2C,RCU0,Instr.dev,strs2bytes(Instr.value))
-              return;
-            elif Instr.type==Vars.DevType.I2Cbb:
-              logging.info(str(('** Set I2Cbb:',Instr.dev,Instr.value)))
-#              self.SetI2C(RCUi,Instr.dev,8,0,strs2bytes(Instr.value))
-              return;
-        V1=Instr.dev
-#        print(Instr.nvalue,V1.nVars,V1.size)
-        if not((Instr.nvalue==V1.nVars) and (Instr.type==Vars.DevType.VarUpdate)) and not(Instr.nvalue==V1.size*self.N):
-             logging.error("Wrong size of value")
-             return False
-        if V1.Vars[0].type==Vars.DevType.Internal:
-          Instr.dev.OPCW.set_value(Instr.value)
-          logging.debug("Update internal variable")
-          return
-#        if V1.Vars[0].type==Vars.DevType.Internal: return;
-        Step=V1.nVars
-        Step2=int(V1.size/V1.nVars)
-        Mask=(Vars.RCU_mask if Step==1 else Vars.Ant_mask)
-        Mask=Mask.OPCW.get_value()
-        value1=strs2bytes(Instr.value) if V1.OPCR is None else strs2bytes(V1.OPCR.get_value())
-        if (len(value1)==V1.nVars) and (self.N>1):  value1=(value1*self.N);
-        if Instr.type==Vars.DevType.Var:
-          logging.info(str(('** Set Var:',V1.name,value1)))
-          for RCUi in range(self.N):
-            for Vari in range(Step):
-                if not(Mask[RCUi*Step+Vari]): continue
-                i0=(RCUi*Step+    Vari)*Step2
-                i1=(RCUi*Step+(Vari+1))*Step2
-                self.SetVarValue(RCUi,V1.Vars[Vari],Instr.value[i0:i1])
-                value2=value1[i0:i1]
-                self.GetVarValue(RCUi,V1.Vars[Vari],value2)
-                value1[i0:i1]=value2
-          if not(V1.OPCR is None): V1.OPCR.set_value(bytes2strs(value1,Step2,V1.type))
-
-        elif Instr.type==Vars.DevType.VarUpdate:
-          self.GetVarValueAll(V1,value1)
-#          if not(V1.OPCR is None): V1.OPCR.get_data_value().Value.Value=bytes2strs(value1,Step2,V1.type)
-          if not(V1.OPCR is None): V1.OPCR.set_value(bytes2strs(value1,Step2,V1.type))
-#          V1.OPCR.get_data_value().Value.Value=value1
-
-        logging.info(str(('** Readback:',V1.name,value1)))
-
-    def GetVarValue(self,RCUi,var,value):
-            logging.info(str(("RCU1 Get ",RCUi,var,value)))
-            if var.type==Vars.DevType.I2C:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.GetI2C(RCUi,var.devreg,var.width,var.bitoffset,value)
-            elif var.type==Vars.DevType.HBA1:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.GetI2CHBA1(RCUi,var.devreg,var.width,var.bitoffset,value)
-            elif var.type==Vars.DevType.I2Cbb:
-                logging.error("I2Cbb Implemented")
-            elif var.type==Vars.DevType.SPIbb:
-                logging.error("SPIbb Implemented")
-            else:
-                logging.error("Not Implemented")
-
-    def GetVarValueAll(self,V1,value1):
-            mask=0;
-            for RCUi in range(self.N):
-                mask|=1<<Vars.RCU_MPaddr.Switch[RCUi]
-            Step=V1.nVars
-            Step2=int(V1.size/V1.nVars)
-            if V1.Vars[0].type==Vars.DevType.I2C:
-              for Vari in range(Step):
-                DevReg=V1.Vars[Vari].devreg
-                self.SWcallback(mask)
-                self.SetI2CAddr(self,DevReg)
-                if DevReg.Register_R>255: self.I2Ccallback(DevReg.Addr,[250],read=3) #Wait for ADC
-                for RCUi in range(self.N):
-                    self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                    i0=(RCUi*Step+    Vari)*Step2
-                    i1=(RCUi*Step+(Vari+1))*Step2
-                    value2=value1[i0:i1]
-                    var=V1.Vars[Vari]
-#                    print(Step,Step2,i0,i1,value2,len(value1))
-                    self.GetI2Cnoreg(RCUi,var.devreg,var.width,var.bitoffset,value2)
-#                    print(value2)
-                    if (var.Scale!=0): value2[0]*=var.Scale;
-                    value1[i0:i1]=value2
-            elif V1.Vars[0].type==Vars.DevType.SPIbb:
-              self.GetBBValueAll(V1,value1,mask)
-#              logging.info("SPIbb all not implemented yet")
-            elif V1.Vars[0].type==Vars.DevType.HBA1:
-              for Vari in range(Step):
-                var=V1.Vars[Vari]
-#                self.SWcallback(mask)
-#                self.SetI2CAddr(self,DevReg)
-                for RCUi in range(self.N):
-                    self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-#                    print(Step,Step2,len(value1),V1.size)
-                    WX=[0]
-                    self.I2Ccallback(0x40,WX,reg=0,read=1)#wakeup, do nothing
-                    self.I2Ccallback(0x40,[10],read=3)
-                    i0=(RCUi*Step+    Vari)*Step2
-                    i1=(RCUi*Step+(Vari+1))*Step2
-                    value2=value1[i0:i1]
-                    self.GetI2CHBA1(RCUi,var.devreg,var.width,var.bitoffset,value2)
-                    value1[i0:i1]=value2
-#                    i0=(RCUi*Step+    Vari)*Step2+16
-#                    i1=(RCUi*Step+(Vari+1))*Step2
-#                    value2=value1[i0:i1]
-#                    self.GetI2Cnoreg(RCUi,var.devreg,var.width,var.bitoffset,value2)
-#                    value1[i0:i1]=value2
-            else:
-               logging.error("Type not implemented")
-#            print(value1)
-    def GetBBValueAll(self,V1,value1,mask):
-        def SetBit(RCUi,dev,width,bitoffset,value,buffer=False):
-            if not(buffer): self.SWcallback(mask)
-            self.SetI2C(RCUi,dev,width,bitoffset,value,buffer=buffer)
-        def GetBit(RCUixx,dev,width,bitoffset,buffer=False):
-            value=[0 for RCUi in range(self.N)]
-            value2=[0]
-            if buffer:
-                for RCUi in range(self.N):
-                  self.GetI2Cbuffer(RCUi,dev,width,bitoffset,value2)
-                  value[RCUi]=value2[0]
-                return value
-            self.SWcallback(mask)
-            self.SetI2CAddr(self,dev)
-            for RCUi in range(self.N):
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                #for i in range(len(value2)): value2[i]*=0;
-                value2[0]=0
-                self.GetI2Cnoreg(RCUi,dev,width,bitoffset,value2)
-                value[RCUi]=value2[0]
-            return value;
-        devs=[V1.Vars[Vari].devreg for Vari in range(V1.nVars)]
-        GetSPIbb2(SetBit,GetBit,0,devs,value1)
-
-
-    def SetVarValue(self,RCUi,var,value):
-            if var.devreg.Register_W==-1: return True; #We can not set it, only read it e.g. temperature
-            logging.debug(str(("RCU1 Set ",RCUi,var,value)))
-            if var.type==Vars.DevType.I2C:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.SetI2C(RCUi,var.devreg,var.width,var.bitoffset,value)
-            elif var.type==Vars.DevType.HBA1:
-                self.SWcallback(1<<Vars.RCU_MPaddr.Switch[RCUi])
-                self.SetHBA1I2C(RCUi,var.devreg,var.width,var.bitoffset,value)
-#                 print("RCU1 Set",RCUi,var,value)
-            elif var.type==Vars.DevType.I2Cbb:
-                logging.error("I2Cbb Implemented")
-            elif var.type==Vars.DevType.SPIbb:
-                logging.error("SPIbb Implemented")
-            else:
-                logging.error("Not Implemented")
-
-    def SetI2C(self,RCUi,dev,width,bitoffset,value,buffer=False):
-        if dev.store>0:
-            previous=self.previous[RCUi,dev.store-1];
-            value[0]=ApplyMask(value[0],width,bitoffset,previous);
-            self.previous[RCUi,dev.store-1]=value[0]
-#            logging.debug(str(('masked to',value)))
-#            logging.debug(str(("Store buffer",RCUi,dev.store,value[0])))
-        if buffer: return True;
-        return self.I2Ccallback(dev.Addr,value,reg=dev.Register_W)
-
-    def SetHBA1I2C(self,RCUi,dev,width,bitoffset,value,buffer=False):
-#        if dev.store>0:
-        previous=self.previousHBA[RCUi,dev.store-1];
-        L=len(value)
-        for i in range(L):
-          value[i]=ApplyMask(value[i],width,bitoffset,previous[i]);
-        self.previousHBA[RCUi,dev.store-1]=value
-#        if buffer: return True;
-        print("HBA set:",value);
-        XX=[0]
-        self.I2Ccallback(0x40,XX,reg=0,read=1)#wakeup, do nothing
-        self.I2Ccallback(dev.Addr,[10],read=3)
-        self.I2Ccallback(dev.Addr,value[:16],reg=dev.Register_W)
-        if L>16:
-              self.I2Ccallback(dev.Addr,[10],read=3)
-              self.I2Ccallback(dev.Addr,value[16:],reg=dev.Register_W+16)
-        self.I2Ccallback(dev.Addr,[600],read=3) #Wait 500ms
-        return True
-#        return self.I2Ccallback(dev.Addr,value,reg=dev.Register_W)
-
-    def GetI2Cbuffer(self,RCUi,dev,width,bitoffset,value):
-        if not(dev.store>0): return False;
-        value[0]=self.previous[RCUi,dev.store-1];
-#        logging.debug(str(("GetI2Cbuffer",RCUi,dev.store,value)))
-        l1=int(np.floor((width+bitoffset+7)/8))
-        if (width!=l1*8) or (bitoffset>0):
-          for i in range(len(value)):
-             value[i]=UnMask(value[i],width,bitoffset)
-        return True
-
-    def GetI2C(self,RCUi,dev,width,bitoffset,value):
-#        if dev.store>0:
-#            value[0]=self.previous[RCUi,dev.store-1]
-#        return True
-        l1=int(np.floor((width+bitoffset+7)/8))
-#        print(width,bitoffset,l1)
-        makesinglevalue=((len(value)==1) and (l1>1));
-        if makesinglevalue: value2=[0 for x in range(l1)]
-        else: value2=value
-        reg=dev.Register_R
-        if reg>255: #This is for the monitor ADC
-          if not(self.I2Ccallback(dev.Addr,int2bytes(reg),read=2)): return False;
-          I2Ccallback(Addr,[250],read=3)
-          if not(self.I2Ccallback(dev.Addr,value2,read=1)): return False;
-        else:
-          if not(self.I2Ccallback(dev.Addr,value2,reg=reg,read=1)): return False;
-        if value2[0] is None:  return False
-        if makesinglevalue: value[0]=bytes2int(value2)
-        else: value[:]=value2[:];
-        if dev.store>0:
-            self.previous[RCUi,dev.store-1]=value[0]
-#            logging.debug(str(("Store buffer",RCUi,dev.store,value[0])))
-        if (width!=l1*8) or (bitoffset>0):
-            for i in range(len(value)):
-              value[i]=UnMask(value[i],width,bitoffset)
-        else: value[0]=value2[0]
-        return True;
-    def GetI2Cbit(self,RCUi,dev,pin):
-           value2=[value]
-           self.I2CGet(RCUi,dev,1,1<<pin,value2)
-           return value2[0]
-
-
-    def SetI2CAddr(self,RCUi,dev):
-        return self.I2Ccallback(dev.Addr,int2bytes(dev.Register_R),read=2)
-
-
-
-    def GetI2Cnoreg(self,RCUi,dev,width,bitoffset,value):
-        #print(width,len(value))
-        l1=int(np.floor((width+bitoffset+7)/8))
-        makesinglevalue=((len(value)==1) and (l1>1));
-        if makesinglevalue: value2=[0 for x in range(l1)]
-        else: value2=value
-        reg=dev.Register_R
-        if not(self.I2Ccallback(dev.Addr,value2,read=1)): return False;
-        if value2[0] is None:  return False
-        if makesinglevalue: value[0]=bytes2int(value2)
-        else: value[:]=value2[:];
-        if dev.store>0:
-            self.previous[RCUi,dev.store-1]=value[0]
-#            logging.debug(str(("Store buffer",RCUi,dev.store,value[0])))
-#        if width<8:
-        if (width!=l1*8) or (bitoffset>0):
-            for i in range(len(value)):
-              value[i]=UnMask(value[i],width,bitoffset)
-#              value[0]=UnMask(value[0],width,bitoffset)
-        #else: value[0]=value2[0]
-        #if (len(value)>1) and (width<8): print value
-        return True;
-
-    def GetI2CHBA1(self,RCUi,dev,width,bitoffset,value):
-        #print(width,len(value))
-        value2=value
-        reg=dev.Register_R
-#        if not(self.I2Ccallback(dev.Addr,[],reg=0x0)): return False;
-        if not(self.I2Ccallback(dev.Addr,value2,read=1)): return False;
-        if value2[0] is None:  return False
-        value[:]=value2[:];
-        print("HBA ",RCUi,dev.Addr," received:",value);
-#        if dev.store>0: #This is disabled due to noise on readback
-#            self.previousHBA[RCUi,dev.store-1]=value[:]
-        for i in range(len(value)):
-              value[i]=UnMask(value[i],width,bitoffset)
-        return True;
-
-
-    def start(self,Q1):
-      def RCUthread(Q1):
-         while True:
-           item = Q1.get()
-           if item is None: break;
-           self.statevar.set_value("busy");
-           self.SetVar(item)
-           if Q1.qsize()==0: self.statevar.set_value("ready");
-         logging.info("End RCU thread")
-
-      RCUthread1 = threading.Thread(target=RCUthread, args=(Q1,))
-      RCUthread1.start()
-
-      return RCUthread1
-
-    def Queue_Monitor(self,Q1,NRCU):
-        Inst1=Vars.Instr(Vars.DevType.VarUpdate,Vars.RCU_temp,NRCU,[0]*NRCU)
-        Q1.put(Inst1)
-        Inst1=Vars.Instr(Vars.DevType.VarUpdate,Vars.RCU_ADC_lock,96,[0]*96)
-        Q1.put(Inst1)
-        return
-    def AddVars(self,Q1,AddVarR,AddVarW,AddVar):
-     self.statevar=AddVar("RCU_state_R","busy")
-     for v in Vars.OPC_devvars:
-        dim1=Vars.RCU_MPaddr.nI2C*Vars.RCU_MPaddr.nSwitch*v.nVars
-        dim2=Vars.RCU_MPaddr.nI2C*Vars.RCU_MPaddr.nSwitch*v.size
-        dim3=int(v.size/v.nVars)
-        #print(v.name,dim)
-        varvalue2=0
-        if   v.type==Vars.datatype.dInt:    varvalue2=dim2*[0]
-        elif v.type==Vars.datatype.dbool:   varvalue2=dim2*[False]
-        elif v.type==Vars.datatype.dfloat:  varvalue2=dim2*[0.0]
-        elif v.type==Vars.datatype.dstring: varvalue2=dim1*[" "*dim3]
-        print(len(varvalue2),varvalue2)
-        if v.RW in [Vars.RW.ReadOnly,Vars.RW.ReadWrite]:
-            var1=AddVarR(v.name+"_R",varvalue2,v)
-#            print(len(varvalue1),len(varvalue2),v.size,dim2)
-            v.OPCR=var1
-            Inst=Vars.Instr(Vars.DevType.VarUpdate,v,dim2,varvalue2)
-            Q1.put(Inst)
-
-        if v.RW in [Vars.RW.WriteOnly,Vars.RW.ReadWrite]:
-            var1=AddVarW(v.name+"_RW",varvalue2,v,Q1)
-            v.OPCW=var1
-
-    def AddMethod(self,Q1,Addmethod):
-      for v in Vars.OPC_methods:
-        Inst1=Vars.Instr(Vars.DevType.Instr,v,0,[])
-        Addmethod(v.name,Inst1,Q1)
diff --git a/rcu/Vars.py b/rcu/Vars.py
deleted file mode 100644
index 7467d6bafa94a9ba86698e6e6f566a09d7dee1bd..0000000000000000000000000000000000000000
--- a/rcu/Vars.py
+++ /dev/null
@@ -1,200 +0,0 @@
-#from collections import namedtuple
-from recordclass import recordclass
-#from enum import Enum
-from .HWconf import *
-
-#OPCUA variables
-RCUmod=I2Cmodules.RCU
-
-#Var2dev=namedtuple("Var2dev","name MPaddr type devreg width bitoffset Scale")
-#VarArray=recordclass("VarArray","name nVars Vars RW type OPCR OPCW") #OPCR and OPCW linked at runtime
-RCU_att1= Var2dev("RCU_att1" ,RCUmod,DevType.I2C,RCU_IO1_OUT1,5 ,0,1)
-RCU_att2= Var2dev("RCU_att2" ,RCUmod,DevType.I2C,RCU_IO1_OUT2,5 ,0,1)
-RCU_att3= Var2dev("RCU_att3" ,RCUmod,DevType.I2C,RCU_IO2_OUT1,5 ,0,1)
-RCU_band1=Var2dev("RCU_band1",RCUmod,DevType.I2C,RCU_IO2_OUT2,2 ,0,1)
-RCU_band2=Var2dev("RCU_band2",RCUmod,DevType.I2C,RCU_IO2_OUT2,2 ,2,1)
-RCU_band3=Var2dev("RCU_band3",RCUmod,DevType.I2C,RCU_IO2_OUT2,2 ,4,1)
-RCU_led0= Var2dev("RCU_led0" ,RCUmod,DevType.I2C,RCU_IO2_OUT2,2 ,6,1)
-RCU_pwrd1=Var2dev("RCU_pwrd1",RCUmod,DevType.I2C,RCU_IO2_OUT1,1 ,6,1)
-RCU_temp1=Var2dev("RCU_temp1",RCUmod,DevType.I2C,RCU_AN_Temp ,23,0,4.21e-3)
-
-dummy=Var2dev("Dummy",RCUmod,DevType.Internal,None,8,0,1)
-
-
-Ant_mask=VarArray("Ant_mask"       ,3,[dummy,dummy,dummy]            ,RW.WriteOnly,datatype.dbool,3,None,None)
-RCU_att =VarArray("RCU_attenuator" ,3,[RCU_att1 ,RCU_att2 ,RCU_att3] ,RW.ReadWrite,datatype.dInt,3,None,None)
-RCU_band=VarArray("RCU_band"       ,3,[RCU_band1,RCU_band2,RCU_band3],RW.ReadWrite,datatype.dInt,3,None,None)
-
-RCU_mask=VarArray("RCU_mask"       ,1,[dummy]    ,RW.WriteOnly,datatype.dbool  ,1,None,None)
-RCU_temp=VarArray("RCU_temperature",1,[RCU_temp1],RW.ReadOnly ,datatype.dfloat,1,None,None)
-RCU_pwrd=VarArray("RCU_Pwr_dig"    ,1,[RCU_pwrd1],RW.ReadOnly ,datatype.dInt  ,1,None,None)
-RCU_LED =VarArray("RCU_LED0"       ,1,[RCU_led0] ,RW.ReadWrite,datatype.dInt  ,1,None,None)
-
-RCU_Dth3_freq=Var2dev("RCU_dth1_freq",RCUmod,DevType.I2Cbb,RCU_Dth3_Freq,32,0,1e-6)
-RCU_Dth2_freq=Var2dev("RCU_dth1_freq",RCUmod,DevType.I2Cbb,RCU_Dth2_Freq,32,0,1e-6)
-RCU_Dth1_freq=Var2dev("RCU_dth1_freq",RCUmod,DevType.I2Cbb,RCU_Dth1_Freq,32,0,1e-6)
-RCU_dth_freq=VarArray("RCU_dither_freq",3,[RCU_Dth1_freq,RCU_Dth2_freq,RCU_Dth3_freq],RW.ReadWrite,datatype.dfloat,3,None,None)
-
-HBA1_Delay=Var2dev("",RCUmod,DevType.HBA1,RCU_HBA1,5,2,1)
-HBA2_Delay=Var2dev("",RCUmod,DevType.HBA1,RCU_HBA2,5,2,1)
-HBA3_Delay=Var2dev("",RCUmod,DevType.HBA1,RCU_HBA3,5,2,1)
-HBA1_led  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA1,1,0,1)
-HBA2_led  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA2,1,0,1)
-HBA3_led  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA3,1,0,1)
-HBA1_pwr  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA1,1,7,1)
-HBA2_pwr  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA2,1,7,1)
-HBA3_pwr  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA3,1,7,1)
-HBA1_pwr2  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA1,1,1,1)
-HBA2_pwr2  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA2,1,1,1)
-HBA3_pwr2  =Var2dev("",RCUmod,DevType.HBA1,RCU_HBA3,1,1,1)
-HBA_Delay=VarArray("HBA_element_beamformer_delays",3,[HBA1_Delay,HBA2_Delay,HBA3_Delay],RW.ReadWrite,datatype.dInt,96,None,None)
-HBA_led  =VarArray("HBA_element_led"  ,3,[HBA1_led  ,HBA2_led  ,HBA3_led  ],RW.ReadWrite,datatype.dInt,96,None,None)
-HBA_pwr  =VarArray("HBA_element_pwr"  ,3,[HBA1_pwr  ,HBA2_pwr  ,HBA3_pwr  ],RW.ReadWrite,datatype.dInt,96,None,None)
-HBA_pwr2 =VarArray("HBA_element_pwr2"  ,3,[HBA1_pwr2  ,HBA2_pwr2  ,HBA3_pwr2  ],RW.ReadWrite,datatype.dInt,96,None,None)
-
-#RCU_ID0=Var2dev("",RCUmod,DevType.I2C,RCU_ROM,8,0,1)
-#RCU_ID=VarArray("RCU_ID",1,[RCU_ID0],RW.ReadOnly,datatype.dInt,4,None,None)
-
-RCU_ID0=Var2dev("",RCUmod,DevType.I2C,RCU_ROM_ID,32,0,1)
-RCU_ID=VarArray("RCU_ID",1,[RCU_ID0],RW.ReadOnly,datatype.dInt,1,None,None)
-RCU_Ver0=Var2dev("",RCUmod,DevType.I2C,RCU_ROM_Ver,7,0,1)
-RCU_VER=VarArray("RCU_version",1,[RCU_Ver0],RW.ReadOnly,datatype.dstring,10,None,None)
-
-
-RCU_uCV_ID    =VarArray("uC_ID"  ,1,[Var2dev("",RCUmod,DevType.I2C,DevReg(0x40,0,0,0),8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-RCU_uCV_spd0  =VarArray("uC_spd0"  ,1,[Var2dev("",RCUmod,DevType.I2C,DevReg(0x40,1,1,0),8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-RCU_uCV_debug =VarArray("uC_debug" ,1,[Var2dev("",RCUmod,DevType.I2C,DevReg(0x40,2,2,0),8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-RCU_uCV_RXspd1=VarArray("uC_RXspd1",1,[Var2dev("",RCUmod,DevType.I2C,DevReg(0x40,3,3,0),8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-RCU_uCV_RXspd2=VarArray("uC_RXspd2",1,[Var2dev("",RCUmod,DevType.I2C,DevReg(0x40,4,4,0),8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-RCU_uCV_TXspd1=VarArray("uC_TXspd1",1,[Var2dev("",RCUmod,DevType.I2C,DevReg(0x40,6,6,0),8 ,0,1)],RW.ReadOnly,datatype.dInt,1,None,None)
-
-
-RCU_ADC1_lock=Var2dev("RCU_ADC1_lock",RCUmod,DevType.SPIbb,RCU_ADC1_PLL_stat,8,0,1)
-RCU_ADC2_lock=Var2dev("RCU_ADC2_lock",RCUmod,DevType.SPIbb,RCU_ADC2_PLL_stat,8,0,1)
-RCU_ADC3_lock=Var2dev("RCU_ADC3_lock",RCUmod,DevType.SPIbb,RCU_ADC3_PLL_stat,8,0,1)
-RCU_ADC_lock=VarArray("RCU_ADC_lock",3,[RCU_ADC1_lock,RCU_ADC2_lock,RCU_ADC3_lock],RW.ReadOnly,datatype.dInt,3,None,None)
-
-RCU_ADC1_SYNC=Var2dev("RCU_ADC1_SYNC",RCUmod,DevType.SPIbb,RCU_ADC1_SYNC_ctr,8,0,1)
-RCU_ADC2_SYNC=Var2dev("RCU_ADC2_SYNC",RCUmod,DevType.SPIbb,RCU_ADC2_SYNC_ctr,8,0,1)
-RCU_ADC3_SYNC=Var2dev("RCU_ADC3_SYNC",RCUmod,DevType.SPIbb,RCU_ADC3_SYNC_ctr,8,0,1)
-RCU_ADC_SYNC=VarArray("RCU_ADC_SYNC",3,[RCU_ADC1_SYNC,RCU_ADC2_SYNC,RCU_ADC3_SYNC],RW.ReadOnly,datatype.dInt,3,None,None)
-
-RCU_ADC1_JESD=Var2dev("RCU_ADC1_SYNC",RCUmod,DevType.SPIbb,RCU_ADC1_JESD_ctr,8,0,1)
-RCU_ADC2_JESD=Var2dev("RCU_ADC2_SYNC",RCUmod,DevType.SPIbb,RCU_ADC2_JESD_ctr,8,0,1)
-RCU_ADC3_JESD=Var2dev("RCU_ADC3_SYNC",RCUmod,DevType.SPIbb,RCU_ADC3_JESD_ctr,8,0,1)
-RCU_ADC_JESD=VarArray("RCU_ADC_JESD",3,[RCU_ADC1_JESD,RCU_ADC2_JESD,RCU_ADC3_JESD],RW.ReadOnly,datatype.dInt,3,None,None)
-
-RCU_ADC1_CML=Var2dev("RCU_ADC1_SYNC",RCUmod,DevType.SPIbb,RCU_ADC1_CML_level,8,0,1)
-RCU_ADC2_CML=Var2dev("RCU_ADC2_SYNC",RCUmod,DevType.SPIbb,RCU_ADC2_CML_level,8,0,1)
-RCU_ADC3_CML=Var2dev("RCU_ADC3_SYNC",RCUmod,DevType.SPIbb,RCU_ADC3_CML_level,8,0,1)
-RCU_ADC_CML=VarArray("RCU_ADC_CML",3,[RCU_ADC1_CML,RCU_ADC2_CML,RCU_ADC3_CML],RW.ReadOnly,datatype.dInt,3,None,None)
-
-
-RCU_IO1_1= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO1_OUT1,8,0,1)
-RCU_IO1_2= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO1_OUT2,8,0,1)
-#RCU_IO1_3= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO1_CONF1,8,0,1)
-#RCU_IO1_4= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO1_CONF2,8,0,1)
-#RCU_IO1=VarArray("RCU_IO1",3,[RCU_IO1_1,RCU_IO1_2,RCU_IO1_3],RW.ReadOnly,datatype.dInt,None,None)
-RCU_IO2_1= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO2_OUT1,8,0,1)
-RCU_IO2_2= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO2_OUT2,8,0,1)
-#RCU_IO2_3= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO2_CONF1,8,0,1)
-#RCU_IO2_4= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO2_CONF2,8,0,1)
-#RCU_IO2=VarArray("RCU_IO2",3,[RCU_IO2_1,RCU_IO2_2,RCU_IO2_3],RW.ReadOnly,datatype.dInt,None,None)
-RCU_IO3_1= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO3_OUT1,8,0,1)
-RCU_IO3_2= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO3_OUT2,8,0,1)
-#RCU_IO3_3= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO3_CONF1,8,0,1)
-#RCU_IO3_4= Var2dev("" ,RCUmod,DevType.I2C,RCU_IO3_CONF2,8,0,1)
-#RCU_IO3=VarArray("RCU_IO3",3,[RCU_IO3_1,RCU_IO3_2,RCU_IO3_3],RW.ReadOnly,datatype.dInt,None,None)
-
-RCU_OUT1=VarArray("RCU_OUT1",3,[RCU_IO1_1,RCU_IO2_1,RCU_IO3_1],RW.ReadOnly,datatype.dInt,3,None,None)
-RCU_OUT2=VarArray("RCU_OUT2",3,[RCU_IO1_2,RCU_IO2_2,RCU_IO3_2],RW.ReadOnly,datatype.dInt,3,None,None)
-#RCU_CNF1=VarArray("RCU_CONF1",3,[RCU_IO1_3,RCU_IO2_3,RCU_IO3_3],RW.ReadOnly,datatype.dInt,None,None)
-#RCU_CNF2=VarArray("RCU_CONF2",3,[RCU_IO1_4,RCU_IO2_4,RCU_IO3_4],RW.ReadOnly,datatype.dInt,None,None)
-
-#OPC_devvars=[RCU_mask,Ant_mask,RCU_att,RCU_band,RCU_temp,RCU_pwrd,RCU_LED,RCU_ID,RCU_VER,HBA_Delay,HBA_led]
-#OPC_devvars=[RCU_mask,Ant_mask,RCU_att,RCU_band,RCU_temp,RCU_pwrd,RCU_LED,RCU_ID,RCU_VER,HBA_Delay,HBA_led,RCU_uCV_ID]
-OPC_devvars=[RCU_mask,Ant_mask,RCU_att,RCU_band,RCU_temp,RCU_pwrd,RCU_LED,RCU_ADC_lock,RCU_ADC_SYNC,RCU_ADC_JESD,RCU_ADC_CML,RCU_OUT1,RCU_OUT2,RCU_ID,RCU_VER,HBA_Delay,HBA_led,HBA_pwr,HBA_pwr2,RCU_uCV_ID]
-#OPC_devvars=[RCU_mask,Ant_mask,RCU_att,RCU_band,RCU_temp,RCU_pwrd,RCU_LED,RCU_uCV_ID,RCU_uCV_spd0,RCU_uCV_RXspd1,RCU_uCV_RXspd2,RCU_uCV_TXspd1,RCU_uCV_debug ]#,HBA1_Pwr]#,RCU_CNF1,RCU_CNF2]
-#Instr=namedtuple("DevInstr","type dev nvalue value")
-#Instrs=namedtuple("Instr","name ninstr instr")
-
-#OPCUA methods
-
-RCU_init=Instrs("ReadRegisters",2,[
-   Instr(DevType.VarUpdate,RCU_OUT1,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_OUT2,3,[0,0,0])
-])
-
-ADC_on=Instrs("ADC_on",17,[
-   Instr(DevType.SPIbb,RCU_ADC1_JESD_ctr,1,[0x14]),
-   Instr(DevType.SPIbb,RCU_ADC1_CML_level,1,[0x7]),
-   Instr(DevType.SPIbb,RCU_ADC1_SYNC_ctr,1,[1]),
-   Instr(DevType.SPIbb,RCU_ADC1_PLL_enc,1,[0x8]),
-   Instr(DevType.SPIbb,RCU_ADC1_update,1,[1]),
-   Instr(DevType.Wait,0,0,[100]),
-   Instr(DevType.SPIbb,RCU_ADC2_JESD_ctr,1,[0x14]),
-   Instr(DevType.SPIbb,RCU_ADC2_CML_level,1,[0x7]),
-   Instr(DevType.SPIbb,RCU_ADC2_SYNC_ctr,1,[1]),
-   Instr(DevType.SPIbb,RCU_ADC2_PLL_enc,1,[0x8]),
-   Instr(DevType.SPIbb,RCU_ADC2_update,1,[1]),
-   Instr(DevType.Wait,0,0,[100]),
-   Instr(DevType.SPIbb,RCU_ADC3_JESD_ctr,1,[0x14]),
-   Instr(DevType.SPIbb,RCU_ADC3_CML_level,1,[0x7]),
-   Instr(DevType.SPIbb,RCU_ADC3_SYNC_ctr,1,[1]),
-   Instr(DevType.SPIbb,RCU_ADC3_PLL_enc,1,[0x8]),
-   Instr(DevType.SPIbb,RCU_ADC3_update,1,[1]),
-   Instr(DevType.Wait,0,0,[500]),
-   Instr(DevType.VarUpdate,RCU_ADC_SYNC,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ADC_JESD,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ADC_CML,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ADC_lock,3,[0,0,0])
-])
-
-RCU_on=Instrs("RCU_on",20,[
-   Instr(DevType.I2C,RCU_IO2_CONF1,1,[0]),
-   Instr(DevType.I2C,RCU_IO2_CONF2,1,[0]),
-   Instr(DevType.I2C,RCU_IO2_OUT1,1,[0x4A]),
-   Instr(DevType.I2C,RCU_IO2_OUT2,1,[0x55]),
-   Instr(DevType.Wait,0,0,[300]),
-   Instr(DevType.I2C,RCU_IO3_CONF1,1,[0]),
-   Instr(DevType.I2C,RCU_IO3_CONF2,1,[0]),
-   Instr(DevType.I2C,RCU_IO1_CONF1,1,[0]),
-   Instr(DevType.I2C,RCU_IO1_CONF2,1,[0]),
-   Instr(DevType.I2C,RCU_IO3_OUT1,1,[0x15]),
-   Instr(DevType.I2C,RCU_IO3_OUT2,1,[0x47]),
-   Instr(DevType.I2C,RCU_IO1_OUT1,1,[0xCA]),
-   Instr(DevType.I2C,RCU_IO1_OUT2,1,[0xCA]),
-   Instr(DevType.Wait,0,0,[200]),
-   Instr(DevType.VarUpdate,RCU_att,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_pwrd,1,[0]),
-   Instr(DevType.VarUpdate,RCU_OUT1,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_OUT2,3,[0,0,0])
-#   Instr(DevType.Wait,0,0,[300]),
-#   Instr(DevType.Instr,ADC_on,0,[])
-])
-
-RCU_off=Instrs("RCU_off",1,[
-#   Instr(DevType.Var,RCU_mask,4,[1,1,1,1]),
-   Instr(DevType.Var,RCU_pwrd,32,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
-   Instr(DevType.I2C,RCU_IO3_OUT1,1,[0x0]),
-   Instr(DevType.I2C,RCU_IO3_OUT2,1,[0x0]),
-#   Instr(DevType.Var,RCU_mask,4,[0,0,0,0])
-])
-
-RCU_update=Instrs("RCU_update",11,[
-   Instr(DevType.VarUpdate,RCU_pwrd,1,[0]),
-   Instr(DevType.VarUpdate,RCU_OUT1,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_OUT2,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ID,1,[0]),
-#   Instr(DevType.VarUpdate,RCU_VER,1,[0]*10),
-   Instr(DevType.VarUpdate,RCU_att,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_band,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_LED,1,[0]),
-   Instr(DevType.VarUpdate,RCU_ADC_SYNC,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ADC_JESD,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ADC_CML,3,[0,0,0]),
-   Instr(DevType.VarUpdate,RCU_ADC_lock,3,[0,0,0])
-])
-
-
-OPC_methods=[RCU_on,RCU_off,ADC_on,RCU_update]
diff --git a/rcu/__init__.py b/rcu/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/requirements.txt b/requirements.txt
index a60ca7ecbd7bfebc36f787dd6425b771587835b1..4a48e3de1ad782a2e988ed6a11bf604165d3a733 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ git+https://github.com/amaork/libi2c.git; platform_system == "linux"
 opcua
 numpy
 recordclass
+pyyaml
diff --git a/scripts/ADCreset.py b/scripts/ADCreset.py
index e42c94acc4acadf705c19747f1f63955e81d6814..7cb6d6e2201c508110731f166f2d2fe911affb63 100644
--- a/scripts/ADCreset.py
+++ b/scripts/ADCreset.py
@@ -3,10 +3,20 @@ from test_common import *
 RCUs=[0,1,2,3];
 setRCUmask(RCUs)
 
-#callmethod("RCU_off")
+def wait(var1="RCU_translator_busy_R"):
+  for x in range(20):
+    busy=get_value(var1)
+#    print(busy)
+    if not(busy): break
+    time.sleep(0.1)
+  print("Time=",x*0.1,"s")
+
+callmethod("RCU_off")
+wait()
 #exit()
 #time.sleep(2)
 callmethod("RCU_on")
+wait()
 #callmethod("RCU_on")
 #time.sleep(1)
 #callmethod("ADC_on")
diff --git a/scripts/CLK.py b/scripts/CLK.py
index 4dbf2b4179174154d421998068cee27faa7108cb..19c524bed4db0b8a5765a96752682c058c9fbe5c 100644
--- a/scripts/CLK.py
+++ b/scripts/CLK.py
@@ -4,8 +4,14 @@ from test_common import *
 #time.sleep(1)
 
 callmethod("CLK_on")
-time.sleep(1)
-callmethod("CLK_PLL_setup")
+for x in range(10):
+  busy=get_value("CLK_translator_busy_R")
+  print(busy)
+  if not(busy): break
+  time.sleep(0.1)
+
+#time.sleep(1)
+#callmethod("CLK_PLL_setup")
 #exit()
 #time.sleep(1)
 #callmethod("RCU_on")
diff --git a/scripts/HBA_wait_PPS.py b/scripts/HBA_wait_PPS.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1d8d74e5553befc000d4e3fec87fbb0c5b8c1d9
--- /dev/null
+++ b/scripts/HBA_wait_PPS.py
@@ -0,0 +1,10 @@
+from test_common import *
+
+RCUs=[0,1,2,3];
+setRCUmask(RCUs)
+#for RCU in RCUs: 
+#setAntmask(RCUs,[True,True,True])
+
+callmethod("RCU_HBAT_WAIT_PPS")
+
+disconnect();
\ No newline at end of file
diff --git a/testCLK.py b/testCLK.py
new file mode 100644
index 0000000000000000000000000000000000000000..52db37dd6c6826e96d19a44ea1dd0547b14a9629
--- /dev/null
+++ b/testCLK.py
@@ -0,0 +1,63 @@
+import logging
+import argparse
+from opcuaserv import opcuaserv
+from opcuaserv import i2client
+from opcuaserv import yamlreader
+#from opcuaserv import pypcc2
+from i2cserv import i2cthread
+import threading
+import time
+import sys
+import signal
+from yamlconfig import Find;
+
+logging.basicConfig(level="DEBUG",format='%(asctime)s [%(levelname)-8s,%(filename)-20s:%(lineno)-3d] %(message)s')
+
+RunTimer=True;
+#def signal_handler(sig, frame):
+#    logging.warn('Stop signal received!')
+#    global RunTimer; 
+#    RunTimer=False
+#signal.signal(signal.SIGINT, signal_handler)
+
+logging.info("Start I2C processes")   
+threads=[]
+I2Cclients=[]
+name='CLK'
+RCU_I2C=i2client.i2client(name=name)
+thread1=i2cthread.start(*RCU_I2C.GetInfo())
+threads.append(thread1)
+I2Cclients.append(RCU_I2C)
+
+#Load yaml so that we know the variable names
+RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile=name)
+RCU_conf.CallInit()
+
+var1=RCU_conf.getvarid('CLK_I2C_OK')
+#RCU_I2C.setvar(var1,[True])
+
+var1=RCU_conf.getvarid('CLK_PLL_locked')
+RCU_I2C.readvar(var1,[])
+
+
+var1=RCU_conf.getvarid('CLK_PLL_locked_SPI')
+#var1=RCU_conf.getvarid('CLK_PLL_r3')
+#RCU_I2C.readvar(var1,[])
+
+
+#var1=RCU_conf.getmethodid('CLK_on');
+var1=RCU_conf.getmethodid('CLK_PLL_setup');
+#RCU_I2C.callmethod(var1,[])
+
+time.sleep(2);
+
+while RCU_I2C.data_waiting():
+    varid,data,mask=RCU_I2C.readdata()
+    print("Results:",RCU_conf.getvar1(varid)['name'],data,mask)
+
+
+logging.info("Stop threads")
+for i2c in I2Cclients:
+    i2c.stop()
+for thread1 in threads:
+    thread1.join()
diff --git a/testHBA.py b/testHBA.py
new file mode 100644
index 0000000000000000000000000000000000000000..f61c8d588241ff56c2e59a782e71127c35a7b788
--- /dev/null
+++ b/testHBA.py
@@ -0,0 +1,61 @@
+import logging
+import argparse
+from opcuaserv import opcuaserv
+from opcuaserv import i2client
+from opcuaserv import yamlreader
+#from opcuaserv import pypcc2
+from i2cserv import i2cthread
+import threading
+import time
+import sys
+import signal
+from yamlconfig import Find;
+
+logging.basicConfig(level="DEBUG",format='%(asctime)s [%(levelname)-8s,%(filename)-20s:%(lineno)-3d] %(message)s')
+
+RunTimer=True;
+#def signal_handler(sig, frame):
+#    logging.warn('Stop signal received!')
+#    global RunTimer; 
+#    RunTimer=False
+#signal.signal(signal.SIGINT, signal_handler)
+
+logging.info("Start I2C processes")   
+threads=[]
+I2Cclients=[]
+name='RCU'
+RCU_I2C=i2client.i2client(name=name)
+thread1=i2cthread.start(*RCU_I2C.GetInfo())
+threads.append(thread1)
+I2Cclients.append(RCU_I2C)
+
+#Load yaml so that we know the variable names
+RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile=name)
+#RCU_conf.CallInit()
+
+var1=RCU_conf.getmethodid('RCU_update');
+#var1=RCU_conf.getmethodid('RCU_on');
+#N=32;
+#mask=[i<2 for i in range(N)];
+#RCU_I2C.callmethod(var1,[])
+
+var1=RCU_conf.getvarid('HBA_element_beamformer_delays');
+N=32*3;
+data=list(range(32))*N;
+mask=[i<1*3 for i in range(N)];
+RCU_I2C.setvar(var1,data,mask);
+#RCU_I2C.readvar(var1,mask);
+
+
+time.sleep(5);
+
+while RCU_I2C.data_waiting():
+    varid,data,mask=RCU_I2C.readdata()
+    print("Results:",RCU_conf.getvar1(varid)['name'],data[:12],mask[:12])
+
+
+logging.info("Stop threads")
+for i2c in I2Cclients:
+    i2c.stop()
+for thread1 in threads:
+    thread1.join()
diff --git a/testRCU.py b/testRCU.py
new file mode 100644
index 0000000000000000000000000000000000000000..27ca7ddeea6cb93e54d9b82739315644eb0a6371
--- /dev/null
+++ b/testRCU.py
@@ -0,0 +1,95 @@
+import logging
+import argparse
+from opcuaserv import opcuaserv
+from opcuaserv import i2client
+from opcuaserv import yamlreader
+#from opcuaserv import pypcc2
+from i2cserv import i2cthread
+import threading
+import time
+import sys
+import signal
+from yamlconfig import Find;
+
+logging.basicConfig(level="INFO",format='%(asctime)s [%(levelname)-8s,%(filename)-20s:%(lineno)-3d] %(message)s')
+
+RunTimer=True;
+#def signal_handler(sig, frame):
+#    logging.warn('Stop signal received!')
+#    global RunTimer; 
+#    RunTimer=False
+#signal.signal(signal.SIGINT, signal_handler)
+
+logging.info("Start I2C processes")   
+threads=[]
+I2Cclients=[]
+name='RCU'
+RCU_I2C=i2client.i2client(name=name)
+thread1=i2cthread.start(*RCU_I2C.GetInfo())
+threads.append(thread1)
+I2Cclients.append(RCU_I2C)
+
+#Load yaml so that we know the variable names
+RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile=name)
+RCU_conf.CallInit()
+
+var1=RCU_conf.getmethodid('RCU_update');
+#var1=RCU_conf.getmethodid('RCU_on');
+#N=32;
+#mask=[i<2 for i in range(N)];
+#RCU_I2C.callmethod(var1,[])
+
+if False:
+    var1=RCU_conf.getvarid('RCU_LED0');
+    N=32;
+    mask=[i<8 for i in range(N)];
+    data=[0]*N;
+elif True:
+    var1=RCU_conf.getvarid('RCU_ADC_lock');
+    N=32*3;
+    mask=[i<5*3 for i in range(N)];
+elif False:
+    var1=RCU_conf.getvarid('RCU_attenuator');
+    N=32*3;
+    mask=[i<6 for i in range(N)];
+    data=[10]*N;
+    data[:6]=[0,1,2,3,4,5]
+else:
+    var1=RCU_conf.getvarid('HBA_element_beamformer_delays');
+    N=32*3;
+    mask=[i<4*3 for i in range(N)];
+    data=[1]*(N*32);
+#print(var1)
+#print("mask=",mask);
+#print("data=",data);
+#RCU_I2C.setvar(var1,data,mask);
+RCU_I2C.readvar(var1,mask);
+
+var1=RCU_conf.getvarid('RCU_temperature');
+N=32;
+mask=[i<2 for i in range(N)];
+#RCU_I2C.readvar(var1,mask);
+
+#data=[0]*N;
+#RCU_I2C.setvar(var1,data,mask);
+#def setvar(self,id1,data=[],mask=[]):
+
+#var1=RCU_conf.getmethodid('RCU_on');
+var1=RCU_conf.getmethodid('RCU_HBAT_WAIT_PPS');
+N=32;
+mask=[i<7 for i in range(N)];
+#RCU_I2C.callmethod(var1,mask)
+
+
+time.sleep(5);
+
+while RCU_I2C.data_waiting():
+    varid,data,mask=RCU_I2C.readdata()
+    print("Results:",RCU_conf.getvar1(varid)['name'],data[:12],mask[:12])
+
+
+logging.info("Stop threads")
+for i2c in I2Cclients:
+    i2c.stop()
+for thread1 in threads:
+    thread1.join()
diff --git a/testUNB2.py b/testUNB2.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6e3530a84a32db8644c76e8258a8f93bae81b75
--- /dev/null
+++ b/testUNB2.py
@@ -0,0 +1,68 @@
+import logging
+import argparse
+from opcuaserv import opcuaserv
+from opcuaserv import i2client
+from opcuaserv import yamlreader
+#from opcuaserv import pypcc2
+from i2cserv import i2cthread
+import threading
+import time
+import sys
+import signal
+from yamlconfig import Find;
+
+logging.basicConfig(level="DEBUG",format='%(asctime)s [%(levelname)-8s,%(filename)-20s:%(lineno)-3d] %(message)s')
+
+RunTimer=True;
+#def signal_handler(sig, frame):
+#    logging.warn('Stop signal received!')
+#    global RunTimer; 
+#    RunTimer=False
+#signal.signal(signal.SIGINT, signal_handler)
+
+logging.info("Start I2C processes")   
+threads=[]
+I2Cclients=[]
+name='UNB2'
+RCU_I2C=i2client.i2client(name=name)
+thread1=i2cthread.start(*RCU_I2C.GetInfo())
+threads.append(thread1)
+I2Cclients.append(RCU_I2C)
+
+#Load yaml so that we know the variable names
+RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile=name)
+var1=RCU_conf.getvarid('UNB2_EEPROM_Unique_ID');
+N=2;
+mask=[i<1 for i in range(N)];
+print("mask=",mask);
+RCU_I2C.readvar(var1,mask);
+
+
+var1=RCU_conf.getvarid('UNB2_DC_DC_48V_12V_VIN');
+N=2;
+mask=[i<2 for i in range(N)];
+print("mask=",mask);
+RCU_I2C.readvar(var1,mask);
+
+var1=RCU_conf.getvarid('UNB2_FPGA_QSFP_CAGE_LOS');
+N=48;
+mask=[i<8 for i in range(N)];
+print("mask=",mask);
+RCU_I2C.readvar(var1,mask);
+
+#var1=RCU_conf.getmethodid('RCU_on');
+#N=32;
+#mask=[i<2 for i in range(N)];
+#RCU_I2C.callmethod(var1,mask)
+
+time.sleep(2);
+
+while RCU_I2C.data_waiting():
+    varid,data,mask=RCU_I2C.readdata()
+    print("Results:",RCU_conf.getvar1(varid)['name'],data)
+
+logging.info("Stop threads")
+for i2c in I2Cclients:
+    i2c.stop()
+for thread1 in threads:
+    thread1.join()
diff --git a/yamlconfig.py b/yamlconfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..2114bb1eef8dfb8c5ec013444fe89e9c64f23d1b
--- /dev/null
+++ b/yamlconfig.py
@@ -0,0 +1,227 @@
+import yaml
+import struct
+import time
+import logging
+
+def Find(L,name,value,default=False):
+  for x in L:
+    if x[name]==value:
+        return x;
+  return default;
+
+
+def GetField(D,name,dev_number,default=None):
+    X=D.get(name,default)
+    return X[dev_number] if isinstance(X,list) else X;
+
+#class AttrDict(dict):
+# def __init__(self,*args,**kwargs):
+#   super(AttrDict,self).__init__(*args,**kwargs)
+#   self.__dict__=self
+
+def str2int(x):
+    return (int(x,16) if x.find('x')>0 else int(x));
+
+class yamlconfig():
+    def __init__(self,yamlfile='RCU'):
+        self.conf=yaml.load(open("config/"+yamlfile+'.yaml'))
+        self.expand_variables()
+#        print([[v['name'],v.get('devreg')] for v in var1])
+#        print(len(self.conf['variables']),N)
+        for i,v in enumerate(self.conf['variables']):
+            v['id']=i
+        for i,v in enumerate(self.conf['methods']):
+            v['id']=i
+
+    def getvars(self):
+        return self.conf['variables'];
+    def getvar1(self,varid):
+        return self.conf['variables'][varid];
+    def getvarid(self,name):
+        var1=Find(self.conf['variables'],'name',name,None);
+        return (var1['id'] if not(var1 is None) else None);
+
+    def getmethod(self,methodid):
+        return self.conf['methods'][methodid];
+#        return Find(self.conf['methods'],'id',methodid);
+    def getmethodid(self,name):
+        var1=Find(self.conf['methods'],'name',name);
+        return (var1['id'] if var1 else var1);
+
+    def expand_variables(self):
+        #expand variables that are combined in single array
+        var1=self.conf['variables']
+        N=len(var1)
+#        print([v['name'] for v in self.conf['variables']])
+        for i in range(N-1,-1,-1):
+            #print(var1[i])
+            if isinstance(var1[i]['name'],list):
+                for x,name in enumerate(var1[i]['name']):
+                    var2=var1[i].copy()
+                    var2['name']=name
+                    var2['devreg']=GetField(var1[i],'devreg',x)
+                    var2['scale']=GetField(var1[i],'scale',x,1)
+                    var1.append(var2)
+                    N+=1;
+                var1.remove(var1[i])
+                N-=1;
+
+    def getdevreg(self,name):
+#        try:
+          dr=self.devreglist.get(name);
+          if dr: return dr;
+          if isinstance(name,int): return {"addr":name}
+          name2=name.split('.')
+#          print(name2,str2int(name2[0]),str2int(name2[1]))
+          logging.debug("New devreg! %s",str((name2)))
+          if len(name2)==2:
+              dev1=Find(self.conf['device_registers'],'name',name2[0])
+              if dev1: 
+                    store=dev1.get('store',False)
+                    devcls=dev1.get('driver');
+                    if not(devcls): logging.error("Can not find driver for register "+name2[0]);
+                    else:
+                       devcls=Find(self.conf['drivers'],'name',devcls)
+                       if not(devcls): logging.error("Can not find device for register "+name2[0]);
+                       else:
+                         devcls=devcls.get('obj')
+#                    print(dev1)
+                    return {"addr":dev1.get('address',0),"register_R":str2int(name2[1]),"register_W":str2int(name2[1]),"store":store,"drivercls":devcls};
+              else: return {"addr":str2int(name2[0]),"register_R":str2int(name2[1]),"register_W":str2int(name2[1])}
+          logging.error("Can not find device register "+str(name));
+#        except:
+#          logging.error("Can not find device register "+str(name));
+#        return None;
+    def linkdevices(self):
+        #replace devreg reference with (pointer to) devreg dict
+        devreglist={}
+        drivers=self.conf['drivers']
+        for dev in self.conf['device_registers']:
+            N=dev.get('dim',1)
+            name=dev['name']    
+            for n in range(N):
+                addr=GetField(dev,'address',n,0)
+                devtype=GetField(dev,'driver',n)
+#                print(addr)
+                if devtype:
+                    devid=Find(drivers,'name',devtype)
+                    #devtype=Find(D.drivers,'name',devtype)['type']
+                else: devtype=None;
+                if N>1: name2=name+str(n+1)
+                else:   name2=name;
+                for reg in dev['registers']:
+                    regR=GetField(reg,'address',0,0)
+                    regW=GetField(reg,'address',1,0)
+                    store=reg.get('store',False)
+                    devregname=name2+'.'+reg['name'];
+                    devreglist[devregname]={"addr":addr,"register_R":regR,"register_W":regW,"store":store,"driver":devid};
+#                    print(devregname,devreglist[devregname]['addr'],devreglist[devregname]['register_R'],devreglist[devregname]['register_W']);
+        self.devreglist=devreglist;
+        for D in drivers:
+            devreg=D.get('devreg');
+            if not(devreg): continue;
+            for i,dr in enumerate(devreg):
+                #print(dr,self.getdevreg(dr))
+                devreg[i]=self.getdevreg(dr)
+
+        for D in self.conf['variables']:
+            devreg=D.get('devreg');
+            if not(devreg): continue;
+            if isinstance(devreg,list):
+                for i,dr in enumerate(devreg):
+                #print("linkdev",dr,self.getdevreg(dr))
+                    devreg[i]=self.getdevreg(dr)
+            else:
+                D['devreg']=[self.getdevreg(devreg)]
+
+        for D in drivers:
+            mask=D.get('status');
+            if mask is None: continue;
+            mask=self.getvarid(mask)
+            if mask is None:
+                logging.warn("Variable %s not found",mask) 
+                continue;
+            D['maskid']=mask
+            #print(D['name'],devreg)
+#         hf.write("inline const t_devreg %s {.address=%i,.register_R=%i,.register_W=%i,.store=%i,.driver=%i};\n" % (devregname,addr,regR,regW,storex,devtype) )
+#hf.write("#define NumberStoreReg %i"%store)
+#        print(devreglist)
+#  return devreglist,store
+
+    def loaddrivers(self):
+        import importlib
+        import sys, inspect
+        for c in self.conf['drivers']:
+#          print("loading",c['name'],c['type']);
+#          try:
+          i = importlib.import_module("i2cserv."+c['type'])
+ #         except:
+  #          logging.warn("No driver for "+c['type'])
+   #         c['obj']=None;
+    #        continue;
+          for name, obj in inspect.getmembers(i,inspect.isclass):
+              if name==c['type']:
+ #                 print("  Load child:",name)
+                  c['obj']=obj(c)
+          if not(c.get('obj')): 
+              logging.warn((("Driver "+c['type']+" not found!")))
+        
+    def linkdrivers(self):
+        drivers=self.conf['drivers']
+        for c in drivers:
+            name=c.get('parent');
+            if not(name): continue;
+            p=Find(drivers,'name',name);
+            if not(p):
+                    logging.error("Can not find driver "+str(name))
+                    continue;
+            c['parentcls']=p['obj'];
+#            print("link ",c['name'],name," to ",p['obj'])
+            #devregs=c.get('devreg')
+            #if not(devregs): continue;
+            #for dr in devregs:
+            #    if not(dr): continue;
+            #    name=dr.get('driver')
+            #    if not(name): #Give it the parents driver
+            #        dr["drivercls"]=p['obj']
+            #    drv=dr.get("drivercls")
+            #    if drv is None:  logging.warn("variable "+c['name']+" register driver not found")
+
+
+
+        for name,c in self.devreglist.items():
+            drv=c['driver'];
+            if not(drv): continue;
+#            print(drv)
+            c['drivercls']=drv.get('obj');
+#            print("link ",name,drv['name']," to ",c.driverobj)
+        for c in self.conf['variables']:
+            name=c.get('driver');
+            if not(name): continue;
+            p=Find(drivers,'name',name);
+            if not(p):
+                    logging.error("Can not find driver "+str(name))
+                    continue;
+            c['drivercls']=p['obj'];
+#            print("link ",c['name'],name," to ",p['obj'])
+
+            devregs=c.get('devreg')
+            if not(devregs): continue;
+            for dr in devregs:
+                if not(dr): continue;
+                name=dr.get('driver')
+                if not(name): #Give it the parents driver
+                    dr["drivercls"]=p['obj']
+                drv=dr.get("drivercls")
+                if drv is None:  logging.warn("variable "+c['name']+" register driver not found")
+     
+        for c in self.conf['methods']:
+            name=c.get('driver');
+            if not(name): continue;
+            p=Find(drivers,'name',name);
+            if not(p):
+                    logging.error("Can not find driver "+str(name))
+                    continue;
+            c['drivercls']=p['obj'];
+
+