// Copyright (c) 2009, 2010 Rowley Associates Limited.
//
// This file may be distributed under the terms of the License Agreement
// provided with this software.
//
// THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include <ctl_api.h>
#include <lm3s_cmsis.h>
#include <targets/LM3S.h>

extern uint32_t SystemCoreClock;

static CTL_ISR_FN_t userTimerISR;

void
SysTick_ISR()
{
  ctl_enter_isr();
  if (SysTick_Control_And_Status & SysTick_Control_And_Status_COUNTFLAG_MASK)
    {
      userTimerISR();        
    }
  ctl_exit_isr();
}

int 
ctl_set_isr(unsigned int irq, 
            unsigned int priority,                 
            CTL_ISR_FN_t isr, 
            CTL_ISR_FN_t *oldisr)
{
  if (oldisr)
    *oldisr = *((CTL_ISR_FN_t*)(SCB->VTOR)+16+irq);
  *((CTL_ISR_FN_t*)(SCB->VTOR)+16+irq) = isr;
  NVIC_SetPriority(irq, (1 << (__NVIC_PRIO_BITS - 1)) + priority);
  return 1;
}

void
ctl_set_priority(int irq, int priority)
{
  NVIC_SetPriority(irq, (1 << (__NVIC_PRIO_BITS - 1)) + priority);
}

int
ctl_unmask_isr(unsigned int irq)
{
  NVIC_EnableIRQ(irq);
  return 1;
}

int
ctl_mask_isr(unsigned int irq)
{
  NVIC_DisableIRQ(irq);
  return 1;
}

void ctl_start_timer(CTL_ISR_FN_t timerFn)
{  
  userTimerISR = timerFn;  
  SysTick_Control_And_Status = SysTick_Control_And_Status_CLKSOURCE_MASK | SysTick_Control_And_Status_TICKINT_MASK | SysTick_Control_And_Status_ENABLE_MASK;
  SysTick_Reload_Value = SystemCoreClock/100; // interrupt every 10 ms 
#ifdef CTL_TASKING
  ctl_time_increment = 10; // so increment the counter by 10 to get the ms counter
#endif
  // Set PendSV priority (PendSV must have lowest priority)
  NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
  // Set SysTick priority
  ctl_set_priority(SysTick_IRQn, 0);
}

int __attribute__((naked))
ctl_global_interrupts_set(int enable)
{
   __asm__ __volatile__("mrs r1, basepri\n"
                        "cmp r0, #0\n"
                        "ite eq\n"
                        "moveq r0, #0x80\n"
                        "movne r0, #0x00\n"
                        "msr basepri, r0\n"
                        "cmp r1, #0x80\n"
                        "ite eq\n"
                        "moveq r0, #0\n"
                        "movne r0, #1\n"
                        "bx lr");
}

unsigned long
ctl_get_ticks_per_second(void)
{
#ifdef CTL_TASKING
  return 1000;
#else
  return 100;
#endif
}


