diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c8557b35adc701ba97d3369fedfac3c6e6a66dfb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,91 @@
+#
+# 'make'        build executable file 'main'
+# 'make clean'  removes all .o and executable files
+#
+
+# define the Cpp compiler to use
+CXX = g++
+
+# define any compile-time flags
+CXXFLAGS	:= -std=c++17 -Wall -Wextra -g
+
+# define library paths in addition to /usr/lib
+#   if I wanted to include libraries not in /usr/lib I'd specify
+#   their path using -Lpath, something like:
+LFLAGS = -lcapnp -lkj
+
+# define output directory
+OUTPUT	:= output
+
+# define source directory
+SRC		:= src
+
+# define include directory
+INCLUDE	:= include
+
+# define lib directory
+LIB		:= lib
+
+ifeq ($(OS),Windows_NT)
+MAIN	:= main.exe
+SOURCEDIRS	:= $(SRC)
+INCLUDEDIRS	:= $(INCLUDE)
+LIBDIRS		:= $(LIB)
+FIXPATH = $(subst /,\,$1)
+RM			:= del /q /f
+MD	:= mkdir
+else
+MAIN	:= main
+SOURCEDIRS	:= $(shell find $(SRC) -type d)
+INCLUDEDIRS	:= $(shell find $(INCLUDE) -type d)
+LIBDIRS		:= $(shell find $(LIB) -type d)
+FIXPATH = $1
+RM = rm -f
+MD	:= mkdir -p
+endif
+
+# define any directories containing header files other than /usr/include
+INCLUDES	:= $(patsubst %,-I%, $(INCLUDEDIRS:%/=%))
+
+# define the C libs
+LIBS		:= $(patsubst %,-L%, $(LIBDIRS:%/=%))
+
+# define the C source files
+SOURCES		:= $(wildcard $(patsubst %,%/*.cpp, $(SOURCEDIRS)))
+
+# define the C object files 
+OBJECTS		:= $(SOURCES:.cpp=.o)
+
+#
+# The following part of the makefile is generic; it can be used to 
+# build any executable just by changing the definitions above and by
+# deleting dependencies appended to the file from 'make depend'
+#
+
+OUTPUTMAIN	:= $(call FIXPATH,$(OUTPUT)/$(MAIN))
+
+all: $(OUTPUT) $(MAIN)
+	@echo Executing 'all' complete!
+
+$(OUTPUT):
+	$(MD) $(OUTPUT)
+
+$(MAIN): $(OBJECTS) 
+	$(CXX) $(CXXFLAGS) $(INCLUDES) -o $(OUTPUTMAIN) $(OBJECTS) $(LFLAGS) $(LIBS)
+
+# this is a suffix replacement rule for building .o's from .c's
+# it uses automatic variables $<: the name of the prerequisite of
+# the rule(a .c file) and $@: the name of the target of the rule (a .o file) 
+# (see the gnu make manual section about automatic variables)
+.cpp.o:
+	$(CXX) $(CXXFLAGS) $(INCLUDES) -c $<  -o $@
+
+.PHONY: clean
+clean:
+	$(RM) $(OUTPUTMAIN)
+	$(RM) $(call FIXPATH,$(OBJECTS))
+	@echo Cleanup complete!
+
+run: all
+	./$(OUTPUTMAIN)
+	@echo Executing 'run: all' complete!
\ No newline at end of file
diff --git a/README.md b/README.md
index 23ec5e0a9d302f8159fd7b5fadf5bc64cd5faf19..e58b63f42d28485b59c0c782ec90ba05ff5a73b2 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +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.
 
 # Prerequisites
diff --git a/compile.sh b/compile.sh
new file mode 100644
index 0000000000000000000000000000000000000000..256c591e106a03f05b35f8c588a3553650920dd3
--- /dev/null
+++ b/compile.sh
@@ -0,0 +1,7 @@
+rm pypcc/pypcc.capnp
+cd src/interface
+capnp compile -oc++ pypcc.capnp
+cp pypcc.capnp ../../pypcc/.
+cd ../..
+make clean
+make
\ No newline at end of file
diff --git a/pcctypes.py b/pcctypes.py
deleted file mode 100644
index 1450ec4701ec6f76d6a96a1141b592e874666fc2..0000000000000000000000000000000000000000
--- a/pcctypes.py
+++ /dev/null
@@ -1,79 +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
-
-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
-
-#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/pypcc/RCU.py b/pypcc/RCU.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c0511a932f9d4796f9cf18ec2c8d1a41ca56d9d
--- /dev/null
+++ b/pypcc/RCU.py
@@ -0,0 +1,348 @@
+from . import Vars
+import numpy as np
+import logging
+from .spibitbang1 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')
+
+    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.Instr:
+              #Execute instructions
+              Iset=Instr.dev;
+              if len(Mask)==0:  Mask=Vars.RCU_mask.OPCW.get_data_value().Value.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_data_value().Value.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.get_data_value().Value.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_data_value().Value.Value
+        value1=strs2bytes(Instr.value) if V1.OPCR is None else strs2bytes(V1.OPCR.get_data_value().Value.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.get_data_value().Value.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)
+#          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.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")
+            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.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 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 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):
+         Inst1=Vars.Instr(Vars.DevType.VarUpdate,Vars.RCU_temp,32,[0]*32)
+         Q1.put(Inst1)
+#         Inst1=Vars.Instr(Vars.DevType.VarUpdate,Vars.RCU_ADC_lock,96,[0]*96)
+#         Q1.put(Inst1)
+
+    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.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/pypcc/i2cserv.py b/pypcc/i2cserv.py
new file mode 100644
index 0000000000000000000000000000000000000000..2867c7cb98b1af6103cfb0bbbdf6f3c6e80acdbe
--- /dev/null
+++ b/pypcc/i2cserv.py
@@ -0,0 +1,50 @@
+
+import capnp
+import pypcc_capnp as pp
+import os
+import select;
+
+
+class i2cserv():
+    def __init__(self,name='RCU'):
+        self.name=name;
+        print("Try to connecting to "+name)
+        self.Output=os.open('../serv_to_'+name,os.O_WRONLY ) #Wait for other side ...
+        self.Input=open('../'+name+'_to_serv','rb' )
+        capnp.TwoPartyClient(self.Input)
+        print("Connected")
+        self.poll=select.poll();
+        self.poll.register(self.Input.fileno(),select.POLLIN)
+        self.message_iterator=iter(pp.OPCUAset.read_multiple_packed(self.Input))
+
+    def __del__(self):
+        print("Disconnecting")
+        os.close(self.Output)
+        self.Input.close()
+
+    def readvar(self,id):
+        Set=pp.OPCUAset.new_message(id=id,type=pp.InstType.varRead)
+        Data=Set.to_bytes_packed()
+        print('Send readvar, len=',len(Data))
+        os.write(self.Output,Data)
+
+    def setvar(self,id,data=[],mask=[]):
+        Set=pp.OPCUAset.new_message(id=id,type=pp.InstType.varSet,data=data,mask=mask) #set_led
+        Data=Set.to_bytes_packed()
+        print('Send setvar, len=',len(Data))
+        os.write(self.Output,Data)
+
+    def callmethod(self,id,mask=[]):
+        Set=pp.OPCUAset.new_message(id=id,type=pp.InstType.method,mask=mask) #set_led
+        Data=Set.to_bytes_packed()
+        print('Send method, lenmask=',len(mask))
+        os.write(self.Output,Data)
+
+    def data_waiting(self):
+        return (self.Input.fileno(),select.POLLIN) in self.poll.poll(100)
+
+    def readdata(self):
+        message=next(self.message_iterator)
+        return message.id,message.data,message.mask
+     
+
diff --git a/opcuaserv.py b/pypcc/opcuaserv.py
similarity index 90%
rename from opcuaserv.py
rename to pypcc/opcuaserv.py
index f38b8acb5a4ced13f3e49bb6d45c1897de1de520..daa3cddd032508c6300deadce94409c870336b38 100644
--- a/opcuaserv.py
+++ b/pypcc/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)
 
@@ -58,18 +59,17 @@ def AddVar(name,value):
 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]
+    Vars_R[myvar.nodeid.Identifier]=[vname,myvar.get_data_value(),varvalue2,v]
     return myvar
 
 def AddVarW(vname,varvalue2,v,Q1):
     logging.info(str(("Variable added: ",vname)))#,'=',varvalue2)
     myvar2 = PCCobj.add_variable(idx, vname, varvalue2)
     myvar2.set_writable()
-    Vars_W[myvar2.nodeid.Identifier]=[v.name,myvar2.get_data_value(),v,Q1]
+    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), [],[] )
     logging.info(str(("AddMethod:",vname)))
diff --git a/pypcc/pypcc.capnp b/pypcc/pypcc.capnp
new file mode 100644
index 0000000000000000000000000000000000000000..8486fe7b70647b2988d05590248ca69d6ff89573
--- /dev/null
+++ b/pypcc/pypcc.capnp
@@ -0,0 +1,14 @@
+@0x9f2c99de8c7edd7f;
+
+enum InstType {
+    varSet     @0;
+    varRead    @1;
+    method     @2;
+}
+
+struct OPCUAset {
+ id   @0: UInt8;
+ type @1: InstType;
+ data @2: List(UInt8);
+ mask @3: List(Bool);
+}
diff --git a/pypcc2.py b/pypcc/pypcc3.py
similarity index 62%
rename from pypcc2.py
rename to pypcc/pypcc3.py
index 9907c49deb224044a780d1129cb57f5b7c6bbf56..906e5e7be22a4af3eb2c4fdfb756301780e7b9cd 100644
--- a/pypcc2.py
+++ b/pypcc/pypcc3.py
@@ -3,9 +3,6 @@ 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
@@ -13,9 +10,11 @@ import time
 #import Vars
 import logging
 import argparse
+import i2cserv
+import yamlreader
 
 parser = argparse.ArgumentParser()
-parser.add_argument("-s", "--simulator", help="Do not connect to I2c, but simulate behaviour.", action="store_true")
+#parser.add_argument("-s", "--simulator", help="Do not connect to I2c, but simulate behaviour.", 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")
 args = parser.parse_args()
@@ -27,31 +26,27 @@ 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
 
 #Queue used to pass instructions from opc-ua server to RCU
-Q1=queue.Queue() #RCUs
-Q2=queue.Queue() #CLK
+#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(I2C.I2C2server) #Dummy switch as their is no switch on LTS
+#SW1=I2Cswitch1.I2Cswitch1(I2C.I2C1server)
+RCU_I2C=i2cserv.i2cserv()
+RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile='RCU')
+#RCU=RCU.RCU1(32,I2C.I2C1server,SW1.SetChannel)
+RCU_conf.AddVars(opcuaserv.AddVarR,opcuaserv.AddVarW)
+RCU_conf.AddMethod(opcuaserv.Addmethod)
+#RCU.load() #Load current register values from HW
 
-RCU=RCU.RCU1(32,I2C.I2C1server,SW1.SetChannel)
-RCU.AddVars(Q1,opcuaserv.AddVarR,opcuaserv.AddVarW)
-RCU.AddMethod(Q1,opcuaserv.Addmethod)
-RCU.load() #Load current register values from HW
-
-CLK=CLK.RCU1(1,I2C.I2C2server,SW0.SetChannel)
-CLK.AddVars(Q2,opcuaserv.AddVarR,opcuaserv.AddVarW)
-CLK.AddMethod(Q2,opcuaserv.Addmethod)
-CLK.load() #Load current register values from HW
+#CLK=CLK.RCU1(1,I2C.I2C1server,SW1.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)))
 
@@ -59,11 +54,11 @@ if False:
   opcuaserv.server.stop()
   exit()
 
-RCUthread1=RCU.start(Q1)
-CLKthread1=CLK.start(Q2)
+#RCUthread1=RCU.start(Q1)
+#CLKthread1=CLK.start(Q2)
 
 RunTimer=True;
-def TimerThread(Q1,RCU):
+def TimerThread(RCU_I2C,RCU_conf):
     V1=opcuaserv.AddVar("RCU_monitor_rate_RW",30)
     cnt=0;#Count second ticks
     while RunTimer:
@@ -73,21 +68,21 @@ def TimerThread(Q1,RCU):
            continue;
        cnt+=1;
        if cnt>=T1:
-         if Q1.qsize()>3: continue;
+ #        if Q1.qsize()>3: continue;
          cnt=0;
-         logging.debug(str(("I2C bytes=",I2C.I2Ccounter," Qlength=",Q1.qsize())))
-         RCU.Queue_Monitor(Q1)
+ #        logging.debug(str(("I2C bytes=",I2C.I2Ccounter," Qlength=",Q1.qsize())))
+ #        RCU.Queue_Monitor(Q1)
 
     logging.info("End Timer thread")
 
-Timerthread1 = threading.Thread(target=TimerThread, args=(Q1,RCU))
+Timerthread1 = threading.Thread(target=TimerThread, args=(RCU_I2C,RCU_conf))
 Timerthread1.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)
+#    Q1.put(None)
+#    Q2.put(None)
     logging.info('Stop timer thread')
     global RunTimer; 
     RunTimer=False
@@ -99,10 +94,12 @@ opcuaserv.start()
 try:
 #Do nothing.
  while RunTimer:
-    time.sleep(1)
+#    time.sleep(0.01)
+    RCU_conf.getvar();
+
 finally:
         logging.info("Stop OPC-UA server")
         opcuaserv.server.stop()
-        RCUthread1.join()
+#        RCUthread1.join()
 #        CLKthread1.join()
         Timerthread1.join()
diff --git a/pypcc/test1.py b/pypcc/test1.py
new file mode 100644
index 0000000000000000000000000000000000000000..2470a7fc27ff1746d24d8c04c033fe207b11b8be
--- /dev/null
+++ b/pypcc/test1.py
@@ -0,0 +1,82 @@
+
+# coding: utf-8
+
+# In[1]:
+
+
+import capnp
+import pypcc_capnp as pp
+import os
+
+
+# In[2]:
+
+
+data=[0]*32;
+mask=[False]*32;
+mask[0]=True;
+Set=pp.OPCUAset.new_message(id=4,type=pp.InstType.varSet,data=data,mask=mask) #set_led
+
+
+# In[3]:
+
+
+print(Set)
+Data=Set.to_bytes_packed()
+#Data=Set.to_bytes()
+print(Data)
+
+
+# In[4]:
+
+
+Output=os.open('../serv_to_RCU',os.O_WRONLY ) #Wait for other side ...
+Input=open('../RCU_to_serv','rb' )
+
+
+# In[11]:
+
+
+os.write(Output,Data)
+os.write(Output,Data)
+
+
+# In[6]:
+
+
+print(Input,Input.fileno())
+
+
+# In[7]:
+
+
+import select;
+poll=select.poll();
+poll.register(Input.fileno(),select.POLLIN)
+
+
+# In[8]:
+
+
+#pp.OPCUAset.`
+message_iterator=iter(pp.OPCUAset.read_multiple_packed(Input))
+
+
+# In[12]:
+
+
+while (Input.fileno(),select.POLLIN) in poll.poll(100):
+#    message=pp.OPCUAset.read_packed(Input)
+    message=next(message_iterator)
+    print("read!",message)
+#    message=pp.OPCUAset.read_packed(Input)
+#    print("read!")
+
+
+# In[13]:
+
+
+os.close(Output)
+Input.close()
+#Input.close()
+
diff --git a/pypcc/yamlreader.py b/pypcc/yamlreader.py
new file mode 100644
index 0000000000000000000000000000000000000000..815e5d53e935eb9bff9b20f8dc540eb903fef937
--- /dev/null
+++ b/pypcc/yamlreader.py
@@ -0,0 +1,185 @@
+import yaml
+import struct
+def Find(L,name,value):
+  for x in L:
+    if x[name]==value:
+        return x;
+  return False;
+
+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():
+    def __init__(self,i2cserver,yamlfile='RCU'):
+        self.conf=yaml.load(open("../src/apsctl/"+yamlfile+'.yaml'))
+        for i,v in enumerate(self.conf['variables']):
+            v['id']=i
+        for i,v in enumerate(self.conf['methods']):
+            v['id']=i
+        self.server=i2cserver;
+
+    
+    def AddVars(self,AddVarR,AddVarW):
+     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*[""]
+#        print(len(varvalue2),varvalue2)
+        if v.get('rw') in ['ro','rw']:
+            var1=AddVarR(name+"_R",varvalue2,v['id'])
+            v['OPCR']=var1
+            print("Var added:"+name+"_R")
+            self.server.readvar(v['id'])
+#            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['OPCW']=var1
+            print("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('rw','')=='hidden': continue;
+          print(v)
+#        Inst1=Vars.Instr(Vars.DevType.Instr,v,0,[])
+          Addmethod(v['name'],v['id'],self)
+          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,id):
+        v=self.conf['methods'][id];
+        print("Method called!",v['name'])
+        mask=v.get('maskOPC',None);
+        mask=mask.get_value() if (mask!=None) else [];
+        self.server.callmethod(id,mask) 
+
+    def setvar(self,id,data=[]):
+        v=self.conf['variables'][id];
+        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 (dtype=="float"): 
+                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:
+                print("setvar",v['name']," unsupported width!",width)
+                return;
+        elif (dtype=="string"):
+                data2=bytearray() 
+                for s in data:
+                    data2.extend('{s:>{width}'.format(s=s[:width],width=width).encode('ascii'));
+        else:
+                print("setvar unsupported type");
+                return;
+        data2=[d for d in data2]
+        print("setvar ",v['name'],data2,mask);
+        self.server.setvar(id,data2,mask) 
+
+    def getvar(self):
+        if not(self.server.data_waiting()): return;
+        print("getvar ...")
+        while True:
+           try:
+                id,data,mask=self.server.readdata(); 
+                print("**getvar",id,data,mask);
+                if len(data)==0: continue;
+           except:
+              print('finished')
+              return;
+           self.OPCset(id,data,mask);
+ 
+    def OPCset(self,id,data,mask):
+        v=self.conf['variables'][id];
+        dtype=v.get('dtype','integer');
+        width=(v.get('width',8)-1)//8+1
+        print("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), 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), data)
+            elif width==8:
+                data2 = struct.unpack('>%sQ' % len(data), data)
+            else:
+                print("OPCset",v['name']," unsupported width!",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)]
+        else:
+                print("OPCset unsupported type");
+                return;
+        if dtype=="float": 
+                scale=float(v.get('scale',1.))
+                data2=[(d*scale) for d in data2]
+        data3=v['OPCR'].get_value();
+#        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;
+        print("OPCset",v['name'],data3)
+        v['OPCR'].set_value(data3);
+
diff --git a/requirements.txt b/requirements.txt
index a60ca7ecbd7bfebc36f787dd6425b771587835b1..e503c85dbfbb6c97a126e513ebc82bc3ba8264cf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-git+https://github.com/amaork/libi2c.git; platform_system == "linux"
 opcua
 numpy
-recordclass
+pycapnp
+capnp
diff --git a/run.sh b/run.sh
new file mode 100644
index 0000000000000000000000000000000000000000..64c418f2dfae847bea63c38072043cc9a9e33681
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,12 @@
+#Make fifo buffers
+rm RCU_to_serv
+rm serv_to_RCU
+mkfifo RCU_to_serv
+mkfifo serv_to_RCU
+
+#Run I2C controller
+./output/main  >log1.txt 2>log2.txt &
+
+#Run OPC-UA server
+cd pypcc
+python3 pypcc3.py 
\ No newline at end of file
diff --git a/scripts/ADCreset.py b/scripts/ADCreset.py
index b0f208abaf03277f350b210cc2ee279566f3c96a..561b6e6dcff36af5f9bb7f02507e39d60c429efa 100644
--- a/scripts/ADCreset.py
+++ b/scripts/ADCreset.py
@@ -3,11 +3,11 @@ from test_common import *
 RCUs=[0];
 setRCUmask(RCUs)
 
-callmethod("RCU_off")
-time.sleep(1)
+#callmethod("RCU_off")
+#time.sleep(1)
 callmethod("RCU_on")
-callmethod("RCU_on")
-time.sleep(1)
-callmethod("ADC_on")
+#callmethod("RCU_on")
+#time.sleep(1)
+#callmethod("ADC_on")
 
 disconnect();
diff --git a/scripts/Att.py b/scripts/Att.py
index 6e5d7b14ec651ce3f809a7a380db6e671faff67c..174e126f3adce597ce62c002bcabbc909c4d3eee 100644
--- a/scripts/Att.py
+++ b/scripts/Att.py
@@ -1,26 +1,19 @@
 from test_common import *
 
 name="RCU_attenuator"
-RCU=0;
-Att=[5,5,5]
+RCU=1;
+Att=[1,2,2]
 
-
-#setAntmask([RCU])
+setAntmask([RCU])
 
 att=get_value(name+"_R")
-val=att.Value.Value
-print("Att old:",val)
-#print("Att old:",att[3*RCU:3*RCU+3])
+print("Att old:",att[3*RCU:3*RCU+3])
 
-val[3*RCU:3*RCU+3]=Att
-att.Value.Value=val
-print("Att set:",val)
-#att[3*RCU]+=1
+att[3*RCU:3*RCU+3]=Att
 set_value(name+"_RW",att)
 
 time.sleep(0.5)
 att=get_value(name+"_R")
-print("Att new:",att.Value.Value)
-#print("Att new:",att[3*RCU:3*RCU+3])
+print("Att new:",att[3*RCU:3*RCU+3])
 
 disconnect()
\ No newline at end of file
diff --git a/scripts/LED.py b/scripts/LED.py
index d1857ae8879599d05c32afecce64f161f5cba1ea..b2c7f906374f635b85733958259544b11f0fa688 100644
--- a/scripts/LED.py
+++ b/scripts/LED.py
@@ -1,18 +1,18 @@
 from test_common import *
 
 name="RCU_LED0"
-RCU=1;
-LEDvalue="on";
+RCU=3;
+LEDvalue=True;
 
 setRCUmask([RCU])
-#exit()
+
 led=get_value(name+"_R")
 print("LED old:",led)
 led[RCU]=LEDvalue
-print("LED changed:",led)
-
+#led[0]=False;
+print("LED set:",led)
 set_value(name+"_RW",led)
-time.sleep(0.1)
+time.sleep(0.5)
 
 print("LED new:",get_value(name+"_R"))
 
diff --git a/scripts/test1.py b/scripts/test1.py
deleted file mode 100644
index a691a74530fd5645c34f885bb2fcc5b59e8a2355..0000000000000000000000000000000000000000
--- a/scripts/test1.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from test_common import *
-
-name="RCU_LED0_RW"
-#RCU=0;
-#LEDvalue=0;
-
-#setRCUmask([RCU])
-
-A=get_value(name)
-print(A)
-#A[0]=1.;
-A[0]='on';
-print(A)
-set_value(name,A)
-#print("LED old:",led)
-#led[RCU]=LEDvalue
-
-#set_value(name+"_RW",led)
-#time.sleep(0.1)
-
-#print("LED new:",get_value(name+"_R"))
-
-disconnect()
diff --git a/scripts/test_common.py b/scripts/test_common.py
index f9e5b4273446be810256f18409c13ae1be6de240..a612569fc7c8f972fe05f26faaf48694ce2ece4e 100644
--- a/scripts/test_common.py
+++ b/scripts/test_common.py
@@ -1,5 +1,4 @@
-#Address="opc.tcp://odroidRCU2:4842/"
-Address="opc.tcp://dop444:4840/"
+Address="opc.tcp://localhost:4842/"
 #Address="opc.tcp://ltspi:4842/"
 import sys
 sys.path.insert(0, "..")
@@ -28,13 +27,11 @@ def disconnect():
 
 def get_value(name):
   var1 = root.get_child(["0:Objects", "2:PCC", "2:"+name])
-#  return var1.get_value()
-  return var1.get_data_value()
+  return var1.get_value()
 
 def set_value(name,value):
   var1 = root.get_child(["0:Objects", "2:PCC", "2:"+name])
   var1.set_value(value)
-#  var1.set_data_value(value,7)
 
 def setRCUmask(rcu=[]):
     name="RCU_mask_RW"
@@ -42,7 +39,6 @@ def setRCUmask(rcu=[]):
     print(name," old:",M)
     M=[False for m in M]
     for r in rcu:
-#        M[r]=1
         M[r]=True
     set_value(name,M)
     print(name," new:",get_value(name))
diff --git a/src/apsctl.schema.json b/src/apsctl.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..07c6b82a4866a48c4d4f4b3166af321404950a95
--- /dev/null
+++ b/src/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/src/apsctl/CLK.h b/src/apsctl/CLK.h
new file mode 100644
index 0000000000000000000000000000000000000000..488c488a49ccd9c6927ad4528a771f6160b5e9c7
--- /dev/null
+++ b/src/apsctl/CLK.h
@@ -0,0 +1,26 @@
+/*** Device Register Definitions ***/
+const t_devreg IO1_CONF1 {.address=32,.register_R=6,.register_W=6,.store=1,.driver=1};
+const t_devreg IO1_CONF2 {.address=32,.register_R=7,.register_W=7,.store=2,.driver=1};
+const t_devreg IO1_GPIO1 {.address=32,.register_R=0,.register_W=2,.store=3,.driver=1};
+const t_devreg IO1_GPIO2 {.address=32,.register_R=1,.register_W=3,.store=4,.driver=1};
+const t_devreg IO2_CONF1 {.address=32,.register_R=6,.register_W=6,.store=5,.driver=1};
+const t_devreg IO2_CONF2 {.address=32,.register_R=7,.register_W=7,.store=6,.driver=1};
+const t_devreg IO2_GPIO1 {.address=32,.register_R=0,.register_W=2,.store=7,.driver=1};
+const t_devreg IO2_GPIO2 {.address=32,.register_R=1,.register_W=3,.store=8,.driver=1};
+const t_devreg IO3_CONF1 {.address=32,.register_R=6,.register_W=6,.store=9,.driver=1};
+const t_devreg IO3_CONF2 {.address=32,.register_R=7,.register_W=7,.store=10,.driver=1};
+const t_devreg IO3_GPIO1 {.address=32,.register_R=0,.register_W=2,.store=11,.driver=1};
+const t_devreg IO3_GPIO2 {.address=32,.register_R=1,.register_W=3,.store=12,.driver=1};
+const t_devreg PLL_PLL_stat {.address=0,.register_R=0,.register_W=0,.store=0,.driver=2};
+#define NumberStoreReg 12
+/*** Variable Definitions ***/
+const t_variable CLK_IGNORE {.name="CLK_IGNORE",.dim=1,.dtype=dt_boolean,.driver=1,.rw=rw_variable,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={0,0,0}};
+#define number_vars 1
+const t_variable variables[number_vars]={CLK_IGNORE,};
+
+/*** Driver Definitions ***/
+#define number_drivers 3
+const t_driver I2C {.name="I2C",.type=drv_i2c,.parent=0,.parameters={1},.devreg={}};
+const t_driver I2C_CLK {.name="I2C_CLK",.type=drv_i2c_devs,.parent=0,.parameters={32},.devreg={}};
+const t_driver SPIbb1 {.name="SPIbb1",.type=drv_spibitbang2,.parent=1,.parameters={4,7,5,6},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_GPIO1,IO3_GPIO1}};
+const t_driver driver_config[number_drivers]={I2C,I2C_CLK,SPIbb1,};
diff --git a/src/apsctl/CLK.yaml b/src/apsctl/CLK.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9edd498bfcd4b8bd13cf44b78ac2355d6ae79447
--- /dev/null
+++ b/src/apsctl/CLK.yaml
@@ -0,0 +1,58 @@
+version: "1.0"
+description: "1234"
+
+drivers:
+ - name: I2C
+   type: i2c
+   parameters: [1] #I2C port number
+ - name: I2C_CLK
+   type: i2c_devs #I2C devices
+   parent: I2C
+   parameters:  [32] #number of RCUs
+ - name: SPIbb1 
+   type: spibitbang2 #SPI bitbang via GPIO expander: CLK, SDI,SDO,CS
+   parent: I2C_CLK
+   devreg: [IO3.GPIO1,IO3.GPIO1,IO3.GPIO1,IO3.GPIO1]
+   parameters: [4,7,5,6]
+
+#This is the I2C devices in the RCU
+device_registers:
+ - name: IO
+   dim: 3
+   description: IO-Expander
+   address: 0x20
+   device: TCA9539/TCA6416?
+   driver: I2C_CLK
+   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: PLL
+   driver: SPIbb1
+   registers:
+    - name: PLL_stat
+      description: PLL locked status
+      address: 0x0
+
+
+variables:
+   - name: CLK_IGNORE
+     description: Only masked RF chains are updated
+     driver: I2C_CLK
+     rw:  variable #server RW variable, not linked to IO
+     dtype: boolean
+
diff --git a/src/apsctl/RCU.yaml b/src/apsctl/RCU.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b0a544345ceb036d56f88f76992a42445418ab29
--- /dev/null
+++ b/src/apsctl/RCU.yaml
@@ -0,0 +1,358 @@
+version: "1.0"
+description: "1234"
+
+drivers:
+ - name: I2C1
+   type: RCU_switch
+   devreg: [SWITCH.MASK]
+   parameters: [1] #I2C port number
+ - name: I2C_RCU 
+   type: i2c_array #An array of similar devices connected to an I2C switch
+   parent: I2C1
+   parameters: [1,32] #start,number of RCUs
+ - name: I2C_RFCHAIN
+   type: i2c_array2 #Array of similar devices with different address on same I2C line e.g. 3 rf chains on 1 RCU
+   parameters: [3] #number of RCUs
+   parent: I2C_RCU
+ - 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
+
+#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: I2C_RCU
+   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: SWITCH
+   description: RCU selection switch
+   address: 0x70
+   device: TCA9548
+   driver: I2C1
+   registers:
+   - name: MASK
+     description: I2C select mask
+
+ - name: ROM
+   description: IO-Expander for filter selection
+   address: 0x50
+   driver: I2C_RCU
+   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: I2C_RCU
+   registers:
+   - name: Ch0
+     address: 0xB080
+   - name: Ch1
+     address: 0xB880
+   - name: Ch2
+     address: 0xB180
+   - name: Ch3
+     address: 0xB980
+   - name: Ch4
+     address: 0xB280
+   - name: Ch5
+     address: 0xBA80
+   - name: Ch6
+     address: 0xB380
+   - name: Ch7
+     address: 0xBB80
+   - name: Temp
+     address: 0xA0C0
+
+#This 'special' devices that uses I2C
+
+ - name: HB_UC
+   description: RCU microcontroller 
+   address: 0x40
+   driver: I2C_RCU
+   registers:
+   - name: ID
+     description: Device ID
+     address: 0
+
+ - name: HBAT
+   dim: 3
+   address: [0x41,0x42,0x43]
+   description: Virtual HBAT0 interface
+   driver: I2C_HBAT
+   registers:
+   - name: XY
+     address: 0x10
+     description: XY delay register
+   - 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: CML_adjust
+      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_RFCHAIN
+     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_attenuator
+     description: Attenuator before ADC
+     driver: I2C_RFCHAIN
+     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_RFCHAIN
+     devreg:  [IO2.GPIO2,IO2.GPIO2,IO2.GPIO2]
+     bitoffset: [0,2,4]
+     width: 2
+     rw:  rw
+     dtype: uint8
+     dim: 96
+     mask: Ant_mask
+
+   - 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
+
+   - 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
+
+   - 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_RFCHAIN
+     devreg:  [ADC1.PLL_stat,ADC2.PLL_stat,ADC3.PLL_stat]
+     width: 8
+     rw:  ro
+     dtype: uint8
+     dim: 96
+     mask: Ant_mask
+
+   - name: RCU_dth1_freq
+     driver: I2C_RFCHAIN
+     devreg:  [DTH1.Freq,DTH2.Freq,DTH3.Freq]
+     width: 32
+     rw:  rw
+     dtype: uint32
+     dim: 96
+     mask: Ant_mask
+
+methods:
+  - name: RCU_on
+    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_attenuator: [10,10,10]  #Set OPC-UA variable
+     - RCU_Pwr_dig: Update  #Read value and update the OPC-UA variable
+     - WAIT: 500         #ms to wait
+     - ADC1_on: 0        #call another opc-ua method
+     - ADC2_on: 0
+     - WAIT: 500         #ms to wait
+     - RCU_ADC_lock: Update
+  - name: ADC1_on
+    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
+    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: RCU_off
+    instructions:
+     - RCU_Pwr_dig: 0 #Switch power off
+     #todo, also make all GPIO pins (except power enables) inputs to remove all power from devices.
\ No newline at end of file
diff --git a/src/apsctl/UNB2.yaml b/src/apsctl/UNB2.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e187ac81108168d9c823cbb708fb5460c79e4693
--- /dev/null
+++ b/src/apsctl/UNB2.yaml
@@ -0,0 +1,128 @@
+version: "0.0"
+description: "UNB2 LTS" 
+
+drivers:
+ - name: I2C1
+   type: UNB2_switch #Special driver mapping internal i2c line address to the 3 switches. 
+   #Address -> switch states       -> array of i2c-devices
+   #00:2F   -> [0:1][0:3][0:3,6:7] -> QSFP
+   #30:38   -> [0:1][0:3][4]       -> DDR4
+   #40:48   -> [0:1][0:3][5]       -> FPGA_PS
+   #80:81   -> [0:1][4]            -> PS
+   #A0:A1   -> [0:1][5]            -> Front panel
+   devreg: [APSCT_SWITCH.MASK,UB2_SWITCH1.MASK,UB2_SWITCH2.MASK] 
+   parameters: [1,0,0,0] #I2C port number, 3x switch reset pins 
+   
+ - name: d_QSFP 
+   type: i2c_array #An array of similar devices connected to an I2C switch
+   parent: I2C1
+   parameters: [0,48] #start,number of QSFP (2 UB x 2 nodes * 6 QSFP)
+ - name: d_DDR4
+   type: i2c_array 
+   parent: I2C1
+   parameters: [0x30,8] 
+ - name: d_FPGA_PS
+   type: i2c_array 
+   parent: I2C1
+   parameters: [0x40,48] 
+ - name: d_PS
+   type: i2c_array 
+   parent: I2C1
+   parameters: [0x80,2] 
+ - name: d_front_panel
+   type: i2c_array 
+   parent: I2C1
+   parameters: [0xA0,2] 
+# - name: GPIO
+#   type: GPIO
+#   parameters: [1] #pin numbers
+
+  
+#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
+
+- name: POL_FPGA_CORE
+  address: 0x01
+  driver: d_FPGA_PS
+  device: BMR4xx
+  registers:
+  - name: READ_VOUT
+    address: 0x8B
+  - name: READ_IOUT
+    address: 0x8C
+  - name: READ_TEMP
+    address: 0x8D
+
+variables:
+   - name: UNB2_mask
+     rw:  variable #translator variable
+     dtype: boolean
+     dim: 2
+
+   - name: UNB2_Front_Panel_LED
+     description: LED on front panel
+     mask: UNB2_mask
+     devreg: FP_IO.GPIO
+     driver: d_front_panel
+     rw:  rw
+     dtype: uint8
+     bitoffset: 4
+     width: 3
+     dim: 2
+
+   - name: UNB2_POL_FPGA_CORE_VOUT
+     driver: d_FPGA_PS
+     devreg:  POL_FPGA_CORE.READ_VOUT
+     width: 16
+     rw:  ro
+     dtype: double
+     scale: 1.2207e-4 #2^-13
+     dim: 8
+     mask: UNB2_node_mask
+
+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/src/apsctl/conf.cpp b/src/apsctl/conf.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac5dc33262894022e2bf918c301158147d40aad3
--- /dev/null
+++ b/src/apsctl/conf.cpp
@@ -0,0 +1,39 @@
+#include "conf.h"
+#include "../drivers/hba1.h"
+#include "../drivers/RCU_switch.h"
+#include "../drivers/spibitbang1.h"
+#include "../drivers/i2cbitbang1.h"
+#include "../drivers/i2c_array2.h"
+#include "../drivers/i2c_array.h"
+c_drivers::c_drivers()
+{
+    c_RCU_switch* i_I2C1=new c_RCU_switch(I2C1);
+    d[0]=i_I2C1;
+    c_i2c_array* i_I2C_RCU=new c_i2c_array(I2C_RCU);
+    d[1]=i_I2C_RCU;
+    c_i2c_array2* i_I2C_RFCHAIN=new c_i2c_array2(I2C_RFCHAIN);
+    d[2]=i_I2C_RFCHAIN;
+    c_hba1* i_I2C_HBAT=new c_hba1(I2C_HBAT);
+    d[3]=i_I2C_HBAT;
+    c_i2cbitbang1* i_I2Cbb1=new c_i2cbitbang1(I2Cbb1);
+    d[4]=i_I2Cbb1;
+    c_i2cbitbang1* i_I2Cbb2=new c_i2cbitbang1(I2Cbb2);
+    d[5]=i_I2Cbb2;
+    c_i2cbitbang1* i_I2Cbb3=new c_i2cbitbang1(I2Cbb3);
+    d[6]=i_I2Cbb3;
+    c_spibitbang1* i_SPIbb1=new c_spibitbang1(SPIbb1);
+    d[7]=i_SPIbb1;
+    c_spibitbang1* i_SPIbb2=new c_spibitbang1(SPIbb2);
+    d[8]=i_SPIbb2;
+    c_spibitbang1* i_SPIbb3=new c_spibitbang1(SPIbb3);
+    d[9]=i_SPIbb3;
+    i_I2C_RCU->parent=i_I2C1;
+    i_I2C_RFCHAIN->parent=i_I2C_RCU;
+    i_I2C_HBAT->parent=i_I2C_RCU;
+    i_I2Cbb1->parent=i_I2C_RCU;
+    i_I2Cbb2->parent=i_I2C_RCU;
+    i_I2Cbb3->parent=i_I2C_RCU;
+    i_SPIbb1->parent=i_I2C_RCU;
+    i_SPIbb2->parent=i_I2C_RCU;
+    i_SPIbb3->parent=i_I2C_RCU;
+};
diff --git a/src/apsctl/conf.cpp.old b/src/apsctl/conf.cpp.old
new file mode 100644
index 0000000000000000000000000000000000000000..efea9d58ea8f17a1ceb08bf7bd8204773e198b76
--- /dev/null
+++ b/src/apsctl/conf.cpp.old
@@ -0,0 +1,13 @@
+#include "conf.h"
+#include "../drivers/i2c_switch.h"
+#include "../drivers/i2c_array.h"
+
+c_drivers::c_drivers()
+{
+    c_i2c_switch* i_I2C1=new c_i2c_switch(I2C1);
+    d[0]=i_I2C1;
+    c_i2c_array* i_I2C_RCU=new c_i2c_array(I2C_RCU);
+    d[1]=i_I2C_RCU;
+    i_I2C_RCU->parent=i_I2C1;
+};
+
diff --git a/src/apsctl/conf.h b/src/apsctl/conf.h
new file mode 100644
index 0000000000000000000000000000000000000000..48ab69d7177a5c63afdea70376e972da6f6cb761
--- /dev/null
+++ b/src/apsctl/conf.h
@@ -0,0 +1,141 @@
+#ifndef HWDEFS_H
+#define HWDEFS_H
+#include "../drivers/drvbase.h"
+#include "../structs.h"
+
+/*** Device Register Definitions ***/
+const t_devreg IO1_CONF1 {.address=117,.register_R=6,.register_W=6,.store=1,.driver=1};
+const t_devreg IO1_CONF2 {.address=117,.register_R=7,.register_W=7,.store=2,.driver=1};
+const t_devreg IO1_GPIO1 {.address=117,.register_R=0,.register_W=2,.store=3,.driver=1};
+const t_devreg IO1_GPIO2 {.address=117,.register_R=1,.register_W=3,.store=4,.driver=1};
+const t_devreg IO2_CONF1 {.address=118,.register_R=6,.register_W=6,.store=5,.driver=1};
+const t_devreg IO2_CONF2 {.address=118,.register_R=7,.register_W=7,.store=6,.driver=1};
+const t_devreg IO2_GPIO1 {.address=118,.register_R=0,.register_W=2,.store=7,.driver=1};
+const t_devreg IO2_GPIO2 {.address=118,.register_R=1,.register_W=3,.store=8,.driver=1};
+const t_devreg IO3_CONF1 {.address=32,.register_R=6,.register_W=6,.store=9,.driver=1};
+const t_devreg IO3_CONF2 {.address=32,.register_R=7,.register_W=7,.store=10,.driver=1};
+const t_devreg IO3_GPIO1 {.address=32,.register_R=0,.register_W=2,.store=11,.driver=1};
+const t_devreg IO3_GPIO2 {.address=32,.register_R=1,.register_W=3,.store=12,.driver=1};
+const t_devreg SWITCH_MASK {.address=112,.register_R=0,.register_W=0,.store=0,.driver=0};
+const t_devreg ROM_ID {.address=80,.register_R=252,.register_W=252,.store=0,.driver=1};
+const t_devreg ROM_Version {.address=80,.register_R=0,.register_W=0,.store=0,.driver=1};
+const t_devreg AN_Ch0 {.address=20,.register_R=45184,.register_W=45184,.store=0,.driver=1};
+const t_devreg AN_Ch1 {.address=20,.register_R=47232,.register_W=47232,.store=0,.driver=1};
+const t_devreg AN_Ch2 {.address=20,.register_R=45440,.register_W=45440,.store=0,.driver=1};
+const t_devreg AN_Ch3 {.address=20,.register_R=47488,.register_W=47488,.store=0,.driver=1};
+const t_devreg AN_Ch4 {.address=20,.register_R=45696,.register_W=45696,.store=0,.driver=1};
+const t_devreg AN_Ch5 {.address=20,.register_R=47744,.register_W=47744,.store=0,.driver=1};
+const t_devreg AN_Ch6 {.address=20,.register_R=45952,.register_W=45952,.store=0,.driver=1};
+const t_devreg AN_Ch7 {.address=20,.register_R=48000,.register_W=48000,.store=0,.driver=1};
+const t_devreg AN_Temp {.address=20,.register_R=41152,.register_W=41152,.store=0,.driver=1};
+const t_devreg HB_UC_ID {.address=64,.register_R=0,.register_W=0,.store=0,.driver=1};
+const t_devreg HBAT1_XY {.address=65,.register_R=16,.register_W=16,.store=0,.driver=3};
+const t_devreg HBAT1_Version {.address=65,.register_R=127,.register_W=127,.store=0,.driver=3};
+const t_devreg HBAT2_XY {.address=66,.register_R=16,.register_W=16,.store=0,.driver=3};
+const t_devreg HBAT2_Version {.address=66,.register_R=127,.register_W=127,.store=0,.driver=3};
+const t_devreg HBAT3_XY {.address=67,.register_R=16,.register_W=16,.store=0,.driver=3};
+const t_devreg HBAT3_Version {.address=67,.register_R=127,.register_W=127,.store=0,.driver=3};
+const t_devreg ADC1_PLL_stat {.address=0,.register_R=10,.register_W=10,.store=0,.driver=7};
+const t_devreg ADC1_JESD_control1 {.address=0,.register_R=95,.register_W=95,.store=0,.driver=7};
+const t_devreg ADC1_CML_adjust {.address=0,.register_R=21,.register_W=21,.store=0,.driver=7};
+const t_devreg ADC1_Update {.address=0,.register_R=255,.register_W=255,.store=0,.driver=7};
+const t_devreg ADC2_PLL_stat {.address=0,.register_R=10,.register_W=10,.store=0,.driver=8};
+const t_devreg ADC2_JESD_control1 {.address=0,.register_R=95,.register_W=95,.store=0,.driver=8};
+const t_devreg ADC2_CML_adjust {.address=0,.register_R=21,.register_W=21,.store=0,.driver=8};
+const t_devreg ADC2_Update {.address=0,.register_R=255,.register_W=255,.store=0,.driver=8};
+const t_devreg ADC3_PLL_stat {.address=0,.register_R=10,.register_W=10,.store=0,.driver=9};
+const t_devreg ADC3_JESD_control1 {.address=0,.register_R=95,.register_W=95,.store=0,.driver=9};
+const t_devreg ADC3_CML_adjust {.address=0,.register_R=21,.register_W=21,.store=0,.driver=9};
+const t_devreg ADC3_Update {.address=0,.register_R=255,.register_W=255,.store=0,.driver=9};
+const t_devreg DTH1_Freq {.address=112,.register_R=4416,.register_W=4417,.store=0,.driver=4};
+const t_devreg DTH1_Property {.address=112,.register_R=17,.register_W=17,.store=0,.driver=4};
+const t_devreg DTH1_Start {.address=112,.register_R=98,.register_W=98,.store=0,.driver=4};
+const t_devreg DTH1_Stop {.address=112,.register_R=103,.register_W=103,.store=0,.driver=4};
+const t_devreg DTH2_Freq {.address=112,.register_R=4416,.register_W=4417,.store=0,.driver=4};
+const t_devreg DTH2_Property {.address=112,.register_R=17,.register_W=17,.store=0,.driver=4};
+const t_devreg DTH2_Start {.address=112,.register_R=98,.register_W=98,.store=0,.driver=4};
+const t_devreg DTH2_Stop {.address=112,.register_R=103,.register_W=103,.store=0,.driver=4};
+const t_devreg DTH3_Freq {.address=112,.register_R=4416,.register_W=4417,.store=0,.driver=4};
+const t_devreg DTH3_Property {.address=112,.register_R=17,.register_W=17,.store=0,.driver=4};
+const t_devreg DTH3_Start {.address=112,.register_R=98,.register_W=98,.store=0,.driver=4};
+const t_devreg DTH3_Stop {.address=112,.register_R=103,.register_W=103,.store=0,.driver=4};
+#define NumberStoreReg 12
+/*** Variable Definitions ***/
+const t_variable Ant_mask {.name="Ant_mask",.dim=96,.dtype=dt_boolean,.driver=2,.rw=rw_variable,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={0,0,0}};
+const t_variable RCU_mask {.name="RCU_mask",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_variable,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={0,0,0}};
+const t_variable RCU_attenuator {.name="RCU_attenuator",.dim=96,.dtype=dt_uint8,.driver=2,.rw=rw_rw,.bitoffset={0,0,0},.width=5,.scale=0,.devreg={IO1_GPIO1,IO1_GPIO2,IO2_GPIO1}};
+const t_variable RCU_band {.name="RCU_band",.dim=96,.dtype=dt_uint8,.driver=2,.rw=rw_rw,.bitoffset={0,2,4},.width=2,.scale=0,.devreg={IO2_GPIO2,IO2_GPIO2,IO2_GPIO2}};
+const t_variable RCU_LED0 {.name="RCU_LED0",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_rw,.bitoffset={6,6,6},.width=1,.scale=0,.devreg={IO2_GPIO2,IO2_GPIO2,IO2_GPIO2}};
+const t_variable RCU_LED1 {.name="RCU_LED1",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_rw,.bitoffset={7,7,7},.width=1,.scale=0,.devreg={IO2_GPIO2,IO2_GPIO2,IO2_GPIO2}};
+const t_variable RCU_temperature {.name="RCU_temperature",.dim=32,.dtype=dt_double,.driver=1,.rw=rw_ro,.bitoffset={0,0,0},.width=23,.scale=0.00421,.devreg={AN_Temp,AN_Temp,AN_Temp}};
+const t_variable RCU_Pwr_dig {.name="RCU_Pwr_dig",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_ro,.bitoffset={6,6,6},.width=1,.scale=0,.devreg={IO2_GPIO1,IO2_GPIO1,IO2_GPIO1}};
+const t_variable HBA_element_beamformer_delays {.name="HBA_element_beamformer_delays",.dim=3072,.dtype=dt_uint8,.driver=3,.rw=rw_rw,.bitoffset={2,2,2},.width=5,.scale=0,.devreg={HBAT1_XY,HBAT2_XY,HBAT3_XY}};
+const t_variable RCU_ID {.name="RCU_ID",.dim=32,.dtype=dt_uint32,.driver=1,.rw=rw_ro,.bitoffset={0,0,0},.width=32,.scale=0,.devreg={ROM_ID,ROM_ID,ROM_ID}};
+const t_variable RCU_version {.name="RCU_version",.dim=32,.dtype=dt_string,.driver=1,.rw=rw_ro,.bitoffset={0,0,0},.width=80,.scale=0,.devreg={ROM_Version,ROM_Version,ROM_Version}};
+const t_variable RCU_ADC_lock {.name="RCU_ADC_lock",.dim=96,.dtype=dt_uint8,.driver=2,.rw=rw_ro,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={ADC1_PLL_stat,ADC2_PLL_stat,ADC3_PLL_stat}};
+const t_variable RCU_dth1_freq {.name="RCU_dth1_freq",.dim=96,.dtype=dt_uint32,.driver=2,.rw=rw_rw,.bitoffset={0,0,0},.width=32,.scale=0,.devreg={DTH1_Freq,DTH2_Freq,DTH3_Freq}};
+#define number_vars 13
+const t_variable variables[number_vars]={Ant_mask,RCU_mask,RCU_attenuator,RCU_band,RCU_LED0,RCU_LED1,RCU_temperature,RCU_Pwr_dig,HBA_element_beamformer_delays,RCU_ID,RCU_version,RCU_ADC_lock,RCU_dth1_freq,};
+
+/*** Driver Definitions ***/
+#define number_drivers 10
+const t_driver I2C1 {.name="I2C1",.type=drv_RCU_switch,.parent=0,.parameters={1},.devreg={SWITCH_MASK}};
+const t_driver I2C_RCU {.name="I2C_RCU",.type=drv_i2c_array,.parent=0,.parameters={1,32},.devreg={}};
+const t_driver I2C_RFCHAIN {.name="I2C_RFCHAIN",.type=drv_i2c_array2,.parent=1,.parameters={3},.devreg={}};
+const t_driver I2C_HBAT {.name="I2C_HBAT",.type=drv_hba1,.parent=1,.parameters={},.devreg={}};
+const t_driver I2Cbb1 {.name="I2Cbb1",.type=drv_i2cbitbang1,.parent=1,.parameters={6,3,3},.devreg={IO1_GPIO1,IO2_GPIO2,IO2_CONF2}};
+const t_driver I2Cbb2 {.name="I2Cbb2",.type=drv_i2cbitbang1,.parent=1,.parameters={7,7,7},.devreg={IO1_GPIO2,IO2_GPIO1,IO1_CONF1}};
+const t_driver I2Cbb3 {.name="I2Cbb3",.type=drv_i2cbitbang1,.parent=1,.parameters={7,7,7},.devreg={IO1_GPIO2,IO2_GPIO1,IO1_CONF1}};
+const t_driver SPIbb1 {.name="SPIbb1",.type=drv_spibitbang1,.parent=1,.parameters={1,0,0,0},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_CONF1,IO3_GPIO2}};
+const t_driver SPIbb2 {.name="SPIbb2",.type=drv_spibitbang1,.parent=1,.parameters={3,2,2,1},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_CONF1,IO3_GPIO2}};
+const t_driver SPIbb3 {.name="SPIbb3",.type=drv_spibitbang1,.parent=1,.parameters={5,4,4,2},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_CONF1,IO3_GPIO2}};
+//const t_driver driver_config[number_drivers]={I2C1,I2C_RCU,I2C_RFCHAIN,I2C_HBAT,I2Cbb1,I2Cbb2,I2Cbb3,SPIbb1,SPIbb2,SPIbb3,};
+
+class c_drivers {
+ public:
+  c_drivers();
+  drvbase* d[number_drivers];
+};
+
+/*** Method Definitions ***/
+#define number_methods 4
+const t_instruction RCU_on_inst[19]={
+        {.type=inst_devreg,.variable=0,.devreg=IO2_CONF1,.len=1,.data={0}},
+        {.type=inst_devreg,.variable=0,.devreg=IO2_GPIO1,.len=1,.data={74}},
+        {.type=inst_devreg,.variable=0,.devreg=IO2_GPIO2,.len=1,.data={85}},
+        {.type=inst_devreg,.variable=0,.devreg=IO3_GPIO1,.len=1,.data={21}},
+        {.type=inst_devreg,.variable=0,.devreg=IO3_GPIO2,.len=1,.data={71}},
+        {.type=inst_devreg,.variable=0,.devreg=IO1_GPIO1,.len=1,.data={202}},
+        {.type=inst_devreg,.variable=0,.devreg=IO1_GPIO2,.len=1,.data={202}},
+        {.type=inst_devreg,.variable=0,.devreg=IO2_CONF2,.len=1,.data={0}},
+        {.type=inst_devreg,.variable=0,.devreg=IO3_CONF1,.len=1,.data={0}},
+        {.type=inst_devreg,.variable=0,.devreg=IO3_CONF2,.len=1,.data={0}},
+        {.type=inst_devreg,.variable=0,.devreg=IO1_CONF1,.len=1,.data={0}},
+        {.type=inst_devreg,.variable=0,.devreg=IO1_CONF1,.len=1,.data={0}},
+        {.type=inst_setvar,.variable=2,.devreg={0},.len=3,.data={10,10,10,}},
+        {.type=inst_getvarall,.variable=7,.devreg={0},.len=0,.data={}},
+        {.type=inst_wait,.variable=0,.devreg={0},.len=1,.data={}},
+        {.type=inst_method,.variable=1,.devreg={0},.len=0,.data={}},
+        {.type=inst_method,.variable=2,.devreg={0},.len=0,.data={}},
+        {.type=inst_wait,.variable=0,.devreg={0},.len=1,.data={}},
+        {.type=inst_getvarall,.variable=11,.devreg={0},.len=0,.data={}},
+      };
+const t_method RCU_on {.name="RCU_on",.len=19,.instructions=RCU_on_inst};
+const t_instruction ADC1_on_inst[2]={
+        {.type=inst_devreg,.variable=0,.devreg=ADC1_JESD_control1,.len=1,.data={20}},
+        {.type=inst_devreg,.variable=0,.devreg=ADC1_Update,.len=1,.data={1}},
+      };
+const t_method ADC1_on {.name="ADC1_on",.len=2,.instructions=ADC1_on_inst};
+const t_instruction ADC2_on_inst[2]={
+        {.type=inst_devreg,.variable=0,.devreg=ADC2_JESD_control1,.len=1,.data={20}},
+        {.type=inst_devreg,.variable=0,.devreg=ADC2_Update,.len=1,.data={1}},
+      };
+const t_method ADC2_on {.name="ADC2_on",.len=2,.instructions=ADC2_on_inst};
+const t_instruction RCU_off_inst[1]={
+        {.type=inst_setvar,.variable=7,.devreg={0},.len=1,.data={0}},
+      };
+const t_method RCU_off {.name="RCU_off",.len=1,.instructions=RCU_off_inst};
+const t_method method_config[number_methods]={RCU_on,ADC1_on,ADC2_on,RCU_off,};
+
+
+#endif
diff --git a/src/apsctl/conf.h.old b/src/apsctl/conf.h.old
new file mode 100644
index 0000000000000000000000000000000000000000..28945b2240d1135b65036884b63390f7a527a664
--- /dev/null
+++ b/src/apsctl/conf.h.old
@@ -0,0 +1,100 @@
+#ifndef HWDEFS_H
+#define HWDEFS_H
+#include "../drivers/drvbase.h"
+#include "../structs.h"
+/*** Device Register Definitions ***/
+const t_devreg IO1_CONF1 {.address=117,.register_R=6,.register_W=6,.store=1,.driver=1};
+const t_devreg IO1_CONF2 {.address=117,.register_R=7,.register_W=7,.store=2,.driver=1};
+const t_devreg IO1_GPIO1 {.address=117,.register_R=0,.register_W=2,.store=3,.driver=1};
+const t_devreg IO1_GPIO2 {.address=117,.register_R=1,.register_W=3,.store=4,.driver=1};
+const t_devreg IO2_CONF1 {.address=118,.register_R=6,.register_W=6,.store=5,.driver=1};
+const t_devreg IO2_CONF2 {.address=118,.register_R=7,.register_W=7,.store=6,.driver=1};
+const t_devreg IO2_GPIO1 {.address=118,.register_R=0,.register_W=2,.store=7,.driver=1};
+const t_devreg IO2_GPIO2 {.address=118,.register_R=1,.register_W=3,.store=8,.driver=1};
+const t_devreg IO3_CONF1 {.address=32,.register_R=6,.register_W=6,.store=9,.driver=1};
+const t_devreg IO3_CONF2 {.address=32,.register_R=7,.register_W=7,.store=10,.driver=1};
+const t_devreg IO3_GPIO1 {.address=32,.register_R=0,.register_W=2,.store=11,.driver=1};
+const t_devreg IO3_GPIO2 {.address=32,.register_R=1,.register_W=3,.store=12,.driver=1};
+const t_devreg SWITCH_MASK {.address=112,.register_R=0,.register_W=0,.store=0,.driver=0};
+const t_devreg ROM_ID {.address=80,.register_R=252,.register_W=252,.store=0,.driver=1};
+const t_devreg ROM_Version {.address=80,.register_R=0,.register_W=0,.store=0,.driver=1};
+const t_devreg AN_Ch0 {.address=20,.register_R=45184,.register_W=45184,.store=0,.driver=1};
+const t_devreg AN_Ch1 {.address=20,.register_R=47232,.register_W=47232,.store=0,.driver=1};
+const t_devreg AN_Ch2 {.address=20,.register_R=45440,.register_W=45440,.store=0,.driver=1};
+const t_devreg AN_Ch3 {.address=20,.register_R=47488,.register_W=47488,.store=0,.driver=1};
+const t_devreg AN_Ch4 {.address=20,.register_R=45696,.register_W=45696,.store=0,.driver=1};
+const t_devreg AN_Ch5 {.address=20,.register_R=47744,.register_W=47744,.store=0,.driver=1};
+const t_devreg AN_Ch6 {.address=20,.register_R=45952,.register_W=45952,.store=0,.driver=1};
+const t_devreg AN_Ch7 {.address=20,.register_R=48000,.register_W=48000,.store=0,.driver=1};
+const t_devreg AN_Temp {.address=20,.register_R=41152,.register_W=41152,.store=0,.driver=1};
+const t_devreg HB_UC_ID {.address=64,.register_R=0,.register_W=0,.store=0,.driver=1};
+const t_devreg HBAT1_XY {.address=65,.register_R=16,.register_W=16,.store=0,.driver=3};
+const t_devreg HBAT1_Version {.address=65,.register_R=127,.register_W=127,.store=0,.driver=3};
+const t_devreg HBAT2_XY {.address=66,.register_R=16,.register_W=16,.store=0,.driver=3};
+const t_devreg HBAT2_Version {.address=66,.register_R=127,.register_W=127,.store=0,.driver=3};
+const t_devreg HBAT3_XY {.address=67,.register_R=16,.register_W=16,.store=0,.driver=3};
+const t_devreg HBAT3_Version {.address=67,.register_R=127,.register_W=127,.store=0,.driver=3};
+const t_devreg ADC1_PLL_stat {.address=0,.register_R=10,.register_W=10,.store=0,.driver=7};
+const t_devreg ADC1_JESD_control1 {.address=0,.register_R=95,.register_W=95,.store=0,.driver=7};
+const t_devreg ADC1_CML_adjust {.address=0,.register_R=21,.register_W=21,.store=0,.driver=7};
+const t_devreg ADC1_Update {.address=0,.register_R=255,.register_W=255,.store=0,.driver=7};
+const t_devreg ADC2_PLL_stat {.address=0,.register_R=10,.register_W=10,.store=0,.driver=8};
+const t_devreg ADC2_JESD_control1 {.address=0,.register_R=95,.register_W=95,.store=0,.driver=8};
+const t_devreg ADC2_CML_adjust {.address=0,.register_R=21,.register_W=21,.store=0,.driver=8};
+const t_devreg ADC2_Update {.address=0,.register_R=255,.register_W=255,.store=0,.driver=8};
+const t_devreg ADC3_PLL_stat {.address=0,.register_R=10,.register_W=10,.store=0,.driver=9};
+const t_devreg ADC3_JESD_control1 {.address=0,.register_R=95,.register_W=95,.store=0,.driver=9};
+const t_devreg ADC3_CML_adjust {.address=0,.register_R=21,.register_W=21,.store=0,.driver=9};
+const t_devreg ADC3_Update {.address=0,.register_R=255,.register_W=255,.store=0,.driver=9};
+const t_devreg DTH1_Freq {.address=112,.register_R=4416,.register_W=4417,.store=0,.driver=4};
+const t_devreg DTH1_Property {.address=112,.register_R=17,.register_W=17,.store=0,.driver=4};
+const t_devreg DTH1_Start {.address=112,.register_R=98,.register_W=98,.store=0,.driver=4};
+const t_devreg DTH1_Stop {.address=112,.register_R=103,.register_W=103,.store=0,.driver=4};
+const t_devreg DTH2_Freq {.address=112,.register_R=4416,.register_W=4417,.store=0,.driver=4};
+const t_devreg DTH2_Property {.address=112,.register_R=17,.register_W=17,.store=0,.driver=4};
+const t_devreg DTH2_Start {.address=112,.register_R=98,.register_W=98,.store=0,.driver=4};
+const t_devreg DTH2_Stop {.address=112,.register_R=103,.register_W=103,.store=0,.driver=4};
+const t_devreg DTH3_Freq {.address=112,.register_R=4416,.register_W=4417,.store=0,.driver=4};
+const t_devreg DTH3_Property {.address=112,.register_R=17,.register_W=17,.store=0,.driver=4};
+const t_devreg DTH3_Start {.address=112,.register_R=98,.register_W=98,.store=0,.driver=4};
+const t_devreg DTH3_Stop {.address=112,.register_R=103,.register_W=103,.store=0,.driver=4};
+#define NumberStoreReg 12
+/*** Variable Definitions ***/
+const t_variable Ant_mask {.name="Ant_mask",.dim=96,.dtype=dt_boolean,.driver=2,.rw=rw_variable,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={0,0,0}};
+const t_variable RCU_mask {.name="RCU_mask",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_variable,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={0,0,0}};
+const t_variable RCU_attenuator {.name="RCU_attenuator",.dim=96,.dtype=dt_integer,.driver=2,.rw=rw_rw,.bitoffset={0,0,0},.width=5,.scale=0,.devreg={IO1_GPIO1,IO1_GPIO2,IO2_GPIO1}};
+const t_variable RCU_band {.name="RCU_band",.dim=96,.dtype=dt_integer,.driver=2,.rw=rw_rw,.bitoffset={0,2,4},.width=2,.scale=0,.devreg={IO2_GPIO2,IO2_GPIO2,IO2_GPIO2}};
+const t_variable RCU_LED0 {.name="RCU_LED0",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_rw,.bitoffset={6,6,6},.width=1,.scale=0,.devreg={IO2_GPIO2,IO2_GPIO2,IO2_GPIO2}};
+const t_variable RCU_LED1 {.name="RCU_LED1",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_rw,.bitoffset={7,7,7},.width=1,.scale=0,.devreg={IO2_GPIO2,IO2_GPIO2,IO2_GPIO2}};
+const t_variable RCU_temperature {.name="RCU_temperature",.dim=32,.dtype=dt_float,.driver=1,.rw=rw_ro,.bitoffset={0,0,0},.width=23,.scale=0.00421,.devreg={AN_Temp,AN_Temp,AN_Temp}};
+const t_variable RCU_Pwr_dig {.name="RCU_Pwr_dig",.dim=32,.dtype=dt_boolean,.driver=1,.rw=rw_ro,.bitoffset={6,6,6},.width=1,.scale=0,.devreg={IO2_GPIO1,IO2_GPIO1,IO2_GPIO1}};
+const t_variable HBA_element_beamformer_delays {.name="HBA_element_beamformer_delays",.dim=3072,.dtype=dt_integer,.driver=3,.rw=rw_rw,.bitoffset={2,2,2},.width=5,.scale=0,.devreg={HBAT1_XY,HBAT2_XY,HBAT3_XY}};
+const t_variable RCU_ID {.name="RCU_ID",.dim=32,.dtype=dt_integer,.driver=1,.rw=rw_ro,.bitoffset={0,0,0},.width=32,.scale=0,.devreg={ROM_ID,ROM_ID,ROM_ID}};
+const t_variable RCU_version {.name="RCU_version",.dim=32,.dtype=dt_string,.driver=1,.rw=rw_ro,.bitoffset={0,0,0},.width=80,.scale=0,.devreg={ROM_Version,ROM_Version,ROM_Version}};
+const t_variable RCU_ADC_lock {.name="RCU_ADC_lock",.dim=96,.dtype=dt_integer,.driver=2,.rw=rw_ro,.bitoffset={0,0,0},.width=8,.scale=0,.devreg={ADC1_PLL_stat,ADC2_PLL_stat,ADC3_PLL_stat}};
+const t_variable RCU_dth1_freq {.name="RCU_dth1_freq",.dim=96,.dtype=dt_integer,.driver=2,.rw=rw_rw,.bitoffset={0,0,0},.width=32,.scale=0,.devreg={DTH1_Freq,DTH2_Freq,DTH3_Freq}};
+#define number_vars 13
+const t_variable variables[number_vars]={Ant_mask,RCU_mask,RCU_attenuator,RCU_band,RCU_LED0,RCU_LED1,RCU_temperature,RCU_Pwr_dig,HBA_element_beamformer_delays,RCU_ID,RCU_version,RCU_ADC_lock,RCU_dth1_freq,};
+
+/*** Driver Definitions ***/
+#define number_drivers 3
+const t_driver I2C1 {.name="I2C1",.type=drv_i2c_switch,.parent=0,.parameters={1},.devreg={SWITCH_MASK}};
+const t_driver I2C_RCU {.name="I2C_RCU",.type=drv_i2c_array,.parent=0,.parameters={1,32},.devreg={}};
+const t_driver I2C_RFCHAIN {.name="I2C_RFCHAIN",.type=drv_i2c_array2,.parent=1,.parameters={3},.devreg={}};
+const t_driver I2C_HBAT {.name="I2C_HBAT",.type=drv_hba1,.parent=1,.parameters={},.devreg={}};
+const t_driver I2Cbb1 {.name="I2Cbb1",.type=drv_i2cbitbang1,.parent=1,.parameters={6,3,3},.devreg={IO1_GPIO1,IO2_GPIO2,IO2_CONF2}};
+const t_driver I2Cbb2 {.name="I2Cbb2",.type=drv_i2cbitbang1,.parent=1,.parameters={7,7,7},.devreg={IO1_GPIO2,IO2_GPIO1,IO1_CONF1}};
+const t_driver I2Cbb3 {.name="I2Cbb3",.type=drv_i2cbitbang1,.parent=1,.parameters={7,7,7},.devreg={IO1_GPIO2,IO2_GPIO1,IO1_CONF1}};
+const t_driver SPIbb1 {.name="SPIbb1",.type=drv_spibitbang1,.parent=1,.parameters={1,0,0,0},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_CONF1,IO3_GPIO2}};
+const t_driver SPIbb2 {.name="SPIbb2",.type=drv_spibitbang1,.parent=1,.parameters={3,2,2,1},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_CONF1,IO3_GPIO2}};
+const t_driver SPIbb3 {.name="SPIbb3",.type=drv_spibitbang1,.parent=1,.parameters={5,4,4,2},.devreg={IO3_GPIO1,IO3_GPIO1,IO3_CONF1,IO3_GPIO2}};
+//const t_driver driver_config[number_drivers]={I2C1,I2C_RCU,I2C_RFCHAIN,I2C_HBAT,I2Cbb1,I2Cbb2,I2Cbb3,SPIbb1,SPIbb2,SPIbb3,};
+
+class c_drivers {
+ public:
+  c_drivers();
+  drvbase* d[number_drivers];
+};
+
+
+#endif
diff --git a/src/apsctl/yaml2head.py b/src/apsctl/yaml2head.py
new file mode 100644
index 0000000000000000000000000000000000000000..82da48d7fd28da1ec79497c78437a214ceef127b
--- /dev/null
+++ b/src/apsctl/yaml2head.py
@@ -0,0 +1,267 @@
+
+yamlfile='RCU'
+#structfile='structs.h'
+ydir='apsctl/'
+cfile='conf'
+
+import yaml;
+D=yaml.load(open(yamlfile+'.yaml'))
+
+
+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;
+
+
+for i,dev in enumerate(D['drivers']):
+    dev['drv_id']=i;
+
+
+
+hf=open(cfile+'.h','w');
+#sf=open(ydir+structfile,'w')
+hf.write("#ifndef HWDEFS_H\n")
+hf.write("#define HWDEFS_H\n")
+hf.write('#include "../drivers/drvbase.h"\n')
+hf.write('#include "../structs.h"\n\n')
+
+devreglist=[]
+store=0;
+hf.write("/*** Device Register Definitions ***/\n")
+#sf.write("struct devreg {int addr,regR,regW,store,driver;};\n")
+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)
+      if devtype:
+        devtype=Find(D['drivers'],'name',devtype)['drv_id']
+      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.append(devregname);
+         hf.write("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)
+
+#    int dim;
+#    t_dtype dtype;
+#    int type;
+#    t_rw rw;
+#    int bitoffset[3];
+#    int width;
+#    t_devreg devreg[3];
+#    double scale;
+hf.write("\n/*** Variable Definitions ***/\n")
+
+varlist=[]
+varcount=0;
+for dev in D['variables']:
+    name=dev['name'];
+    dev['id']=varcount;
+    varcount+=1;
+    varlist.append(name);
+    devtype=GetField(dev,'driver',0)
+    if devtype:
+        devtype=Find(D['drivers'],'name',devtype)
+        if not(devtype): print ("Can not find ",name,GetField(dev,'driver',0))
+        devtype=devtype['drv_id']
+    else: devtype=0;
+    dim=int(dev.get('dim',1));
+    s='{';
+    for x in range(3): s+=str(GetField(dev,'bitoffset',x,0))+','
+    bitoffset=s[:-1]+'}';
+    s='{';
+    for x in range(3): s+=str(GetField(dev,'devreg',x,0))+','
+    devreg=s[:-1]+'}';
+    devreg=devreg.replace('.','_')
+    print(devreg)
+    hf.write('const t_variable %s {.name="%s",.dim=%i,.dtype=%s,.driver=%i,.rw=%s,.bitoffset=%s,.width=%i,.scale=%s,.devreg=%s};\n' % (
+         name,
+         name,
+         dim,
+         "dt_"+dev.get('dtype','integer'),
+         devtype,
+         "rw_"+dev.get('rw','hidden'),
+         bitoffset,
+         int(dev.get('width',8)),
+         dev.get('scale',0),
+         devreg
+    ));
+
+hf.write("#define number_vars %i\n" % len(varlist))
+s='';
+for v in varlist:
+    s+=v+','
+hf.write("const t_variable variables[number_vars]={%s};\n" % s )
+
+hf.write("\n/*** Driver Definitions ***/\n")
+hf.write("#define number_drivers %i\n" % len(D['drivers']))
+
+
+#struct t_driver {
+#    char* name;
+#    t_drivers type;
+#//    int parent;
+#//    int* parameters;
+#//    const t_devreg* devreg;
+ #               "name" : {"type":"string"},
+  #              "type" : {"enum":["i2c","i2c_array","i2c_array2","hba1","i2cbitbang1","spibitbang1"]},
+  #              "parent" : {"type":"string"},
+  #              "parameters" : {"type":"array","items":{"type":"integer"}} ,
+  #              "registers" :{}
+
+
+drvlist=[]
+for dev in D['drivers']:
+    name=dev['name'];
+    drvlist.append(name)
+    parent=GetField(dev,'parent',0)
+    if parent:
+        parent=Find(D['drivers'],'name',parent)
+        if not(parent): print ("Can not find ",name,GetField(dev,'parent',0))
+        parent=parent['drv_id']
+    else: parent=0;
+    parameters=dev.get("parameters");
+    if parameters:
+      s='{'
+      for x in parameters:
+          s+=str(x)+','
+      parameters=s[:-1]+'}';
+    else: parameters={};
+    devreg=dev.get("devreg");
+    if devreg:
+      s='{';
+      for x in devreg: s+=x+','
+      devreg=s[:-1]+'}';
+      devreg=devreg.replace('.','_')
+    else: devreg={}
+    print(devreg)
+    hf.write('const t_driver %s {.name="%s",.type=%s,.parent=%i,.parameters=%s,.devreg=%s};\n' % (
+         name,
+         name,
+         "drv_"+dev.get("type","i2c"),
+         parent,
+         parameters,
+         devreg
+    ));
+
+s='';
+for v in drvlist:
+    s+=v+','
+hf.write("//const t_driver driver_config[number_drivers]={%s};\n\n" % s )
+
+hf.write("class c_drivers {\n")
+hf.write(" public:\n")
+hf.write("  c_drivers();\n")
+hf.write("  drvbase* d[number_drivers];\n")
+hf.write("};\n")
+
+hf.write("\n/*** Method Definitions ***/\n")
+for i,dev in enumerate(D['methods']):
+    dev['id']=i
+hf.write("#define number_methods %i\n" % len(D['methods']))
+
+methodlist=[]
+for dev in D['methods']:
+    name=dev['name'];
+    methodlist.append(name)
+
+    hf.write('const t_instruction %s[%i]={\n'  % (
+         name+'_inst',
+         len(dev['instructions'])
+    ))
+    for inst in dev['instructions']: 
+      for key,value in inst.items():
+        if isinstance(value,list):
+          len1=len(value)
+          data='{'
+          for v1 in value: data+=str(v1)+','
+          data+='}'
+        else: 
+          len1=1;
+          data='{'+str(value)+'}'
+        
+        if value=='Update':
+           var=Find(D['variables'],'name',key)
+           if not(var):
+             print('can not find var',key)
+             continue;
+           hf.write('        {.type=inst_getvarall,.variable=%i,.devreg={0},.len=0,.data={}},\n'%(var['id']))
+        elif (key=='WAIT'):
+           hf.write('        {.type=inst_wait,.variable=0,.devreg={0},.len=1,.data={}},\n');
+        elif (Find(D['variables'],'name',key)):
+           var=Find(D['variables'],'name',key)
+           hf.write('        {.type=inst_setvar,.variable=%i,.devreg={0},.len=%i,.data=%s},\n'%(var['id'],len1,data))
+        elif (Find(D['methods'],'name',key)):
+           var=Find(D['methods'],'name',key)
+           hf.write('        {.type=inst_method,.variable=%i,.devreg={0},.len=0,.data={}},\n'%(var['id']))
+        elif (key.replace('.','_') in devreglist):
+           var=(key.replace('.','_'))
+           hf.write('        {.type=inst_devreg,.variable=0,.devreg=%s,.len=%i,.data=%s},\n'%(var,len1,data))
+        else:
+             print('can not find ',key)
+    hf.write('      };\n')
+    hf.write('const t_method %s {.name="%s",.len=%i,.instructions=%s};\n' % (
+         name,
+         name,
+         len(dev['instructions']),
+         name+'_inst'
+    ))
+          
+s='';
+for v in methodlist:
+    s+=v+','
+hf.write("const t_method method_config[number_methods]={%s};\n\n" % s )
+
+
+hf.write("\n#endif\n")
+hf.close()
+
+hf=open(cfile+'.cpp','w');
+hf.write('#include "'+cfile+'.h"\n');
+drvtypes=set([dev['type'] for dev in D['drivers']])
+for s in drvtypes:
+   hf.write('#include "../drivers/'+s+'.h"\n')
+#include "../drivers/i2c_array.h"
+#
+hf.write('c_drivers::c_drivers()\n')
+hf.write('{\n')
+for i,dev in enumerate(D['drivers']):
+  cname='i_'+dev['name']
+  ctype='c_'+dev['type']
+  hf.write('    %s* %s=new %s(%s);\n' % (ctype,cname,ctype,dev['name']))
+  hf.write('    d[%i]=%s;\n' % (i,cname))
+
+for i,dev in enumerate(D['drivers']):
+  pr=dev.get('parent')
+  if not(pr): continue;
+  pr=Find(D['drivers'],'name',pr)
+  cname='i_'+dev['name']
+  pname='i_'+pr['name'];
+  hf.write('    %s->parent=%s;\n' % (cname,pname))
+
+#    i_I2C_RCU->parent=i_I2C1;
+hf.write('};\n')
+
+#sf.close()
+hf.close();
+exit()
diff --git a/src/drivers/RCU_switch.cpp b/src/drivers/RCU_switch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a91e43dc45977743c9251669be7c062f3f5c8e14
--- /dev/null
+++ b/src/drivers/RCU_switch.cpp
@@ -0,0 +1,29 @@
+#include "RCU_switch.h"
+#include "../apsctl/conf.h"
+#include <iostream>
+
+c_RCU_switch::c_RCU_switch(const t_driver config1) : c_i2c (config1){
+      state=0;
+};
+
+bool c_RCU_switch::I2Csend_swreg(unsigned int swstate,int addr,int reg,int len,t_buffer* data)
+{
+  if (swstate!=state) {
+    state=t_buffer(swstate);
+    t_buffer SW1=state & 0xff;
+    if (!(c_i2c::I2Csend(config.devreg->address,1,&SW1))) return false;
+  }
+  return c_i2c::I2Csend_reg(addr,reg,len,data);
+}
+
+bool c_RCU_switch::I2Cset_switch(unsigned int swstate)
+{
+  if (swstate!=state) {
+    std::cout << "state=" << swstate << "->" << int(state) <<"\n";
+    state=(swstate);
+    t_buffer SW1=state & 0xff;
+    t_buffer SW2=(state>>8) & 0xff; //TODO: implemented for DTS
+    if (!(c_i2c::I2Csend(config.devreg->address,1,&SW1))) return false;
+  }
+  return true;
+}
diff --git a/src/drivers/RCU_switch.h b/src/drivers/RCU_switch.h
new file mode 100644
index 0000000000000000000000000000000000000000..bae88d24abaf529bd53aa0f674a2a6c148812929
--- /dev/null
+++ b/src/drivers/RCU_switch.h
@@ -0,0 +1,19 @@
+#ifndef RCU_SWITCH_H
+#define RCU_SWITCH_H
+#include "../structs.h"
+#include "drvbase.h"
+#include "i2c.h"
+
+class c_RCU_switch : public c_i2c {
+    public:
+      c_RCU_switch(const t_driver config1);
+      bool I2Cset_switch(unsigned int swstate);
+      bool I2Csend_swreg(unsigned int swstate,int addr,int reg,int len,t_buffer* data);
+
+    private:
+      t_devreg devreg;
+      unsigned int state;    
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/drivers/drvbase.cpp b/src/drivers/drvbase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa739bb17cb7b444bda9e813e16c2bdf761160a0
--- /dev/null
+++ b/src/drivers/drvbase.cpp
@@ -0,0 +1,20 @@
+#include "drvbase.h"
+#include <iostream>
+
+drvbase::drvbase(const t_driver config1) : config (config1){};
+
+
+int ApplyMask(int value,int width,int bitoffset,int old){
+  t_buffer mask=(1<<width)-1;
+  value<<=bitoffset;
+  mask<<=bitoffset;
+  return (value & mask)+(old - (old & mask));
+}
+int UnMask(int value,int width,int bitoffset){
+  t_buffer mask=(1<<width)-1;
+  value>>=bitoffset;
+  return (value & mask);
+}
+
+
+
diff --git a/src/drivers/drvbase.h b/src/drivers/drvbase.h
new file mode 100644
index 0000000000000000000000000000000000000000..13b489c0d8c97c09c77035c3878d54e2bad6473f
--- /dev/null
+++ b/src/drivers/drvbase.h
@@ -0,0 +1,18 @@
+#ifndef DRVBASE_H
+#define DRVBASE_H
+#include "../structs.h"
+
+int ApplyMask(int value,int width,int bitoffset,int old);
+int UnMask(int value,int width,int bitoffset);
+
+class drvbase{
+    public:
+    drvbase(const t_driver config1);
+//    drvbase* parent;
+    virtual bool setvar(int x,int len,t_buffer* buffer,int lenmask,bool* mask){};
+    virtual int  getvar(int x,t_buffer* buffer,int lenmask,bool* mask){return 0;};
+    virtual bool setdevreg(t_devreg devreg,int len,t_buffer* buffer,int lenmask,bool* mask){};
+//    protected:
+    const t_driver config;
+};
+#endif
\ No newline at end of file
diff --git a/src/drivers/hba1.cpp b/src/drivers/hba1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..08d1b1138f219c3e870b7be6a11f89ce49fa3d6e
--- /dev/null
+++ b/src/drivers/hba1.cpp
@@ -0,0 +1,9 @@
+#include "hba1.h"
+#include "../apsctl/conf.h"
+#include <iostream>
+
+
+c_hba1::c_hba1(const t_driver config1) : drvbase (config1){};
+
+
+
diff --git a/src/drivers/hba1.h b/src/drivers/hba1.h
new file mode 100644
index 0000000000000000000000000000000000000000..e532745f5e319fa588f472bb0c2b811d055e8839
--- /dev/null
+++ b/src/drivers/hba1.h
@@ -0,0 +1,14 @@
+#ifndef HBA1_H
+#define HBA1_H
+#include "../structs.h"
+#include "drvbase.h"
+#include "i2c_array.h"
+
+class c_hba1 : public drvbase {
+    public:
+    c_hba1(const t_driver config1);
+    c_i2c_array* parent;
+
+    private:
+};
+#endif
\ No newline at end of file
diff --git a/src/drivers/i2c.cpp b/src/drivers/i2c.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..741431818c4740da24cb22f84c9a41543b402b6e
--- /dev/null
+++ b/src/drivers/i2c.cpp
@@ -0,0 +1,81 @@
+#include "i2c.h"
+#include <iostream>
+#include <linux/i2c-dev.h>
+#include <i2c/smbus.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+/*
+__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
+				 const __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,	I2C_SMBUS_BLOCK_DATA, &data);
+}
+__s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length,
+				     const __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file, I2C_SMBUS_WRITE, command,
+				I2C_SMBUS_I2C_BLOCK_DATA, &data);
+}
+__s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 length,
+				    __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i, err;
+
+	data.block[0] = length;
+
+	err = i2c_smbus_access(file, I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA, &data);
+	if (err < 0)
+		return false;
+
+	for (i = 1; i <= data.block[0]; i++)
+		values[i-1] = data.block[i];
+	return (data.block[0]==length);
+}
+*/
+c_i2c::c_i2c(const t_driver config1) : drvbase (config1){
+  std::cout << config.name <<": i2c server, connecting to device " << config.parameters[0] << "\n";
+  char filename[20];
+  snprintf(filename, 19, "/dev/i2c-%d", config.parameters[0]);
+  file = open(filename, O_RDWR);
+  if (file < 0) {
+    std::cout << config.name <<": Error connecting!\n";
+    exit(1);
+  }
+};
+
+bool c_i2c::I2Csend_reg(int addr,int reg,int len,t_buffer* data){
+  std::cout << config.name <<": i2c send to addr="<<addr<<" reg="<<reg<<" len="<<len<<" value="<<int(data[0]) <<"\n";
+  if (ioctl(file, I2C_SLAVE, addr)<0) return false;
+  return true;
+//  return (i2c_smbus_write_block_data(file,reg,len,data)>=0);
+}
+
+bool c_i2c::I2Cget_reg(int addr,int reg,int len,t_buffer* data){
+  std::cout << config.name <<": i2c get from addr="<<addr<<" reg="<<reg<<" len="<<len<<" value="<<int(data[0]) <<"\n";
+  if (ioctl(file, I2C_SLAVE, addr)<0) return false;
+  return true;
+//  return i2c_smbus_read_i2c_block_data(file,reg,len,data);
+}
+
+bool c_i2c::I2Csend(int addr,int len,t_buffer* data){
+  std::cout << config.name <<": i2c send to addr="<<addr<<" len="<<len<<" value="<<int(data[0])<<"\n";
+}
+
+
diff --git a/src/drivers/i2c.h b/src/drivers/i2c.h
new file mode 100644
index 0000000000000000000000000000000000000000..df46dd1b5dc57259821257cfe7d89bcdced3486e
--- /dev/null
+++ b/src/drivers/i2c.h
@@ -0,0 +1,15 @@
+#ifndef I2C_H
+#define I2C_H
+#include "../structs.h"
+#include "drvbase.h"
+class c_i2c : public drvbase {
+    public:
+    c_i2c(const t_driver config1);
+
+    bool I2Csend_reg(int addr,int reg,int len,t_buffer* data);
+    bool I2Cget_reg(int addr,int reg,int len,t_buffer* data);
+    bool I2Csend(int addr,int len,t_buffer* data);
+    private:
+    int file;
+};
+#endif
\ No newline at end of file
diff --git a/src/drivers/i2c_array.cpp b/src/drivers/i2c_array.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a00d7ccdda7c6dc8fb82cd447fc76e95d7a53bf
--- /dev/null
+++ b/src/drivers/i2c_array.cpp
@@ -0,0 +1,95 @@
+#include "i2c_array.h"
+#include "../apsctl/conf.h"
+#include <iostream>
+
+
+c_i2c_array::c_i2c_array(const t_driver config1) : drvbase (config1){
+  N=config.parameters[1];
+  std::cout << config.name << ": i2c array, # devices " << N << "\n";
+};
+
+bool c_i2c_array::setvar(int x,int len,t_buffer* buffer,int lenmask,bool* mask){
+  std::cout << config.name << ": setvar " << variables[x].name << "\n";
+  int stride=((variables[x].width+variables[x].bitoffset[0]-1)>>3)+1; //1..8 bits = 1 byte, 9..16 bits=2bytes etc.
+  if ((variables[x].dim*stride!=len) && (len!=stride)) {
+    std::cout << config.name <<": setvar: wrong length " << len << "!=" << variables[x].dim <<"x" << stride << "\n";
+    return false;
+  }
+  if (variables[x].rw==rw_variable)  return false;
+  if ((lenmask>0) && (lenmask<N)){
+    std::cout << config.name <<": servar: wrong mask length\n";
+    return false;
+  }
+  if (len==stride) return setvar2(variables[x],0,0     ,buffer,1,mask);
+  else             return setvar2(variables[x],0,stride,buffer,1,mask);
+};
+
+bool c_i2c_array::setvar2(t_variable variable,int Ndev,int stepbuf,t_buffer* buffer,int stepmask,bool* mask){
+  if (variable.devreg[Ndev].register_W==-1) return true; //We can not set it e.g. temperature
+  for (int rcui=0;rcui<N;rcui++){
+    if ((stepmask>0) && (!mask[rcui*stepmask])) continue;
+    parent->I2Cset_switch(1<<rcui);//todo add offset 
+    seti2c(rcui,variable.devreg[Ndev],variable.width,variable.bitoffset[Ndev],&(buffer[rcui*stepbuf]));
+  }
+}
+
+int  c_i2c_array::getvar(int x,t_buffer* buffer,int lenmask,bool* mask){
+  std::cout << config.name << ": getvar " << variables[x].name << "\n";
+  int stride=((variables[x].width+variables[x].bitoffset[0]-1)>>3)+1; //1..8 bits = 1 byte, 9..16 bits=2bytes etc.
+  for (int x=0;x<stride*N;x++) buffer[x]=0;
+  int stepmask=1;
+  if (lenmask==0) stepmask=0;
+  getvar2(variables[x],0,stride,buffer,stepmask,mask);
+  return stride*N;
+};
+
+int c_i2c_array::getvar2(t_variable variable,int Ndev,int stepbuf,t_buffer* buffer,int stepmask,bool* mask){
+  for (int rcui=0;rcui<N;rcui++){
+    if ((stepmask>0) && (!mask[rcui*stepmask])) continue;
+    parent->I2Cset_switch(1<<rcui);//todo add offset 
+    geti2c(rcui,variable.devreg[Ndev],variable.width,variable.bitoffset[Ndev],&(buffer[rcui*stepbuf]));
+  }
+  return N;
+};
+
+bool c_i2c_array::setdevreg(t_devreg devreg,int len,t_buffer* buffer,int lenmask,bool* mask){
+    if ((lenmask>0) && (lenmask<N)){
+    std::cout << config.name <<": setdevreg: wrong mask length\n";
+    return false;
+  } 
+  int stride=len/N;
+  int width=stride*8;
+  if (width==0) width=8;//todo: make this a broadcast
+  for (int rcui=0;rcui<N;rcui++){
+    if ((lenmask>0) && (!mask[rcui])) continue;
+    parent->I2Cset_switch(1<<rcui);//todo add offset 
+    seti2c(rcui,devreg,width,0,&(buffer[rcui*stride]));
+  }
+}
+
+void c_i2c_array::seti2c(int rcui,const t_devreg devreg,int width,int bitoffset,t_buffer* buffer){
+    t_buffer oldvalue=0;
+    if (devreg.store>0) {
+      oldvalue=storedRegs[devreg.store-1][rcui];
+      buffer[0]=ApplyMask(buffer[0],width,bitoffset,oldvalue);
+      storedRegs[devreg.store-1][rcui]=buffer[0];
+    }
+
+    int len2=((width+bitoffset-1)>>3)+1; //1..8 bits = 1 byte, 9..16 bits=2bytes etc.
+    parent->I2Csend_reg(devreg.address,devreg.register_W,len2,buffer);
+}
+
+void c_i2c_array::geti2c(int rcui,const t_devreg devreg,int width,int bitoffset,t_buffer* buffer){
+    int len2=((width+bitoffset-1)>>3)+1; //1..8 bits = 1 byte, 9..16 bits=2bytes etc.
+    parent->I2Cget_reg(devreg.address,devreg.register_W,len2,buffer);
+    if (devreg.store>0) {
+      std::cout << "DEBUG: USED stored value="<< int(buffer[0]) <<"\n";
+      buffer[0]=storedRegs[devreg.store-1][rcui];
+//      storedRegs[devreg.store-1][rcui]=buffer[0];
+      buffer[0]=UnMask(buffer[0],width,bitoffset);
+    }
+
+}
+
+
+
diff --git a/src/drivers/i2c_array.h b/src/drivers/i2c_array.h
new file mode 100644
index 0000000000000000000000000000000000000000..a2c094e4a175bee8da3cf07f0588b152ff916a35
--- /dev/null
+++ b/src/drivers/i2c_array.h
@@ -0,0 +1,28 @@
+#ifndef I2C_ARRAY_H
+#define I2C_ARRAY_H
+#include "../structs.h"
+#include "drvbase.h"
+#include "RCU_switch.h"
+#include "../apsctl/conf.h"
+
+class c_i2c_array : public drvbase {
+    public:
+    c_i2c_array(const t_driver config1);
+    bool setvar(int x,int len,t_buffer* buffer,int lenmask,bool* mask);
+    int  getvar(int x,t_buffer* buffer,int lenmask,bool* mask);
+
+    bool setvar2(t_variable variable,int Ndev,int stepbuf,t_buffer* buffer,int stepmask,bool* mask);
+    int  getvar2(t_variable variable,int Ndev,int stepbuf,t_buffer* buffer,int stepmask,bool* mask);
+
+    void seti2c(int rcui,const t_devreg devreg,int width,int bitoffset,t_buffer* buffer);
+    void geti2c(int rcui,const t_devreg devreg,int width,int bitoffset,t_buffer* buffer);
+    bool setdevreg(t_devreg devreg,int len,t_buffer* buffer,int lenmask,bool* mask);
+
+    c_RCU_switch* parent;
+
+    int N;  //number of devices
+    private:
+    int switch_dev;
+    t_buffer storedRegs[NumberStoreReg][32];  //Todo: use N instead of 32
+};
+#endif
\ No newline at end of file
diff --git a/src/drivers/i2c_array2.cpp b/src/drivers/i2c_array2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5977d56291427e436e81b88e879f34e90625310c
--- /dev/null
+++ b/src/drivers/i2c_array2.cpp
@@ -0,0 +1,41 @@
+#include "i2c_array2.h"
+#include "../apsctl/conf.h"
+#include <iostream>
+
+
+c_i2c_array2::c_i2c_array2(const t_driver config1) : drvbase (config1){
+  N2=config.parameters[0];
+  std::cout << config.name << ": i2c array2, # devices " << N2 << "\n";
+};
+
+bool c_i2c_array2::setvar(int x,int len,t_buffer* buffer,int lenmask,bool* mask){
+  std::cout << config.name << ": setvar " << variables[x].name << " lenbuff=" << len << " lenmask=" << lenmask << "\n";
+  int stride=(((variables[x].width+variables[x].bitoffset[0]-1)>>3)+1); //1..8 bits = 1 byte, 9..16 bits=2bytes etc.
+  //Todo check mask&data length!
+  if (len==N2){//All the same from method call TODO: make faster
+      for (int y=0;y<N2;y++)
+         parent->setvar2(variables[x],y,0,&(buffer[y]),1,mask);
+  } else {
+      for (int y=0;y<N2;y++)
+         parent->setvar2(variables[x],y,stride*N2,&(buffer[y]),N2,&(mask[y]));
+  }
+}
+
+int  c_i2c_array2::getvar(int x,t_buffer* buffer,int lenmask,bool* mask){
+  int stride=((variables[x].width+variables[x].bitoffset[0]-1)>>3)+1; //1..8 bits = 1 byte, 9..16 bits=2bytes etc.
+//  for (int x=0;x<stride*N;x++) buffer[x]=0;
+  std::cout << config.name << ": getvar " << variables[x].name << " lenmask=" << lenmask << "\n";
+  int stepmask=N2;
+  if (lenmask==0) stepmask=0;
+  int N=0;
+  if (lenmask==parent->N)
+      for (int y=0;y<N2;y++)
+            N=parent->getvar2(variables[x],y,stride*N2,&(buffer[y*stride]),1,mask);
+  else
+      for (int y=0;y<N2;y++)
+            N=parent->getvar2(variables[x],y,stride*N2,&(buffer[y*stride]),stepmask,&(mask[y]));
+  return stride*N*N2;
+};
+
+
+
diff --git a/src/drivers/i2c_array2.h b/src/drivers/i2c_array2.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad3027473005c47deb2ea07644ce1a5231b49fa9
--- /dev/null
+++ b/src/drivers/i2c_array2.h
@@ -0,0 +1,18 @@
+#ifndef I2C_ARRAY2_H
+#define I2C_ARRAY2_H
+#include "../structs.h"
+#include "drvbase.h"
+#include "i2c_array.h"
+
+class c_i2c_array2 : public drvbase {
+    public:
+    c_i2c_array2(const t_driver config1);
+    c_i2c_array* parent;
+
+    bool setvar(int x,int len,t_buffer* buffer,int lenmask,bool* mask);
+    int  getvar(int x,t_buffer* buffer,int lenmask,bool* mask);
+
+    private:
+    int N2;
+};
+#endif
\ No newline at end of file
diff --git a/src/drivers/i2cbitbang1.cpp b/src/drivers/i2cbitbang1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..91fcd5fbe4c36cec0390ddc791b844846792ae66
--- /dev/null
+++ b/src/drivers/i2cbitbang1.cpp
@@ -0,0 +1,9 @@
+#include "i2cbitbang1.h"
+#include "../apsctl/conf.h"
+#include <iostream>
+
+
+c_i2cbitbang1::c_i2cbitbang1(const t_driver config1) : drvbase (config1){};
+
+
+
diff --git a/src/drivers/i2cbitbang1.h b/src/drivers/i2cbitbang1.h
new file mode 100644
index 0000000000000000000000000000000000000000..92a3bb6969fc86db77e489598123e5bf33c8c418
--- /dev/null
+++ b/src/drivers/i2cbitbang1.h
@@ -0,0 +1,14 @@
+#ifndef i2cbitbang1_H
+#define i2cbitbang1_H
+#include "../structs.h"
+#include "drvbase.h"
+#include "i2c_array.h"
+
+class c_i2cbitbang1 : public drvbase {
+    public:
+    c_i2cbitbang1(const t_driver config1);
+    c_i2c_array* parent;
+
+    private:
+};
+#endif
\ No newline at end of file
diff --git a/src/drivers/spibitbang1.cpp b/src/drivers/spibitbang1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f144883f6f716db31167b34735f454a746c8a0a7
--- /dev/null
+++ b/src/drivers/spibitbang1.cpp
@@ -0,0 +1,9 @@
+#include "spibitbang1.h"
+#include "../apsctl/conf.h"
+#include <iostream>
+
+
+c_spibitbang1::c_spibitbang1(const t_driver config1) : drvbase (config1){};
+
+
+
diff --git a/src/drivers/spibitbang1.h b/src/drivers/spibitbang1.h
new file mode 100644
index 0000000000000000000000000000000000000000..baa0748ba1c3156800deb59af0edc5b79f7db633
--- /dev/null
+++ b/src/drivers/spibitbang1.h
@@ -0,0 +1,14 @@
+#ifndef spibitbang1_H
+#define spibitbang1_H
+#include "../structs.h"
+#include "drvbase.h"
+#include "i2c_array.h"
+
+class c_spibitbang1 : public drvbase {
+    public:
+    c_spibitbang1(const t_driver config1);
+    c_i2c_array* parent;
+
+    private:
+};
+#endif
\ No newline at end of file
diff --git a/src/interface/pypcc.capnp b/src/interface/pypcc.capnp
new file mode 100644
index 0000000000000000000000000000000000000000..8486fe7b70647b2988d05590248ca69d6ff89573
--- /dev/null
+++ b/src/interface/pypcc.capnp
@@ -0,0 +1,14 @@
+@0x9f2c99de8c7edd7f;
+
+enum InstType {
+    varSet     @0;
+    varRead    @1;
+    method     @2;
+}
+
+struct OPCUAset {
+ id   @0: UInt8;
+ type @1: InstType;
+ data @2: List(UInt8);
+ mask @3: List(Bool);
+}
diff --git a/src/interface/pypcc.capnp.c++ b/src/interface/pypcc.capnp.c++
new file mode 100644
index 0000000000000000000000000000000000000000..0747af5de3fe1071f73b7ab211f1370cc98fb16d
--- /dev/null
+++ b/src/interface/pypcc.capnp.c++
@@ -0,0 +1,162 @@
+// Generated by Cap'n Proto compiler, DO NOT EDIT
+// source: pypcc.capnp
+
+#include "pypcc.capnp.h"
+
+namespace capnp {
+namespace schemas {
+static const ::capnp::_::AlignedData<29> b_b1dfe08305a4b99c = {
+  {   0,   0,   0,   0,   5,   0,   6,   0,
+    156, 185, 164,   5, 131, 224, 223, 177,
+     12,   0,   0,   0,   2,   0,   0,   0,
+    127, 221, 126, 140, 222, 153,  44, 159,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     21,   0,   0,   0, 170,   0,   0,   0,
+     29,   0,   0,   0,   7,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     25,   0,   0,   0,  79,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    112, 121, 112,  99,  99,  46,  99,  97,
+    112, 110, 112,  58,  73, 110, 115, 116,
+     84, 121, 112, 101,   0,   0,   0,   0,
+      0,   0,   0,   0,   1,   0,   1,   0,
+     12,   0,   0,   0,   1,   0,   2,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     29,   0,   0,   0,  58,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      1,   0,   0,   0,   0,   0,   0,   0,
+     21,   0,   0,   0,  66,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      2,   0,   0,   0,   0,   0,   0,   0,
+     13,   0,   0,   0,  58,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    118,  97, 114,  83, 101, 116,   0,   0,
+    118,  97, 114,  82, 101,  97, 100,   0,
+    109, 101, 116, 104, 111, 100,   0,   0, }
+};
+::capnp::word const* const bp_b1dfe08305a4b99c = b_b1dfe08305a4b99c.words;
+#if !CAPNP_LITE
+static const uint16_t m_b1dfe08305a4b99c[] = {2, 1, 0};
+const ::capnp::_::RawSchema s_b1dfe08305a4b99c = {
+  0xb1dfe08305a4b99c, b_b1dfe08305a4b99c.words, 29, nullptr, m_b1dfe08305a4b99c,
+  0, 3, nullptr, nullptr, nullptr, { &s_b1dfe08305a4b99c, nullptr, nullptr, 0, 0, nullptr }
+};
+#endif  // !CAPNP_LITE
+CAPNP_DEFINE_ENUM(InstType_b1dfe08305a4b99c, b1dfe08305a4b99c);
+static const ::capnp::_::AlignedData<85> b_aaca83afea5f387e = {
+  {   0,   0,   0,   0,   5,   0,   6,   0,
+    126,  56,  95, 234, 175, 131, 202, 170,
+     12,   0,   0,   0,   1,   0,   1,   0,
+    127, 221, 126, 140, 222, 153,  44, 159,
+      2,   0,   7,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     21,   0,   0,   0, 170,   0,   0,   0,
+     29,   0,   0,   0,   7,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     25,   0,   0,   0, 231,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    112, 121, 112,  99,  99,  46,  99,  97,
+    112, 110, 112,  58,  79,  80,  67,  85,
+     65, 115, 101, 116,   0,   0,   0,   0,
+      0,   0,   0,   0,   1,   0,   1,   0,
+     16,   0,   0,   0,   3,   0,   4,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   1,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     97,   0,   0,   0,  26,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     92,   0,   0,   0,   3,   0,   1,   0,
+    104,   0,   0,   0,   2,   0,   1,   0,
+      1,   0,   0,   0,   1,   0,   0,   0,
+      0,   0,   1,   0,   1,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    101,   0,   0,   0,  42,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     96,   0,   0,   0,   3,   0,   1,   0,
+    108,   0,   0,   0,   2,   0,   1,   0,
+      2,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   1,   0,   2,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    105,   0,   0,   0,  42,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    100,   0,   0,   0,   3,   0,   1,   0,
+    128,   0,   0,   0,   2,   0,   1,   0,
+      3,   0,   0,   0,   1,   0,   0,   0,
+      0,   0,   1,   0,   3,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    125,   0,   0,   0,  42,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    120,   0,   0,   0,   3,   0,   1,   0,
+    148,   0,   0,   0,   2,   0,   1,   0,
+    105, 100,   0,   0,   0,   0,   0,   0,
+      6,   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,
+      6,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    116, 121, 112, 101,   0,   0,   0,   0,
+     15,   0,   0,   0,   0,   0,   0,   0,
+    156, 185, 164,   5, 131, 224, 223, 177,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+     15,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    100,  97, 116,  97,   0,   0,   0,   0,
+     14,   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,   3,   0,   1,   0,
+      6,   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,
+     14,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+    109,  97, 115, 107,   0,   0,   0,   0,
+     14,   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,   3,   0,   1,   0,
+      1,   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,
+     14,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0,
+      0,   0,   0,   0,   0,   0,   0,   0, }
+};
+::capnp::word const* const bp_aaca83afea5f387e = b_aaca83afea5f387e.words;
+#if !CAPNP_LITE
+static const ::capnp::_::RawSchema* const d_aaca83afea5f387e[] = {
+  &s_b1dfe08305a4b99c,
+};
+static const uint16_t m_aaca83afea5f387e[] = {2, 0, 3, 1};
+static const uint16_t i_aaca83afea5f387e[] = {0, 1, 2, 3};
+const ::capnp::_::RawSchema s_aaca83afea5f387e = {
+  0xaaca83afea5f387e, b_aaca83afea5f387e.words, 85, d_aaca83afea5f387e, m_aaca83afea5f387e,
+  1, 4, i_aaca83afea5f387e, nullptr, nullptr, { &s_aaca83afea5f387e, nullptr, nullptr, 0, 0, nullptr }
+};
+#endif  // !CAPNP_LITE
+}  // namespace schemas
+}  // namespace capnp
+
+// =======================================================================================
+
+
+// OPCUAset
+constexpr uint16_t OPCUAset::_capnpPrivate::dataWordSize;
+constexpr uint16_t OPCUAset::_capnpPrivate::pointerCount;
+#if !CAPNP_LITE
+constexpr ::capnp::Kind OPCUAset::_capnpPrivate::kind;
+constexpr ::capnp::_::RawSchema const* OPCUAset::_capnpPrivate::schema;
+#endif  // !CAPNP_LITE
+
+
+
diff --git a/src/interface/pypcc.capnp.h b/src/interface/pypcc.capnp.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e968c2970b023977d2afcbe8bdb575db56635d6
--- /dev/null
+++ b/src/interface/pypcc.capnp.h
@@ -0,0 +1,259 @@
+// Generated by Cap'n Proto compiler, DO NOT EDIT
+// source: pypcc.capnp
+
+#ifndef CAPNP_INCLUDED_9f2c99de8c7edd7f_
+#define CAPNP_INCLUDED_9f2c99de8c7edd7f_
+
+#include <capnp/generated-header-support.h>
+
+#if CAPNP_VERSION != 6001
+#error "Version mismatch between generated code and library headers.  You must use the same version of the Cap'n Proto compiler and library."
+#endif
+
+
+namespace capnp {
+namespace schemas {
+
+CAPNP_DECLARE_SCHEMA(b1dfe08305a4b99c);
+enum class InstType_b1dfe08305a4b99c: uint16_t {
+  VAR_SET,
+  VAR_READ,
+  METHOD,
+};
+CAPNP_DECLARE_ENUM(InstType, b1dfe08305a4b99c);
+CAPNP_DECLARE_SCHEMA(aaca83afea5f387e);
+
+}  // namespace schemas
+}  // namespace capnp
+
+
+typedef ::capnp::schemas::InstType_b1dfe08305a4b99c InstType;
+
+struct OPCUAset {
+  OPCUAset() = delete;
+
+  class Reader;
+  class Builder;
+  class Pipeline;
+
+  struct _capnpPrivate {
+    CAPNP_DECLARE_STRUCT_HEADER(aaca83afea5f387e, 1, 2)
+    #if !CAPNP_LITE
+    static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
+    #endif  // !CAPNP_LITE
+  };
+};
+
+// =======================================================================================
+
+class OPCUAset::Reader {
+public:
+  typedef OPCUAset Reads;
+
+  Reader() = default;
+  inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
+
+  inline ::capnp::MessageSize totalSize() const {
+    return _reader.totalSize().asPublic();
+  }
+
+#if !CAPNP_LITE
+  inline ::kj::StringTree toString() const {
+    return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
+  }
+#endif  // !CAPNP_LITE
+
+  inline  ::uint8_t getId() const;
+
+  inline  ::InstType getType() const;
+
+  inline bool hasData() const;
+  inline  ::capnp::List< ::uint8_t>::Reader getData() const;
+
+  inline bool hasMask() const;
+  inline  ::capnp::List<bool>::Reader getMask() const;
+
+private:
+  ::capnp::_::StructReader _reader;
+  template <typename, ::capnp::Kind>
+  friend struct ::capnp::ToDynamic_;
+  template <typename, ::capnp::Kind>
+  friend struct ::capnp::_::PointerHelpers;
+  template <typename, ::capnp::Kind>
+  friend struct ::capnp::List;
+  friend class ::capnp::MessageBuilder;
+  friend class ::capnp::Orphanage;
+};
+
+class OPCUAset::Builder {
+public:
+  typedef OPCUAset Builds;
+
+  Builder() = delete;  // Deleted to discourage incorrect usage.
+                       // You can explicitly initialize to nullptr instead.
+  inline Builder(decltype(nullptr)) {}
+  inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
+  inline operator Reader() const { return Reader(_builder.asReader()); }
+  inline Reader asReader() const { return *this; }
+
+  inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
+#if !CAPNP_LITE
+  inline ::kj::StringTree toString() const { return asReader().toString(); }
+#endif  // !CAPNP_LITE
+
+  inline  ::uint8_t getId();
+  inline void setId( ::uint8_t value);
+
+  inline  ::InstType getType();
+  inline void setType( ::InstType value);
+
+  inline bool hasData();
+  inline  ::capnp::List< ::uint8_t>::Builder getData();
+  inline void setData( ::capnp::List< ::uint8_t>::Reader value);
+  inline void setData(::kj::ArrayPtr<const  ::uint8_t> value);
+  inline  ::capnp::List< ::uint8_t>::Builder initData(unsigned int size);
+  inline void adoptData(::capnp::Orphan< ::capnp::List< ::uint8_t>>&& value);
+  inline ::capnp::Orphan< ::capnp::List< ::uint8_t>> disownData();
+
+  inline bool hasMask();
+  inline  ::capnp::List<bool>::Builder getMask();
+  inline void setMask( ::capnp::List<bool>::Reader value);
+  inline void setMask(::kj::ArrayPtr<const bool> value);
+  inline  ::capnp::List<bool>::Builder initMask(unsigned int size);
+  inline void adoptMask(::capnp::Orphan< ::capnp::List<bool>>&& value);
+  inline ::capnp::Orphan< ::capnp::List<bool>> disownMask();
+
+private:
+  ::capnp::_::StructBuilder _builder;
+  template <typename, ::capnp::Kind>
+  friend struct ::capnp::ToDynamic_;
+  friend class ::capnp::Orphanage;
+  template <typename, ::capnp::Kind>
+  friend struct ::capnp::_::PointerHelpers;
+};
+
+#if !CAPNP_LITE
+class OPCUAset::Pipeline {
+public:
+  typedef OPCUAset Pipelines;
+
+  inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
+  inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
+      : _typeless(kj::mv(typeless)) {}
+
+private:
+  ::capnp::AnyPointer::Pipeline _typeless;
+  friend class ::capnp::PipelineHook;
+  template <typename, ::capnp::Kind>
+  friend struct ::capnp::ToDynamic_;
+};
+#endif  // !CAPNP_LITE
+
+// =======================================================================================
+
+inline  ::uint8_t OPCUAset::Reader::getId() const {
+  return _reader.getDataField< ::uint8_t>(
+      ::capnp::bounded<0>() * ::capnp::ELEMENTS);
+}
+
+inline  ::uint8_t OPCUAset::Builder::getId() {
+  return _builder.getDataField< ::uint8_t>(
+      ::capnp::bounded<0>() * ::capnp::ELEMENTS);
+}
+inline void OPCUAset::Builder::setId( ::uint8_t value) {
+  _builder.setDataField< ::uint8_t>(
+      ::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
+}
+
+inline  ::InstType OPCUAset::Reader::getType() const {
+  return _reader.getDataField< ::InstType>(
+      ::capnp::bounded<1>() * ::capnp::ELEMENTS);
+}
+
+inline  ::InstType OPCUAset::Builder::getType() {
+  return _builder.getDataField< ::InstType>(
+      ::capnp::bounded<1>() * ::capnp::ELEMENTS);
+}
+inline void OPCUAset::Builder::setType( ::InstType value) {
+  _builder.setDataField< ::InstType>(
+      ::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
+}
+
+inline bool OPCUAset::Reader::hasData() const {
+  return !_reader.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
+}
+inline bool OPCUAset::Builder::hasData() {
+  return !_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
+}
+inline  ::capnp::List< ::uint8_t>::Reader OPCUAset::Reader::getData() const {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::get(_reader.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS));
+}
+inline  ::capnp::List< ::uint8_t>::Builder OPCUAset::Builder::getData() {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::get(_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS));
+}
+inline void OPCUAset::Builder::setData( ::capnp::List< ::uint8_t>::Reader value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::set(_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS), value);
+}
+inline void OPCUAset::Builder::setData(::kj::ArrayPtr<const  ::uint8_t> value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::set(_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS), value);
+}
+inline  ::capnp::List< ::uint8_t>::Builder OPCUAset::Builder::initData(unsigned int size) {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::init(_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS), size);
+}
+inline void OPCUAset::Builder::adoptData(
+    ::capnp::Orphan< ::capnp::List< ::uint8_t>>&& value) {
+  ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::adopt(_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
+}
+inline ::capnp::Orphan< ::capnp::List< ::uint8_t>> OPCUAset::Builder::disownData() {
+  return ::capnp::_::PointerHelpers< ::capnp::List< ::uint8_t>>::disown(_builder.getPointerField(
+      ::capnp::bounded<0>() * ::capnp::POINTERS));
+}
+
+inline bool OPCUAset::Reader::hasMask() const {
+  return !_reader.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
+}
+inline bool OPCUAset::Builder::hasMask() {
+  return !_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
+}
+inline  ::capnp::List<bool>::Reader OPCUAset::Reader::getMask() const {
+  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::get(_reader.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS));
+}
+inline  ::capnp::List<bool>::Builder OPCUAset::Builder::getMask() {
+  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::get(_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS));
+}
+inline void OPCUAset::Builder::setMask( ::capnp::List<bool>::Reader value) {
+  ::capnp::_::PointerHelpers< ::capnp::List<bool>>::set(_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS), value);
+}
+inline void OPCUAset::Builder::setMask(::kj::ArrayPtr<const bool> value) {
+  ::capnp::_::PointerHelpers< ::capnp::List<bool>>::set(_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS), value);
+}
+inline  ::capnp::List<bool>::Builder OPCUAset::Builder::initMask(unsigned int size) {
+  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::init(_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS), size);
+}
+inline void OPCUAset::Builder::adoptMask(
+    ::capnp::Orphan< ::capnp::List<bool>>&& value) {
+  ::capnp::_::PointerHelpers< ::capnp::List<bool>>::adopt(_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
+}
+inline ::capnp::Orphan< ::capnp::List<bool>> OPCUAset::Builder::disownMask() {
+  return ::capnp::_::PointerHelpers< ::capnp::List<bool>>::disown(_builder.getPointerField(
+      ::capnp::bounded<1>() * ::capnp::POINTERS));
+}
+
+
+#endif  // CAPNP_INCLUDED_9f2c99de8c7edd7f_
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c5af4e72149a06623d94bff6b1b2c1549a1621f3
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,135 @@
+#include <iostream>
+#include "apsctl/conf.h"
+//#include "structs.h"
+#include "drivers/drvbase.h"
+
+#include <capnp/message.h>
+#include <capnp/serialize-packed.h>
+#include "interface/pypcc.capnp.h"
+#include <fcntl.h>
+
+c_drivers drivers1;
+t_buffer buffer[3072]; 
+bool mask[96]; 
+int fd_out;
+
+void SetResult(int id,int lenbuffer,int lenmask){
+  std::cout << "Set Result lenbuf="<<lenbuffer<<" lenmask="<<lenmask<<"\n";
+  ::capnp::MallocMessageBuilder message;
+  OPCUAset::Builder result = message.initRoot<OPCUAset>();
+  result.setId(id);
+  result.setType(InstType::VAR_SET);
+  ::capnp::List<uint8_t>::Builder buf2=  result.initData(lenbuffer);
+  for (int x=0;x<lenbuffer;x++) buf2.set(x,buffer[x]);
+  ::capnp::List<bool>::Builder mask2=  result.initMask(lenmask);
+  for (int x=0;x<lenmask;x++) mask2.set(x,mask[x]);
+  std::cout << "Send result id=" << id << "\n";
+  writePackedMessageToFd(fd_out,message);
+};
+
+void getvar(int varid,int lenmask){
+   if ((varid<0) || (varid>number_vars)){
+          std::cout << "get var: Invalid variable id!\n";
+          return;
+   };
+   int drvnum=variables[varid].driver;
+   std::cout << "getvar: id=" << varid << " name=" << variables[varid].name << " driver=" << drvnum << "\n"; 
+   int lenbuffer=drivers1.d[drvnum]->getvar(varid,buffer,lenmask,mask);
+   SetResult(varid,lenbuffer,lenmask);
+}
+
+void setvar(int varid,int lenbuffer,int lenmask){
+   if ((varid<0) || (varid>number_vars)){
+          std::cout << "Set var: Invalid variable id!\n";
+          return;
+   };
+   int drvnum=variables[varid].driver;
+   std::cout << "set variable call: Inst id=" << varid <<"=" << variables[varid].name << " len="<<lenbuffer<<"\n";
+   //std::cout << "Mask=" << lenmask << "," << mask[0] << "," << mask[1] <<"\n"; 
+//       std::cout << "Driver " << drvnum << " lenbuffer="  << lenbuffer << " len mask" << lenmask <<"\n";
+   drivers1.d[drvnum]->setvar(varid,lenbuffer,buffer,lenmask,mask);
+}
+
+void setdev(t_devreg devreg,int lenbuffer,int lenmask){
+   std::cout << "setdev " << devreg.driver << ":"<<devreg.address <<":"<<devreg.register_W<<"\n";
+   drivers1.d[devreg.driver]->setdevreg(devreg,lenbuffer,buffer,lenmask,mask);
+}
+
+void methodcall(int varid,int lenmask)
+{
+   if ((varid<0) || (varid>number_methods)){
+          std::cout << "Set var: Invalid method id!\n";
+          return;
+   };
+   t_method method=method_config[varid];
+   for (int x=0;x<method.len;x++)
+   { t_instruction I=method.instructions[x];
+     switch (I.type){
+        case inst_setvar:
+             for (int x=0;x<I.len;x++) buffer[x]=I.data[x];
+             setvar(I.variable,I.len,lenmask);
+             getvar(I.variable,lenmask);
+             break;
+        case inst_getvar:
+             getvar(I.variable,lenmask);
+             break;
+        case inst_getvarall:
+             getvar(I.variable,0);
+             break;
+        case inst_wait:
+             std::cout << "Sleep not implemented yet!!\n";
+             break;
+        case inst_devreg:
+             for (int x=0;x<I.len;x++) buffer[x]=I.data[x];
+             setdev(I.devreg,I.len,lenmask);
+             break;
+        case inst_method:
+             methodcall(I.variable,lenmask);
+             break;
+     }
+   }
+}
+
+
+int main(int argc, char *argv[])
+{
+//  driver
+//  std::cout << drivers1.d[0]->config.name << "\n";
+//  std::cout << drivers1.d[1]->config.name << "\n";
+//  std::cout << drivers1.d[1]->parent->config.name << "\n";
+//  c_i2c i2c1(I2C1);
+//  u_char buffer[32];
+//  for (int x=0;x<32;x++) buffer[x]=0; 
+//  for (int x=0;x<3;x++) buffer[x]=1; 
+//  buffer[2]=1;
+//  drivers1.d[1]->setvar(1,32,buffer);
+//  for (int x=0;x<3;x++) buffer[x]=x; 
+//  drivers1.d[1]->setvar(4,32,buffer);
+//  for (int x=0;x<number_vars;x++)
+//    std::cout << variables[x].name << "\n";
+ std::cout << "Open read pipe\n";
+ int fd_in=open("serv_to_RCU",O_RDONLY);
+ if (fd_in<0) return false;
+ fd_out=open("RCU_to_serv",O_WRONLY);
+ if (fd_out<0) return false;
+ while (1) {
+   ::capnp::PackedFdMessageReader message(fd_in);
+//   ::capnp::StreamFdMessageReader message(fd_in);
+   OPCUAset::Reader Inst=message.getRoot<OPCUAset>();
+  // int encoded_array=capnp::messageToFlatArray(Inst);
+   int lenbuffer=0;
+   for (uint8_t value: Inst.getData()) buffer[lenbuffer++]=value;
+   int lenmask=0;
+   for (bool value: Inst.getMask()) mask[lenmask++]=value;
+   int varid=Inst.getId();
+   if (Inst.getType()==InstType::METHOD){
+      std::cout << "Method call: Inst id=" << int(Inst.getId()) <<"\n";
+      methodcall(varid,lenmask);
+      continue;
+   } 
+   if (Inst.getType()==InstType::VAR_SET) setvar(varid,lenbuffer,lenmask);
+   getvar(varid,lenmask);
+
+ };
+// fclose(fd);
+};
\ No newline at end of file
diff --git a/src/structs.h b/src/structs.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ba69331d14bb595675720ad2d4cb05b32f02ff0
--- /dev/null
+++ b/src/structs.h
@@ -0,0 +1,43 @@
+#ifndef STRUCTS_H
+#define STRUCTS_H
+typedef unsigned char t_buffer;
+struct t_devreg {int address,register_R,register_W,store,driver;};
+enum t_dtype {dt_double,dt_boolean,dt_string,dt_uint8,dt_uint16,dt_uint32,dt_uint64};
+enum t_rw {rw_variable,rw_rw,rw_ro,rw_hidden};
+
+enum t_drivers {drv_i2c,drv_RCU_switch,drv_i2c_devs,drv_i2c_array,drv_i2c_array2,drv_hba1,drv_i2cbitbang1,drv_spibitbang1,drv_spibitbang2};
+
+struct t_variable {
+    char* name;
+    int dim;
+    t_dtype dtype;
+    int driver;
+    t_rw rw;
+    int bitoffset[3];
+    int width;
+    double scale;
+    const t_devreg devreg[3];
+};
+struct t_driver {
+    char* name;
+    t_drivers type;
+    int parent;
+    int parameters[4];
+    const t_devreg devreg[4];
+};
+enum t_inst_type {inst_setvar,inst_getvar,inst_getvarall,inst_wait,inst_devreg,inst_method};
+struct t_instruction {
+   t_inst_type type;
+   int variable; //or method number
+   t_devreg devreg;
+   int len;
+   t_buffer data[8];
+};
+
+struct t_method {
+   char* name;
+   int len;
+   const t_instruction* instructions;
+};
+
+#endif
\ No newline at end of file