#include "lamp_dark_init.h"
#include "lamp_i2c_read.h"
#include "lamp_i2c_write.h"
static const uint8_t addr[3]={0x15u,0x19u,0x65u};
static lamp_i2c_write writer;
static lamp_i2c_read reader;
static uint32_t started,last_poll,wake_started;
static uint16_t index;
static enum {DARK_IDLE,DARK_WRITE_BEGIN,DARK_WRITE_WAIT,DARK_READ_BEGIN,DARK_READ_WAIT,DARK_WAKE,DARK_DONE,DARK_FAILED} state;
void lamp_dark_init_abort(void){
 lamp_i2c_write_cancel(&writer);lamp_i2c_read_cancel(&reader);state=DARK_FAILED;
}
bool lamp_dark_init_begin(uint32_t now){
 if(state!=DARK_IDLE)return false;
 lamp_i2c_write_reset(&writer);lamp_i2c_read_reset(&reader);
 started=last_poll=now;index=0;state=DARK_WRITE_BEGIN;return true;
}
void lamp_dark_init_poll(uint32_t now){
 if(state==DARK_IDLE || state==DARK_DONE || state==DARK_FAILED)return;
 if(now-last_poll>5u || now-started>500u){lamp_dark_init_abort();return;}
 last_poll=now;uint8_t chip=(uint8_t)(index/58u),reg=(uint8_t)(index%58u);
 switch(state){
 case DARK_WRITE_BEGIN:{
  const uint8_t frame[2]={reg,0u};
  if(!lamp_i2c_write_start(&writer,addr[chip],frame,2u,now)){lamp_dark_init_abort();return;}
  state=DARK_WRITE_WAIT;break;
 }
 case DARK_WRITE_WAIT:
  lamp_i2c_write_poll(&writer,now);
  if(writer.state==LIW_FAILED){lamp_dark_init_abort();return;}
  if(lamp_i2c_write_done(&writer,now))state=DARK_READ_BEGIN;
  break;
 case DARK_READ_BEGIN:
  if(!lamp_i2c_read_start(&reader,addr[chip],reg,now)){lamp_dark_init_abort();return;}
  state=DARK_READ_WAIT;break;
 case DARK_READ_WAIT:{
  lamp_i2c_read_poll(&reader,now);
  if(reader.state==LIR_FAILED){lamp_dark_init_abort();return;}
  uint8_t value;
  if(lamp_i2c_read_get(&reader,now,&value)){
   /* MODE2 status bits must also be clear; no EFCLR is ever written. */
   if(value!=(reg==1u?0x05u:0u)){lamp_dark_init_abort();return;}
   ++index;
   if(reg==0u){wake_started=now;state=DARK_WAKE;}
   else state=index==174u?DARK_DONE:DARK_WRITE_BEGIN;
  }
  break;
 }
 case DARK_WAKE:
  /* MODE1 wake needs 500 us max; two 1 ms differences imply >=1 ms. */
  if(now-wake_started>=2u)state=DARK_WRITE_BEGIN;
  break;
 default:lamp_dark_init_abort();break;
 }
}
bool lamp_dark_init_done(void){return state==DARK_DONE;}
bool lamp_dark_init_failed(void){return state==DARK_FAILED;}
