//******************************************************************************
//  Секция include: здесь подключается заголовочный файл к модулю
// Работа с портами ввода/вывода
// Функции:
//    - IO_Digital() - настраивает пин порта на ввод вывод
//******************************************************************************
#include  <stdint.h>
#include "IO_Digital.h"      // Включаем файл заголовка для нашего модуля

// ==================== CONSTRUCTOR ====================
IO_Digital::IO_Digital(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, bool IO = OUTPUT, uint8_t PULL = NO_PULL)
{
  _GPIOx = GPIOx;
  _GPIO_Pin = GPIO_Pin;
  _IO = IO;
  _PULL = PULL;

#if defined(STM32F030x6)
  if(_GPIOx == GPIOA) RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
  if(_GPIOx == GPIOB) RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
  if(_GPIOx == GPIOC) RCC->AHBENR |= RCC_AHBENR_GPIOCEN;
  if(_GPIOx == GPIOD) RCC->AHBENR |= RCC_AHBENR_GPIODEN;
  if(_GPIOx == GPIOF) RCC->AHBENR |= RCC_AHBENR_GPIOFEN;

  uint32_t I;
  uint16_t D;

  // Инициализируем вывод
  I = 0;
  D = _GPIO_Pin;
  while(I < 16) { D = D >> 1; if(D == 0) break; I++; }                          // Подсчитываем номер бита который соответствует настраиваемому выводу
  // Инициализация вход/выход
  _GPIOx->MODER    &= ~(0b11 << (I * 2));                                       // Затираем биты порта устанавливая порт на вход
  if(_IO)
    _GPIOx->MODER |= 0b01 << (I * 2);                                           // Если надо, врубаем на выход
  _GPIOx->OSPEEDR  |=  0b11 << (I * 2);                                         // Врубаем максимальную скорость порта

  _GPIOx->PUPDR &= ~(0b11 << (I * 2));                                          // Сбрасываем регистр подтяжки
  switch (PULL)
  {
    case NO_PULL:
      break;
    case PULL_UP:
      _GPIOx->PUPDR |=  0b01 << (I * 2);                                        // Подтягиваем вывод к питанию
      break;
    case PULL_DOWN:
      _GPIOx->PUPDR |=  0b10 << (I * 2);                                        // Подтягиваем вывод к земле
      break;
    default:
      break;
  }
#endif // defined(STM32F030x6)

#if defined(STM32F103xE)
  if(_GPIOx == GPIOA) RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
  if(_GPIOx == GPIOB) RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
  if(_GPIOx == GPIOC) RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
  if(_GPIOx == GPIOD) RCC->APB2ENR |= RCC_APB2ENR_IOPDEN;
  if(_GPIOx == GPIOF) RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;

  uint32_t I;
  uint16_t D;

  // Инициализируем вывод
  I = 0;
  D = _GPIO_Pin;
  while(I < 16) { D = D >> 1; if(D == 0) break; I++; }                          // Подсчитываем номер бита который соответствует настраиваемому выводу
  // Инициализация вход/выход
  if(I<8)
  {
    _GPIOx->CRL &= ~(0b0100<<(I*4));                                            // Выставляем порт в исходное состояние как при сбросе
    if(_IO)
    {
      _GPIOx->CRL |= (0b0011<<(I*4));                                           // Настраиваем на выход с максимальной скоростью в режиме PUSH/PULL
    }
    else
    {
      switch (PULL)
      {
        case NO_PULL:
          _GPIOx->CRL |= (0b0100<<(I*4));
          break;
        case PULL_UP:
          _GPIOx->CRL |= (0b1000<<(I*4));
          _GPIOx->ODR |= (1<<I);
          break;
        case PULL_DOWN:
          _GPIOx->CRL |= (0b1000<<(I*4));
          _GPIOx->ODR &= ~(1<<I);
          break;
        default:
          break;
      }
    }
  }
  else
  {
    _GPIOx->CRH &= ~(0b0100<<((I-8)*4));                                            // Выставляем порт в исходное состояние как при сбросе
    if(_IO)
    {
      _GPIOx->CRH |= (0b0011<<((I-8)*4));                                           // Настраиваем на выход с максимальной скоростью в режиме PUSH/PULL
    }
    else
    {
      switch (PULL)
      {
        case NO_PULL:
          _GPIOx->CRH |= (0b0100<<((I-8)*4));
          break;
        case PULL_UP:
          _GPIOx->CRH |= (0b1000<<((I-8)*4));
          _GPIOx->ODR |= (1<<I);
          break;
        case PULL_DOWN:
          _GPIOx->CRH |= (0b1000<<((I-8)*4));
          _GPIOx->ODR &= ~(1<<I);
          break;
        default:
          break;
      }
    }
  }
#endif // defined(STM32F103xE)

}

void IO_Digital::digitalWrite(bool DWrite)
{
  if(DWrite)
    _GPIOx->BSRR = _GPIO_Pin;                                                   // Устанавливаем 1 на выходе
  else
    _GPIOx->BSRR = _GPIO_Pin << 16;                                             // Сбрасываем в 0
}

bool IO_Digital::digitatRead()
{
  if(_GPIOx->IDR & _GPIO_Pin)
    return 1;
  else
    return 0;
}

void IO_Digital::digitalTogglePin(void)
{
  if(_GPIOx->IDR & _GPIO_Pin)
    _GPIOx->BSRR = _GPIO_Pin << 16;                                             // Если был 1, сбрасываем в 0
  else
    _GPIOx->BSRR = _GPIO_Pin;                                                   // Если был 0, устанавливаем в 1
}
//******************************************************************************
//  ENF OF FILE
//******************************************************************************

