#include "process.h"
#include "kernel.h"
#include "target.h"

extern TKernel Kernel;

BaseProcess::BaseProcess(StackItem* Stack, Priority pr, void (*exec)())
    : _stackPointer(Stack)
    , _timeout(0)
    , _priority(pr)
{
    Kernel.RegisterProcess(this, _priority);

    *(--_stackPointer)  = 0x01000000L;             // xPSR
    *(--_stackPointer)  = reinterpret_cast<uint32_t>(exec); // Entry Point
    _stackPointer -= 14;                           // emulate "push R14,R12,R3,R2,R1,R0,R11-R4"

    // The code below can be used for debug purpose. In this case comment
    // line above and uncomment block below.
/*
    *(--StackPointer)  = 0xFFFFFFFEL;             // R14 (LR) (init value will cause fault if ever used)
    *(--StackPointer)  = 0x12121212L;             // R12
    *(--StackPointer)  = 0x03030303L;             // R3
    *(--StackPointer)  = 0x02020202L;             // R2
    *(--StackPointer)  = 0x01010101L;             // R1
    *(--StackPointer)  = 0x00000000L;             // R0

                                                  // Remaining registers saved on process stack
    *(--StackPointer)  = 0x11111111L;             // R11
    *(--StackPointer)  = 0x10101010L;             // R10
    *(--StackPointer)  = 0x09090909L;             // R9
    *(--StackPointer)  = 0x08080808L;             // R8
    *(--StackPointer)  = 0x07070707L;             // R7
    *(--StackPointer)  = 0x06060606L;             // R6
    *(--StackPointer)  = 0x05050505L;             // R5
    *(--StackPointer)  = 0x04040404L;             // R4
*/
}

bool BaseProcess::IsSleeping() const
{
	CriticalSection cs;
	if(_timeout)
		return true;
	else
		return false;
}

bool BaseProcess::IsBlocked(void) const
{
	CriticalSection cs;
#if 0
	if (Kernel.ReadyProcessMap & getPrioTag(_priority))
		return false;
	else
		return true;
#endif
	return false;
}

void BaseProcess::Sleep(Timeout ticks)
{
	CriticalSection cs;
	BaseProcess* current = Kernel.Running();
	current->_timeout = ticks;
	Kernel.BlockProcess(current->_priority);
	Kernel.Scheduler();
}

bool BaseProcess::WakeUpProcess(void)
{
	CriticalSection cs;
	if (_timeout > 0) {
		if (--_timeout == 0) {
			return true;
		}
	}
	return false;
}
