#include "drill_clock.h"
#include "stm32g4xx.h"
#include "drill_timebase.h"
#include "drill_pwm_stage.h"
#include <stddef.h>
static bool timebase_owned;
volatile uint32_t drill_debug_tick_wakeups;
static bool timebase_clock_ok(void) {return drill_clock_available();}
static bool timebase_available(void) {
 if(!timebase_owned||!timebase_clock_ok()||!(RCC->APB1ENR1&RCC_APB1ENR1_TIM2EN)||(RCC->APB1RSTR1&RCC_APB1RSTR1_TIM2RST))return false;
 const uint32_t control=SysTick->CTRL;
 return TIM2->CR1==TIM_CR1_CEN&&TIM2->CR2==0&&TIM2->SMCR==0&&TIM2->DIER==0&&TIM2->CCER==0&&TIM2->PSC==127u&&TIM2->ARR==UINT32_MAX&&
 TIM2->CCMR1==0&&TIM2->CCMR2==0&&SysTick->LOAD==127999u&&
 (control&~SysTick_CTRL_COUNTFLAG_Msk)==(SysTick_CTRL_CLKSOURCE_Msk|SysTick_CTRL_ENABLE_Msk|SysTick_CTRL_TICKINT_Msk);
}
bool drill_timebase_init(void) {
 if(timebase_owned)return timebase_available();
 if(!timebase_clock_ok()||!drill_pwm_stage_available()||(RCC->APB1ENR1&RCC_APB1ENR1_TIM2EN)||(SysTick->CTRL&SysTick_CTRL_ENABLE_Msk))return false;
 if(RCC->APB1RSTR1&RCC_APB1RSTR1_TIM2RST)return false;
 RCC->APB1ENR1|=RCC_APB1ENR1_TIM2EN;(void)RCC->APB1ENR1;__DSB();
 RCC->APB1RSTR1|=RCC_APB1RSTR1_TIM2RST;__DSB();RCC->APB1RSTR1&=~RCC_APB1RSTR1_TIM2RST;__DSB();
 TIM2->CR1=0;TIM2->CR2=0;TIM2->SMCR=0;TIM2->DIER=0;TIM2->CCER=0;TIM2->CCMR1=0;TIM2->CCMR2=0;
 TIM2->PSC=127;TIM2->ARR=UINT32_MAX;TIM2->CNT=0;TIM2->EGR=TIM_EGR_UG;TIM2->SR=0;TIM2->CR1=TIM_CR1_CEN;
 if(SysTick_Config(128000u)!=0u){TIM2->CR1=0;return false;}
 __DSB();timebase_owned=true;return timebase_available();
}
bool drill_timebase_get(uint32_t *now) {
 if(!now||!timebase_available())return false;
 *now=TIM2->CNT;return true;
}
void SysTick_Handler(void){++drill_debug_tick_wakeups;}
