/****************************************************************************
 *
 * Projekt			:	Glacier Batterieboxdeckel Prüfgerät
 * Dateiname		:	DrvUart.c
 * Autor			:	orginal MHoffmann, abgeändert für dieses Projekt Irene Saxer
 * Erstellungsdatum	:	17.04.2019
 * Beschreibung		:	"Treiber der asynchronen Schnittstellen des ATmega"
 *
 *
 * Versionsgeschichte
 * 	Revision 1.0	17.04.2019 SAI erste Version
 *
 ****************************************************************************/

/****************************************************************************/
/* COMPILER Direktiven */

/****************************************************************************/
/* INCLUDE Dateien */
#include "DrvUart.h"

/****************************************************************************/
/* KONSTANTEN */

/****************************************************************************/
/* Globale Variablen */
TUartPara	gudt_MoniIntf;

/****************************************************************************/
/* Funktionen */

void DrvUart_Init(void)
/*============================================================================
 *
 *  Funktion:		DrvUart_Init
 *  Ü-Parameter:	-
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Initialisierung der seriellen Schnittstellen
 *  				UART0: Monitor/serielle Programmierung	115.200 k
 *  				UART1: Systeminterface					115.200 k
 *
 *==========================================================================*/
{
	//Monitorschnittstelle (8 Bit, 1 Stopbit, kein Parity, 115.2k, RX-Int)
	//Buffer initialisieren
	gudt_MoniIntf.udt_rxbuf.u8_iwrite = 0;
	gudt_MoniIntf.udt_rxbuf.u8_iread  = 0;
	gudt_MoniIntf.udt_rxbuf.u8_count = 0;
	gudt_MoniIntf.udt_txbuf.u8_iwrite = 0;
	gudt_MoniIntf.udt_txbuf.u8_iread  = 0;
	gudt_MoniIntf.udt_txbuf.u8_count = 0;

	gudt_MoniIntf.u8_id = 0;

	//Config-Register schreiben
	UBRR0H = 0x00;
	UBRR0L = 42;	// 57600Baud -0,9% (bei 2-fach Mode)
	UCSR0A = (1 << U2X0) | (0 << MPCM0);
	UCSR0B = (1 << RXCIE0) | (0 << TXCIE0) | (0 << UDRIE0) | (0 << RXEN0) | (0 << TXEN0) | (0 << UCSZ02);
	UCSR0C = (0 << UMSEL01) | (0 << UMSEL00) | (0 << UPM01) | (0 << UPM00) | (0 << USBS0) | (1 << UCSZ01) | (1 << UCSZ00) | (0 << UCPOL0);

	DrvTim_DelayClk5();

	//UART0 enablen
	UCSR0B |= (1 << RXEN0) | (1 << TXEN0);

}

int16_t DrvUart_Transmit(TUartPara *pudt_uart)
/*============================================================================
 *
 *  Funktion:		DRVUARTxmit
 *  Ü-Parameter:	Zeiger auf dir Struktur einer seriellen Schnittstelle
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Sendet alle Daten in der Sendequeue von pudt_uart
 *
 *==========================================================================*/
{
	int16_t 	int_Ergebnis = ERROR_NOERROR;
	uint8_t		u8_MaxCharCnt = 0;

	while ((pudt_uart->udt_txbuf.u8_count > 0)  && (u8_MaxCharCnt < DRVUART_MAXCHARS_PER_TX))
	{

		switch (pudt_uart->u8_id)
		{
			case 0:
			{
				//warten, bis das Shiftregister leer ist
				while ((UCSR0A & (1<<UDRE0)) == 0);

				//das naechste Byte in den Transmitbuffer schreiben
				UDR0 = pudt_uart->udt_txbuf.u8_buffer[pudt_uart->udt_txbuf.u8_iread++];

				u8_MaxCharCnt++;

				break;
			}
			default:
			{
				int_Ergebnis = ERROR_DRVUART_TRANSMIT_INVALID_UARTID;
			}
		}

		//pruefen, ob Ueberlauf des Index vorliegt
		pudt_uart->udt_txbuf.u8_iread %= UARTMAXTXBUFSIZE;

		//Bytezaehler aktualisieren (dekrement)
		pudt_uart->udt_txbuf.u8_count--;

	}

	return int_Ergebnis;
}

ISR(USART0_RX_vect)
/*============================================================================
 *
 *  Funktion:		SIGNAL(USART0_RX_vect)
 *  Ü-Parameter:	Interruptvektor
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Behandelt eingehende Zeichen auf der UART1 (Systeminterface)
 *
 *==========================================================================*/
{
	//Statusregister sichern
	uint8_t uchr_TempStatReg = SREG;
	int16_t int_Ergebnis = ERROR_NOERROR;
	uint8_t u8_Data;
	uint8_t u8_Status;

	u8_Status = UCSR0A;

	//Zeichen auf alle Faelle lesen, um INT-Bedingung zurueckzusetzen
	u8_Data = UDR0;

	//wenn das Zeichen-Empfangen-Flag gesetzt ist
	if ( (u8_Status & (1<<RXC0)) > 0)
	{
		if ( (gudt_MoniIntf.udt_rxbuf.u8_count < UARTMAXRXBUFSIZE) &&
			 ((u8_Status & (1<<FE0)) == 0) &&
			 ((u8_Status & (1<<DOR0)) == 0) )
		{
			// eichen in die EmpfangsFIFO kopieren
			gudt_MoniIntf.udt_rxbuf.u8_buffer[gudt_MoniIntf.udt_rxbuf.u8_iwrite++] = u8_Data;

			//iwrite-Ueberlauf abfangen
			if (gudt_MoniIntf.udt_rxbuf.u8_iwrite >= UARTMAXRXBUFSIZE)
			{
				gudt_MoniIntf.udt_rxbuf.u8_iwrite -= UARTMAXRXBUFSIZE;
			}

			//FIFO-Zaehler inkrementieren
			gudt_MoniIntf.udt_rxbuf.u8_count++;
		}
		else
		{
			//Pufferueberlauf -> Fehler melden
			int_Ergebnis = ERROR_DRVUART_SIGNALRX1_RXBUF_OVF;
		}
	}
	//else: kein Zeichen empfangen


	//Statusregister zurueckschreiben
	SREG = uchr_TempStatReg;
}

int16_t DrvUart_Getchar(TUartPara *pudt_uart)
/*============================================================================
 *
 *  Funktion:		DrvUart_Getchar
 *  Ü-Parameter:	Zeiger auf die Schnittstellenstruktur
 *  R-Parameter:	Das empfangene Zeichen bzw. Fehlercode
 *  Beschreibung:	Liest ein Zeichen aus der Monitor Empfangsqueue.
 *                  Gibt einen Fehler zurueck, wenn kein Zeichen in der Queue
 *                  vorhanden ist.
 *
 *==========================================================================*/
{
	int16_t int_Ergebnis = ERROR_NOERROR;

	switch (pudt_uart->u8_id)
	{
		case 0:
		case 1:
		{
			//wenn Queue nicht leer
			if (pudt_uart->udt_rxbuf.u8_count > 0)
			{
			    //Zeichen lesen
				int_Ergebnis = (int16_t)pudt_uart->udt_rxbuf.u8_buffer[pudt_uart->udt_rxbuf.u8_iread++];

				//Lesezeiger ggf. korrigieren
				if (pudt_uart->udt_rxbuf.u8_iread >= UARTMAXRXBUFSIZE)
				{
					pudt_uart->udt_rxbuf.u8_iread -= UARTMAXRXBUFSIZE;
				}

				UCSR0B &= ~(1 << RXCIE0);

				//Queuecount um Eins dekrementieren
				pudt_uart->udt_rxbuf.u8_count--;

				//UARTRXints wieder einschalten
				UCSR0B |= (1 << RXCIE0);
			}
			else
			{
				//Fehlercode in Rueckgabevariable
				int_Ergebnis = (int16_t)ERROR_DRVUART_GETCHAR_EMPTYBUF;
			}
			break;
		}
		default:
		{
			int_Ergebnis = (int16_t)ERROR_DRVUART_GETCHAR_INVALID_UARTID;
		}
	}

    return (int_Ergebnis);
}

int16_t DrvUart_Putchar(TUartPara *pudt_uart, uint8_t u8_char)
/*============================================================================
 *
 *  Funktion:		DrvUart_Putchar
 *  Ü-Parameter:	ID des UART, zu sendendes Zeichen
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	schreibt das uebergebene Zeichen in die TX-Queue der
 *  				angegebenen UART
 *
 *==========================================================================*/
{
	int16_t	int_Ergebnis = ERROR_NOERROR;

	switch (pudt_uart->u8_id)
	{
		case 0:
		case 1:
		{
			//wenn noch platz in der TX-Queue
			if (pudt_uart->udt_txbuf.u8_count < UARTMAXTXBUFSIZE)
			{
				//Zeichen in den Puffer schreiben
				pudt_uart->udt_txbuf.u8_buffer[pudt_uart->udt_txbuf.u8_iwrite++] = u8_char;

				//ggf. den Schreibindex korrigieren
				if (pudt_uart->udt_txbuf.u8_iwrite >= UARTMAXTXBUFSIZE)
				{
					pudt_uart->udt_txbuf.u8_iwrite -= UARTMAXTXBUFSIZE;
				}

				//Fuellstand des Puffers aktualisieren
				pudt_uart->udt_txbuf.u8_count++;
			}
			else
			{
				//TX-Queue voll
				int_Ergebnis = ERROR_DRVUART_PUTCHAR_BUFOVF;
			}

			break;
		}
		default:
		{
			//ungueltige UART-ID
			int_Ergebnis = ERROR_DRVUART_PUTCHAR_INVALID_UARTID;
		}
	}

	return int_Ergebnis;
}

int16_t DrvUart_Puts(TUartPara* pudt_uart, const char* pchr_char)
/*============================================================================
 *
 *  Funktion:		DrvUart_Puts
 *  Ü-Parameter:	Zeiger auf die UART, Zeiger auf den 0-terminierten String
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Ausgabe eines Strings
 *
 *==========================================================================*/
{
	int16_t int_Ergebnis = ERROR_NOERROR;
	uint8_t u8_Tmp;

	while( (u8_Tmp = *pchr_char++) && (int_Ergebnis == ERROR_NOERROR) )
	{
		//aktuelles Zeichen ausgeben
		int_Ergebnis = DrvUart_Putchar(pudt_uart, u8_Tmp);
	}

	return int_Ergebnis;
}

int16_t DrvUart_Putbyteh(TUartPara* pudt_uart, uint8_t u8_byte)
/*============================================================================
 *
 *  Funktion:		DrvUart_Putbyteh
 *  Ü-Parameter:	Zeiger auf Schnittstellenstruktur, das auszugebende Byte
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Ausgabe eines unsigned Bytes auf einer seriellen Schnittstelle
 *
 *==========================================================================*/
{
	int16_t	int_Ergebnis = ERROR_NOERROR;

	switch ((u8_byte>>4) & 0x0F)
	{
		case  0:	{	DrvUart_Puts(pudt_uart, "0"); break;	}
		case  1:	{	DrvUart_Puts(pudt_uart, "1"); break;	}
		case  2:	{	DrvUart_Puts(pudt_uart, "2"); break;	}
		case  3:	{	DrvUart_Puts(pudt_uart, "3"); break;	}
		case  4:	{	DrvUart_Puts(pudt_uart, "4"); break;	}
		case  5:	{	DrvUart_Puts(pudt_uart, "5"); break;	}
		case  6:	{	DrvUart_Puts(pudt_uart, "6"); break;	}
		case  7:	{	DrvUart_Puts(pudt_uart, "7"); break;	}
		case  8:	{	DrvUart_Puts(pudt_uart, "8"); break;	}
		case  9:	{	DrvUart_Puts(pudt_uart, "9"); break;	}
		case 10:	{	DrvUart_Puts(pudt_uart, "A"); break;	}
		case 11:	{	DrvUart_Puts(pudt_uart, "B"); break;	}
		case 12:	{	DrvUart_Puts(pudt_uart, "C"); break;	}
		case 13:	{	DrvUart_Puts(pudt_uart, "D"); break;	}
		case 14:	{	DrvUart_Puts(pudt_uart, "E"); break;	}
		case 15:	{	DrvUart_Puts(pudt_uart, "F"); break;	}
	}

	switch (u8_byte & 0x0F)
	{
		case  0:	{	DrvUart_Puts(pudt_uart, "0"); break;	}
		case  1:	{	DrvUart_Puts(pudt_uart, "1"); break;	}
		case  2:	{	DrvUart_Puts(pudt_uart, "2"); break;	}
		case  3:	{	DrvUart_Puts(pudt_uart, "3"); break;	}
		case  4:	{	DrvUart_Puts(pudt_uart, "4"); break;	}
		case  5:	{	DrvUart_Puts(pudt_uart, "5"); break;	}
		case  6:	{	DrvUart_Puts(pudt_uart, "6"); break;	}
		case  7:	{	DrvUart_Puts(pudt_uart, "7"); break;	}
		case  8:	{	DrvUart_Puts(pudt_uart, "8"); break;	}
		case  9:	{	DrvUart_Puts(pudt_uart, "9"); break;	}
		case 10:	{	DrvUart_Puts(pudt_uart, "A"); break;	}
		case 11:	{	DrvUart_Puts(pudt_uart, "B"); break;	}
		case 12:	{	DrvUart_Puts(pudt_uart, "C"); break;	}
		case 13:	{	DrvUart_Puts(pudt_uart, "D"); break;	}
		case 14:	{	DrvUart_Puts(pudt_uart, "E"); break;	}
		case 15:	{	DrvUart_Puts(pudt_uart, "F"); break;	}
	}

	return int_Ergebnis;
}

int16_t DrvUart_Putbyte(TUartPara* pudt_uart, uint8_t u8_byte)
/*============================================================================
 *
 *  Funktion:		DrvUart_Putbyte
 *  Ü-Parameter:	Zeiger auf Schnittstellenstruktur, das auszugebende Byte
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Ausgabe eines unsigned Bytes auf einer seriellen Schnittstelle
 *
 *==========================================================================*/
{
	int16_t	int_Ergebnis = ERROR_NOERROR;
	uint8_t 	u8_Tmp = 0;
	uint8_t	u8_Hunderter = 0;
	uint8_t	u8_Zehner = 0;
	uint8_t	u8_Einer = 0;

	u8_Tmp = u8_byte;

	//Hunderter berechnen
	u8_Hunderter = u8_Tmp/100;

	//Zehner berechnen
	u8_Tmp -= u8_Hunderter*100;
	u8_Zehner = u8_Tmp/10;

	//Einer berechnen
	u8_Einer = u8_Tmp - (u8_Zehner*10);

	//Hunderter ausgeben
	if (u8_Hunderter != 0)
	{
		int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Hunderter));
	}

	//Zehner ausgeben
	if ( (u8_Zehner != 0) || (u8_Hunderter != 0) )
	{
		int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Zehner));
	}

	//Einer ausgeben
	int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Einer));

	return int_Ergebnis;
}

int16_t DrvUart_Putu32(TUartPara* pudt_uart, uint32_t u32_int)
/*============================================================================
 *
 *  Funktion:		DrvUart_Putu32
 *  Ü-Parameter:	Zeiger auf Schnittstellenstruktur, der auszugebende Integer
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Ausgabe eines unsigned Int auf einer seriellen Schnittstelle
 *					(keine fuehrenden Nullen)
 *
 *==========================================================================*/
{
	uint32_t 	u32_Tmp = u32_int;

	if (u32_int >= 1000000000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/1000000000);u32_Tmp %= 1000000000;}
	if (u32_int >= 100000000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/100000000);u32_Tmp %= 100000000;}
	if (u32_int >= 10000000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/10000000);u32_Tmp %= 10000000;}
	if (u32_int >= 1000000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/1000000);u32_Tmp %= 1000000;}
	if (u32_int >= 100000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/100000);u32_Tmp %= 100000;}
	if (u32_int >= 10000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/10000);u32_Tmp %= 10000;}
	if (u32_int >= 1000){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/1000);u32_Tmp %= 1000;}
	if (u32_int >= 100){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/100);u32_Tmp %= 100;}
	if (u32_int >= 10){DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp/10);u32_Tmp %= 10;}
	DrvUart_Putchar(&gudt_MoniIntf, '0'+u32_Tmp);

	return 0;
}

int16_t DrvUart_Putuint(TUartPara* pudt_uart, uint16_t u16_int)
/*============================================================================
 *
 *  Funktion:		DrvUart_Putuint
 *  Ü-Parameter:	Zeiger auf Schnittstellenstruktur, der auszugebende Integer
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Ausgabe eines unsigned Int auf einer seriellen Schnittstelle
 *
 *
 *==========================================================================*/
{
	int16_t	int_Ergebnis = ERROR_NOERROR;
	uint16_t 	u16_Tmp = 0;
	uint8_t	u8_Zehntausender = 0;
	uint8_t	u8_Tausender = 0;
	uint8_t	u8_Hunderter = 0;
	uint8_t	u8_Zehner = 0;
	uint8_t	u8_Einer = 0;

	u16_Tmp = u16_int;

	//Zehntausender berechnen
	u8_Zehntausender = (uint8_t)(u16_Tmp/10000);

	//Tausender berechnen
	u16_Tmp -= u8_Zehntausender*10000;
	u8_Tausender = (uint8_t)(u16_Tmp/1000);

	//Hunderter berechnen
	u16_Tmp -= u8_Tausender*1000;
	u8_Hunderter = (uint8_t)(u16_Tmp/100);

	//Zehner berechnen
	u16_Tmp -= u8_Hunderter*100;
	u8_Zehner = (uint8_t)(u16_Tmp/10);

	//Einer berechnen
	u8_Einer = (uint8_t)(u16_Tmp - (u8_Zehner*10));


	//Zehntausender ausgeben
	if (u8_Zehntausender != 0)
	{
		int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Zehntausender));
	}

	//Tausender ausgeben
	if ( (u8_Zehntausender != 0) || (u8_Tausender != 0) )
	{
		int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Tausender));
	}

	//Hunderter ausgeben
	if ( (u8_Zehntausender != 0) || (u8_Tausender != 0) || (u8_Hunderter != 0) )
	{
		int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Hunderter));
	}

	//Zehner ausgeben
	if ( (u8_Zehntausender != 0) || (u8_Tausender != 0) || (u8_Hunderter != 0) || (u8_Zehner != 0) )
	{
		int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Zehner));
	}

	//Einer ausgeben
	int_Ergebnis |= DrvUart_Putchar(pudt_uart, (uint8_t)(48 + u8_Einer));

	return int_Ergebnis;
}

int16_t DrvUart_Putint(TUartPara* pudt_uart, int16_t int_int)
/*============================================================================
 *
 *  Funktion:		DrvUart_Putint
 *  Ü-Parameter:	Zeiger auf Schnittstellenstruktur, der auszugebende Integer
 *  R-Parameter:	Fehlercode
 *  Beschreibung:	Ausgabe eines unsigned Int auf einer seriellen Schnittstelle
 *
 *==========================================================================*/
{
	int16_t	int_Ergebnis = ERROR_NOERROR;

	//Vorzeichenbehandlung
	if (int_int < 0)
	{
		//negatives VZ ausgeben
		DrvUart_Putchar(pudt_uart, (uint8_t)45);

		//den Betrag ausgeben
		DrvUart_Putuint(pudt_uart, (uint16_t)-int_int);
	}
	else
		DrvUart_Putuint(pudt_uart, (uint16_t)int_int);

	return int_Ergebnis;
}
