#include "stm32g4xx.h"
#include "drill_encoder.h"
#include "drill_encoder_target.h"
static de_state encoder;
static bool owned;
volatile de_snapshot drill_debug_encoder;
_Static_assert(sizeof(de_snapshot)==36u,"encoder snapshot ABI");
static uint8_t read_ab(void){
 /* Different ports cannot be atomically sampled. Invalid two-bit jumps are
    detected, but whole skipped cycles and some skewed samples are undetectable. */
 uint32_t a=GPIOB->IDR;uint32_t b=GPIOC->IDR;
 return (uint8_t)(((a>>2)&1u)*2u+((b>>15)&1u));
}
static bool pins_ok(void){
 return (RCC->AHB2ENR&(RCC_AHB2ENR_GPIOBEN|RCC_AHB2ENR_GPIOCEN))==
        (RCC_AHB2ENR_GPIOBEN|RCC_AHB2ENR_GPIOCEN) && !(RCC->BDCR&RCC_BDCR_LSEON) &&
        !(GPIOB->MODER&(3u<<4)) && !(GPIOB->PUPDR&(3u<<4)) &&
        !(GPIOC->MODER&(3u<<30)) && !(GPIOC->PUPDR&(3u<<30));
}
bool drill_encoder_init(uint32_t now){
 if(owned)return pins_ok();
 /* PC15 is shared with LSE: reject an active LSE before changing its mode. */
 if(RCC->BDCR&RCC_BDCR_LSEON)return false;
 RCC->AHB2ENR|=RCC_AHB2ENR_GPIOBEN|RCC_AHB2ENR_GPIOCEN;(void)RCC->AHB2ENR;__DSB();
 GPIOB->MODER&=~(3u<<4);GPIOB->PUPDR&=~(3u<<4);
 GPIOC->MODER&=~(3u<<30);GPIOC->PUPDR&=~(3u<<30);__DSB();
 if(!pins_ok()||!de_init(&encoder,now,read_ab()))return false;
 owned=true;drill_debug_encoder.available=1u;return true;
}
void drill_encoder_poll(uint32_t now){
 if(!owned)return;
 if(!pins_ok()){
  ++drill_debug_encoder.epoch;__DMB();drill_debug_encoder.available=0u;
  __DMB();++drill_debug_encoder.epoch;owned=false;return;
 }
 uint8_t ab=read_ab();(void)de_sample(&encoder,now,ab);
 ++drill_debug_encoder.epoch;__DMB();
 ++drill_debug_encoder.samples;drill_debug_encoder.last_us=now;drill_debug_encoder.ab=ab;
 drill_debug_encoder.edge_position=encoder.edge_position;
 drill_debug_encoder.invalid_transitions=encoder.invalid_transitions;
 drill_debug_encoder.service_gaps=encoder.service_gaps;drill_debug_encoder.saturated=encoder.saturated;
 __DMB();++drill_debug_encoder.epoch;
}
