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

class GPTIMAnalyzer(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.ENR1.GPTIM1!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将HPSYS_RCC的ESR1_GPTIM1置1以开启模块时钟")
                inst_error = 1
            if (HPSYS_RCC.RSTR1.GPTIM1!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将HPSYS_RCC的RSTR1_GPTIM1置0以释放模块复位")
                inst_error = 1
            ch1_pin = HPSYS_CFG.GPTIM1_PINR.CH1_PIN
            ch2_pin = HPSYS_CFG.GPTIM1_PINR.CH2_PIN
            ch3_pin = HPSYS_CFG.GPTIM1_PINR.CH3_PIN
            ch4_pin = HPSYS_CFG.GPTIM1_PINR.CH4_PIN
            etr_pin = HPSYS_CFG.ETR_PINR.ETR1_PIN
            tim_clkname = "pclk_hpsys"
        elif (inst_num==2):
            if (HPSYS_RCC.ENR1.GPTIM2!=1):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块时钟未开启",\
                         "需将HPSYS_RCC的ESR1_GPTIM2置1以开启模块时钟")
                inst_error = 1
            if (HPSYS_RCC.RSTR1.GPTIM2!=0):
                self.log(LogLevel.ERROR, f"{self.periph_name}模块被复位",\
                         "需将HPSYS_RCC的RSTR1_GPTIM2置0以释放模块复位")
                inst_error = 1
            ch1_pin = HPSYS_CFG.GPTIM2_PINR.CH1_PIN
            ch2_pin = HPSYS_CFG.GPTIM2_PINR.CH2_PIN
            ch3_pin = HPSYS_CFG.GPTIM2_PINR.CH3_PIN
            ch4_pin = HPSYS_CFG.GPTIM2_PINR.CH4_PIN
            etr_pin = HPSYS_CFG.ETR_PINR.ETR2_PIN
            tim_clkname = "clk_peri_hpsys"
            
        if (inst_num<3): #HPSYS的GPTIM
            #检查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}")
            #检查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}")
        else: #LPSYS的GPTIM
            return

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

        #PINMUX检查
        if (inst_num<3): #HPSYS的GPTIM
            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
            #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
        else: #LPSYS的GPTIM
            #LPSYS_PINMUX = self.read_peripheral("lpsys_pinmux")
            return

                
        #以下是各实例共同的内容 
        #读取GPTIM寄存器
        GPTIM = 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 / (GPTIM.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 (GPTIM.CR1.OPM):
            if (GPTIM.RCR.REP > 0):
                tim_opm_str = f"重复{GPTIM.RCR.REP}次"
            else:
                tim_opm_str = "单次"
        else:
            tim_opm_str = "循环"
        if (GPTIM.ARR.ARR == 0):
            self.log(LogLevel.INFO, f"计数值未配置(ARR=0)")
        elif (GPTIM.CR1.CMS == 0): #边沿对齐计数
            tim_cycle = tim_period*(GPTIM.ARR.ARR+1)/1000
            if not (GPTIM.CR1.DIR):
                self.log(LogLevel.INFO, f"{tim_opm_str}计数0->{GPTIM.ARR.ARR},一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
            else:
                self.log(LogLevel.INFO, f"{tim_opm_str}计数{GPTIM.ARR.ARR}->0,一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
        else: #中心对齐计数
            tim_cycle = tim_period*2*GPTIM.ARR.ARR/1000
            if (GPTIM.CR1.OPM):
                self.log(LogLevel.INFO, f"重复{(GPTIM.RCR.REP+1)/2}次计数0->{GPTIM.ARR.ARR}->0,一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
                if not (GPTIM.RCR.REP & 1): #奇数次重复时
                    self.log(LogLevel.WARN, f"重复进行中心对齐计数时,最后一个周期当上升计数完成后就停止",\
                             "如果最后一个周期需要完整计数，需要将重复次数(GPTIM.RCR.REP+1)配置为偶数")
            else:
                self.log(LogLevel.INFO, f"循环计数0->{GPTIM.ARR.ARR}->0,一次完整计数周期{tim_cycle:.3f}us({1000/tim_cycle:.3f}KHz)")
        if (GPTIM.CR1.CEN):
            self.log(LogLevel.INFO, f"计数已启动，当前计数值{GPTIM.CNT.CNT}")
        else:
            self.log(LogLevel.INFO, f"计数未启动")
            
        #检查GPTIM模块状态
        for ch_num in range(1,5):
            if (ch_num<3):
                ch_ccs   = GPTIM.CCMR1.__dict__[f"CC{ch_num}S"]
                ch_icf   = GPTIM.CCMR1.__dict__[f"IC{ch_num}F"]
                ch_icpsc = GPTIM.CCMR1.__dict__[f"IC{ch_num}PSC"]
                ch_ocm   = GPTIM.CCMR1.__dict__[f"OC{ch_num}M"]
            else:
                ch_ccs   = GPTIM.CCMR2.__dict__[f"CC{ch_num}S"]
                ch_icf   = GPTIM.CCMR2.__dict__[f"IC{ch_num}F"]
                ch_icpsc = GPTIM.CCMR2.__dict__[f"IC{ch_num}PSC"]
                ch_ocm   = GPTIM.CCMR2.__dict__[f"OC{ch_num}M"]
            ch_ccp   = GPTIM.CCER.__dict__[f"CC{ch_num}P"]
            ch_ccnp  = GPTIM.CCER.__dict__[f"CC{ch_num}NP"]
            ch_cce   = GPTIM.CCER.__dict__[f"CC{ch_num}E"]
            ch_ccr   = GPTIM.__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):
                    ch_cce_str = "当前输出开启"
                else:
                    ch_cce_str = "当前输出关闭"
                if (ch_ocm==6 or ch_ocm==7):
                    if (GPTIM.CR1.CMS == 0): #边沿对齐
                        if (GPTIM.CR1.DIR == 0): #递增计数
                            if (ch_ccr > GPTIM.ARR.ARR):
                                ch_duty = 100;
                            else:
                                ch_duty = 100 * ch_ccr / (GPTIM.ARR.ARR + 1);
                        else: #递减计数
                            if (ch_ccr >= GPTIM.ARR.ARR):
                                ch_duty = 100;
                            else:
                                ch_duty = 100 * (ch_ccr + 1) / (GPTIM.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}")
                    else: #中心对齐
                        self.log(LogLevel.INFO, f"通道{ch_num}为中心对齐PWM输出,{ch_cce_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 (GPTIM.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("GPTIM", GPTIMAnalyzer)

