#******************************************#
# Read hardware info from UNB2c
# Created: 2021-05-10
#******************************************#

import sys
import time
sys.path.insert(0,'.')
import os
if os.name =="posix":
    from I2C_serial_pi import *
else:
    from I2C_serial import *

from UniBoard2_I2C import *
I2CBUSNR=3

QSFP_PORT=[]
QSFP_PORT.append(0x08)
QSFP_PORT.append(0x04)
QSFP_PORT.append(0x02)
QSFP_PORT.append(0x01)
QSFP_PORT.append(0x40)
QSFP_PORT.append(0x80)

def rw_eeprom(value=0xAB):
    I2C_eeprom = I2C(0x53)
    I2C_eeprom.bus = I2CBUSNR
    ret_ack, ret_value = I2C_eeprom.read_bytes(0)
    if ret_ack < 1:
        print("no device found")
    else:
        pr_stri = "Found device at address 0x{:02x}".format(I2C_eeprom.I2C_Address)
        print(pr_stri)
        I2C_eeprom.write_bytes(0x00, value)
        ret_ack, ret_value = I2C_eeprom.read_bytes(0x00, 1)
        stri = "Wrote to EEPROM: {0}, Read from EEPROM: {1} ".format(value, ret_value)
        print(stri)

def front_led(value=0xFF):
    main_switch = I2C(0x71)
    main_switch.bus = I2CBUSNR
    ret_ack = main_switch.write_bytes(0x20,0x20) #select LED
    if ret_ack < 1:
        print("Main I2C switch not found")
    else:
        front = I2C(0x41)
        front.bus = I2CBUSNR
        ret_ack = front.write_bytes(0x03, 0)
        if ret_ack < 1:
            print("Front LED driver not found")
        else:
            front.write_bytes(0x01, value)
            sleep(0.5)
            for cnt in range(6):
                front.write_bytes(0x01, (1 << cnt%3)^0xff)
                sleep(0.2)
            front.write_bytes(0x01, 0)
            sleep(0.2)
            front.write_bytes(0x01, 0xf)

def read_pol(node_nr, i2c_addr):
    main_switch = I2C(0x71)
    main_switch.bus = I2CBUSNR
    ret_ack = main_switch.write_bytes(0x0, 0x01<<node_nr) #select Node
    if ret_ack < 1:
        print("Main I2C switch not found")
    else:
        node_switch = I2C(0x72)
        node_switch.bus = I2CBUSNR
        ret_ack = node_switch.write_bytes(0x0, 0x20) #select DDR4
        if ret_ack < 1:
            print("Node I2C switch not found")
        else:
            LOC_PWR = I2C(i2c_addr)
            LOC_PWR.bus = I2CBUSNR
            ret_ack, ret_value = LOC_PWR.read_bytes(0)
            if ret_ack < 1:
                print("no device found")
            else:
    #            pr_stri = "Found device at address 0x{:02x}".format(LOC_PWR.I2C_Address)
    #            print(pr_stri)
                ret_ack, vout_mod = LOC_PWR.read_bytes(LP_VOUT, 2)
    #            vout_mod = int(vout_mod,16)
    #            vout = calc_lin_3bytes(ret_value, vout_mod)
                ret_ack,raw_value = LOC_PWR.read_bytes(LP_IOUT, 2)
                ret_value=[]
                ret_value.append(int(raw_value[:2],16))
                ret_value.append(int(raw_value[2:],16))
                iout = calc_lin_2bytes(ret_value)
                stri="Output Current :{0:2.2f} A".format(iout)
                print(stri)
                ret_ack,raw_value = LOC_PWR.read_bytes(LP_temp, 2)
                ret_value=[]
                ret_value.append(int(raw_value[:2],16))
                ret_value.append(int(raw_value[2:],16))
                temp = calc_lin_2bytes(ret_value)
                stri="temperature :{0:2.2f} Deg C".format(temp)
                print(stri)

def read_ddr(node_nr = 0, module=0):
    main_switch = I2C(0x71)
    main_switch.bus = I2CBUSNR
    ret_ack = main_switch.write_bytes(0x0, 0x01<<node_nr) #select Node
    if ret_ack < 1:
        print("Main I2C switch not found")
    else:
        node_switch = I2C(0x72)
        node_switch.bus = I2CBUSNR
        ret_ack = node_switch.write_bytes(0x0, 0x10) #select DDR4
        if ret_ack < 1:
            print("Node I2C switch not found")
        else:
            if module==0:
                ddr_module = I2C(MB_I_TEMP_I2C_ADDR)
            else:
                ddr_module = I2C(MB_II_TEMP_I2C_ADDR)
            ddr_module.bus = I2CBUSNR
            ret_ack, raw_ret = ddr_module.read_bytes(MB_TEMP_REG, 2)
            if ret_ack < 1:
                stri = "No DDR moduel in slot {0} node  {1}".format(module, node_nr)
            else:
                ret_value=[]
                ret_value.append(int(raw_ret[:2],16))
                ret_value.append(int(raw_ret[2:],16))
                temp = (((ret_value[0] & 0x1F) * 0x100) + (ret_value[1] & 0xFC)) * 0.0625
                stri = "Temperature DDR4 in slot {0} node  {1} is {2:3.2f} C".format(module, node_nr, temp)
            print(stri)

def read_qsfp(node_nr = 0, module=0):
    main_switch = I2C(0x71)
    main_switch.bus = I2CBUSNR
    ret_ack = main_switch.write_bytes(0x00, 0x01<<node_nr) #select Node
    if ret_ack < 1:
        print("Main I2C switch not found")
    else:
        node_switch = I2C(0x72)
        node_switch.bus = I2CBUSNR
        ret_ack = node_switch.write_bytes(0x0, QSFP_PORT[module]) #select QSFP cage 1
        if ret_ack < 1:
            print("Node I2C switch not found")
        else:
            QSFP_cage = I2C(QSFP_I2C_ADDR)
            QSFP_cage.bus = I2CBUSNR
            ret_ack, raw_ret = QSFP_cage.read_bytes(QSFP_TEMP, 2)
            if (ret_ack < 1) | (raw_ret[:2]=='ff'):
                stri = "No QSFP module in slot {0} node  {1}".format(module, node_nr)
                print(stri)
            else:
                ret_value=[]
                ret_value.append(int(raw_ret[:2],16))
                ret_value.append(int(raw_ret[2:],16))
                temp_in_mod = (ret_value[0] * 256 + ret_value[1]) / 256
                stri =  "Temperature QSFP in slot {0} node  {1} is {2:3.2f} gr. C".format(module, node_nr, temp_in_mod)
                print(stri)
                ret_ack, raw_ret = QSFP_cage.read_bytes(QSFP_VOLT, 2)
                ret_value.append(int(raw_ret[:2],16))
                ret_value.append(int(raw_ret[2:],16))
                Power_in_mod = (ret_value[0] * 256 + ret_value[1]) * 0.0001
                stri =  "Voltage QSFP in slot {0} node  {1} is {2:3.2f} V".format(module, node_nr, Power_in_mod)
                print(stri)

if 1:
    rw_eeprom(0xCD)
    front_led()
    for node_cnt in range(4):
        for module_cnt in range(2):
            read_ddr(node_nr=node_cnt,module=module_cnt)
    for node_cnt in range(4):
        for qsfp_cnt in range(6):
            read_qsfp(node_nr = node_cnt, module=qsfp_cnt)
    for node_cnt in range(4):
        read_pol(node_cnt, LOC_POWER_CORE)