/*
 * sys_tick.c
 *
 *  Created on: Sep 25, 2015
 *      Author: tkl
 */
#include <stddef.h>
#include <stdbool.h>

#include "irq.h"
#include "timer.h"
#include "stack.h"
#include "queue.h"
#include "thread.h"
#include "schedule.h"
#include "sys_tick.h"

struct sys_tick_obj
{
	struct loki_timer *hw_timer;
	unsigned long tick;
	unsigned int used;
};

extern volatile struct thread_context *current_thread;
extern volatile struct thread_list threads;
static struct sys_tick_obj sys_tick_obj;

void *timer_cb(void *arg)
{
	int i;
	sys_tick_obj.tick++;
	for(i = 0; i < threads.count; i++) {
		if(threads.list[i]->status == THREAD_STATUS_SLEEPING) {
			if(threads.list[i]->next_executing_time <= sys_tick_obj.tick) {
				threads.list[i]->status = THREAD_STATUS_EXECUTING;
				sys_tick_obj.used--;
				if(sys_tick_obj.used == 0)
					timer_close(sys_tick_obj.hw_timer);
			}
		}
	}
	return arg;
}

void sys_tick_init(const struct loki_timer *hw_timer)
{
	if(NULL == hw_timer)
		return;
	sys_tick_obj.tick = 0;
	sys_tick_obj.used = 0;
	sys_tick_obj.hw_timer = (struct loki_timer *)hw_timer;
	timer_set_it_callback(hw_timer, timer_cb, NULL);
}

void sleep_ms(unsigned int ms)
{
	int irq;
	irq = disable_irq();

	current_thread->next_executing_time = sys_tick_obj.tick + ms;
	current_thread->status = THREAD_STATUS_SLEEPING;

	sys_tick_obj.used++;
	if(sys_tick_obj.used == 1)
		timer_open(sys_tick_obj.hw_timer);
	restore_irq(irq);
	schedule();
}

