From 8a348612baf0b64e493961faef192251050c09d4 Mon Sep 17 00:00:00 2001
From: kruger <kruger@astron.nl>
Date: Wed, 28 Jul 2021 07:06:29 +0200
Subject: [PATCH] fixed SMBus 2's complementary bug

---
 config/UNB2TR.yaml       |  2 +-
 i2cserv/i2c_smbus.py     |  2 +-
 i2cserv/i2c_switch2.py   | 19 +++++++++++++------
 opcuaserv/smbus_float.py | 11 ++++++-----
 opcuaserv/yamlreader.py  |  3 ++-
 5 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/config/UNB2TR.yaml b/config/UNB2TR.yaml
index bdef91e..d3e1936 100644
--- a/config/UNB2TR.yaml
+++ b/config/UNB2TR.yaml
@@ -450,7 +450,7 @@ variables:
      dim: 8
      dim2: [4,2]
      debug: true
-     monitor: true
+#     monitor: true
 
 
 ##Local MP per FPGA node, QSFP cage
diff --git a/i2cserv/i2c_smbus.py b/i2cserv/i2c_smbus.py
index 9a45b9d..5f7ee97 100644
--- a/i2cserv/i2c_smbus.py
+++ b/i2cserv/i2c_smbus.py
@@ -71,7 +71,7 @@ class i2c_smbus(hwdev):
                            data[:]=data2[:-1]
                            crc=crc8(data,crc)
                            if not(crc==data2[-1]): 
-                                    logging.warning("CRC error")
+                                    logging.warning("CRC error addr=%i, reg=%i" % (addr,reg))
                                     return False;
 #                           print("CRC",hex(addr),hex(reg),[hex(x) for x in data],hex(data2[-1]),hex(crc))
                      else: logging.warning("SMBUS crc without register not implemented!")
diff --git a/i2cserv/i2c_switch2.py b/i2cserv/i2c_switch2.py
index b0b1620..1ac79c5 100644
--- a/i2cserv/i2c_switch2.py
+++ b/i2cserv/i2c_switch2.py
@@ -13,6 +13,11 @@ class i2c_switch2(i2c):
         self.channel3=-1
         logging.info("i2c switch2 at address %i,%i,%i" % (self.SWaddr1,self.SWaddr2,self.SWaddr3))
 #        logging.warn("APSCT switch disabled for testing")
+    def setI2Cswitch(self,addr,state):
+        res=self.i2csetget(addr,[state]);
+        if not(res):
+           logging.warning("Error setting switch, switch reset not implemented!");
+        return res;
 
     def SetSW1(self,channelbit):
         channel=1<<(channelbit)
@@ -22,7 +27,7 @@ class i2c_switch2(i2c):
         self.channel2=-1
         self.channel3=-1
 #        return True; #testing without APSCT switch
-        return self.i2csetget(self.SWaddr1,[channel])
+        return self.setI2Cswitch(self.SWaddr1,channel)
 
     def SetSW2(self,channelbit):
         channel=1<<(channelbit)
@@ -30,30 +35,32 @@ class i2c_switch2(i2c):
         logging.debug("SetChannel2=%i" % channelbit)
         self.channel2=channel
         self.channel3=-1
-        return self.i2csetget(self.SWaddr2,[channel])
+        return self.setI2Cswitch(self.SWaddr2,channel)
 
     def SetSW3(self,channelbit):
         channel=1<<(channelbit)
         if (channel)==self.channel3: return True;
         logging.debug("SetChannel3=%i" % channelbit)
         self.channel3=channel
-        return self.i2csetget(self.SWaddr3,[channel])
+        return self.setI2Cswitch(self.SWaddr3,channel)
 
     def SetSWx(self,sw1,sw2,sw3):
         channel=0;
         for x in sw1: channel+=(1<<x);
         self.channel1=channel;
-        self.i2csetget(self.SWaddr1,[channel])
+        self.setI2Cswitch(self.SWaddr1,channel)
         if channel==0: return;
         channel=0;
         for x in sw2: channel+=(1<<x);
         self.channel2=channel;
-        self.i2csetget(self.SWaddr2,[channel])
+#        self.i2csetget(self.SWaddr2,[channel])
+        self.setI2Cswitch(self.SWaddr2,channel)
         if channel==0: return;
         channel=0;
         for x in sw3: channel+=(1<<x);
         if channel==0: return;
         self.channel3=channel;
-        self.i2csetget(self.SWaddr3,[channel])
+#        self.i2csetget(self.SWaddr3,[channel])
+        self.setI2Cswitch(self.SWaddr3,channel)
       
 
diff --git a/opcuaserv/smbus_float.py b/opcuaserv/smbus_float.py
index 0379856..9190699 100644
--- a/opcuaserv/smbus_float.py
+++ b/opcuaserv/smbus_float.py
@@ -1,10 +1,11 @@
 def smbus_2bytes_to_float(data):
-    expo = ((data & 0xf8)>>3) 
-    if expo == 1:
+    #PMBus Specification, part II, section 7.1
+    expo = ((data & 0xf8)>>3)  #5 bit 2's complement
+    if expo >= 2**4: expo-=2**5
+    if expo == 1: #PK: Reference to this special case?
         expo = -7
-    if expo > 2**4:
-        expo = expo-2**5
-    mantisse = ((data & 0x7)<<8) + ((data & 0xff00) >> 8)
+    mantisse = ((data & 0x7)<<8) + ((data & 0xff00) >> 8) #11 bits 2's complement
+    if mantisse >= 2**10: mantisse-=2**11;
     output = mantisse * 2**expo
     return output
 
diff --git a/opcuaserv/yamlreader.py b/opcuaserv/yamlreader.py
index 3033ae8..35e9833 100644
--- a/opcuaserv/yamlreader.py
+++ b/opcuaserv/yamlreader.py
@@ -227,7 +227,7 @@ class yamlreader(yamlconfig):
         if dtype=="double": 
                 scale=v.get('scale',1.)
                 if scale in ["smbus_2bytes_to_float","smbus_2bytes_to_float_exp12","smbus_2bytes_to_float_exp13"]: 
-                     data2=[eval(scale)(d) for d in data2]
+                     data2=[float(eval(scale)(d)) for d in data2]
                 else:
                     scale=float(scale)
                     data2=[(d*scale) for d in data2]
@@ -252,6 +252,7 @@ class yamlreader(yamlconfig):
             data3=data2;
 #        print("OPCset",v['name'],data3[:64],mask)
         logging.info(str(("OPCset",v['name'],data3[:64])))
+        if v['name']=='UNB2_FPGA_POL_ERAM_IOUT': logging.warn(str((data3,data2,mask,var1.get_value(),[hex(d) for d in data])));
         if len(data3)==1: data3=data3[0];
         var1.set_value(data3);
 
-- 
GitLab