#include "firmware/固件/drill_target/src/drill_pwm_stage.c"
#include <assert.h>
#include <stdio.h>
#include <string.h>
RCC_TypeDef rcc;GPIO_TypeDef ga,gb,gf;TIM_TypeDef timer;
static void fixture(void) {
 memset(&rcc,0,sizeof rcc);memset(&ga,0,sizeof ga);memset(&gb,0,sizeof gb);memset(&gf,0,sizeof gf);memset(&timer,0,sizeof timer);owned=false;
 rcc.CR=RCC_CR_HSION|RCC_CR_HSIRDY;rcc.CFGR=RCC_CFGR_SW_HSI|RCC_CFGR_SWS_HSI;
 rcc.AHB2ENR=RCC_AHB2ENR_GPIOAEN|RCC_AHB2ENR_GPIOBEN|RCC_AHB2ENR_GPIOFEN;
 for(unsigned p=5;p<=10;++p)if(p!=6)ga.MODER|=1u<<(p*2);
 gb.MODER=5;gf.MODER=4;
}
int main(void) {
 unsigned cases=0;fixture();assert(drill_pwm_stage_init());assert(drill_pwm_stage_available());
 GPIO_TypeDef ac=ga,bc=gb,fc=gf;
 for(unsigned value=0;value<65536;++value) {
  TIM_TypeDef before=timer;uint32_t expect=((uint32_t)value*400+32767)/65535;
  bool ok=drill_pwm_stage_write(value,32768,32768);
  assert(ok==(expect>16&&expect<384));
  if(ok)assert(timer.CCR1==expect&&timer.CCR2==200&&timer.CCR3==200);
  else assert(memcmp(&timer,&before,sizeof timer)==0);
  assert(timer.CCER==0&&!(timer.BDTR&TIM_BDTR_MOE)&&!(timer.CR1&TIM_CR1_CEN));++cases;
 }
 assert(memcmp(&ga,&ac,sizeof ga)==0&&memcmp(&gb,&bc,sizeof gb)==0&&memcmp(&gf,&fc,sizeof gf)==0);
 for(unsigned field=0;field<6;++field)for(unsigned bit=0;bit<32;++bit) {
  fixture();assert(drill_pwm_stage_init());
  volatile uint32_t *regs[]={&timer.CR1,&timer.CR2,&timer.SMCR,&timer.DIER,&timer.CCER,&timer.BDTR};
  *regs[field]^=1u<<bit;TIM_TypeDef before=timer;
  assert(!drill_pwm_stage_available());assert(!drill_pwm_stage_write(32768,32768,32768));assert(memcmp(&timer,&before,sizeof timer)==0);++cases;
 }
 for(unsigned mode=0;mode<4;++mode)for(unsigned pin=0;pin<8;++pin) {
  fixture();GPIO_TypeDef *ps[]={&ga,&gf,&ga,&ga,&ga,&ga,&gb,&gb};unsigned pins[]={5,1,7,8,9,10,0,1};
  ps[pin]->MODER=(ps[pin]->MODER&~(3u<<(2*pins[pin])))|(mode<<(2*pins[pin]));
  bool ok=drill_pwm_stage_init();assert(ok==(mode==1));++cases;
 }
 for(unsigned fault=0;fault<10;++fault) {
  fixture();if(fault==0)rcc.CR&=~RCC_CR_HSIRDY;if(fault==1)rcc.CR|=RCC_CR_HSEON;
  if(fault==2)rcc.CFGR=RCC_CFGR_SW_PLL|RCC_CFGR_SWS_PLL;if(fault==3)rcc.CFGR|=RCC_CFGR_HPRE_DIV2;
  if(fault==4)rcc.CFGR|=RCC_CFGR_PPRE2_DIV2;if(fault==5)rcc.AHB2ENR=0;
  if(fault==6)rcc.APB2ENR|=RCC_APB2ENR_TIM1EN;if(fault==7)ga.IDR|=1u<<5;
  if(fault==8)gf.ODR|=2;if(fault==9)gb.OTYPER|=1;
  TIM_TypeDef before=timer;assert(!drill_pwm_stage_init());assert(memcmp(&timer,&before,sizeof timer)==0);++cases;
 }
 fixture();assert(drill_pwm_stage_init());TIM_TypeDef before=timer;
 assert(!drill_pwm_stage_write(32768,0,32768));assert(memcmp(&timer,&before,sizeof timer)==0);++cases;
 assert(!drill_pwm_stage_write(32768,32768,65535));assert(memcmp(&timer,&before,sizeof timer)==0);++cases;
 puts("PWM GPIO UNCHANGED, TIMER NEVER STARTED, NO MOE/CHANNEL ENABLE");printf("%u PWM STAGE CASES PASS\n",cases);
}
