#include "drill_config_async.h"
#include "drv8316.h"
#include <stddef.h>
static const uint8_t dc_settings[8][2]={{3,3},{4,0x43},{5,0x4f},{6,0x10},{7,1},{8,1},{12,0},{3,6}};
static bool dc_valid(const dc_hal *h){return h&&h->off_ok&&h->fault_high&&h->awake&&h->submit&&h->receive&&h->io_failed&&h->stop;}
static void dc_fail(dc_runtime *r,const dc_hal *h,dc_error e){
 if(h&&h->stop)h->stop(h->ctx);
 if(r){r->state=DC_FAILED;r->error=e;}
}
static void dc_command(unsigned step,bool *read,uint8_t *addr,uint8_t *value){
 *value=0;
 if(step<3){*read=true;*addr=(uint8_t)step;}
 else if(step<19){unsigned i=(step-3)/2;*read=((step-3)&1u)!=0;*addr=dc_settings[i][0];if(!*read)*value=dc_settings[i][1];}
 else {*read=true;*addr=(uint8_t)(step-19);}
}
bool dc_begin(dc_runtime *r,const dc_hal *h,uint32_t now,bool permission){
 if(!r||!dc_valid(h))return false;
 /* Unqualified or repeated requests do not change GPIO or active ownership. */
 if(!permission||r->state!=DC_IDLE)return false;
 if(!h->off_ok(h->ctx)||h->io_failed(h->ctx)){dc_fail(r,h,DC_INTERLOCK);return false;}
 *r=(dc_runtime){.state=DC_SLEEP,.last=now,.origin=now,.phase=now};
 if(!h->awake(h->ctx,false)){dc_fail(r,h,DC_IO);return false;}
 return true;
}
void dc_poll(dc_runtime *r,const dc_hal *h,uint32_t now){
 if(!r||r->state==DC_IDLE||r->state==DC_FAILED)return;
 if(!dc_valid(h)){dc_fail(r,h,DC_ARGUMENT);return;}
 if(now-r->last>0x7fffffffu){dc_fail(r,h,DC_TIME);return;}
 r->last=now;
 if(!h->off_ok(h->ctx)||h->io_failed(h->ctx)){dc_fail(r,h,DC_INTERLOCK);return;}
 if(r->state==DC_READY){if(!h->fault_high(h->ctx))dc_fail(r,h,DC_STATUS);return;}
 if(now-r->origin>20000u){dc_fail(r,h,DC_TIME);return;}
 if(r->state==DC_SLEEP){
  if(now-r->phase>=1000u){if(!h->awake(h->ctx,true)){dc_fail(r,h,DC_IO);return;}r->phase=now;r->state=DC_WAKE;}return;
 }
 if(r->state==DC_WAKE){if(now-r->phase<2000u)return;r->state=DC_SUBMIT;r->phase=now;}
 /* nFAULT may be low during wake. Afterwards reject low conservatively;
  * DRVOFF-related indication is not silently allowlisted. */
 if(!h->fault_high(h->ctx)){dc_fail(r,h,DC_STATUS);return;}
 if(r->state==DC_SUBMIT){
  if(now-r->phase<2u)return; /* CS-high gap after consuming prior response */
  bool read;uint8_t addr,value;uint16_t frame;
  dc_command(r->step,&read,&addr,&value);
  if(!drv8316_frame(read,addr,value,&frame)||!h->submit(h->ctx,frame,now)){dc_fail(r,h,DC_IO);return;}
  r->phase=now;r->state=DC_RECEIVE;return;
 }
 if(r->state==DC_RECEIVE){
  if(now-r->phase>250u){dc_fail(r,h,DC_TIME);return;}
  uint16_t rx;if(!h->receive(h->ctx,&rx,now))return;
  r->header=(uint8_t)(rx>>8);r->data=(uint8_t)rx;
  if((r->header&0xf7u)||(r->npor_required&&!(r->header&8u))){dc_fail(r,h,DC_STATUS);return;}
  if(r->step<3||r->step>=19){
   unsigned i=r->step<3?r->step:r->step-19;
   if((r->data&(i==0?0xf7u:0xffu))||(r->step>=19&&i==0&&!(r->data&8u))){dc_fail(r,h,DC_STATUS);return;}
  }else if((r->step-3)&1u){
   unsigned i=(r->step-3)/2;uint8_t expect=dc_settings[i][1];if(i==1)expect&=0xfeu;
   if(r->data!=expect){dc_fail(r,h,DC_READBACK);return;}
   if(i==1){if(!(r->header&8u)){dc_fail(r,h,DC_STATUS);return;}r->npor_required=true;}
  }
  ++r->step;r->phase=now;r->state=r->step==22?DC_READY:DC_SUBMIT;
 }
}
