/*
  Copyright (c) 2011 Arduino.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "Arduino.h"

#ifdef __cplusplus
extern "C" {
#endif

#include "mik32_hal_scr1_timer.h"

uint32_t start_del, current_del;

// system timer initialization
SCR1_TIMER_HandleTypeDef hscr1_timer;

#define TICKS_IN_SYSTIMER   ((uint64_t)(hscr1_timer.Instance->MTIMEH)<<32 | hscr1_timer.Instance->MTIME)

void SysTick_Init(void)
{
    hscr1_timer.Instance = SCR1_TIMER;
    hscr1_timer.ClockSource = SCR1_TIMER_CLKSRC_INTERNAL; 
    hscr1_timer.Divider = 0;
    HAL_SCR1_Timer_Init(&hscr1_timer); // Ticks are 32 MHz
}

uint64_t SysTick_GetTicks(void)
{
  return TICKS_IN_SYSTIMER;
}

// number of microseconds since start of the program
uint32_t micros(void)
{
  // cast to uint32_t and assume that when HAL_SCR1_Timer_Get_Ticks() returns a number 
  // greater than 2^32/32, the variable will overflow itself
  return (uint32_t)(TICKS_IN_SYSTIMER >> 5);
}

// there may be a problem with the timer counter overflow, because by the time it 
// overflows the number of milliseconds will not have time to reach the maximum, 
// and when it overflows it will be reseted to 0 ahead of time - the delay will be 
// incorrect. But 64 bits will take a very long time to fill, so we'll leave it like that
volatile uint32_t millis(void)
{
  return (uint32_t) (TICKS_IN_SYSTIMER / (uint64_t)(32000));
}

void delay(uint32_t ms)
{
  if (ms > 0) 
  {
    start_del = millis();
    while (1)
    {
      current_del = millis();
      // Let's check if there was an overflow. 
      if (((current_del > start_del) ? (current_del - start_del) : (current_del + ~start_del + 1)) >= ms)
        // exit if we got the required amount
        break;
    }
  }
}

void delayMicroseconds(uint16_t us)
{
  if (us > 0) 
  {
    start_del = micros();
    while (1)
    {
      current_del = micros();
      // Let's check if there was an overflow. 
      if (((current_del > start_del) ? (current_del - start_del) : (current_del + ~start_del + 1)) >= us)
        // exit if we got the required amount
        break;
    }
  }
}

#ifdef __cplusplus
}
#endif
