#define main drill_entry
#include "firmware/固件/drill_target/src/main.c"
#undef main
#include "firmware/固件/drill_target/src/drill_clock.c"
#include "firmware/固件/drill_target/src/drill_timing.c"
#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 "firmware/固件/drill_target/src/drill_dual_adc.c"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "host_clock_fixture.h"
host_dwt_type dwt;host_debug_type coredebug;
#include <setjmp.h>
DMA_TypeDef dma;DMA_Channel_TypeDef dma_channel;DMAMUX_Channel_TypeDef mux;DMAMUX_ChannelStatus_TypeDef mux_status;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;
static unsigned stream_race;
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.AHB1RSTR&RCC_AHB1RSTR_DMA1RST){memset(&dma,0,sizeof dma);memset(&dma_channel,0,sizeof dma_channel);}
 if(rcc.AHB1RSTR&RCC_AHB1RSTR_DMAMUX1RST){memset(&mux,0,sizeof mux);memset(&mux_status,0,sizeof mux_status);}
 if(dma.IFCR){if(dma.IFCR&DMA_IFCR_CGIF1)dma.ISR&=~15u;else dma.ISR&=~dma.IFCR;dma.IFCR=0;}
 if(mux_status.CFR){mux_status.CSR&=~mux_status.CFR;mux_status.CFR=0;}
 if(stream_race){unsigned kind=stream_race;stream_race=0;if(kind==1)--dma_channel.CNDTR;if(kind==2)timer2.CNT+=31;if(kind==3)dma.ISR|=DMA_ISR_TEIF1;if(kind==4)adc2.ISR|=ADC_ISR_OVR;if(kind==5)timer2.CNT+=2;}
if(timer.EGR&TIM_EGR_UG){timer.CNT=0;timer.EGR=0;}if(adc2.ISR==ADC_ISR_ADRDY || adc2.ISR==(ADC_ISR_EOC|ADC_ISR_EOS|ADC_ISR_EOSMP))adc2.ISR=0;if(adc1.ISR==ADC_ISR_ADRDY || adc1.ISR==(ADC_ISR_EOC|ADC_ISR_EOS|ADC_ISR_EOSMP))adc1.ISR=0;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;}}
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);memset(&timer2,0,sizeof timer2);memset(&spi,0,sizeof spi);memset(&systick,0,sizeof systick);memset(&adc1,0,sizeof adc1);memset(&adc2,0,sizeof adc2);memset(&adc_common,0,sizeof adc_common);
 memset(&dma,0,sizeof dma);memset(&dma_channel,0,sizeof dma_channel);memset(&mux,0,sizeof mux);memset(&mux_status,0,sizeof mux_status);ds_owned=ds_pending=false;stream_race=0;
 owned=sampling_owned=timebase_owned=false;state=UNINITIALIZED;drill_config=(dc_runtime){0};drill_adc_state=DA_IDLE;drill_dual_state=DU_IDLE;drill_dual_error=0;host_clock_profile();
 drill_safe_boot();assert(drill_pwm_stage_init());assert(drill_timebase_init());assert(drill_spi_init(0));ga.MODER&=~(3u<<12);ga.ODR|=1u<<6;ga.IDR|=1u<<6;gf.BSRR=2u;host_dsb();drill_config.state=DC_READY;spi.SR=SPI_SR_TXE;
}
static void poll(uint32_t now){timer2.CNT=now;drill_config_service(now);drill_dual_poll(now);}
static void ready(uint32_t n){
 drill_config.last=n;
 assert(drill_dual_bench_begin(n,true));assert(drill_dual_state==DU_REG&&adc1.CR==ADC_CR_ADVREGEN&&adc2.CR==ADC_CR_ADVREGEN);
 assert(adc_common.CCR==0x30006&&adc1.CFGR==0x540&&adc2.CFGR==0&&adc1.SQR1==0x40&&adc2.SQR1==0x80&&adc1.SMPR1==0x10&&adc2.SMPR1==0x80);
 assert(timer.CR2==0x700000&&timer.CCR4==200&&timer.CCER==0&&!(timer.BDTR&TIM_BDTR_MOE)&&!(timer.CR1&TIM_CR1_CEN));
 poll(n+39);assert(drill_dual_state==DU_REG);poll(n+40);assert(drill_dual_state==DU_CAL&&(adc1.CR&ADC_CR_ADCAL)&&(adc2.CR&ADC_CR_ADCAL));
 adc1.CR&=~ADC_CR_ADCAL;poll(n+49);assert(drill_dual_state==DU_CAL);adc2.CR&=~ADC_CR_ADCAL;poll(n+50);assert(drill_dual_state==DU_GAP);poll(n+51);assert(!(adc1.CR&ADC_CR_ADEN));poll(n+52);assert(drill_dual_state==DU_ENABLE);
 adc1.ISR=ADC_ISR_ADRDY;poll(n+53);assert(drill_dual_state==DU_ENABLE);adc2.ISR=ADC_ISR_ADRDY;poll(n+55);assert(drill_dual_state==DU_READY&&drill_spi_available());
}
static void off(void){assert(drill_dual_state==DU_FAILED&&drill_config.state==DC_FAILED&&!sampling_owned);assert(!(rcc.AHB2ENR&RCC_AHB2ENR_ADC12EN));assert(!(gf.ODR&2u));assert(!(ga.ODR&((1u<<5)|(1u<<7)|(7u<<8)))&&!(gb.ODR&3u)&&(ga.ODR&(1u<<12)));assert(timer.CCER==0&&!(timer.CR1&TIM_CR1_CEN)&&!(timer.BDTR&TIM_BDTR_MOE));assert(!drill_dual_bench_begin(10000,true));}
static void streaming(uint32_t n){fixture();ready(n);timer2.CNT=n+60;assert(drill_dual_stream_start(n+60));assert(drill_dual_state==DU_STREAM&&dma_channel.CNDTR==2&&dma_channel.CCR==0x2aa1&&mux.CCR==5&&adc_common.CCR==0x3a006&&timer.CCER==0&&!(timer.BDTR&TIM_BDTR_MOE));}
static void transfer(uint32_t raw){unsigned index=(2u-dma_channel.CNDTR)&1u;ds_ring[index]=raw;if(dma_channel.CNDTR<=1){dma_channel.CNDTR=2;dma.ISR|=DMA_ISR_TCIF1;}else{--dma_channel.CNDTR;if(dma_channel.CNDTR==1)dma.ISR|=DMA_ISR_HTIF1;}}
static void stream_off(void){off();assert(!ds_owned&&!ds_pending&&!(rcc.AHB1ENR&(RCC_AHB1ENR_DMA1EN|RCC_AHB1ENR_DMAMUX1EN)));assert(!(dma_channel.CCR&DMA_CCR_EN));}
int main(void){unsigned cases=0;
 for(unsigned wrap=0;wrap<2;++wrap){uint32_t n=wrap?UINT32_MAX-1000:0;streaming(n);uint32_t now=n+60;du_sample out;memset(&out,0xa5,sizeof out);du_sample old=out;assert(!drill_dual_stream_take(&out,now)&&!memcmp(&old,&out,sizeof out));
  for(unsigned i=0;i<64;++i){now+=25;poll(now);now+=25;timer2.CNT=now;transfer((uint32_t)(i&4095u)|((4095u-i)<<16));poll(now);assert(drill_dual_state==DU_STREAM&&ds_pending);assert(drill_dual_stream_take(&out,now)&&out.ia_raw==i&&out.ib_raw==4095-i&&out.sequence==i+1&&!out.calibration_verified&&out.observed_us==now);old=out;assert(!drill_dual_stream_take(&out,now)&&!memcmp(&old,&out,sizeof out));assert(!(dma.ISR&(DMA_ISR_HTIF1|DMA_ISR_TCIF1)));assert((gf.ODR&2u)&&timer.CCER==0&&!(timer.BDTR&TIM_BDTR_MOE));++cases;}
  drill_dual_stream_stop();stream_off();++cases;
 }
 /* Every selected DMA/DMAMUX config bit must be rejected. */
 for(unsigned reg=0;reg<4;++reg)for(unsigned bit=0;bit<32;++bit){streaming(0);volatile uint32_t *regs[]={&dma_channel.CCR,&dma_channel.CPAR,&dma_channel.CMAR,&mux.CCR};*regs[reg]^=1u<<bit;poll(61);stream_off();++cases;}
 for(unsigned mode=0;mode<15;++mode){streaming(0);du_sample out;memset(&out,0xa5,sizeof out);du_sample old=out;
  if(mode==0)poll(91);if(mode==1){poll(85);poll(110);poll(135);poll(160);poll(161);}if(mode==2){transfer(1);transfer(2);poll(61);}if(mode==3){transfer(1);poll(61);transfer(2);poll(62);}if(mode==4){dma_channel.CNDTR=17;poll(61);}if(mode==5){dma.ISR|=DMA_ISR_TEIF1;poll(61);}if(mode==6){mux_status.CSR|=DMAMUX_CSR_SOF0;poll(61);}if(mode==7){transfer(0x1000);poll(61);}if(mode==8){transfer(0x10000000);poll(61);}if(mode>=9&&mode<=12){transfer(0x08000800);stream_race=mode-8;poll(61);}if(mode==13){rcc.AHB1ENR|=RCC_AHB1ENR_DMA2EN;poll(61);}if(mode==14){transfer(1);poll(61);assert(!drill_dual_stream_take(&out,92));}
  stream_off();assert(!drill_dual_stream_take(&out,200)&&!memcmp(&out,&old,sizeof out));++cases;
 }
 /* Circular reload may be observed momentarily as zero. */
 streaming(0);uint32_t now=60;du_sample out;for(unsigned i=0;i<1;++i){now+=25;poll(now);now+=25;transfer(i);timer2.CNT=now;assert(drill_dual_stream_take(&out,now));}now+=25;poll(now);now+=25;ds_ring[1]=0x01230456;dma_channel.CNDTR=0;dma.ISR|=DMA_ISR_TCIF1;timer2.CNT=now;assert(drill_dual_stream_take(&out,now)&&out.ia_raw==0x456&&out.ib_raw==0x123&&out.sequence==2);dma_channel.CNDTR=2;assert(!drill_dual_stream_take(&out,now));++cases;drill_dual_stream_stop();stream_off();
 for(unsigned mode=0;mode<5;++mode){fixture();ready(0);ADC_Common_TypeDef before=adc_common;TIM_TypeDef oldtimer=timer;
  if(mode==0)rcc.AHB1ENR|=RCC_AHB1ENR_DMA1EN;if(mode==1)rcc.AHB1ENR|=RCC_AHB1ENR_DMAMUX1EN;if(mode==2)rcc.AHB1ENR|=RCC_AHB1ENR_DMA2EN;if(mode==3)rcc.AHB1RSTR|=RCC_AHB1RSTR_DMA1RST;if(mode==4)rcc.AHB1RSTR|=RCC_AHB1RSTR_DMAMUX1RST;
  assert(!drill_dual_stream_start(60)&&drill_dual_state==DU_READY&&!ds_owned&&!memcmp(&before,&adc_common,sizeof before)&&!memcmp(&oldtimer,&timer,sizeof oldtimer));++cases;
 }
 /* Completion flags prove the word transfer; a pre-latch counter is not published. */
 streaming(0);dma_channel.CNDTR=1;ds_ring[0]=0x04560123;timer2.CNT=80;assert(!drill_dual_stream_take(&out,80)&&drill_dual_state==DU_STREAM);dma.ISR|=DMA_ISR_HTIF1;timer2.CNT=81;assert(drill_dual_stream_take(&out,81)&&out.ia_raw==0x123&&out.ib_raw==0x456);++cases;drill_dual_stream_stop();stream_off();
 for(unsigned flags=0;flags<2;++flags){streaming(0);if(flags==0){dma_channel.CNDTR=1;dma.ISR|=DMA_ISR_HTIF1|DMA_ISR_TCIF1;}else dma.ISR|=DMA_ISR_HTIF1;poll(61);stream_off();++cases;}
 /* Main may pass the pre-poll timestamp again; take refreshes real TIM2. */
 streaming(0);timer2.CNT=80;transfer(0x04560123);stream_race=5;drill_dual_poll(80);assert(drill_dual_state==DU_STREAM&&ds_sample.observed_us==82);assert(drill_dual_stream_take(&out,80)&&out.observed_us==82&&out.ia_raw==0x123);++cases;drill_dual_stream_stop();stream_off();
 for(unsigned mode=0;mode<11;++mode){streaming(0);
  if(mode==0)rcc.CR&=~RCC_CR_PLLRDY;if(mode==1)rcc.PLLCFGR^=RCC_PLLCFGR_PLLN_0;if(mode==2)rcc.CFGR|=RCC_CFGR_HPRE_DIV2;
  if(mode==3)rcc.CFGR|=RCC_CFGR_PPRE1_DIV2;if(mode==4)rcc.CFGR|=RCC_CFGR_PPRE2_DIV2;if(mode==5)pwr.CR1^=PWR_CR1_VOS_0;
  if(mode==6)pwr.CR5&=~PWR_CR5_R1MODE;if(mode==7)pwr.SR2|=PWR_SR2_VOSF;if(mode==8)flash.ACR=0;if(mode==9)SystemCoreClock=16000000;
  if(mode==10)rcc.APB1ENR1&=~RCC_APB1ENR1_PWREN;poll(61);stream_off();++cases;
 }
 printf("%u DMA STREAM / CONSUMER SOURCE MODEL SCENARIOS PASS\n",cases);
}
