From cb6c0105a11d965b4eddbf01bb2afda8b124c055 Mon Sep 17 00:00:00 2001
From: Paulus <kruger@astron.nl>
Date: Thu, 22 Apr 2021 01:11:01 +0100
Subject: [PATCH] 1st working version

---
 config/RCU.yaml         | 91 ++++++++++++++++++++++-------------------
 i2cserv/i2c.py          | 16 +++++---
 i2cserv/i2c_array.py    | 45 ++++++++++++--------
 i2cserv/i2c_switch.py   |  5 ++-
 i2cserv/i2cthread.py    | 16 ++++++--
 i2cserv/spibitbang1.py  | 17 +++++---
 opcuaserv/yamlreader.py |  2 +-
 testRCU.py              | 26 +++++++++---
 yamlconfig.py           |  1 +
 9 files changed, 137 insertions(+), 82 deletions(-)

diff --git a/config/RCU.yaml b/config/RCU.yaml
index 338f910..258c543 100644
--- a/config/RCU.yaml
+++ b/config/RCU.yaml
@@ -9,7 +9,7 @@ drivers:
  - 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
+   parameters: [0,31] #start,number of RCUs
  - name: I2C_HBAT 
    type: hba1 #Special driver to manage HBAT1s.
    parent: I2C_RCU
@@ -186,6 +186,13 @@ variables:
      dtype: boolean
      dim: 32
 
+   - name: RCU_I2C_OK
+     description: Only OK RCUs are monitored
+     driver: I2C_RCU
+     rw:  variable #server RW variable, not linked to IO
+     dtype: boolean
+     dim: 32
+
    - name: RCU_state
      description: State of RCUs 0=unknown, 1=ready, 2=busy, 3=error
      driver: I2C_RCU
@@ -215,24 +222,14 @@ variables:
      dim: 96
      mask: Ant_mask
 
-   - name: RCU_GPIO1
+   - name: [RCU_IO1_GPIO1,RCU_IO1_GPIO2,RCU_IO2_GPIO1,RCU_IO2_GPIO2,RCU_IO3_GPIO1,RCU_IO3_GPIO2]
      driver: I2C_RCU
-     devreg:  [IO1.GPIO1,IO2.GPIO1,IO3.GPIO1]
+     devreg:  [IO1.GPIO1,IO1.GPIO2,IO2.GPIO1,IO2.GPIO2,IO3.GPIO1,IO3.GPIO2]
      width: 8
      rw:  ro
      dtype: uint8
-     dim: 96
-     mask: Ant_mask
-     debug: True
-
-   - name: RCU_GPIO2
-     driver: I2C_RCU
-     devreg:  [IO1.GPIO2,IO2.GPIO2,IO3.GPIO2]
-     width: 8
-     rw:  ro
-     dtype: uint8
-     dim: 96
-     mask: Ant_mask
+     dim: 32
+     mask: RCU_mask
      debug: True
 
    - name: RCU_LED0
@@ -240,22 +237,22 @@ variables:
      description: LED on RCU
      devreg:  IO2.GPIO2
      bitoffset: 6
-     width: 1
+     width: 2
      rw:  rw
-     dtype: boolean
+     dtype: uint8
      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_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
@@ -267,6 +264,7 @@ variables:
      dtype: double
      dim: 32
      monitor: true
+     mask: RCU_I2C_OK
 
    - name: RCU_Pwr_dig
      description: Enable LDOs
@@ -318,7 +316,7 @@ variables:
      rw:  ro
      dtype: uint8
      dim: 96
-     mask: Ant_mask
+     mask: RCU_I2C_OK
      monitor: true
 
    - name: RCU_dth1_freq
@@ -331,12 +329,6 @@ variables:
      mask: Ant_mask
 
 methods:
-  - name: RCU_update
-    mask: RCU_mask
-    debug: True
-    instructions:
-     - RCU_ADC_lock: Update
-
   - name: RCU_on
     driver: I2C_RCU
     mask: RCU_mask
@@ -353,13 +345,30 @@ methods:
      - 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
+#     - RCU_GPIO1: Update
+#     - RCU_GPIO2: Update
+#     - RCU_attenuator: [10,10,10]  #Set OPC-UA variable
+#     - WAIT: 500         #ms to wait
+#     - ADC1_on: 0        #call another opc-ua method
+#     - ADC2_on: 0
+#     - WAIT: 500         #ms to wait
+     - RCU_update: 0
+
+  - name: RCU_update
+    driver: I2C_RCU
+    mask: RCU_mask
+    debug: True
+    instructions:
+#     - RCU_ADC_lock: Update
+      - RCU_IO1_GPIO1 : Update
+      - RCU_IO1_GPIO2 : Update
+      - RCU_IO2_GPIO1 : Update
+      - RCU_IO2_GPIO2 : Update
+      - RCU_IO3_GPIO1 : Update
+      - RCU_IO3_GPIO2 : Update
+      - RCU_Pwr_dig: Update  #Read value and update the OPC-UA variable
+      - RCU_ADC_lock: Update
+
 
   - name: ADC1_on
     driver: I2C_RCU
diff --git a/i2cserv/i2c.py b/i2cserv/i2c.py
index a12df13..3eb98b2 100644
--- a/i2cserv/i2c.py
+++ b/i2cserv/i2c.py
@@ -1,6 +1,6 @@
 import os
-if os.sys.platform is 'linux':
-    import pylibi2c;
+#if os.sys.platform is 'linux':
+import pylibi2c;
 import time
 import logging
 #read=0: write to register
@@ -20,10 +20,10 @@ class i2c(hwdev):
 #       logging.debug(str(("I2C",addr,reg,data,read)))
        bus=None;
        try:
+#       if True:
               if read==3:
                      time.sleep(data[0]/1000.)
                      return True
-              logging.debug(str(("I2C",addr,reg,data,read)))
 
 #       return True;
               bus=pylibi2c.I2CDevice(self.I2Cdev,addr)
@@ -31,18 +31,22 @@ class i2c(hwdev):
                      length=len(data)
                      bus.iaddr_bytes=0
                      if not(reg is None):
-                            bus.ioctl_write(0,str(bytearray([reg])))
+                            bus.ioctl_write(0,bytes(bytearray([reg])))
                      data[:]=[int(x) for x in bus.ioctl_read(0,length)]
+                     logging.debug(str(("I2C get",addr,reg,data,read)))
 #         print("I2C read",addr,reg,data,read)
               else:
                      if reg is None: 
                             bus.iaddr_bytes=0
-                     reg=0;
-                     bus.ioctl_write(reg,str(bytearray(data)))
+                            reg=0;
+                     logging.debug(str(("I2C set",addr,reg,bytes(bytearray(data)),read)))
+                     bus.ioctl_write(reg,bytes(bytearray(data)))
               bus.close()
               return True;
        except:
+#       else:
               if bus: bus.close()
+              logging.debug("I2C failed!")
 #       data[0]=0xff
               return False;
 
diff --git a/i2cserv/i2c_array.py b/i2cserv/i2c_array.py
index 11b7d9f..293c5a8 100644
--- a/i2cserv/i2c_array.py
+++ b/i2cserv/i2c_array.py
@@ -124,8 +124,10 @@ class i2c_array(hwdev):
     def OPCUASetVariable(self,varid,var1,data,mask):
        if var1['rw']=='variable': return;
        logging.info(str(("Set Var",var1['name'],data,mask)))
-       data=self.SetGetVarValueMask(var1,data,mask);
-       Data=OPCUAset(varid,InstType.varSet,data,mask)
+       data,mask2=self.SetGetVarValueMask(var1,data,mask);
+#       if len(mask)==len(mask2): mask[:]=mask2[:];
+#       elif len(mask)==0: (mask.append(x) for x in mask2);
+       Data=OPCUAset(varid,InstType.varSet,data,mask2)
        return [Data]
 
     def OPCUAReadVariable(self,varid,var1,mask):
@@ -133,8 +135,10 @@ class i2c_array(hwdev):
       if len(mask)==0: mask=[True]*self.N; 
       #data=self.GetVarValueAll(var1)
       #else:             
-      data=self.GetVarValueMask(var1,mask);
-      Data=OPCUAset(varid,InstType.varSet,data,mask)
+      data,mask2=self.GetVarValueMask(var1,mask);
+#      if len(mask)==len(mask2): mask[:]=mask2[:];
+#      elif len(mask)==0: (mask.append(x) for x in mask2);
+      Data=OPCUAset(varid,InstType.varSet,data,mask2)
       return [Data]
 
 #    def OPCUAcallMethod(self,var1,data,mask):
@@ -167,6 +171,7 @@ class i2c_array(hwdev):
             print("Check mask length!");
             return;
 #        if (len(value1)==V1.nVars) and (self.N>1):  value1=(value1*self.N);
+#        logging.debug(str(("Step=",Step,"Mask=",mask)))
         i2c=self.conf['parentcls'];
         for RCUi in range(self.N):
             for Vari in range(Step):
@@ -178,11 +183,12 @@ class i2c_array(hwdev):
                 bitoffset=GetField(var1,'bitoffset',Vari,0)
                 self.SetSwitch(RCUi);
                 self.RCUi=RCUi;
-                self.SetVarValue(devreg,width,bitoffset,data[i0:i1])
+                mask[RCUi*Step+Vari]=self.SetVarValue(devreg,width,bitoffset,data[i0:i1])
+                if not(mask[RCUi*Step+Vari]): continue
                 value2=value1[i0:i1]
-                self.GetVarValue(devreg,width,bitoffset,value2)
+                mask[RCUi*Step+Vari]=self.GetVarValue(devreg,width,bitoffset,value2)
                 value1[i0:i1]=value2
-        return value1
+        return value1,mask
 
 
 
@@ -197,6 +203,7 @@ class i2c_array(hwdev):
             return;
 #        if (len(value1)==V1.nVars) and (self.N>1):  value1=(value1*self.N);
         i2c=self.conf['parentcls'];
+#        logging.debug(str(("Step=",Step,"Mask=",mask)))
         for RCUi in range(self.N):
             for Vari in range(Step):
                 if not(mask[RCUi*Step+Vari]): continue
@@ -208,9 +215,9 @@ class i2c_array(hwdev):
                 self.SetSwitch(RCUi);
                 value2=value1[i0:i1]
                 self.RCUi=RCUi;
-                self.GetVarValue(devreg,width,bitoffset,value2)
+                mask[RCUi*Step+Vari]=self.GetVarValue(devreg,width,bitoffset,value2)
                 value1[i0:i1]=value2
-        return value1
+        return value1,mask
 
 
     def getstorearray(self,devreg):
@@ -221,14 +228,15 @@ class i2c_array(hwdev):
           return storearray;
 
     def Setdevreg(self,devreg,value,mask=[]):
- #       if devreg.get('store')>0: logging.warn("Setdevreg not working correctly for stored registers!")
-        if devreg['store']>0:
+#        if devreg.get('store'): logging.debug("Stored")
+#        print(devreg['store'])
+        if devreg.get('store'):
                 storearray=self.getstorearray(devreg);
                 for RCUi in range(self.N):
                   if mask[RCUi]:   
                       storearray[RCUi]=value[0]
                       self.RCUi=RCUi;
-#                print("Stored values:",self.getstorearray(devreg))
+                logging.debug(str(("Stored values:",self.getstorearray(devreg))))
         self.SetSwitchMask(mask)
         self.SetVarValue(devreg,8,0,value)
         return True;
@@ -238,12 +246,12 @@ class i2c_array(hwdev):
             if devreg['register_W']==-1: return True; #We can not set it, only read it e.g. temperature
             logging.debug(str(("RCU1 Set ",self.RCUi,devreg['addr'],value)))
             #self.parentcls.SetChannel(1<<RCU_Switch[RCUi]);
-            if devreg['store']>0:
+            if devreg['store']:
                 storearray=self.getstorearray(devreg);
                 previous=storearray[self.RCUi];
                 value[0]=ApplyMask(value[0],width,bitoffset,previous);
                 storearray[self.RCUi]=value[0]
-#                print("Stored values:",self.getstorearray(devreg))
+                logging.debug("Stored value:"+str(value[0]))
             #  devreg['drivercls'].i2csetget
             return devreg['drivercls'].i2csetget(devreg['addr'],value,reg=devreg['register_W'])
 
@@ -266,14 +274,17 @@ class i2c_array(hwdev):
           if not(callback(devreg['addr'],value2,reg=reg,read=1)): return False;
         if value2[0] is None:  return False
         value[:]=value2[:];
-        if devreg['store']>0:
+        if devreg['store']:
              storearray=self.getstorearray(devreg);
              storearray[self.RCUi]=value[0]
              logging.debug(str(("Store buffer",self.RCUi,value[0])))
  #            print("Stored values:",self.getstorearray(devreg))
         if (width!=l1*8) or (bitoffset>0):
-            for i in range(len(value)):
-              value[i]=UnMask(value[i],width,bitoffset)
+            if (width<8):
+              for i in range(len(value)):
+                value[i]=UnMask(value[i],width,bitoffset)
+            else:
+                value[0]=UnMask(value[0],width-(l1-1)*8,bitoffset)
         else: value[0]=value2[0]
         return True;
 
diff --git a/i2cserv/i2c_switch.py b/i2cserv/i2c_switch.py
index f6a59b9..6863b5a 100644
--- a/i2cserv/i2c_switch.py
+++ b/i2cserv/i2c_switch.py
@@ -11,13 +11,14 @@ class i2c_switch(i2c):
         logging.info("i2c switch at address "+str(self.SWaddr))
 
     def SetSW1(self,channelbit):
-        channel=1<<(channelbit)
+        channel=(0 if (channelbit>5) else 1<<(channelbit)) #LTS
         if (channel)==self.CurrentChannel: return True;
-        logging.debug("SetChannel=%i" % channelbit)
+        logging.debug("SetChannelbit=%i" % channelbit)
         self.CurrentChannel=channel
         return self.i2csetget(self.SWaddr,[channel])
 
     def SetChannel(self,channel):
+        channel&=0x3F;#LTS
         if (channel)==self.CurrentChannel: return True;
         logging.debug("SetChannel=%i" % channel)
         self.CurrentChannel=channel
diff --git a/i2cserv/i2cthread.py b/i2cserv/i2cthread.py
index c76a1ec..3fa382f 100644
--- a/i2cserv/i2cthread.py
+++ b/i2cserv/i2cthread.py
@@ -35,20 +35,20 @@ def runmethod(conf,Qout,methodid,mask):
     for inst in var1['instructions']:
         for key,value in inst.items():
             if not(isinstance(value,list)): value=[value]
-            logging.info(str(("Run instruction",key,value)));
+            logging.info(str(("Run instruction",key,value,mask)));
             if (key=='WAIT'):
                 sleep(value[0]/1000.)
                 continue;
             v1=conf.getvarid(key)
             if v1: 
                 if value[0]=='Update':
-                   getvar(conf,Qout,v1,mask)
+                   mask=getvar(conf,Qout,v1,mask)
                 else:
-                   setvar(conf,Qout,v1,value,mask)
+                   mask=setvar(conf,Qout,v1,value,mask)
                 continue;
             v1=conf.getmethodid(key)
             if v1: 
-                runmethod(conf,Qout,v1,mask)
+                mask=runmethod(conf,Qout,v1,mask)
                 continue;
             v1=conf.getdevreg(key)
             if v1:
@@ -65,6 +65,8 @@ def runmethod(conf,Qout,methodid,mask):
 #                   continue;
 #               for data in drv.OPCUAcallMethod(item.id,var1,item.data,item.mask):
 #                   Qout.put(data)
+    return mask
+
 def setvar(conf,Qout,varid,data,mask):
     var1=conf.getvars()[varid]
     drv=var1.get('drivercls');
@@ -72,7 +74,10 @@ def setvar(conf,Qout,varid,data,mask):
         logging.warn(var1['name']+" driver not found!")
         return;
     for data in drv.OPCUASetVariable(varid,var1,data,mask):
+        if len(mask)==len(data.mask): mask[:]=data.mask[:];
+        elif len(mask)==0: mask=data.mask.copy();
         Qout.put(data)
+    return mask;
 
 def getvar(conf,Qout,varid,mask):
     var1=conf.getvars()[varid]
@@ -81,7 +86,10 @@ def getvar(conf,Qout,varid,mask):
         logging.warn(var1['name']+" driver not found!")
         return;
     for data in drv.OPCUAReadVariable(varid,var1,mask):
+        if len(mask)==len(data.mask): mask[:]=data.mask[:];
+        elif len(mask)==0: mask=data.mask.copy();
         Qout.put(data)
+    return mask;
 
 
 def I2Cserver(Qin,Qout,name):
diff --git a/i2cserv/spibitbang1.py b/i2cserv/spibitbang1.py
index 7db2517..2148d30 100644
--- a/i2cserv/spibitbang1.py
+++ b/i2cserv/spibitbang1.py
@@ -15,8 +15,8 @@ class spibitbang1(hwdev):
 #    logging.info("spibitbang todo")
 
   def i2csetget(self,addr,data,reg=None,read=0):
-    if read==0: return self.SetSPIbb(addr,data)
-    elif read==1: return self.GetSPIbb(addr,data)
+    if read==0: return self.SetSPIbb(reg,data)
+    elif read==1: return self.GetSPIbb(reg,data)
     else: logging.warn("Not implemented!")
     return False;
 
@@ -39,7 +39,7 @@ class spibitbang1(hwdev):
           
         bit_array = "{0:{fill}24b}".format(data2, fill='0')
       #    print(bit_array)
-        SetI2C(CSdev,1,CSpin,[0]) #enable
+        if not(SetI2C(CSdev,1,CSpin,[0])): return False #enable
         for bit in bit_array:
               SetI2C(SDOdev,1,SDOpin,[int(bit)]) 
               SetI2C(CLKdev,1,CLKpin,[1]) 
@@ -57,7 +57,11 @@ class spibitbang1(hwdev):
         CLKpin=self.conf['parameters'][SPIBB_pins.CLK.value]
         SDIOdirdev=self.conf['devreg'][SPIBB_pins.SDIOdir.value]
         SDIOdirpin=self.conf['parameters'][SPIBB_pins.SDIOdir.value]
-
+#        print("SPI registers")
+#        print("CS",CSdev,CSpin)
+#        print("SDO",SDOdev,SDOpin)
+#        print("CLK",CLKdev,CLKpin)
+#        print("DIR",SDIOdirdev,SDIOdirpin)
         logging.info(str(("SPIbb get",ADC_reg_address)))
           
         ADC_bytes = 0x00
@@ -67,10 +71,11 @@ class spibitbang1(hwdev):
 
         SetI2C=self.conf['parentcls'].SetVarValue
         GetI2C=self.conf['parentcls'].GetVarValue
-        SetI2C(CSdev,1,CSpin,[0]) #enable
+        if not(SetI2C(CSdev,1,CSpin,[0])): return False #enable
 
 
         bit_array = "{0:{fill}16b}".format(data, fill='0')
+        #print("SPI TX bits",bit_array)
         for bit in bit_array:
               SetI2C(SDOdev,1,SDOpin,[int(bit)]) 
               SetI2C(CLKdev,1,CLKpin,[1]) 
@@ -87,11 +92,13 @@ class spibitbang1(hwdev):
         for i in range(N): value[i]=0
         for cnt in range(8*(ADC_bytes+1)):
               GetI2C(SDOdev,1,SDOpin,ret_value) #enable
+#              logging.debug("Got bit"+str((ret_value)))
               for i in range(N): value[i]=(value[i]<<1)+ ret_value[i]
               SetI2C(CLKdev,1,CLKpin,[1]) 
               SetI2C(CLKdev,1,CLKpin,[0])  #read after falling edge
         SetI2C(CSdev,1,CSpin,[1]) #disable
         SetI2C(SDIOdirdev,1,SDIOdirpin,[0]) #output
+#        logging.debug(str(("SPIbb got",value)))
         return True;
 
 def GetSPIbb2(SetI2C,GetI2C,RCUi,SPIdev,I2Cdev,I2Cpins,value):
diff --git a/opcuaserv/yamlreader.py b/opcuaserv/yamlreader.py
index 380da01..7b8e259 100644
--- a/opcuaserv/yamlreader.py
+++ b/opcuaserv/yamlreader.py
@@ -181,7 +181,7 @@ class yamlreader(yamlconfig):
                 if mask[i//step]: data3[i]=data2[i]
         else:
             data3=data2;
-        logging.debug(str(("OPCset",v['name'],data3)))
+        logging.info(str(("OPCset",v['name'],data3)))
         v['OPCR'].set_value(data3);
 
     def Monitor(self):
diff --git a/testRCU.py b/testRCU.py
index 1576f31..f68c675 100644
--- a/testRCU.py
+++ b/testRCU.py
@@ -32,10 +32,16 @@ I2Cclients.append(RCU_I2C)
 #Load yaml so that we know the variable names
 RCU_conf=yamlreader.yamlreader(RCU_I2C,yamlfile=name)
 
+var1=RCU_conf.getmethodid('RCU_update');
+#var1=RCU_conf.getmethodid('RCU_on');
+#N=32;
+#mask=[i<2 for i in range(N)];
+#RCU_I2C.callmethod(var1,[])
+
 if True:
     var1=RCU_conf.getvarid('RCU_LED0');
     N=32;
-    mask=[i<2 for i in range(N)];
+    mask=[i<8 for i in range(N)];
     data=[0]*N;
 elif True:
     var1=RCU_conf.getvarid('RCU_attenuator');
@@ -46,20 +52,28 @@ elif True:
 #print(var1)
 print("mask=",mask);
 print("data=",data);
-RCU_I2C.setvar(var1,data,mask);
+#RCU_I2C.setvar(var1,data,mask);
+
+var1=RCU_conf.getvarid('RCU_temperature');
+N=32;
+mask=[i<2 for i in range(N)];
+RCU_I2C.readvar(var1,mask);
+
+#data=[0]*N;
+#RCU_I2C.setvar(var1,data,mask);
 #def setvar(self,id1,data=[],mask=[]):
 
 var1=RCU_conf.getmethodid('RCU_on');
 N=32;
-mask=[i<2 for i in range(N)];
-RCU_I2C.callmethod(var1,mask)
+mask=[i<7 for i in range(N)];
+#RCU_I2C.callmethod(var1,mask)
 
 
-time.sleep(2);
+time.sleep(5);
 
 while RCU_I2C.data_waiting():
     varid,data,mask=RCU_I2C.readdata()
-    print("Results:",RCU_conf.getvar1(varid)['name'],data)
+    print("Results:",RCU_conf.getvar1(varid)['name'],data,mask)
 
 
 logging.info("Stop threads")
diff --git a/yamlconfig.py b/yamlconfig.py
index fb32013..7dd994a 100644
--- a/yamlconfig.py
+++ b/yamlconfig.py
@@ -73,6 +73,7 @@ class yamlconfig():
           if isinstance(name,int): return {"addr":name}
           name2=name.split('.')
 #          print(name2,str2int(name2[0]),str2int(name2[1]))
+          logging.debug("New devreg!")
           if len(name2)==2:
               return {"addr":str2int(name2[0]),"register_R":str2int(name2[1]),"register_W":str2int(name2[1])}
           logging.error("Can not find device register "+str(name));
-- 
GitLab