#define main drill_entry
#include "firmware/固件/drill_target/src/main.c"
#undef main
#include "firmware/固件/drill_target/src/drill_pwm_stage.c"
#include "firmware/固件/drill_target/src/drill_spi_transport.c"
#include "firmware/固件/drill_target/src/drill_timebase.c"
#include "firmware/固件/drill_target/src/drill_safe_gpio.c"
#include "firmware/固件/drill_target/src/drill_config_binding.c"
#include "firmware/固件/drill_target/src/drill_config_async.c"
#include "firmware/固件/drill_driver/drv8316.c"
#include "firmware/固件/drill_target/src/drill_adc_capture.c"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
ADC_TypeDef adc1,adc2;ADC_Common_TypeDef adc_common;RCC_TypeDef rcc;GPIO_TypeDef ga,gb,gf;TIM_TypeDef timer,timer2;SPI_TypeDef spi;host_systick_type systick;unsigned host_systick_config_calls;
static jmp_buf returned;
static unsigned resets,wfi_calls;
void host_wait(void){if(++wfi_calls==1){timer2.CNT+=1000;SysTick_Handler();return;}longjmp(returned,1);}
static void pins(GPIO_TypeDef *p){p->ODR=(p->ODR|(p->BSRR&65535u))&~(p->BSRR>>16);p->IDR=p->ODR;p->BSRR=0;}
void host_dsb(void){if(rcc.AHB2RSTR&RCC_AHB2RSTR_ADC12RST){memset(&adc1,0,sizeof adc1);memset(&adc2,0,sizeof adc2);memset(&adc_common,0,sizeof adc_common);adc1.CR=adc2.CR=ADC_CR_DEEPPWD;}if(rcc.APB1RSTR1&RCC_APB1RSTR1_TIM2RST)memset(&timer2,0,sizeof timer2);if(rcc.APB1RSTR1&RCC_APB1RSTR1_SPI2RST)memset(&spi,0,sizeof spi);pins(&ga);pins(&gb);pins(&gf);if(rcc.APB2RSTR&RCC_APB2RSTR_TIM1RST){memset(&timer,0,sizeof timer);++resets;}}
int main(void){unsigned cases=0;
 for(unsigned mode=0;mode<24;++mode){
  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);memset(&timer2,0,sizeof timer2);memset(&spi,0,sizeof spi);memset(&systick,0,sizeof systick);
  owned=timebase_owned=false;state=UNINITIALIZED;drill_config=(dc_runtime){0};rcc.CR=RCC_CR_HSION|RCC_CR_HSIRDY;rcc.CFGR=RCC_CFGR_SW_HSI|RCC_CFGR_SWS_HSI;
  drill_safe_boot();assert(drill_pwm_stage_init());assert(drill_timebase_init());assert(drill_spi_init(0));ga.ODR|=1u<<6;ga.IDR|=1u<<6;
  assert(drill_config_bench_begin(0,true));unsigned responses=0;spi.SR=SPI_SR_TXE;
  for(uint32_t n=0;n<20000 && drill_config.state!=DC_READY && drill_config.state!=DC_FAILED;++n){
   timer2.CNT=n;uint32_t stamp;assert(drill_timebase_get(&stamp)&&stamp==n);
   if(state==RECEIVE && !(spi.SR&SPI_SR_RXNE)){
    unsigned step=responses++;unsigned adr=(tx>>9)&63;bool read=(tx&0x8000)!=0;static const unsigned expect[8]={3,0x42,0x4f,0x10,1,1,0,6};uint8_t data=0;
    if(step<3||step>=19)data=adr==0?8:0;
    else if(read)data=expect[(step-3)/2];
    if(mode<22 && step==mode)data|=0x80;
    spi.DR=0x0800|data;spi.SR=SPI_SR_TXE|SPI_SR_RXNE;
   }
   drill_spi_poll(stamp);if(state!=RECEIVE)spi.SR=SPI_SR_TXE;
   drill_config_service(stamp);
   assert(timer.CCER==0&&!(timer.CR1&TIM_CR1_CEN)&&!(timer.BDTR&TIM_BDTR_MOE));assert(!(ga.ODR&((1u<<5)|(1u<<7)|(7u<<8)))&&!(gb.ODR&3u)&&(ga.ODR&(1u<<12)));
  }
  /* A write's OLD data is not verified. Only status/read frames should reject data injection. */
  if(mode<3 || (mode>=3&&mode<19&&((mode-3)&1u)) || (mode>=19&&mode<22))assert(drill_config.state==DC_FAILED&&!(gf.ODR&2u));
  else assert(drill_config.state==DC_READY&&responses==22&&(gf.ODR&2u));
  if(mode==22){gf.ODR&=~2u;gf.IDR&=~2u;drill_config_service(timer2.CNT+1);assert(drill_config.state==DC_FAILED);}
  if(mode==23){ga.IDR&=~(1u<<6);drill_config_service(timer2.CNT+1);assert(drill_config.state==DC_FAILED);}
  ++cases;
 }
 printf("%u REAL SPI/CONFIG BINDING SCENARIOS PASS\n",cases);
}
