From 515a9aa8beab0316869695855e5feb7b1a6a594d Mon Sep 17 00:00:00 2001
From: Gijs <schoonderbeek@astron.nl>
Date: Tue, 11 Oct 2022 17:57:23 +0200
Subject: [PATCH] Added setting of the output voltage

---
 production_apspu.py | 318 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 318 insertions(+)
 create mode 100644 production_apspu.py

diff --git a/production_apspu.py b/production_apspu.py
new file mode 100644
index 0000000..de71804
--- /dev/null
+++ b/production_apspu.py
@@ -0,0 +1,318 @@
+"""
+Copyright 2021 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
+ASTRON Netherlands Institute for Radio Astronomy
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+  Created: 2021-05-10
+This file contains the UniBoard2 class with all monitoring function. It can be used stand-alone to test it.
+
+"""
+
+import sys
+sys.path.insert(0, '.')
+import os
+import math
+# import time
+from APSPU_I2C import *
+if os.name == "posix":
+    from I2C_serial_pi2 import *
+else:
+    from I2C_serial import *
+
+
+I2CBUSNR = 3
+DEBUG = False
+
+class ApspuClass:
+    #
+    # Class that contains all parts on a UniBoard2
+    #
+    def __init__(self):
+        self.status = False
+        self.pols = []
+        for pol in list(CTR_POLS.keys()):
+            self.pols.append(PolClass(pol))
+        self.dev_i2c_eeprom = I2C(EEPROM)
+        self.dev_i2c_eeprom.bus_nr = I2CBUSNR
+        self.fans = FanmonitorClass()
+
+    def write_eeprom(self, data=0x01):
+        #
+        # Write the EEPROM with the serial number etc.
+        #
+        ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(0)
+        if ret_ack < 1:
+            print("EEPROM not found during write")
+            return False
+        else:
+            self.dev_i2c_eeprom.write_bytes(0x00, data)
+            sleep(0.1)
+            return True
+
+    def read_eeprom(self):
+        #
+        # Read the EEPROM with the serial number etc.
+        #
+        ret_ack, ret_value = self.dev_i2c_eeprom.read_last_reg(1)
+        if ret_ack < 1:
+            print("no EEPROM found during read")
+            return False
+        else:
+            ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(0x00, 1)
+            return ret_value
+
+    def wr_rd_eeprom(self, value=0x34):
+        #
+        # Write and Read the EEPROM to check functionality
+        #
+        if self.write_eeprom(value):
+            ret_value = self.read_eeprom()
+            stri = "Wrote to EEPROM: 0x{0:X}, Read from EEPROM: 0x{1} ".format(value, ret_value)
+            print(stri)
+        return True
+
+    def read_all(self):
+        #
+        # Function to read all monitoring points of the UniBoard
+        #
+        print("Read POLs")
+        for pol in self.pols:
+            pol.read_all()
+        self.fans.read_all()
+        return True
+
+    def print_status(self):
+        #
+        # Function to dump monitoring information on the screen
+        #
+        print("Power supplies")
+        for pol in self.pols:
+            pol.print_status()
+        self.wr_rd_eeprom()
+        self.fans.print_status()
+        return True
+
+    def set_pols(self):
+        for pol in self.pols:
+            pol.set_vout_pol(VOUT_POLS[pol.name])
+            pol.read_vout_set()
+        
+
+
+class PolClass:
+    #
+    # Class to read all monitoring points Point of Load DC/DC converter
+    #
+    def __init__(self, name):
+        #
+        # All monitoring points Point of Load DC/DC converter
+        #
+        self.name = name
+        self.vout = 0
+        self.iout = 0
+        self.temp = 0
+        self.pol_dev = I2C(CTR_POLS[self.name])
+        self.pol_dev.bus_nr = I2CBUSNR
+        ret_ack, ret_value = self.pol_dev.read_bytes(1)
+        if ret_ack < 1:
+            stri = " Device {0} at address 0x{1:X} not found".format(self.name, CTR_POLS[self.name])
+            print(stri)
+            self.status = False
+        else:
+            self.status = True
+
+
+    def read_vout_set(self):
+        #
+        # Function to read the output voltage of the Point of Load DC/DC converter
+        #
+        if self.status:
+            ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_COMMAND, 2)
+            if len(raw_value)<4:
+                raw_value = '0' + raw_value
+            ret_value = []
+            ret_value= int(raw_value[2:], 16) * 2**8  
+            ret_value += int(raw_value[:2], 16)
+            output_value = ret_value * 2**-11
+            print(f"Output set to: = {output_value} V using hex value {raw_value}")
+        return True
+
+    def set_vout_pol(self, value):
+        #
+        # Function to read the output voltage of the Point of Load DC/DC converter
+        #
+        if self.status:
+            set_value = int(value * (2**11))
+            hex_set_value = hex(set_value)
+            wr_value = (hex_set_value[4:6] + hex_set_value[2:4])
+            print(f"Calculated wr_value is {wr_value}")
+            wr_data =[]
+            wr_data.append(int(hex_set_value[4:6], 16))
+            wr_data.append(int(hex_set_value[2:4], 16))
+            ret_ack = self.pol_dev.write_bytes(LP_VOUT_COMMAND, wr_data)
+        return True
+
+
+    def read_vout(self):
+        #
+        # Function to read the output voltage of the Point of Load DC/DC converter
+        #
+        if self.status:
+            ret_ack, vout_mod = self.pol_dev.read_bytes(LP_VOUT_MODE, 1)
+            ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT, 2) 
+            vout_mod = int(vout_mod, 16)
+            ret_value = []
+            ret_value.append(int(raw_value[:2], 16))
+            ret_value.append(int(raw_value[2:], 16))
+            self.vout = calc_lin_3bytes(ret_value, [vout_mod])
+        else:
+            self.vout = 999
+ 
+    def read_iout(self):
+        #
+        # Function to read the output current of the Point of Load DC/DC converter
+        #
+        if self.status:
+            ret_ack, raw_value = self.pol_dev.read_bytes(0x39,2)
+            ret_ack, raw_value = self.pol_dev.read_bytes(LP_IOUT, 2)
+            ret_value = []
+            ret_value.append(int(raw_value[:2], 16))
+            ret_value.append(int(raw_value[2:], 16))
+            self.iout = calc_lin_2bytes(ret_value)
+        else:
+            self.iout = 999
+
+    def read_temp(self):
+        #
+        # Function to read the temperature of the Point of Load DC/DC converter
+        #
+        if self.status:
+            ret_ack, raw_value = self.pol_dev.read_bytes(LP_temp, 2)
+            ret_value = []
+            ret_value.append(int(raw_value[:2], 16))
+            ret_value.append(int(raw_value[2:], 16))
+            self.temp = calc_lin_2bytes(ret_value)
+        else:
+            self.temp = 999
+
+    def read_all(self):
+        #
+        # Function to read all monitoring points of the Point of Load DC/DC converter
+        #
+        self.read_vout()
+        self.read_iout()
+        self.read_temp()
+
+    def print_status(self):
+        #
+        # Function to dump all monitoring points of the Point of Load DC/DC converter on the screen
+        #
+        if self.status:
+            stri = "POL: " + self.name + "  "
+            stri += "Output voltage :{0: <5.2f} V ".format(self.vout)
+            stri += "Output Current :{0: <5.2f} A ".format(self.iout)
+            stri += "temperature :{0: <5.2f} Deg C".format(self.temp)
+            print(stri)
+            self.read_vout_set()
+
+class FanmonitorClass:
+    #
+    # Class to read all monitoring points Point of Load DC/DC converter
+    #
+    def __init__(self):
+        #
+        # All monitoring points Point of Load DC/DC converter
+        #
+        self.rpm = []
+        self.fanmonitor_dev = I2C(MAX6620)
+        self.fanmonitor_dev.bus_nr = I2CBUSNR
+        ret_ack, ret_value = self.fanmonitor_dev.read_bytes(1)
+        if ret_ack < 1:
+            stri = " Device {0} at address 0x{1:X} not found".format("MAX6620", MAX6620)
+            print(stri)
+            self.status = False
+        else:
+            if DEBUG:
+                stri = "Device {0} at address 0x{1:X} is found ".format("MAX6620", MAX6620)
+                print(stri)
+            self.set_active()
+            self.status = True
+
+    def set_active(self):
+        #
+        # Function to activate monitoring
+        #
+        ret_ack, reg_before = self.fanmonitor_dev.read_bytes(REG_GLOBAL, 1)
+        self.fanmonitor_dev.write_bytes(REG_GLOBAL, RUN_MONITOR)
+        ret_ack, reg_after = self.fanmonitor_dev.read_bytes(REG_GLOBAL, 1)
+        if DEBUG:
+            stri = "Reg at address 0x{0} before : {1} and after write action {2}".format(REG_GLOBAL, reg_before, reg_after)
+            print(stri)
+        fan_config_reg = int((math.log(TACH_PERIODS) / math.log(2))) << 5
+        for fan_cnt in range(NOF_APS_FANS):
+            self.fanmonitor_dev.write_bytes(0x02 + fan_cnt, 0x88)
+            self.fanmonitor_dev.write_bytes(0x06 + fan_cnt, fan_config_reg)
+
+    def read_fan(self, fan_nr):
+        #
+        # Function to a single fan
+        #
+        ret_ack, tach_msb = self.fanmonitor_dev.read_bytes(REG_TACH_MSP_REGS[fan_nr], 1)
+        tach_msb = int(tach_msb, 16) & 0xFF
+        if tach_msb > 254:
+            if DEBUG :
+                tach_lsb = 255
+                tach = 99999
+            rpm = 0
+        else:
+            ret_ack, tach_lsb = self.fanmonitor_dev.read_bytes(REG_TACH_LSP_REGS[fan_nr], 1)
+            tach_lsb = int(tach_lsb, 16) & 0xE0
+            tach = tach_msb*16 + tach_lsb/8
+            rpm = float((TACH_COUNT_FREQ*TACH_PERIODS*60))/(FAN_TACHS*tach)
+        if DEBUG:
+            stri = "MSP: {0}, LSB: {1}, TACH : {2}".format(tach_msb, tach_lsb, tach)
+            print(stri)
+        return rpm
+    
+    def read_all(self):
+        #
+        # Function to read all fan's
+        #
+        for fan_counter in range(NOF_APS_FANS):
+            self.rpm.append(self.read_fan(fan_counter))
+
+    def print_status(self):
+        #
+        # Function to dump all monitoring points of the Point of Load DC/DC converter on the screen
+        #
+        if self.status:
+            stri = "Fan speeds of "
+            for fan_cnt in range(len(self.rpm)):
+                stri += "FAN_" + str(fan_cnt+1)
+                stri += " :{0: <5.2f} RPM ".format(self.rpm[fan_cnt])
+            print(stri)
+
+
+def main():
+    #
+    # Function to test the class, read all info and dump on the screen
+    #
+    apspu = ApspuClass()
+    print("read / write EEPROM")
+    apspu.wr_rd_eeprom(value=0x34)
+    apspu.set_pols()
+    apspu.read_all()
+    apspu.print_status()
+
+
+if __name__ == "__main__":
+    main()
-- 
GitLab