# -- coding: utf-8 --
from analyzer import Analyzer
from analyzer import register_analyzer
from analyzer import LogLevel

class RCCAnalyzer(Analyzer):
    def run(self):
        super().run()
        inst_error = 0
        
        #HPSYS时钟检查
        if (self.periph_name.upper() == "HPSYS_RCC"):
            HPSYS_RCC = self.read_peripheral("hpsys_rcc")
            HPSYS_CFG = self.read_peripheral("hpsys_cfg")
            #检查当前工作模式
            if (HPSYS_CFG.SYSCR.LDO_VSEL):
                self.log(LogLevel.INFO, f"HPSYS当前为基础工作模式,系统最高频率48MHz")
            else:
                self.log(LogLevel.INFO, f"HPSYS当前为增强工作模式,系统最高频率240MHz")
            #TODO，检查clk_hrc48频率
            #输出clk_hpsys状态
            if (HPSYS_RCC.CSR.SEL_SYS_LP):
                self.log(LogLevel.ERROR, f"系统时钟被误切换到clk_wdt",\
                         "需将HPSYS_RCC的CSR.SEL_SYS_LP置0")
                inst_error = 1
            elif (HPSYS_RCC.CSR.SEL_SYS == 0):
                self.log(LogLevel.INFO, f"clk_hpsys时钟源是clk_hrc48")
            elif (HPSYS_RCC.CSR.SEL_SYS == 1):
                self.log(LogLevel.INFO, f"clk_hpsys时钟源是clk_hxt48")
            elif (HPSYS_RCC.CSR.SEL_SYS == 2):
                self.log(LogLevel.ERROR, f"系统时钟被误切换到源2",\
                         "HPSYS_RCC的CSR.SEL_SYS有效值为0,1,3")
                inst_error = 1
            elif (HPSYS_RCC.CSR.SEL_SYS == 3):
                self.log(LogLevel.INFO, f"clk_hpsys时钟源是clk_dll1")
                if (HPSYS_CFG.SYSCR.LDO_VSEL):
                    self.log(LogLevel.ERROR, f"基础工作模式不能使用clk_dll1",\
                             "基础工作模式下,HPSYS_RCC的CSR.SEL_SYS有效值为0,1")
                    inst_error = 1
            #输出clk_peri_hpsys状态
            if (HPSYS_RCC.CSR.SEL_PERI == 0):
                self.log(LogLevel.INFO, f"clk_peri_hpsys时钟源是clk_hrc48")
            else:
                self.log(LogLevel.INFO, f"clk_peri_hpsys时钟源是clk_hxt48")
            #输出时钟频率
            clk_hpsys,hclk_hpsys,pclk_hpsys,pclk2_hpsys,\
            clk_dll1,clk_dll2,clk_audpll \
            = self.get_clk("clk_hpsys","hclk_hpsys","pclk_hpsys","pclk2_hpsys",\
                           "clk_dll1","clk_dll2","clk_audpll")
            if (clk_hpsys == 999):
                self.log(LogLevel.ERROR, f"clk_hpsys频率获取异常")
                inst_error = 1
            elif (HPSYS_CFG.SYSCR.LDO_VSEL and clk_hpsys > 48):
                self.log(LogLevel.ERROR, f"clk_hpsys {clk_hpsys}MHz,超出48MHz频率上限")
                inst_error = 1
            elif (clk_hpsys > 240):
                self.log(LogLevel.ERROR, f"clk_hpsys {clk_hpsys}MHz,超出240MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"clk_hpsys {clk_hpsys}MHz")
            if (hclk_hpsys == 999):
                self.log(LogLevel.ERROR, f"hclk_hpsys频率获取异常")
                inst_error = 1
            elif (HPSYS_CFG.SYSCR.LDO_VSEL and hclk_hpsys > 48):
                self.log(LogLevel.ERROR, f"hclk_hpsys {hclk_hpsys}MHz,超出48MHz频率上限")
                inst_error = 1
            elif (hclk_hpsys > 240):
                self.log(LogLevel.ERROR, f"hclk_hpsys {hclk_hpsys}MHz,超出240MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"hclk_hpsys {hclk_hpsys}MHz")
            if (pclk_hpsys == 999):
                self.log(LogLevel.ERROR, f"pclk_hpsys频率获取异常")
                inst_error = 1
            elif (HPSYS_CFG.SYSCR.LDO_VSEL and pclk_hpsys > 48):
                self.log(LogLevel.ERROR, f"pclk_hpsys {pclk_hpsys}MHz,超出48MHz频率上限")
                inst_error = 1
            elif (pclk_hpsys > 120):
                self.log(LogLevel.ERROR, f"pclk_hpsys {pclk_hpsys}MHz,超出120MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"pclk_hpsys {pclk_hpsys}MHz")
            if (pclk2_hpsys == 999):
                self.log(LogLevel.ERROR, f"pclk2_hpsys频率获取异常")
                inst_error = 1
            elif (HPSYS_CFG.SYSCR.LDO_VSEL and pclk2_hpsys > 6):
                self.log(LogLevel.ERROR, f"pclk2_hpsys {pclk2_hpsys}MHz,超出6MHz频率上限")
                inst_error = 1
            elif (pclk2_hpsys > 7.5):
                self.log(LogLevel.ERROR, f"pclk2_hpsys {pclk2_hpsys}MHz,超出7.5MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"pclk2_hpsys {pclk2_hpsys}MHz")
            if (clk_dll1 == 999):
                self.log(LogLevel.ERROR, f"clk_dll1频率获取异常")
                inst_error = 1
            elif (clk_dll1 == 0):
                self.log(LogLevel.INFO, f"clk_dll1未开启")
            else:
                self.log(LogLevel.INFO, f"clk_dll1 {clk_dll1}MHz")
            if (clk_dll2 == 999):
                self.log(LogLevel.ERROR, f"clk_dll2频率获取异常")
                inst_error = 1
            elif (clk_dll2 == 0):
                self.log(LogLevel.INFO, f"clk_dll2未开启")
            else:
                self.log(LogLevel.INFO, f"clk_dll2 {clk_dll2}MHz")
##            if (clk_audpll == 999):
##                self.log(LogLevel.ERROR, f"clk_audpll频率获取异常")
##                inst_error = 1
##            elif (clk_audpll == 0):
##                self.log(LogLevel.INFO, f"clk_audpll未开启")
##            else:
##                self.log(LogLevel.INFO, f"clk_audpll {clk_audpll}MHz")

            #输出MPI功能时钟
            if (HPSYS_RCC.ENR2.MPI1):
                if (HPSYS_RCC.CSR.SEL_MPI1 == 0):
                    self.log(LogLevel.INFO, f"MPI1的功能时钟是clk_peri_hpsys(48MHz)")
                elif (HPSYS_RCC.CSR.SEL_MPI1 == 1):
                    self.log(LogLevel.INFO, f"MPI1的功能时钟是clk_dll1({clk_dll1}MHz)")
                    if (clk_dll1 == 0):
                        self.log(LogLevel.WARN, f"clk_dll1未开启，MPI1无法工作")
                elif (HPSYS_RCC.CSR.SEL_MPI1 == 2):
                    self.log(LogLevel.INFO, f"MPI1的功能时钟是clk_dll2({clk_dll2}MHz)")
                    if (clk_dll2 == 0):
                        self.log(LogLevel.WARN, f"clk_dll2未开启，MPI1无法工作")
                else:
                    self.log(LogLevel.ERROR, f"MPI1的功能时钟选择错误",\
                             "HPSYS_RCC的CSR.SEL_MPI1有效值为0,1,2")
                    inst_error = 1
            if (HPSYS_RCC.ENR2.MPI2):
                if (HPSYS_RCC.CSR.SEL_MPI2 == 0):
                    self.log(LogLevel.INFO, f"MPI2的功能时钟是clk_peri_hpsys(48MHz)")
                elif (HPSYS_RCC.CSR.SEL_MPI2 == 1):
                    self.log(LogLevel.INFO, f"MPI2的功能时钟是clk_dll1({clk_dll1}MHz)")
                    if (clk_dll1 == 0):
                        self.log(LogLevel.WARN, f"clk_dll1未开启，MPI1无法工作")
                elif (HPSYS_RCC.CSR.SEL_MPI2 == 2):
                    self.log(LogLevel.INFO, f"MPI2的功能时钟是clk_dll2({clk_dll2}MHz)")
                    if (clk_dll2 == 0):
                        self.log(LogLevel.WARN, f"clk_dll2未开启，MPI1无法工作")
                else:
                    self.log(LogLevel.ERROR, f"MPI2的功能时钟选择错误",\
                             "HPSYS_RCC的CSR.SEL_MPI2有效值为0,1,2")
                    inst_error = 1

        #LPSYS时钟检查
        elif (self.periph_name.upper() == "LPSYS_RCC"):
            HPSYS_AON = self.read_peripheral("hpsys_aon")
            if not (HPSYS_AON.ISSR.LP_ACTIVE):
                self.log(LogLevel.ERROR, f"LPSYS处于睡眠状态，无法访问{self.periph_name}",\
                         f"需将LPSYS唤醒后才能访问{self.periph_name}")
                inst_error = 1
                return
            LPSYS_RCC = self.read_peripheral("lpsys_rcc")
            LPSYS_CFG = self.read_peripheral("lpsys_cfg")
            #检查当前工作模式
            if (LPSYS_CFG.SYSCR.LDO_VSEL):
                self.log(LogLevel.INFO, f"LPSYS当前为增强工作模式,系统最高频率48MHz")
            else:
                self.log(LogLevel.INFO, f"LPSYS当前为基础工作模式,系统最高频率24MHz")
            #输出clk_lpsys状态
            if (LPSYS_RCC.CSR.SEL_SYS_LP):
                self.log(LogLevel.ERROR, f"系统时钟被误切换到clk_wdt",\
                         "需将LPSYS_RCC的CSR.SEL_SYS_LP置0")
                inst_error = 1
            elif (LPSYS_RCC.CSR.SEL_SYS == 0):
                self.log(LogLevel.INFO, f"clk_lpsys时钟源是clk_hrc48")
            elif (LPSYS_RCC.CSR.SEL_SYS == 1):
                self.log(LogLevel.INFO, f"clk_lpsys时钟源是clk_hxt48")
            #输出clk_peri_hpsys状态
            if (LPSYS_RCC.CSR.SEL_PERI == 0):
                self.log(LogLevel.INFO, f"clk_peri_lpsys时钟源是clk_hrc48")
            else:
                self.log(LogLevel.INFO, f"clk_peri_lpsys时钟源是clk_hxt48")
            #输出时钟频率
            clk_lpsys,hclk_lpsys,pclk_lpsys,pclk2_lpsys \
            = self.get_clk("clk_lpsys","hclk_lpsys","pclk_lpsys","pclk2_lpsys")
            if (clk_lpsys == 999):
                self.log(LogLevel.ERROR, f"clk_lpsys频率获取异常")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"clk_lpsys {clk_lpsys}MHz")
            if (hclk_lpsys == 999):
                self.log(LogLevel.ERROR, f"hclk_lpsys频率获取异常")
                inst_error = 1
            elif (not LPSYS_CFG.SYSCR.LDO_VSEL and hclk_lpsys > 24):
                self.log(LogLevel.ERROR, f"hclk_lpsys {hclk_lpsys}MHz,超出24MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"hclk_lpsys {hclk_lpsys}MHz")
            if (pclk_lpsys == 999):
                self.log(LogLevel.ERROR, f"pclk_lpsys频率获取异常")
                inst_error = 1
            elif (not LPSYS_CFG.SYSCR.LDO_VSEL and pclk_lpsys > 24):
                self.log(LogLevel.ERROR, f"pclk_lpsys {pclk_lpsys}MHz,超出24MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"pclk_lpsys {pclk_lpsys}MHz")
            if (pclk2_lpsys == 999):
                self.log(LogLevel.ERROR, f"pclk2_lpsys频率获取异常")
                inst_error = 1
            elif (LPSYS_CFG.SYSCR.LDO_VSEL and pclk2_lpsys > 6):
                self.log(LogLevel.ERROR, f"pclk2_lpsys {pclk2_lpsys}MHz,超出6MHz频率上限")
                inst_error = 1
            elif (not LPSYS_CFG.SYSCR.LDO_VSEL and pclk2_lpsys > 3):
                self.log(LogLevel.ERROR, f"pclk2_lpsys {pclk2_lpsys}MHz,超出3MHz频率上限")
                inst_error = 1
            else:
                self.log(LogLevel.INFO, f"pclk2_lpsys {pclk2_lpsys}MHz")
                
        if (inst_error==1):
            self.log(LogLevel.ERROR, f"{self.periph_name}配置发现错误",\
                     "请检查配置")
        else:
            self.log(LogLevel.INFO, f"{self.periph_name}分析结束，未发现错误")

    def get_clk(self,*clk_list):
        results = []
        inst_error = 0
        HPSYS_RCC = self.read_peripheral("hpsys_rcc")
        #self.print_reg(HPSYS_RCC)
        #计算clk_hpsys
        if (HPSYS_RCC.CSR.SEL_SYS_LP):
            self.log(LogLevel.ERROR, f"系统时钟被误切换到clk_wdt",\
                     "需将HPSYS_RCC的CSR.SEL_SYS_LP置0")
            inst_error = 1
        elif (HPSYS_RCC.CSR.SEL_SYS < 2):
            clk_hpsys = 48
        elif (HPSYS_RCC.CSR.SEL_SYS == 2):
            self.log(LogLevel.ERROR, f"系统时钟被误切换到源2",\
                     "HPSYS_RCC的CSR.SEL_SYS有效值为0，1，3")
            inst_error = 1
        else:
            clk_dll1 = 24 * (HPSYS_RCC.DLL1CR.STG + 1)
            if (HPSYS_RCC.DLL1CR.OUT_DIV2_EN):
                clk_dll1 /= 2;
            clk_hpsys = clk_dll1
        #计算hclk_hpsys
        if (inst_error == 0):
            if (HPSYS_RCC.CFGR.HDIV<2):
                hclk_hpsys = clk_hpsys
            else:
                hclk_hpsys = clk_hpsys / HPSYS_RCC.CFGR.HDIV
            pclk_hpsys = hclk_hpsys / (2 ** HPSYS_RCC.CFGR.PDIV1)
            pclk2_hpsys = hclk_hpsys / (2 ** HPSYS_RCC.CFGR.PDIV2)

        #根据传递的clk名称计算clk频率，并添加到返回值中
        for clk_name in clk_list:
            if (inst_error == 1):
                results.append(999) #返回值999表示执行出错
            elif (clk_name=="clk_hpsys"):
                results.append(clk_hpsys)
            elif (clk_name=="hclk_hpsys"):
                results.append(hclk_hpsys)
            elif (clk_name=="pclk_hpsys"):
                results.append(pclk_hpsys)
            elif (clk_name=="pclk2_hpsys"):
                results.append(pclk2_hpsys)
            elif (clk_name=="clk_peri_hpsys"):
                results.append(48)
            elif (clk_name=="clk_dll1"):
                if (HPSYS_RCC.DLL1CR.EN == 0):
                    clk_dll1 = 0;
                else:
                    clk_dll1 = 24 * (HPSYS_RCC.DLL1CR.STG + 1)
                    if (HPSYS_RCC.DLL1CR.OUT_DIV2_EN):
                        clk_dll1 /= 2;
                results.append(clk_dll1)
            elif (clk_name=="clk_dll2"):
                if (HPSYS_RCC.DLL2CR.EN == 0):
                    clk_dll2 = 0;
                else:
                    clk_dll2 = 24 * (HPSYS_RCC.DLL2CR.STG + 1)
                    if (HPSYS_RCC.DLL2CR.OUT_DIV2_EN):
                        clk_dll2 /= 2;
                results.append(clk_dll2)
            elif (clk_name=="clk_audpll"):
                clk_audpll = 999 #TODO
                results.append(clk_audpll)
            elif ("lpsys" in clk_name):
                HPSYS_AON = self.read_peripheral("hpsys_aon")
                if (HPSYS_AON.ISSR.LP_ACTIVE):
                    LPSYS_RCC = self.read_peripheral("lpsys_rcc")
                    clk_lpsys = 48
                    #计算hclk_lpsys
                    hclk_lpsys = clk_lpsys / LPSYS_RCC.CFGR.HDIV1
                    pclk_lpsys = hclk_lpsys / (2 ** LPSYS_RCC.CFGR.PDIV1)
                    pclk2_lpsys = hclk_lpsys / (2 ** LPSYS_RCC.CFGR.PDIV2)
                    if (clk_name=="clk_lpsys"):
                        results.append(clk_lpsys)
                    elif (clk_name=="hclk_lpsys"):
                        results.append(hclk_lpsys)
                    elif (clk_name=="pclk_lpsys"):
                        results.append(pclk_lpsys)
                    elif (clk_name=="pclk2_lpsys"):
                        results.append(pclk2_lpsys)
                    elif (clk_name=="clk_peri_lpsys"):
                        results.append(48)
                    else:
                        self.log(LogLevel.ERROR, f"{clk_name}是非法的clk名称",\
                                 "请检查clk名称")
                        results.append(999) #返回值999表示执行出错
                else:
                    self.log(LogLevel.ERROR, f"LPSYS处于睡眠状态，无法访问{clk_name}",\
                             "需将LPSYS唤醒后才能访问")
                    results.append(999)
            else:
                self.log(LogLevel.ERROR, f"{clk_name}是非法的clk名称",\
                         "请检查clk名称")
                results.append(999) #返回值999表示执行出错

        return tuple(results)
        
register_analyzer("HPSYS_RCC", RCCAnalyzer)
register_analyzer("LPSYS_RCC", RCCAnalyzer)

