#include "timer.h"
#include <stm32f4xx.h>

void timer_init(timer_t *timer, TIM_TypeDef *peripheral, uint8_t timer_idx) {
  timer->periph = peripheral;
  timer->idx = timer_idx;
}
void timer_enable(timer_t *timer) {
  timer->periph->CR1 |= TIM_CR1_CEN;
}
void timer_disable(timer_t *timer) {
  timer->periph->CR1 &= ~TIM_CR1_CEN;
}

uint32_t timer_is_enabled(timer_t *timer) {
  return timer->periph->CR1 & TIM_CR1_CEN;
}

void timer_set_refresh(timer_t *timer, uint32_t refresh_value) {
  timer->periph->ARR = refresh_value;
}
void timer_set_counter(timer_t *timer, uint32_t counter) {
  timer->periph->CNT = counter;
}

uint16_t timer_count(timer_t *timer) {
  return timer->periph->CNT;
}

// TODO: rest of parameters...?
void timer_configure(timer_t *timer, uint8_t buffered_reload,
                     uint16_t prescaler, uint8_t one_pulse_mode) {
  timer->periph->CR1 = (0 << TIM_CR1_CKD_Pos) | (buffered_reload << TIM_CR1_ARPE_Pos) |
    (0 << TIM_CR1_CMS_Pos) | (0 << TIM_CR1_DIR_Pos) |
    (one_pulse_mode << TIM_CR1_OPM_Pos) | (1 << TIM_CR1_URS_Pos);
  timer->periph->CR2 = 0;
  timer->periph->PSC = prescaler - 1;
}

IRQn_Type timer_irq_idx(uint8_t line) {
  switch (line) {
  case 1:
    return TIM1_UP_TIM10_IRQn;
  case 2:
    return TIM2_IRQn;
  case 3:
    return TIM3_IRQn;
  case 4:
    return TIM4_IRQn;
  case 5:
    return TIM5_IRQn;
  default:
    return -1;
  }
}

void timer_enable_interrupt(timer_t *timer) {
  timer_clear_interrupt(timer);
  timer->periph->DIER |= TIM_DIER_UIE;
  IRQn_Type irq = timer_irq_idx(timer->idx);
  NVIC_SetPriority(irq, 1);
  NVIC_EnableIRQ(irq);
}
void timer_disable_interrupt(timer_t *timer) {
  timer->periph->DIER &= ~TIM_DIER_UIE;
}
uint32_t timer_is_interrupt(timer_t *timer) {
  return timer->periph->SR & TIM_SR_UIF;
}
void timer_clear_interrupt(timer_t *timer) {
  timer->periph->SR = ~TIM_SR_UIF;
}
