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

class ATIMAnalyzer(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.ENR2.ATIM1!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将HPSYS_RCC的ESR2_ATIM1置1以开启模块时钟")
                inst_error = 1
            if (HPSYS_RCC.RSTR2.ATIM1!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将HPSYS_RCC的RSTR2_ATIM1置0以释放模块复位")
                inst_error = 1
            ch1_pin  = HPSYS_CFG.ATIM1_PINR1.CH1_PIN
            ch2_pin  = HPSYS_CFG.ATIM1_PINR1.CH2_PIN
            ch3_pin  = HPSYS_CFG.ATIM1_PINR1.CH3_PIN
            ch4_pin  = HPSYS_CFG.ATIM1_PINR1.CH4_PIN
            ch1n_pin = HPSYS_CFG.ATIM1_PINR2.CH1N_PIN
            ch2n_pin = HPSYS_CFG.ATIM1_PINR2.CH2N_PIN
            ch3n_pin = HPSYS_CFG.ATIM1_PINR2.CH3N_PIN
            bk_pin   = HPSYS_CFG.ATIM1_PINR3.BK_PIN
            bk2_pin  = HPSYS_CFG.ATIM1_PINR3.BK2_PIN
            etr_pin  = HPSYS_CFG.ATIM1_PINR3.ETR_PIN
            tim_clkname = "pclk_hpsys"
            
        #检查CH1分配
        if (ch1_pin==0x3f):
            self.log(LogLevel.INFO, "CH1没有分配IO")
        elif (ch1_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH1分配的PA{ch1_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH1分配到PA{ch1_pin:02d}")
        #检查CH2分配
        if (ch2_pin==0x3f):
            self.log(LogLevel.INFO, "CH2没有分配IO")
        elif (ch2_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH2分配的PA{ch2_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH2分配到PA{ch2_pin:02d}")
        #检查CH3分配
        if (ch3_pin==0x3f):
            self.log(LogLevel.INFO, "CH3没有分配IO")
        elif (ch3_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH3分配的PA{ch3_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH3分配到PA{ch3_pin:02d}")
        #检查CH4分配
        if (ch4_pin==0x3f):
            self.log(LogLevel.INFO, "CH4没有分配IO")
        elif (ch4_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH4分配的PA{ch4_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH4分配到PA{ch4_pin:02d}")
        #检查CH1N分配
        if (ch1n_pin==0x3f):
            self.log(LogLevel.INFO, "CH1N没有分配IO")
        elif (ch1n_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH1N分配的PA{ch1n_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH1N分配到PA{ch1n_pin:02d}")
        #检查CH2N分配
        if (ch2n_pin==0x3f):
            self.log(LogLevel.INFO, "CH2N没有分配IO")
        elif (ch2n_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH2N分配的PA{ch2n_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH2N分配到PA{ch2n_pin:02d}")
        #检查CH3N分配
        if (ch3n_pin==0x3f):
            self.log(LogLevel.INFO, "CH3N没有分配IO")
        elif (ch1n_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"CH3N分配的PA{ch3n_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"CH3N分配到PA{ch3n_pin:02d}")
        #检查ETR分配
        if (etr_pin==0x3f):
            self.log(LogLevel.INFO, "ETR没有分配IO")
        elif (etr_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"ETR分配的PA{etr_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"ETR分配到PA{etr_pin:02d}")
        #检查BK分配
        if (bk_pin==0x3f):
            self.log(LogLevel.INFO, "BK没有分配IO")
        elif (bk_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"BK分配的PA{bk_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"BK分配到PA{bk_pin:02d}")
        #检查BK2分配
        if (bk2_pin==0x3f):
            self.log(LogLevel.INFO, "BK2没有分配IO")
        elif (bk2_pin>44):
            inst_error = 1
            self.log(LogLevel.ERROR, f"BK2分配的PA{bk2_pin:02d}不存在",\
                     "可分配IO为PA00~PA44")
        else:
            self.log(LogLevel.INFO, f"BK2分配到PA{bk2_pin:02d}")
            
        #前置检查结束，如果出错就中止分析
        if (inst_error==1):
            self.log(LogLevel.ERROR, f"{self.periph_name}上述初始配置发现错误，分析无法继续进行",\
                     "请将上述错误修正后重新启动分析")
            return
        #self.log(LogLevel.INFO, "初始配置分析完成，未发现错误，启动功能分析")

        #PINMUX检查
        HPSYS_PINMUX = self.read_peripheral("hpsys_pinmux")
        #CH1 IO检查
        if (ch1_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch1_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH1 PA{ch1_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch1_pin:02d}.FSEL设为5")
                inst_error = 1
        #CH2 IO检查
        if (ch2_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch2_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH2 PA{ch2_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch2_pin:02d}.FSEL设为5")
                inst_error = 1
        #CH3 IO检查
        if (ch3_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch3_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH3 PA{ch3_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch3_pin:02d}.FSEL设为5")
                inst_error = 1
        #CH4 IO检查
        if (ch4_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch4_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH4 PA{ch4_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch4_pin:02d}.FSEL设为5")
                inst_error = 1
        #CH1N IO检查
        if (ch1n_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch1n_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH1N PA{ch1n_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch1n_pin:02d}.FSEL设为5")
                inst_error = 1
        #CH2N IO检查
        if (ch2n_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch2n_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH1N PA{ch2n_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch2n_pin:02d}.FSEL设为5")
                inst_error = 1
        #CH3N IO检查
        if (ch3n_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{ch3n_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"CH1N PA{ch3n_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{ch3n_pin:02d}.FSEL设为5")
                inst_error = 1
        #ETR IO检查
        if (etr_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{etr_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"ETR PA{etr_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{etr_pin:02d}.FSEL设为5")
                inst_error = 1
        #BK IO检查
        if (bk_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{bk_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"BK PA{bk_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{bk_pin:02d}.FSEL设为5")
                inst_error = 1
        #BK2 IO检查
        if (bk2_pin<=44):
            if (HPSYS_PINMUX.__dict__[f"PAD_PA{bk2_pin:02d}"].FSEL != 5):
                self.log(LogLevel.ERROR, f"BK2 PA{bk2_pin:02d}功能错误，未选择TIM功能",\
                         f"应将HPSYS_PINMUX->PAD_PA{bk2_pin:02d}.FSEL设为5")
                inst_error = 1
                
        #读取ATIM寄存器
        ATIM = self.read_peripheral(self.periph_name)

        #基本计数信息
        rcc = RCCAnalyzer(self.device,"rcc",self.port,self.baudrate);
        tim_clk, = rcc.get_clk(tim_clkname);
        tim_freq = tim_clk / (ATIM.PSC.PSC + 1);
        tim_period = 1000/tim_freq;
        #打印频率信息
        self.log(LogLevel.INFO, f"源时钟{tim_clkname} {tim_clk}MHz,分频后计数时钟{tim_freq}MHz({tim_period:.1f}ns)")
        #打印计数信息
        if (ATIM.CR1.OPM):
            if (ATIM.RCR.REP > 0):
                tim_opm_str = f"重复{ATIM.RCR.REP}次"
            else:
                tim_opm_str = "单次"
        else:
            tim_opm_str = "循环"
        if (ATIM.ARR.ARR == 0):
            self.log(LogLevel.INFO, f"计数值未配置(ARR=0)")
        elif (ATIM.CR1.CMS == 0): #边沿对齐计数
            tim_cycle = tim_period*(ATIM.ARR.ARR+1)/1000
            if not (ATIM.CR1.DIR):
                self.log(LogLevel.INFO, f"{tim_opm_str}计数0->{ATIM.ARR.ARR},一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
            else:
                self.log(LogLevel.INFO, f"{tim_opm_str}计数{ATIM.ARR.ARR}->0,一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
        else: #中心对齐计数
            tim_cycle = tim_period*2*ATIM.ARR.ARR/1000
            if (ATIM.CR1.OPM):
                self.log(LogLevel.INFO, f"重复{(ATIM.RCR.REP+1)/2}次计数0->{ATIM.ARR.ARR}->0,一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
                if not (ATIM.RCR.REP & 1): #奇数次重复时
                    self.log(LogLevel.WARN, f"重复进行中心对齐计数时,最后一个周期当上升计数完成后就停止",\
                             "如果最后一个周期需要完整计数，需要将重复次数(ATIM.RCR.REP+1)配置为偶数")
            else:
                self.log(LogLevel.INFO, f"循环计数0->{ATIM.ARR.ARR}->0,一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
        if (ATIM.CR1.CEN):
            self.log(LogLevel.INFO, f"计数已启动，当前计数值{ATIM.CNT.CNT}")
        else:
            self.log(LogLevel.INFO, f"计数未启动")
        #死区计算
        if (ATIM.BDTR.DTG != 0):
            tim_deadtime = (ATIM.BDTR.DTG + 1) * 1000 / tim_clk
            if (ATIM.BDTR.DTPSC):
                tim_deadtime *= 16
            self.log(LogLevel.INFO, f"死区时间为{tim_deadtime:.0f}ns")
        else:
            self.log(LogLevel.INFO, f"没有配置死区")
        #寄存器锁
        if (ATIM.AF1.LOCK !=0):
                    self.log(LogLevel.WARN, f"已开启{ATIM.AF1.LOCK}级寄存器锁,部分寄存器无法改写",\
                             "复位后才能进行修改")
            
        #输出各通道状态
        for ch_num in range(1,5):
            if (ch_num<3):
                ch_ccs   = ATIM.CCMR1.__dict__[f"CC{ch_num}S"]
                ch_icf   = ATIM.CCMR1.__dict__[f"IC{ch_num}F"]
                ch_icpsc = ATIM.CCMR1.__dict__[f"IC{ch_num}PSC"]
                ch_ocm   = ATIM.CCMR1.__dict__[f"OC{ch_num}M"]
            else:
                ch_ccs   = ATIM.CCMR2.__dict__[f"CC{ch_num}S"]
                ch_icf   = ATIM.CCMR2.__dict__[f"IC{ch_num}F"]
                ch_icpsc = ATIM.CCMR2.__dict__[f"IC{ch_num}PSC"]
                ch_ocm   = ATIM.CCMR2.__dict__[f"OC{ch_num}M"]
            ch_ccp   = ATIM.CCER.__dict__[f"CC{ch_num}P"]
            ch_ccnp  = ATIM.CCER.__dict__[f"CC{ch_num}NP"]
            ch_cce   = ATIM.CCER.__dict__[f"CC{ch_num}E"]
            if (ch_num<4):
                ch_ccne = ATIM.CCER.__dict__[f"CC{ch_num}NE"]
            else:
                ch_ccne = 0
            ch_ccr   = ATIM.__dict__[f"CCR{ch_num}"].__dict__[f"CCR{ch_num}"]
            if (ch_ccs > 0): #输入捕获
                self.log(LogLevel.INFO, f"通道{ch_num}为输入捕获,最近捕获值为{ch_ccr}")
            else: #输出比较
                if (ch_cce):
                    if (ATIM.BDTR.MOE):
                        ch_cce_str = "当前输出开启"
                    else:
                        ch_cce_str = "当前输出使能，但MOE关闭，无法输出"
                else:
                    ch_cce_str = "当前输出关闭"
                if (ch_ccne):
                    if (ATIM.BDTR.MOE):
                        ch_ccne_str = "互补输出开启"
                    else:
                        ch_ccne_str = "互补输出使能，但MOE关闭，无法输出"
                else:
                    ch_ccne_str = "互补输出关闭"
                if (ch_ocm==6 or ch_ocm==7):
                    if (ATIM.CR1.CMS == 0): #边沿对齐
                        if (ATIM.CR1.DIR == 0): #递增计数
                            if (ch_ccr > ATIM.ARR.ARR):
                                ch_duty = 100;
                            else:
                                ch_duty = 100 * ch_ccr / (ATIM.ARR.ARR + 1);
                        else: #递减计数
                            if (ch_ccr >= ATIM.ARR.ARR):
                                ch_duty = 100;
                            else:
                                ch_duty = 100 * (ch_ccr + 1) / (ATIM.ARR.ARR + 1);
                        if (ch_ocm==7): #PWM mode 2
                            ch_duty = 100 - ch_duty;
                        if (ch_ccp): #output reversed
                            ch_duty = 100 - ch_duty;
                        #print (ch_duty)
                        self.log(LogLevel.INFO, f"通道{ch_num}为基础PWM输出,高电平占空比约{ch_duty:.0f}%,{ch_cce_str}")
                        self.log(LogLevel.INFO, f"通道{ch_num}{ch_ccne_str}")
                    else: #中心对齐
                        self.log(LogLevel.INFO, f"通道{ch_num}为中心对齐PWM输出,{ch_cce_str}")
                        self.log(LogLevel.INFO, f"通道{ch_num}{ch_ccne_str}")
                elif (ch_ocm==12 or ch_ocm==13):
                    self.log(LogLevel.INFO, f"通道{ch_num}为组合PWM输出,{ch_cce_str}")
                elif (ch_ocm==14 or ch_ocm==15):
                    self.log(LogLevel.INFO, f"通道{ch_num}为非对称PWM输出,{ch_cce_str}")
                    if (ATIM.CR1.CMS == 0): #边沿对齐
                        self.log(LogLevel.ERROR, f"非对称PWM应采用中心对齐计数",\
                                 "请检查配置")
                else:
                    self.log(LogLevel.INFO, f"通道{ch_num}为非PWM输出,{ch_cce_str}")

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

