/**
  ******************************************************************************
  * @file    SHAL_CORE.h
  * @author  Luca Lizaranzu
  * @brief   Defines universal macros and objects used across all STM32 families
  * Includes for ST Microelectronics pre-made C headers for STM32 device families
  ******************************************************************************
  */
#ifndef SHMINGO_HAL_SHAL_CORE_H
#define SHMINGO_HAL_SHAL_CORE_H

#include <cstdint>
#include <cstddef>

//Overall init function for SHAL --------------------------

void SHAL_init();

//---------------------------------------------------------




//Universal structs and defines ---------------------------

enum class SHAL_Result{
    OKAY,
    ERROR
};


#define SHAL_CALL(func) \
    if(func != SHAL_Result::OKAY){ \
        return SHAL_Result::ERROR; \
    }

#define SHAL_WAIT_FOR_CONDITION_US(cond, timeout_us) \
    SHAL_wait_for_condition_us([&](){ return (cond); }, (timeout_us))

#define SHAL_WAIT_FOR_CONDITION_MS(cond, timeout_ms) \
    SHAL_wait_for_condition_ms([&](){ return (cond); }, (timeout_ms))


//Currently configures systick to count down in microseconds
inline uint32_t ticks = 0;
void systick_init();

extern "C" void SysTick_Handler();

static uint32_t millis();

//Max of 16ms, use SHAL_delay_ms for longer delay
void SHAL_delay_us(uint32_t us);

void SHAL_delay_ms(uint32_t ms);

template<typename Condition>
bool SHAL_wait_for_condition_us(Condition cond, uint32_t timeout_us) {
    while (timeout_us--) {
        if (cond()) {
            return true; // success
        }
        SHAL_delay_us(1);
    }
    return false; // timeout
}

template<typename Condition>
bool SHAL_wait_for_condition_ms(Condition cond, uint32_t timeout_ms) {
    while (timeout_ms--) {
        if (cond()) {
            return true; // success
        }
        SHAL_delay_ms(1);
    }
    return false; // timeout
}

bool SHAL_check_bit(const volatile uint32_t* reg, uint32_t mask);

bool SHAL_wait_for_bit_set_us(const volatile uint32_t* reg, uint32_t mask, uint16_t timeout);

bool SHAL_wait_for_bit_clear_us(const volatile uint32_t* reg, uint32_t mask, uint16_t timeout);

bool SHAL_wait_for_bit_set_ms(const volatile uint32_t* reg, uint32_t mask, uint16_t timeout);

bool SHAL_wait_for_bit_clear_ms(const volatile uint32_t* reg, uint32_t mask, uint16_t timeout);



#define SHAL_set_bits(reg, size, bits, offset)                    \
    do {                                                          \
        if ((reg) != NULL) {                                      \
            uint32_t _mask = (size == 32) ? 0xFFFFFFFFU : ((1U << (size)) - 1U);               \
            *(reg) &= ~((uint32_t)(_mask) << (offset));           \
            *(reg) |= ((uint32_t)(bits) << (offset));             \
        }                                                         \
    } while (0)

#define SHAL_flip_bits(reg, size, offset)                         \
    do {                                                          \
        if ((reg) != NULL) {                                      \
            uint32_t _mask = ((1U << (size)) - 1U);               \
            *(reg) ^= (_mask << (offset));                         \
        }                                                         \
    } while (0)

#define SHAL_set_bits_16(reg, size, bits, offset)                 \
    do {                                                          \
        if ((reg) != NULL) {                                      \
            uint16_t _mask = (uint16_t)((1U << (size)) - 1U);     \
            *(reg) &= (uint16_t)~((uint16_t)(_mask) << (offset)); \
            *(reg) |= (uint16_t)((uint16_t)(bits) << (offset));   \
        }                                                         \
    } while (0)

#define SHAL_clear_bitmask(reg, mask)                             \
    do {                                                          \
        *(reg) &= ~(mask);                                        \
    } while (0)

#define SHAL_apply_bitmask(reg, mask)                             \
    do {                                                          \
        SHAL_clear_bitmask((reg), (mask));                        \
        *(reg) |= (mask);                                         \
    } while (0)

#define SHAL_clear_register_value(reg)                            \
    do {                                                          \
        if ((reg) != NULL) {                                      \
            *(reg) = 0;                                           \
        }                                                         \
    } while (0)

#define SHAL_set_register_value(reg, value)                       \
    do {                                                          \
        if ((reg) != NULL) {                                      \
            *(reg) = (uint32_t)(value);                           \
        }                                                         \
    } while (0)

#define SHAL_set_register_value_16(reg, value)                    \
    do {                                                          \
        if ((reg) != NULL) {                                      \
            *(reg) = (uint16_t)(value);                           \
        }                                                         \
    } while (0)


void SHAL_print_register(const volatile uint32_t* reg);

//---------------------------------------------------------


#if defined(STM32F030x6)
#include "stm32f030x6.h"
#elif defined(STM32F030x8)
#include "stm32f030x8.h"
#elif defined(STM32F031x6)
#include "stm32f031x6.h"
#elif defined(STM32F038xx)
#include "stm32f038xx.h"
#elif defined(STM32F042x6)
#include "stm32f042x6.h"
#elif defined(STM32F048xx)
#include "stm32f048xx.h"
#elif defined(STM32F051x8)
#include "stm32f051x8.h"
#elif defined(STM32F058xx)
#include "stm32f058xx.h"
#elif defined(STM32F070x6)
#include "stm32f070x6.h"
#elif defined(STM32F070xB)
#include "stm32f070xb.h"
#elif defined(STM32F071xB)
#include "stm32f071xb.h"
#elif defined(STM32F072xB)
#include "stm32f072xb.h"
#elif defined(STM32F078xx)
#include "stm32f078xx.h"
#elif defined(STM32F091xC)
  #include "stm32f091xc.h"
#elif defined(STM32F098xx)
  #include "stm32f098xx.h"
#elif defined(STM32L412xx)
#include "stm32l412xx.h"
#elif defined(STM32L422xx)
#include "stm32l422xx.h"
#elif defined(STM32L431xx)
#include "stm32l431xx.h"
#elif defined(STM32L432xx)
#include "stm32l432xx.h"
#elif defined(STM32L433xx)
#include "stm32l433xx.h"
#elif defined(STM32L442xx)
  #include "stm32l442xx.h"
#elif defined(STM32L443xx)
  #include "stm32l443xx.h"
#elif defined(STM32L451xx)
  #include "stm32l451xx.h"
#elif defined(STM32L452xx)
  #include "stm32l452xx.h"
#elif defined(STM32L462xx)
  #include "stm32l462xx.h"
#elif defined(STM32L471xx)
  #include "stm32l471xx.h"
#elif defined(STM32L475xx)
  #include "stm32l475xx.h"
#elif defined(STM32L476xx)
  #include "stm32l476xx.h"
#elif defined(STM32L485xx)
  #include "stm32l485xx.h"
#elif defined(STM32L486xx)
  #include "stm32l486xx.h"
#elif defined(STM32L496xx)
  #include "stm32l496xx.h"
#elif defined(STM32L4A6xx)
  #include "stm32l4a6xx.h"
#elif defined(STM32L4P5xx)
  #include "stm32l4p5xx.h"
#elif defined(STM32L4Q5xx)
  #include "stm32l4q5xx.h"
#elif defined(STM32L4R5xx)
  #include "stm32l4r5xx.h"
#elif defined(STM32L4R7xx)
  #include "stm32l4r7xx.h"
#elif defined(STM32L4R9xx)
  #include "stm32l4r9xx.h"
#elif defined(STM32L4S5xx)
  #include "stm32l4s5xx.h"
#elif defined(STM32L4S7xx)
  #include "stm32l4s7xx.h"
#elif defined(STM32L4S9xx)
#elif defined(STM32F030xC)
  #include "stm32f030xc.h"
#elif defined(STM32H753ZIT6)
#include "SHAL_TIM_REG_H753xx.h"
#elif defined(STM32H743xx)
#include "stm32h743xx.h"
#elif defined(STM32H753xx)
#include "stm32h753xx.h"
#elif defined(STM32H750xx)
#include "stm32h750xx.h"
#elif defined(STM32H742xx)
#include "stm32h742xx.h"
#elif defined(STM32H745xx)
#include "stm32h745xx.h"
#elif defined(STM32H745xG)
#include "stm32h745xg.h"
#elif defined(STM32H755xx)
#include "stm32h755xx.h"
#elif defined(STM32H747xx)
#include "stm32h747xx.h"
#elif defined(STM32H747xG)
#include "stm32h747xg.h"
#elif defined(STM32H757xx)
#include "stm32h757xx.h"
#elif defined(STM32H7B0xx)
#include "stm32h7b0xx.h"
#elif defined(STM32H7B0xxQ)
#include "stm32h7b0xxq.h"
#elif defined(STM32H7A3xx)
#include "stm32h7a3xx.h"
#elif defined(STM32H7B3xx)
#include "stm32h7b3xx.h"
#elif defined(STM32H7A3xxQ)
#include "stm32h7a3xxq.h"
#elif defined(STM32H7B3xxQ)
#include "stm32h7b3xxq.h"
#elif defined(STM32H735xx)
#include "stm32h735xx.h"
#elif defined(STM32H733xx)
#include "stm32h733xx.h"
#elif defined(STM32H730xx)
#include "stm32h730xx.h"
#elif defined(STM32H730xxQ)
#include "stm32h730xxq.h"
#elif defined(STM32H725xx)
#include "stm32h725xx.h"
#elif defined(STM32H723xx)
#include "stm32h723xx.h"
#else
 #error "Please select first the target STM32 device used in your application (in stm32f0xx.h file)"
#endif


#endif //SHMINGO_HAL_SHAL_CORE_H
