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


class USARTAnalyzer(Analyzer):
    def run(self):
        super().run()
        self.log(LogLevel.INFO, f"{self.periph_name}分析启动")
        inst_num = self.get_instance_num(self.periph_name)
        inst_error = 0
        
        #前置检查开始，如果出错就需要中止分析，以防读寄存器卡死或出现非法值
        HPSYS_RCC = self.read_peripheral("hpsys_rcc")
        HPSYS_CFG = self.read_peripheral("hpsys_cfg")
        #self.print_reg(HPSYS_CFG)
        
        #以下是根据实例编号需要区分的内容
        #检查时钟与复位
        if (inst_num==1):
            if (HPSYS_RCC.RSTR1.USART1!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将HPSYS_RCC的RSTR1_USART1置0以释放模块复位")
                inst_error = 1
            cts_pin = HPSYS_CFG.USART1_PINR.CTS_PIN
            rts_pin = HPSYS_CFG.USART1_PINR.RTS_PIN
            rxd_pin = HPSYS_CFG.USART1_PINR.RXD_PIN
            txd_pin = HPSYS_CFG.USART1_PINR.TXD_PIN
        elif (inst_num==2):
            if (HPSYS_RCC.ENR1.USART2!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将HPSYS_RCC的ESR1_USART2置1以开启模块时钟")
                inst_error = 1
            if (HPSYS_RCC.RSTR1.USART2!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将HPSYS_RCC的RSTR1_USART2置0以释放模块复位")
                inst_error = 1
            cts_pin = HPSYS_CFG.USART2_PINR.CTS_PIN
            rts_pin = HPSYS_CFG.USART2_PINR.RTS_PIN
            rxd_pin = HPSYS_CFG.USART2_PINR.RXD_PIN
            txd_pin = HPSYS_CFG.USART2_PINR.TXD_PIN
        elif (inst_num==3):
            if (HPSYS_RCC.ENR2.USART3!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将HPSYS_RCC的ESR2_USART3置1以开启模块时钟")
                inst_error = 1
            if (HPSYS_RCC.RSTR2.USART3!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将HPSYS_RCC的RSTR2_USART3置0以释放模块复位")
                inst_error = 1
            cts_pin = HPSYS_CFG.USART3_PINR.CTS_PIN
            rts_pin = HPSYS_CFG.USART3_PINR.RTS_PIN
            rxd_pin = HPSYS_CFG.USART3_PINR.RXD_PIN
            txd_pin = HPSYS_CFG.USART3_PINR.TXD_PIN
        elif (inst_num==4):
            HPSYS_AON = self.read_peripheral("hpsys_aon")
            if (HPSYS_AON.ISSR.LP_ACTIVE == 0):
                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_RCC.ENR1.USART4!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将LPSYS_RCC的ESR1_USART4置1以开启模块时钟")
                inst_error = 1
            if (LPSYS_RCC.RSTR1.USART4!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将LPSYS_RCC的RSTR1_USART4置0以释放模块复位")
                inst_error = 1
            cts_pin = LPSYS_CFG.USART4_PINR.CTS_PIN
            rts_pin = LPSYS_CFG.USART4_PINR.RTS_PIN
            rxd_pin = LPSYS_CFG.USART4_PINR.RXD_PIN
            txd_pin = LPSYS_CFG.USART4_PINR.TXD_PIN
        elif (inst_num==5):
            HPSYS_AON = self.read_peripheral("hpsys_aon")
            if (HPSYS_AON.ISSR.LP_ACTIVE == 0):
                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_RCC.ENR1.USART5!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将LPSYS_RCC的ESR1_USART5置1以开启模块时钟")
                inst_error = 1
            if (LPSYS_RCC.RSTR1.USART5!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将LPSYS_RCC的RSTR1_USART5置0以释放模块复位")
                inst_error = 1
            cts_pin = LPSYS_CFG.USART5_PINR.CTS_PIN
            rts_pin = LPSYS_CFG.USART5_PINR.RTS_PIN
            rxd_pin = LPSYS_CFG.USART5_PINR.RXD_PIN
            txd_pin = LPSYS_CFG.USART5_PINR.TXD_PIN
            
        if (inst_num<4): #HPSYS的USART
            #检查CTS分配
            if (cts_pin==0x3f):
                self.log(LogLevel.INFO, "CTS没有分配IO")
            elif (cts_pin>44):
                inst_error = 1
                self.log(LogLevel.ERROR, f"CTS分配的PA{cts_pin:02d}不存在",\
                         "可分配IO为PA00~PA44")
            else:
                self.log(LogLevel.INFO, f"CTS分配到PA{cts_pin:02d}")
            #检查RTS分配
            if (rts_pin==0x3f):
                self.log(LogLevel.INFO, "RTS没有分配IO")
            elif (rts_pin>44):
                inst_error = 1
                self.log(LogLevel.ERROR, f"RTS分配的PA{rts_pin:02d}不存在",\
                         "可分配IO为PA00~PA44")
            else:
                self.log(LogLevel.INFO, f"RTS分配到PA{rts_pin:02d}")
            #检查RXD分配
            if (rxd_pin==0x3f):
                self.log(LogLevel.WARN, "RXD没有分配IO",\
                         f"需将HPSYS_CFG->{self.periph_name.upper()}_PINR.RXD_PIN配置到对应IO")
            elif (rxd_pin>44):
                inst_error = 1
                self.log(LogLevel.ERROR, f"RXD分配的PA{rxd_pin:02d}不存在",\
                         "可分配IO为PA00~PA44")
            else:
                self.log(LogLevel.INFO, f"RXD分配到PA{rxd_pin:02d}")
            #检查TXD分配
            if (txd_pin==0x3f):
                self.log(LogLevel.WARN, "TXD没有分配IO",\
                         f"需将HPSYS_CFG->{self.periph_name.upper()}_PINR.TXD_PIN配置到对应IO")
            elif (txd_pin>44):
                inst_error = 1
                self.log(LogLevel.ERROR, f"TXD分配的PA{txd_pin:02d}不存在",\
                         "可分配IO为PA00~PA44")
            else:
                self.log(LogLevel.INFO, f"TXD分配到PA{txd_pin:02d}")
        else: #LPSYS的USART
            #检查CTS分配
            if (cts_pin==7):
                self.log(LogLevel.INFO, "CTS没有分配IO")
            elif (cts_pin>3):
                inst_error = 1
                self.log(LogLevel.ERROR, f"CTS分配的PB{cts_pin:02d}不存在",\
                         "可分配IO为PB00~PB03")
            else:
                self.log(LogLevel.INFO, f"CTS分配到PB{cts_pin:02d}")
            #检查RTS分配
            if (rts_pin==7):
                self.log(LogLevel.INFO, "RTS没有分配IO")
            elif (rts_pin>3):
                inst_error = 1
                self.log(LogLevel.ERROR, f"RTS分配的PB{rts_pin:02d}不存在",\
                         "可分配IO为PB00~PB03")
            else:
                self.log(LogLevel.INFO, f"RTS分配到PB{rts_pin:02d}")
            #检查RXD分配
            if (rxd_pin==7):
                self.log(LogLevel.WARN, "RXD没有分配IO",\
                         f"需将LPSYS_CFG->{self.periph_name.upper()}_PINR.RXD_PIN配置到对应IO")
            elif (rxd_pin>3):
                inst_error = 1
                self.log(LogLevel.ERROR, f"RXD分配的PB{rxd_pin:02d}不存在",\
                         "可分配IO为PB00~PB03")
            else:
                self.log(LogLevel.INFO, f"RXD分配到PB{rxd_pin:02d}")
            #检查TXD分配
            if (txd_pin==7):
                self.log(LogLevel.WARN, "TXD没有分配IO",\
                         f"需将LPSYS_CFG->{self.periph_name.upper()}_PINR.TXD_PIN配置到对应IO")
            elif (txd_pin>3):
                inst_error = 1
                self.log(LogLevel.ERROR, f"TXD分配的PB{txd_pin:02d}不存在",\
                         "可分配IO为PB00~PB03")
            else:
                self.log(LogLevel.INFO, f"TXD分配到PB{txd_pin:02d}")
            
        #TODO，check_pin_collision()

        #前置检查结束，如果出错就中止分析
        if (inst_error==1):
            self.log(LogLevel.ERROR, f"{self.periph_name}上述初始配置发现错误，分析无法继续进行",\
                     "请将上述错误修正后重新启动分析")
            return
        #self.log(LogLevel.INFO, "初始配置分析完成，未发现错误，启动功能分析")

        #PINMUX检查
        if (inst_num<4): #HPSYS的USART
            HPSYS_PINMUX = self.read_peripheral("hpsys_pinmux")
            #CTS IO检查
            if (cts_pin<=44):
                if (HPSYS_PINMUX.__dict__[f"PAD_PA{cts_pin:02d}"].FSEL != 4):
                    self.log(LogLevel.ERROR, f"CTS PA{cts_pin:02d}功能错误，未选择UART功能",\
                             f"应将HPSYS_PINMUX->PAD_PA{cts_pin:02d}.FSEL设为4")
                    inst_error = 1
                if (HPSYS_PINMUX.__dict__[f"PAD_PA{cts_pin:02d}"].IE != 1):
                    self.log(LogLevel.ERROR, f"CTS PA{cts_pin:02d}输入未使能",\
                             f"应将HPSYS_PINMUX->PAD_PA{cts_pin:02d}.IE设为1")
                    inst_error = 1
                if ((HPSYS_PINMUX.__dict__[f"PAD_PA{cts_pin:02d}"].PE == 1) and \
                    (HPSYS_PINMUX.__dict__[f"PAD_PA{cts_pin:02d}"].PS == 1)):
                    self.log(LogLevel.WARN, f"CTS PA{cts_pin:02d}内部上拉开启，可能产生漏电",\
                             f"可将HPSYS_PINMUX->PAD_PA{cts_pin:02d}.PS设为0改为内部下拉")
            #RTS IO检查
            if (rts_pin<=44):
                if (HPSYS_PINMUX.__dict__[f"PAD_PA{rts_pin:02d}"].FSEL != 4):
                    self.log(LogLevel.ERROR, f"RTS PA{rts_pin:02d}功能错误，未选择UART功能",\
                             f"应将HPSYS_PINMUX->PAD_PA{rts_pin:02d}.FSEL设为4")
                    inst_error = 1
                if ((HPSYS_PINMUX.__dict__[f"PAD_PA{rts_pin:02d}"].PE == 1) and \
                    (HPSYS_PINMUX.__dict__[f"PAD_PA{rts_pin:02d}"].PS == 1)):
                    self.log(LogLevel.WARN, f"RTS PA{rts_pin:02d}内部上拉开启，可能产生漏电",\
                             f"可将HPSYS_PINMUX->PAD_PA{rts_pin:02d}.PE设为0以关闭内部上拉")
            #RXD IO检查
            if (rxd_pin<=44):
                if (HPSYS_PINMUX.__dict__[f"PAD_PA{rxd_pin:02d}"].FSEL != 4):
                    self.log(LogLevel.ERROR, f"RXD PA{rxd_pin:02d}功能错误，未选择UART功能",\
                             f"应将HPSYS_PINMUX->PAD_PA{rxd_pin:02d}.FSEL设为4")
                    inst_error = 1
                if (HPSYS_PINMUX.__dict__[f"PAD_PA{rxd_pin:02d}"].IE != 1):
                    self.log(LogLevel.ERROR, f"RXD PA{rxd_pin:02d}输入未使能",\
                             f"应将HPSYS_PINMUX->PAD_PA{rxd_pin:02d}.IE设为1")
                    inst_error = 1
                if ((HPSYS_PINMUX.__dict__[f"PAD_PA{rxd_pin:02d}"].PE == 1) and \
                    (HPSYS_PINMUX.__dict__[f"PAD_PA{rxd_pin:02d}"].PS == 0)):
                    self.log(LogLevel.WARN, f"RXD PA{rxd_pin:02d}内部下拉开启，可能产生漏电",\
                             f"可将HPSYS_PINMUX->PAD_PA{rxd_pin:02d}.PE设为0以关闭内部下拉")
            #TXD IO检查
            if (txd_pin<=44):
                if (HPSYS_PINMUX.__dict__[f"PAD_PA{txd_pin:02d}"].FSEL != 4):
                    self.log(LogLevel.ERROR, f"TXD PA{txd_pin:02d}功能错误，未选择UART功能",\
                             f"应将HPSYS_PINMUX->PAD_PA{txd_pin:02d}.FSEL设为4")
                    inst_error = 1
                if ((HPSYS_PINMUX.__dict__[f"PAD_PA{txd_pin:02d}"].PE == 1) and \
                    (HPSYS_PINMUX.__dict__[f"PAD_PA{txd_pin:02d}"].PS == 0)):
                    self.log(LogLevel.ERROR, f"TXD PA{txd_pin:02d}内部下拉开启，可能产生漏电",\
                             f"可将HPSYS_PINMUX->PAD_PA{txd_pin:02d}.PE设为0以关闭内部下拉")
                    inst_error = 1
        else: #LPSYS的USART
            LPSYS_PINMUX = self.read_peripheral("lpsys_pinmux")
            #CTS IO检查
            if (cts_pin<=3):
                if (LPSYS_PINMUX.__dict__[f"PAD_PB{cts_pin:02d}"].FSEL != 1):
                    self.log(LogLevel.ERROR, f"CTS PB{cts_pin:02d}功能错误，未选择UART功能",\
                             f"应将LPSYS_PINMUX->PAD_PB{cts_pin:02d}.FSEL设为1")
                    inst_error = 1
                if (LPSYS_PINMUX.__dict__[f"PAD_PB{cts_pin:02d}"].IE != 1):
                    self.log(LogLevel.ERROR, f"CTS PB{cts_pin:02d}输入未使能",\
                             f"应将LPSYS_PINMUX->PAD_PB{cts_pin:02d}.IE设为1")
                    inst_error = 1
                if ((LPSYS_PINMUX.__dict__[f"PAD_PB{cts_pin:02d}"].PE == 1) and \
                    (LPSYS_PINMUX.__dict__[f"PAD_PB{cts_pin:02d}"].PS == 1)):
                    self.log(LogLevel.WARN, f"CTS PB{cts_pin:02d}内部上拉开启，可能产生漏电",\
                             f"可将LPSYS_PINMUX->PAD_PB{cts_pin:02d}.PS设为0改为内部下拉")
            #RTS IO检查
            if (rts_pin<=3):
                if (LPSYS_PINMUX.__dict__[f"PAD_PB{rts_pin:02d}"].FSEL != 1):
                    self.log(LogLevel.ERROR, f"RTS PB{rts_pin:02d}功能错误，未选择UART功能",\
                             f"应将LPSYS_PINMUX->PAD_PB{rts_pin:02d}.FSEL设为1")
                    inst_error = 1
                if ((LPSYS_PINMUX.__dict__[f"PAD_PB{rts_pin:02d}"].PE == 1) and \
                    (LPSYS_PINMUX.__dict__[f"PAD_PB{rts_pin:02d}"].PS == 1)):
                    self.log(LogLevel.WARN, f"RTS PB{rts_pin:02d}内部上拉开启，可能产生漏电",\
                             f"可将LPSYS_PINMUX->PAD_PB{rts_pin:02d}.PE设为0以关闭内部上拉")
            #RXD IO检查
            if (rxd_pin<=3):
                if (LPSYS_PINMUX.__dict__[f"PAD_PB{rxd_pin:02d}"].FSEL != 1):
                    self.log(LogLevel.ERROR, f"RXD PB{rxd_pin:02d}功能错误，未选择UART功能",\
                             f"应将LPSYS_PINMUX->PAD_PB{rxd_pin:02d}.FSEL设为1")
                    inst_error = 1
                if (LPSYS_PINMUX.__dict__[f"PAD_PB{rxd_pin:02d}"].IE != 1):
                    self.log(LogLevel.ERROR, f"RXD PB{rxd_pin:02d}输入未使能",\
                             f"应将LPSYS_PINMUX->PAD_PB{rxd_pin:02d}.IE设为1")
                    inst_error = 1
                if ((LPSYS_PINMUX.__dict__[f"PAD_PB{rxd_pin:02d}"].PE == 1) and \
                    (LPSYS_PINMUX.__dict__[f"PAD_PB{rxd_pin:02d}"].PS == 0)):
                    self.log(LogLevel.WARN, f"RXD PB{rxd_pin:02d}内部下拉开启，可能产生漏电",\
                             f"可将LPSYS_PINMUX->PAD_PB{rxd_pin:02d}.PE设为0以关闭内部下拉")
            #TXD IO检查
            if (txd_pin<=3):
                if (LPSYS_PINMUX.__dict__[f"PAD_PB{txd_pin:02d}"].FSEL != 1):
                    self.log(LogLevel.ERROR, f"TXD PB{txd_pin:02d}功能错误，未选择UART功能",\
                             f"应将LPSYS_PINMUX->PAD_PB{txd_pin:02d}.FSEL设为1")
                    inst_error = 1
                if ((LPSYS_PINMUX.__dict__[f"PAD_PB{txd_pin:02d}"].PE == 1) and \
                    (LPSYS_PINMUX.__dict__[f"PAD_PB{txd_pin:02d}"].PS == 0)):
                    self.log(LogLevel.ERROR, f"TXD PB{txd_pin:02d}内部下拉开启，可能产生漏电",\
                             f"可将LPSYS_PINMUX->PAD_PB{txd_pin:02d}.PE设为0以关闭内部下拉")
                    inst_error = 1
                
        #以下是各实例共同的内容 
        #读取USART寄存器
        USART = self.read_peripheral(self.periph_name)

        #检查USART波特率
##        i2c_mode = I2C.CR.MODE;
##        if (i2c_mode == 0):
##            self.log(LogLevel.INFO, "I2C为标准模式(standard-mode)")
##            if (I2C.LCR.SLV > (2*I2C.WCR.CNT + 6)):
##                i2c_freq = 48000/(2*I2C.LCR.SLV + 7 + I2C.CR.DNF);
##            else:
##                i2c_freq = 48000/(I2C.LCR.SLV + 2*I2C.WCR.CNT + 6 + 7 + I2C.CR.DNF);
##        elif (i2c_mode == 1):
##            self.log(LogLevel.INFO, "I2C为快速或快速增强模式(fast-mode/fast-mode plus)")
##            if (I2C.LCR.FLV > (2*I2C.WCR.CNT + 6)):
##                i2c_freq = 48000/(2*I2C.LCR.FLV + 7 + I2C.CR.DNF);
##            else:
##                i2c_freq = 48000/(I2C.LCR.FLV + 2*I2C.WCR.CNT + 6 + 7 + I2C.CR.DNF);
##        else:
##            self.log(LogLevel.WARN, "I2C为高速模式，需使用专用格式访问",\
##                     "请确认是否需要3.4M高速模式(HS-mode)")
##            i2c_freq = 48000/(I2C.LCR.HLVH + I2C.LCR.HLVL + 7 + 2*I2C.CR.DNF);
##        self.log(LogLevel.INFO, f"接口频率约{i2c_freq:.0f}kHz")
##        if (i2c_freq >= 1000):
##            self.log(LogLevel.INFO, "外部上拉电阻推荐1K欧")
##        elif (i2c_freq >= 400):
##            self.log(LogLevel.INFO, "外部上拉电阻推荐4.7K欧")

        #检查USART模块状态
        #TODO

            
        #输出分析结果
        if (inst_error==1):
            self.log(LogLevel.ERROR, f"{self.periph_name}配置发现错误",\
                     "请检查配置")
        else:
            self.log(LogLevel.INFO, f"{self.periph_name}分析结束，未发现错误")
        
register_analyzer("USART", USARTAnalyzer)

