#include "pca9956b_async_bank.h"
#include <stddef.h>
static const uint8_t addr[3]={0x15u,0x19u,0x65u};
static const uint32_t populated[3]={0xffffffu,0xffffffu,0x1fffu};
static void fail(pca_async_bank *b){
 b->valid=false;b->failed=true;
 if(b->pending)b->ops.cancel(b->ctx);
 b->pending=false;
}
bool pca_async_init(pca_async_bank *b,void *ctx,pca_async_ops ops,const uint32_t eligible[3],uint32_t now){
 if(b==NULL)return false;
 *b=(pca_async_bank){0};
 if(eligible==NULL || ops.begin==NULL || ops.poll==NULL || ops.take==NULL ||
    ops.failed==NULL || ops.cancel==NULL){b->failed=true;return false;}
 for(unsigned i=0;i<3;i++)if((eligible[i]&~populated[i])!=0u){b->failed=true;return false;}
 b->ctx=ctx;b->ops=ops;b->last_poll=now;b->bound=true;
 for(unsigned i=0;i<3;i++)b->eligible[i]=eligible[i];
 return true;
}
void pca_async_poll(pca_async_bank *b,uint32_t now){
 if(b==NULL || !b->bound || b->failed)return;
 if(now-b->last_poll>5u){fail(b);return;}
 b->last_poll=now;
 if(b->valid){b->valid=false;b->reads=0;}
 if(b->reads==0 && !b->pending)b->first_read=now;
 if(now-b->first_read>20u){fail(b);return;}
 unsigned i=b->reads%3u,step=b->reads/3u;
 if(!b->pending){
   uint8_t reg=(step==0 || step==7)?1u:(uint8_t)(0x40u+step);
   if(!b->ops.begin(b->ctx,addr[i],reg,now)){fail(b);return;}
   b->pending=true;b->request_started=now;
   if(step==0)b->first[i]=now;
   return;
 }
 if(now-b->request_started>5u){fail(b);return;}
 b->ops.poll(b->ctx,now);
 if(b->ops.failed(b->ctx)){fail(b);return;}
 uint8_t value;
 if(!b->ops.take(b->ctx,now,&value))return;
 b->pending=false;b->raw[i][step]=value;if(step==7)b->completed[i]=now;++b->reads;
 if(b->reads==23u){
   pca_async_snapshot s={0};
   for(unsigned j=0;j<3;j++){
     if(!pca_fault_decode(b->raw[j][0],b->raw[j][7],&b->raw[j][1],
                          populated[j],b->eligible[j],&s.chip[j])){fail(b);return;}
     s.chip[j].first_read_ms=b->first[j];s.chip[j].completed_ms=b->completed[j];
     s.chip[j].sequence=b->sequence+1u;
   }
   s.first_read_ms=b->first_read;s.completed_ms=now;s.sequence=++b->sequence;
   b->snapshot=s;b->valid=true;
 }
}
bool pca_async_get(const pca_async_bank *b,uint32_t now,pca_async_snapshot *out){
 if(b==NULL || out==NULL || !b->bound || b->failed || !b->valid ||
    now-b->first_read>20u || now-b->last_poll>5u)return false;
 *out=b->snapshot;return true;
}
