"""
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2022 CERN
"""

import pytest
import subprocess
import time
import re
import os
import smbus

MONIMOD_ADDRESS = 0x12
MONIMOD_BUS = 0x9
MONIMOD_MFR_MODEL_BOOTLOADER = "DI/OT MoniMod (bl)"
MONIMOD_MFR_MODEL_MAIN = "DI/OT MoniMod"
MONIMOD_UPTIME_ADDR = 0xd7
MONIMOD_UPTIME_SIZE = 4
MONIMOD_TMR_ADDR = 0xd8
MONIMOD_TMR_SIZE = 4
MONIMOD_PEC_ON_MAGIC  = 0x37
MONIMOD_PEC_OFF_MAGIC = 0x0F


class monimod:
    FW_UNKNOWN = 0
    FW_BOOTLOADER = 1
    FW_MAIN = 2
    PEC_ON_MAGIC  = 0x37
    PEC_OFF_MAGIC = 0x0F

    cmd_ids = {
        "PAGE"               : 0x00,
        "CAPABILITY"         : 0x19,
        "QUERY"              : 0x1A,
        "VOUT_MODE"          : 0x20,
        "FAN_CONFIG_1_2"     : 0x3A,
        "FAN_COMMAND_1"      : 0x3B,
        "FAN_COMMAND_2"      : 0x3C,
        "FAN_CONFIG_3_4"     : 0x3D,
        "FAN_COMMAND_3"      : 0x3E,
        "STATUS_BYTE"        : 0x78,
        "STATUS_CML"         : 0x7E,
        "READ_VOUT"          : 0x8B,
        "READ_IOUT"          : 0x8C,
        "READ_TEMPERATURE_1" : 0x8D,
        "READ_TEMPERATURE_2" : 0x8E,
        "READ_TEMPERATURE_3" : 0x8F,
        "READ_FAN_SPEED_1"   : 0x90,
        "READ_FAN_SPEED_2"   : 0x91,
        "READ_FAN_SPEED_3"   : 0x92,
        "READ_POUT"          : 0x96,
        "MFR_ID"             : 0x99,
        "MFR_MODEL"          : 0x9A,
        "MFR_REVISION"       : 0x9B,
        "MFR_LOCATION"       : 0x9C,
        "MFR_DATE"           : 0x9D,
        "MFR_SERIAL"         : 0x9E,
        "IC_DEVICE_REV"      : 0xAE,
        # manufacturer specific commands
        "WRITTEN_FW_SIZE"    : 0xD1,
        "WRITTEN_FW_BLOCK"   : 0xD2,
        "WRITTEN_FW_CHKSUM"  : 0xD3,
        "LOCAL_FW_CHKSUM"    : 0xD4,
        "BOOT_NEW_FW"        : 0xD5,
        "UC_RESET"           : 0xD6,
        "UPTIME_SECS"        : 0xD7,
        "TMR_ERROR_CNT"      : 0xD8,
        "USE_PEC"            : 0xD9,
        "TEMP_CURVE_POINTS"  : 0xE0,
        "TEMP_MATRIX_ROW"    : 0xE1,
        "TC_ONOFF"           : 0xE2,

        "DUMMY"              : 0xfe,
        "PMBUS_COMMAND_EXT"  : 0xFF,
    }

    def __init__(self):
        self.bus = smbus.SMBus(MONIMOD_BUS)

    def var_to_str(self, var_as_ints):
        return "".join([chr(x) for x in var_as_ints])

    def pmbus_read_byte_cmd(self, cmd):
        return self.bus.read_byte_data(MONIMOD_ADDRESS, cmd)

    def pmbus_write_byte_cmd(self, cmd, data):
        return self.bus.write_byte_data(MONIMOD_ADDRESS, cmd, data)

    def pmbus_read_word_cmd(self, cmd):
        return self.bus.read_word_data(MONIMOD_ADDRESS, cmd)

    def pmbus_write_word_cmd(self, cmd, data):
        return self.bus.write_word_data(MONIMOD_ADDRESS, cmd, data)

    def pmbus_read_block_cmd(self, cmd):
        return self.bus.read_block_data(MONIMOD_ADDRESS, cmd)

    def pmbus_write_block_cmd(self, cmd, data):
        return self.bus.write_block_data(MONIMOD_ADDRESS, cmd, data)

    def read_i2c_block_data(self, cmd, read_size):
        return self.bus.read_i2c_block_data(MONIMOD_ADDRESS, cmd, read_size)

    def pmbus_block_process_call(self, cmd, vals):
        return self.bus.block_process_call(MONIMOD_ADDRESS, cmd, vals)

    def write_i2c_block_data(self, cmd, data):
        return self.bus.write_i2c_block_data(MONIMOD_ADDRESS, cmd, data)

    def get_fw_mode(self):
        fw_model = self.pmbus_read_byte_cmd(self.cmd_ids["BOOT_NEW_FW"])
        if fw_model == self.FW_BOOTLOADER:
            return self.FW_BOOTLOADER
        if fw_model == self.FW_MAIN:
            return self.FW_MAIN
        return self.FW_UNKNOWN

    def switch_fw_mode(self):
        return self.pmbus_write_byte_cmd(self.cmd_ids["BOOT_NEW_FW"], 0xAD)

    def set_page(self, page):
        pass

    def get_uptime(self):
        data = self.pmbus_read_block_cmd(self.cmd_ids["UPTIME_SECS"])
        return int.from_bytes(bytes(data), "little")

    def get_tmr(self):
        data = self.pmbus_read_block_cmd(self.cmd_ids["TMR_ERROR_CNT"])
        return int.from_bytes(bytes(data), "little")

    def clear_tmr(self):
        data = self.pmbus_write_block_cmd(self.cmd_ids["TMR_ERROR_CNT"], [0,0,0,0])

    def set_pec(self, pec_val):
        # Turn off PEC in Linux i2c driver if enabled.
        # Setting PEC in Monimod is possible only with PEC disabled in
        # the linux driver.
        if self.bus.pec:
            self.bus.pec = False
        if pec_val:
            pec_magic = self.PEC_ON_MAGIC
        else:
            pec_magic = self.PEC_OFF_MAGIC
        self.pmbus_write_byte_cmd(self.cmd_ids["USE_PEC"], pec_magic)
        # Turn on PEC in Linux i2c driver if PEC was enabled in Monimod
        if pec_val:
            self.bus.pec = True

@pytest.fixture(scope="session")
def monimod_bus():
    monimod_instance = monimod()
    yield monimod_instance

def pytest_addoption(parser):
    pass

def pytest_configure(config):
    pass

