/**
 * @file   fcUART.c
 * @brief  This is the print function in fastcall
 */

#include "stdarg.h"
#include "drStd.h"

#include "fcUART.h"

#ifdef FC_DR_DEBUG
#if TBASE_API_LEVEL >= 5
extern addr_t uart_sfr_va;
#endif
static char *itoa(long val, char *buf, const uint32_t radix)
{
	char *p;		/* pointer to traverse string */
	char *firstdig;		/* pointer to first digit */
	char temp;		/* temp char */
	uint32_t digval;	/* value of digit */

	p = buf;

	if (radix == 10 && val < 0) {	/* negative, so output '-' and negate */
		*p++ = '-';
		val = (unsigned long)(-(long)val);
	}

	firstdig = p;	/* save pointer to first digit */

	do {
		digval = (uint32_t) (val % radix);
		val /= radix; /* get next digit */

		/* convert to ascii and store */
		if (digval > 9)
			*p++ = (char) (digval - 10 + 'a');	/* a letter */
		else
			*p++ = (char) (digval + '0');		/* a digit */
	} while (val > 0);

	/* We now have the digit of the number in the buffer, but in reverse order. Thus we reverse them now. */

	*p-- = '\0';	/* terminate string; p points to last digit */

	do {
		temp = *p;
		*p = *firstdig;
		*firstdig = temp;	/* swap *p and *firstdig */
		--p;
		++firstdig;		/* advance to next two digits */
	} while (firstdig < p);		/* repeat until halfway */

	return buf;
}

static inline int err_check(uint32_t  uart, int op)
{
	unsigned int mask;

	/*
	 * UERSTAT
	 * Break Detect [3]
	 * Frame Err    [2] : receive operation
	 * Parity Err   [1] : receive operation
	 * Overrun Err  [0] : receive operation
	 */
	if (op)
		mask = 0x8;
	else
		mask = 0xf;

	return REG_OFF_READ32(uart, 0x14) & mask;
}

void uart_putchar(uint32_t uart, const char chr)
{
	/* If in FIFO mode - after Linux initializes the console */
	if (REG_OFF_READ32(uart, 0x8) & 0x1) {
		/* FIFO is full, wait for it */
		while (REG_OFF_READ32(uart, 0x18) & (1 << 24)) {
			if (err_check(uart, 1))
				break;
		}
	} else {
		/* Non FIFO mode */
		while (!(REG_OFF_READ32(uart, 0x10) & 0x7)) {
			if (err_check(uart, 1))
				break;
		}
	}

	/* utxh = chr; */
	REG_OFF_WRITE8(uart, 0x20, chr);
}

void uart_ps(char *s)
{
	uint32_t uart;
#if TBASE_API_LEVEL >= 5
	uart = (uint32_t *)uart_sfr_va;
#else
	uart = UART_SFR_VA;
#endif
	while (*s) {
		uart_putchar(uart, *s);
		s++;
	}
	uart_putchar(uart, '\r');
	uart_putchar(uart, '\n');
}

void uart_psd(char *s, ...)
{
	uint32_t uart;
	uint32_t var;
	char str[20];
	va_list ap;
	int i = 0;
#if TBASE_API_LEVEL >= 5
	uart = (uint32_t *)uart_sfr_va;
#else
	uart = UART_SFR_VA;
#endif
	while (*s) {
		uart_putchar(uart, *s);
		s++;
	}

	va_start(ap, s);
	var = va_arg(ap, uint32_t);
	va_end(ap);

	itoa(var, str, 10);

	while (str[i]) {
		uart_putchar(uart, str[i]);
		i++;
	}
	uart_putchar(uart, '\r');
	uart_putchar(uart, '\n');
}

void uart_psh(char *s, ...)
{
	uint32_t uart;
	uint32_t var;
	char str[20];
	va_list ap;
	int i = 0;
#if TBASE_API_LEVEL >= 5
	uart = (uint32_t *)uart_sfr_va;
#else
	uart = UART_SFR_VA;
#endif
	while (*s) {
		uart_putchar(uart, *s);
		s++;
	}

	va_start(ap, s);
	var = va_arg(ap, uint32_t);
	va_end(ap);

	itoa(var, str, 16);

	while (str[i]) {
		uart_putchar(uart, str[i]);
		i++;
	}
	uart_putchar(uart, '\r');
	uart_putchar(uart, '\n');
}
#else
void uart_ps(char *s)
{
}
void uart_psd(char *s, ...)
{
}
void uart_psh(char *s, ...)
{
}
#endif

