#include "host_stream_fixture.h"
static void timing_reset(void){
 drill_debug_timing_capture_request=drill_debug_timing_capture_epoch=0;drill_debug_timing_capture=(dt_snapshot){0};
 timing_owned=timing_failed=timing_open=previous_busy=have_previous=false;drill_debug_timing=(dt_record){0};
 memset(&dwt,0,sizeof dwt);memset(&coredebug,0,sizeof coredebug);timing_model_cycles_per_barrier=8;timing_model_fail_enable=false;
}
static void timing_ready(void){timing_reset();fixture();assert(drill_timing_init()&&drill_debug_timing.flags==1&&drill_debug_timing.windows==0);}
static void invalid(dt_fault f){assert(timing_failed&&drill_debug_timing.fault==(uint32_t)f&&!(drill_debug_timing.flags&2u)&&!(drill_debug_timing.epoch&1u));uint32_t n;assert(!drill_timing_begin(&n)&&!drill_timing_end(false)&&!drill_timing_init());}
int main(void){unsigned cases=0;uint32_t now;
 /* Real monitor boundary decisions, with both counters supplied by the model. */
 const uint32_t values[]={1,127,128,129,2048,3839,3840,3841,4096,UINT32_MAX};
 for(unsigned wrap=0;wrap<2;++wrap)for(unsigned i=0;i<sizeof values/sizeof values[0];++i){timing_ready();timer2.CNT=wrap?UINT32_MAX-15:10;dwt.CYCCNT=wrap?UINT32_MAX-127:1000;assert(drill_timing_begin(&now));
  timer2.CNT=begin_us+20;dwt.CYCCNT=begin_cycles+values[i];bool good=values[i]<=3840;assert(drill_timing_end(false)==good);assert(drill_debug_timing.last_cycles==values[i]&&drill_debug_timing.last_us==20);if(!good)invalid(DT_LIMIT);else assert(drill_debug_timing.flags==3&&drill_debug_timing.windows==1&&drill_debug_timing.active_windows==1);++cases;
 }
 for(unsigned wrap=0;wrap<2;++wrap)for(unsigned us=29;us<=31;++us){timing_ready();timer2.CNT=wrap?UINT32_MAX-15:100;assert(drill_timing_begin(&now));timer2.CNT=begin_us+us;dwt.CYCCNT=begin_cycles+2000;assert(drill_timing_end(true)==(us<=30));if(us==31)invalid(DT_LIMIT);else assert(!drill_debug_timing.active_windows);++cases;}
 /* Acquisition/startup counters must demonstrably progress; neither enabled bits
  * nor synthetic instruction counts qualify a frozen counter. */
 for(unsigned mode=0;mode<3;++mode){timing_reset();fixture();if(mode==0)dwt.CTRL=1u<<25;if(mode==1)timing_model_cycles_per_barrier=0;if(mode==2)timing_model_fail_enable=true;assert(!drill_timing_init());invalid(DT_COUNTER);++cases;}
 timing_reset();fixture();timer2.PSC^=1;assert(!drill_timing_init());invalid(DT_CLOCK);++cases;
 for(unsigned mode=0;mode<5;++mode){timing_ready();assert(drill_timing_begin(&now));
  if(mode==0)dwt.CTRL&=~1u;if(mode==1)coredebug.DEMCR&=~(1u<<24);if(mode==2)dwt.CTRL|=1u<<25;if(mode==3)dwt.CYCCNT=begin_cycles;if(mode==4)timer2.PSC^=1;
  assert(!drill_timing_end(false));invalid(mode==4?DT_CLOCK:DT_COUNTER);++cases;
 }
 for(unsigned mode=0;mode<5;++mode){timing_reset();fixture();if(mode!=0)assert(drill_timing_init());
  if(mode==0)assert(!drill_timing_begin(&now));if(mode==1)assert(!drill_timing_begin(NULL));if(mode==2)assert(!drill_timing_end(false));if(mode==3){assert(drill_timing_begin(&now));assert(!drill_timing_begin(&now));}if(mode==4){assert(drill_timing_begin(&now));dwt.CYCCNT=begin_cycles+100;assert(drill_timing_end(true));assert(!drill_timing_end(true));}
  invalid(DT_SEQUENCE);++cases;
 }
 /* Busy inter-start gap includes monitor publication and main-loop overhead;
  * an expected idle WFI is excluded from this gap constraint. */
 for(unsigned idle=0;idle<2;++idle)for(unsigned gap=29;gap<=31;++gap){timing_ready();assert(drill_timing_begin(&now));dwt.CYCCNT=begin_cycles+100;assert(drill_timing_end(idle!=0));timer2.CNT=previous_us+gap;dwt.CYCCNT=previous_cycles+gap*128;
  bool good=idle||gap<=30;assert(drill_timing_begin(&now)==good);if(!good)invalid(DT_LIMIT);else{dwt.CYCCNT=begin_cycles+100;assert(drill_timing_end(true));}++cases;
 }
 timing_ready();assert(drill_timing_begin(&now));dwt.CYCCNT=begin_cycles+100;assert(drill_timing_end(false));timer2.CNT=previous_us+29;dwt.CYCCNT=previous_cycles+3841;assert(!drill_timing_begin(&now));invalid(DT_LIMIT);++cases;
 timing_ready();dwt.CTRL|=1u<<22;coredebug.DEMCR|=1u;uint32_t saved=dwt.CYCCNT;assert(drill_timing_init()&&dwt.CYCCNT==saved&&(dwt.CTRL&(1u<<22))&&(coredebug.DEMCR&1));++cases;
 timing_ready();drill_debug_timing.windows=drill_debug_timing.active_windows=UINT32_MAX;assert(drill_timing_begin(&now));dwt.CYCCNT=begin_cycles+100;assert(drill_timing_end(false)&&drill_debug_timing.windows==UINT32_MAX&&drill_debug_timing.active_windows==UINT32_MAX);++cases;
 /* Actual timed service consumes a pair under a valid timing epoch. */
 timing_reset();streaming(0);assert(drill_timing_init());timer2.CNT=80;transfer(0x04560123);drill_debug_timing_capture_request=1;bool idle=true;drill_debug_stream_received=drill_debug_stream_epoch=0;assert(drill_timed_foreground(&idle)&&!idle&&drill_debug_stream_received==1&&drill_debug_timing.flags==3&&drill_debug_timing.fault==0&&!(drill_debug_timing.epoch&1));++cases;
 assert(drill_debug_timing_capture_epoch==2&&drill_debug_timing_capture_request==0&&drill_debug_timing_capture.timing.windows==1&&drill_debug_timing_capture.sample.ia_raw==0x123&&drill_debug_timing_capture.dual_state==DU_STREAM&&drill_debug_timing_capture.stream_received==1);
 dt_snapshot kept=drill_debug_timing_capture;timer2.CNT=85;assert(drill_timed_foreground(&idle));dt_snapshot retained=drill_debug_timing_capture;assert(!memcmp(&kept,&retained,sizeof kept)&&drill_debug_timing_capture_epoch==2);++cases;
 drill_debug_timing_capture_request=2;timer2.CNT=86;assert(drill_timed_foreground(&idle)&&drill_debug_timing_capture_request==2&&drill_debug_timing_capture_epoch==2);++cases;
 for(unsigned mode=0;mode<3;++mode){timing_reset();streaming(0);assert(drill_timing_init());timer2.CNT=80;transfer(0x04560123);drill_debug_stream_received=0;
  if(mode==0)timing_model_cycles_per_barrier=1000;if(mode==1)stream_race=6;if(mode==2)dwt.CTRL=0;
  assert(!drill_timed_foreground(&idle));stream_off();assert(drill_debug_timing_capture_epoch==2&&drill_debug_timing_capture.timing.fault==(mode==2?DT_COUNTER:DT_LIMIT)&&drill_debug_timing_capture.dual_state==DU_FAILED&&drill_debug_timing_capture.config_state==DC_FAILED);invalid(mode==2?DT_COUNTER:DT_LIMIT);++cases;
 }
 /* Universal abort also covers acquired ADC phases before DMA ownership. */
 timing_reset();fixture();assert(drill_timing_init());assert(drill_dual_bench_begin(0,true));dwt.CTRL=0;assert(!drill_timed_foreground(&idle));off();invalid(DT_COUNTER);++cases;
 timing_reset();fixture();assert(drill_timing_init());assert(drill_adc_bench_begin(0,true));dwt.CTRL=0;assert(!drill_timed_foreground(&idle));assert(drill_adc_state==DA_FAILED&&!(rcc.AHB2ENR&RCC_AHB2ENR_ADC12EN)&&!(gf.ODR&2)&&(ga.ODR&(1u<<12)));invalid(DT_COUNTER);++cases;
 timing_ready();assert(!drill_timed_foreground(NULL));assert(drill_config.state==DC_FAILED&&!(gf.ODR&2));invalid(DT_SEQUENCE);++cases;
 printf("%u DWT/TIM2 WINDOW / WRAP / FAIL-OFF SCENARIOS PASS\n",cases);
}
