#include "stm32g0xx.h"
#include "lamp_i2c_clock.h"
#include "lamp_frame_stage.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
GPIO_TypeDef b;RCC_TypeDef r;I2C_TypeDef i;
bool lamp_i2c_pins_available(void){return true;}
static lamp_frame_stage stage;static lg_guard g;static lamp_current_profile p;
static unsigned tick;static uint32_t base;static bool slow;
static uint32_t now(void){return base+tick/20;}
static void poll(uint32_t flags){i.ISR=flags;g.last_poll_ms=now();lamp_frame_stage_poll(&stage,&g,&p,now());
 if(slow && stage.state==LFS_FAILED){assert(now()-base>500u);puts("PASS total frame update deadline with current authorization and timely transactions");exit(0);}
 tick+=slow?20u:1u;}
static uint8_t fixture(unsigned chip,unsigned reg){
 if(reg==1)return 5;
 if(reg>=2 && reg<=7){static const uint8_t last[]={0xaa,0xaa,0xaa,0x02,0,0};return chip==2?last[reg-2]:0xaa;}
 if(reg>=10 && reg<=33){unsigned ch=chip*24+reg-10;return ch<61?(uint8_t)(ch*37+9):0;}
 if(reg>=34 && reg<=57){unsigned ch=chip*24+reg-34;return ch<61?(uint8_t)(ch*7%63+1):0;}
 return 0;
}
static void revoke(unsigned n){
 switch(n){
 case 0:g.armed=false;break;case 1:g.output_enable=false;break;
 case 2:g.configured=false;break;case 3:g.session_id++;break;
 case 4:g.cfg.calibration_id++;break;case 5:p.calibration_id++;break;
 case 6:p.physically_qualified=false;break;case 7:g.mode=LG_OFF;break;
 case 8:g.hand_present=false;break;case 9:g.inputs.infrared_hand_present=false;break;
 case 10:g.inputs.temperature_ok=false;break;case 11:g.inputs.supply_ok=false;break;
 case 12:g.inputs.led_driver_ok=false;break;case 13:g.inputs.hardware_interlock_ok=false;break;
 case 14:g.vision_status_seen=false;break;case 15:g.frame_active=false;break;
 case 16:g.cfg.channels=60;break;case 17:g.cfg.max_poll_gap_ms=0;break;
 case 18:g.cfg.ticket_lifetime_ms=0;break;case 19:g.run_duration_ms=0;break;
 case 20:g.pwm[60]^=1;break;case 21:p.iref[60]^=1;break;
 case 22:g.vision_status_ms=now()-1000u;break;case 23:g.frame_issued_ms=now()-1000u;break;
 case 24:g.run_started_ms=now()-2000u;break;default:assert(0);
 }
}
int main(int argc,char **argv){
 unsigned scenario=argc>1?(unsigned)atoi(argv[1]):0;int pos=argc>2?atoi(argv[2]):-1;
 slow=scenario==10;
 base=scenario==1?UINT32_MAX-10u:0;
 r.CR=RCC_CR_HSION|RCC_CR_HSIRDY;r.APBENR1=RCC_APBENR1_I2C1EN;b.IDR=(1u<<6)|(1u<<7);assert(lamp_i2c_clock_init());
 g.configured=g.armed=g.output_enable=g.hand_present=g.vision_status_seen=g.frame_active=true;
 g.mode=LG_AI;g.session_id=123;g.cfg.channels=61;g.cfg.calibration_id=7;
 g.cfg.max_poll_gap_ms=5;g.cfg.ticket_lifetime_ms=1000;g.run_duration_ms=2000;
 g.last_poll_ms=g.vision_status_ms=g.frame_issued_ms=g.run_started_ms=base;
 g.inputs=(lg_inputs){true,true,true,true,true};p.calibration_id=7;p.physically_qualified=true;
 for(unsigned j=0;j<61;j++){g.pwm[j]=(uint8_t)(j*37+9);p.iref[j]=(uint8_t)(j*7%63+1);}
 if(scenario==5){revoke((unsigned)pos);if(pos==3)g.session_id=0;assert(!lamp_frame_stage_begin(&stage,&g,&p,base));assert(i.CR2==0);return 0;}
 if(scenario==9){g.last_poll_ms=base-6u;assert(!lamp_frame_stage_begin(&stage,&g,&p,base));assert(i.CR2==0);return 0;}
 if(scenario==8){p.iref[0]=0;assert(!lamp_frame_stage_begin(&stage,&g,&p,base));assert(i.CR2==0);return 0;}
 assert(lamp_frame_stage_begin(&stage,&g,&p,base));poll(0);
 if(scenario==11){g.last_poll_ms=base+6u;lamp_frame_stage_poll(&stage,&g,&p,base+6u);goto failed;}
 if(scenario==12){i.TIMINGR^=1;poll(0);goto failed;}
 if(scenario==6){revoke((unsigned)pos);poll(0);goto failed;}
 if(scenario==7){p.iref[0]=0;lamp_frame_stage_abort(&stage);assert(!lamp_frame_stage_begin(&stage,&g,&p,base));return 0;}
 for(unsigned n=0;n<174;n++){
  unsigned reg=n%58,chip=n/58;uint8_t addresses[]={0x15,0x19,0x65};uint8_t value=fixture(chip,reg);
  assert((i.CR2&I2C_CR2_SADD)==(unsigned)addresses[chip]<<1);
  if(scenario==2 && n==(unsigned)pos){poll(I2C_ISR_NACKF|I2C_ISR_BUSY);goto failed;}
  poll(I2C_ISR_TXIS|I2C_ISR_BUSY);assert(i.TXDR==reg);
  poll(I2C_ISR_TXIS|I2C_ISR_BUSY);assert(i.TXDR==(reg==1?0:value));
  poll(I2C_ISR_STOPF);assert(!lamp_frame_stage_done(&stage,&g,&p,now()));poll(0);
  if(scenario==3 && n==(unsigned)pos){poll(I2C_ISR_NACKF|I2C_ISR_BUSY);goto failed;}
  poll(I2C_ISR_TXIS|I2C_ISR_BUSY);assert(i.TXDR==reg);poll(I2C_ISR_TC|I2C_ISR_BUSY);
  i.RXDR=value;if(scenario==4 && n==(unsigned)pos)i.RXDR^=1;
  poll(I2C_ISR_RXNE|I2C_ISR_BUSY);poll(I2C_ISR_STOPF);
  if(scenario==4 && n==(unsigned)pos)goto failed;
  if(n<173){if(reg==0){poll(0);tick+=40;poll(0);}poll(0);}
 }
 assert(lamp_frame_stage_done(&stage,&g,&p,now()));assert(stage.index==174);
 g.output_enable=false;assert(!lamp_frame_stage_done(&stage,&g,&p,now()));poll(0);assert(stage.state==LFS_FAILED);
 puts("PASS qualified-fixture 61-channel image, 174 readbacks, unused channels zero, post-commit revocation; no physical output");return 0;
failed:
 assert(stage.state==LFS_FAILED && !lamp_frame_stage_done(&stage,&g,&p,now()));uint32_t cr2=i.CR2;poll(0);assert(i.CR2==cr2);return 0;
}
