#pragma once

inline void PlatformDelayCycle32(uint32_t delayLoops)
{
	uint16_t hi = delayLoops >> 16;
	uint16_t lo = delayLoops;
	__asm__ __volatile__
	(
		"1: \n"
		"add.w	#0xffff,	%[delayLoopsLow] \n"
		"addc.w	#0xffff,	%[delayLoopsHi] \n"
		"jc	1b \n"
        :   [delayLoopsLow] "+r"(lo),
            [delayLoopsHi] "+r"(hi)
	);
}

inline void PlatformDelayCycle16(uint16_t delayLoops)
{
	__asm__ __volatile__
	(
		"1: \n"
		" dec %[delayLoops] \n"
		" jne 1b \n"
        : [delayLoops] "+r"(delayLoops));
}

enum
{
	PlatformCyslesPerDelayLoop32 = 4,
	PlatformCyslesPerDelayLoop16 = 3,
	PlatformCyslesPerDelayLoop8 = 3
};

template<unsigned long ns, unsigned long CpuFreq>
void delay_ns()
{
            const unsigned long delayLoops32 = (unsigned long)(CpuFreq / (1.0e9 * PlatformCyslesPerDelayLoop32) * ns);
            const unsigned long delayLoops16 = (unsigned long)(CpuFreq / (1.0e9 * PlatformCyslesPerDelayLoop16) * ns);
            
    if(delayLoops16 > 0xfffful)
        PlatformDelayCycle32(delayLoops32);
    else
        PlatformDelayCycle16((uint16_t)delayLoops16);
}
    
template<int TxPin, uint32_t Baud>
class SoftUsart
{
    static const uint32_t BitDelay = 1000000000/ Baud;
    public:
    static void Putch(uint8_t value)
    {
        P1DIR |= 1 << TxPin;
        P1OUT &= ~(1 << TxPin);
        delay_ns<BitDelay, 16000000>();
        for(uint8_t i = 0; i < 8; i++)
        {
            if(value & 1)
                P1OUT |= 1 << TxPin;
            else
                P1OUT &= ~(1 << TxPin);
            value >>= 1;
            delay_ns<BitDelay, 16000000>();
        }
        P1OUT |= 1 << TxPin;
        delay_ns<BitDelay*5, 16000000>();
    }
};
