/*
 * UART_NetworkLayer_V10.c
 *
 * Created: 11.10.2015 11:51:52
 *  Author: Chenda
 */ 

#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>

#include "../../conf/conf_uart.h"
#include "../../conf/conf_brd.h"
//#include "../../lib_mcu/uart/uart_drv.h"
#include "../../Common/DataOperations.h"
#include "UART_LinkLayer_V10.h"
#include "UART_NetworkLayer_V10.h"

/************************************************************************/
/* Global variables                                                     */
/************************************************************************/
static struct stNL_UARTx stNL_UART0;
static struct stNL_UARTx *spNL_UART0 = &stNL_UART0;
static struct stLL_UARTx *spLL_UART0;

/************************************************************************/
/* Private functions prototypes                                         */
/************************************************************************/
void U0_ReceiverError(void);
void U0_ReceiverMessReceived(void);
void U0_ReceiverClerLinkLayerInterface(void);

void U0_TransmitterError(void);
void U0_TransmitterMessSend(void);
void U0_TransmitterClerLinkLayerInterface(void);

/************************************************************************/
/* Public functions                                                     */
/************************************************************************/
struct stNL_UARTx* UART_NL_U0_INIT (void)
{
	uint8_t AddBuilder = DEF_UART0_ADD;
	mDevAddCfg();
	spLL_UART0 = UART_LL_U0_INT();
	if (!mGetDevAdd_2_0()) AddBuilder += 1;
	if (!mGetDevAdd_2_1()) AddBuilder += 2;
	if (!mGetDevAdd_2_2()) AddBuilder += 4;
	if (!mGetDevAdd_2_3()) AddBuilder += 8;
	spNL_UART0->NL.PeriphAddress = AddBuilder;
	spNL_UART0->NL.SubBrdCst = DEV_ADD_PS_BASE;
	return spNL_UART0;
}

struct stLL_UARTx* UART_NL_U0_GET_LL (void)
{
	return spLL_UART0;
}

void UART_NL_U0(void)
{
	/* Link layer UART1 */
	UART_LL_U0();
	/* Network layer RX */
	// -- update status of transmitter from link layer (only if no action or receiving
	// -- according status do action (if possible always download data) 
	if (spNL_UART0->NL_Int.RX.Event <= UART_NL_RECEIVING) {	
		if (!spLL_UART0->LL_Int.RX.Busy) {
			if (spLL_UART0->LL_Int.RX.E_Nr) {
				U0_ReceiverError();
			}
			else if (spLL_UART0->LL_Int.RX.PacketReceived) {
				U0_ReceiverMessReceived();
			}
			else {
				spNL_UART0->NL_Int.RX.Event = UART_NL_NO_ACTION;
			}
		}
		else {
			spNL_UART0->NL_Int.RX.Event = UART_NL_RECEIVING;
		}
	}
	
	/* Network layer TX */
	// -- update status of transmitter from link layer level
	// -- if event is not "UART_NL_TRANSMITTING" & if exist something to send, send it
	if (spNL_UART0->NL_Int.TX.Event <= UART_NL_TRANSMITTING) {
		if (!spLL_UART0->LL_Int.TX.Busy) {
			if (spLL_UART0->LL_Int.TX.E_Nr) {
				U0_TransmitterError();
			}
			else if (spLL_UART0->LL_Int.TX.PacketTransmitted) {
				U0_TransmitterClerLinkLayerInterface();
				spNL_UART0->NL_Int.TX.Event = UART_NL_TRANSMITED;
			}
			else if (spNL_UART0->NL_Int.TX.Length > 0) {
				U0_TransmitterMessSend();
			}
			else {
				spNL_UART0->NL_Int.TX.Event = UART_NL_NO_ACTION;
			}
		}
		else {
			spNL_UART0->NL_Int.TX.Event = UART_NL_TRANSMITTING;
		}
	}	
}

/* Sender address equal to Periphery address, last sender address from 
incoming private message or last used recipient as recipient address */
void UART_NL_SEND1_U0(uint8_t *Mess, uint8_t Length) 
{
	DAT_OPS_MoveData(Mess, spNL_UART0->NL_Int.TX.Buff,Length,false);
	spNL_UART0->NL_Int.TX.SenderAddress = spNL_UART0->NL.PeriphAddress;
	spNL_UART0->NL_Int.TX.Length = Length;
}

/* Recipient address editable, Sender address equal to Periphery address */
void UART_NL_SEND2_U0(uint8_t *Mess, uint8_t Length, uint8_t RecAdd)
{
	DAT_OPS_MoveData(Mess, spNL_UART0->NL_Int.TX.Buff,Length,false);
	spNL_UART0->NL_Int.TX.SenderAddress = spNL_UART0->NL.PeriphAddress;
	spNL_UART0->NL_Int.TX.RecipientAddress = RecAdd;
	spNL_UART0->NL_Int.TX.Length = Length;
}

/* Sender address & Recipient address fully editable */
void UART_NL_SEND3_U0(uint8_t *Mess, uint8_t Length, uint8_t RecAdd, uint8_t SrcAdd)
{
	DAT_OPS_MoveData(Mess, spNL_UART0->NL_Int.TX.Buff,Length,false);
	spNL_UART0->NL_Int.TX.RecipientAddress = RecAdd;
	spNL_UART0->NL_Int.TX.SenderAddress = SrcAdd;
	spNL_UART0->NL_Int.TX.Length = Length;
}

/************************************************************************/
/* Private functions                                                    */
/************************************************************************/

// RX
void U0_ReceiverError(void)
{
	spNL_UART0->NL_Int.RX.E_Nr = spLL_UART0->LL_Int.RX.E_Nr;
	spNL_UART0->NL_Int.RX.MissedRxBytes = spLL_UART0->LL_Int.RX.MissedRx;
	spNL_UART0->NL_Int.RX.Length = spLL_UART0->LL_Int.RX.PacketLength;
	DAT_OPS_MoveData(spLL_UART0->LL_Int.RX.Buff,spNL_UART0->NL_Int.RX.Buff,spLL_UART0->LL_Int.RX.PacketLength,false);
	U0_ReceiverClerLinkLayerInterface();
	spNL_UART0->NL_Int.RX.Event = UART_NL_ERROR_REC;
}

void U0_ReceiverMessReceived(void)
{
	uint8_t DatCount = 0;
	uint8_t PacketID;
	spNL_UART0->NL_Int.RX.RecipientAddress = spLL_UART0->LL_Int.RX.Buff[DatCount++];
	spNL_UART0->NL_Int.RX.SenderAddress = spLL_UART0->LL_Int.RX.Buff[DatCount++];
	PacketID = (spLL_UART0->LL_Int.RX.Buff[DatCount++]>>3);		// removing first 3 bits (prepared for multi frame)
	spNL_UART0->NL_Int.RX.Length = spLL_UART0->LL_Int.RX.PacketLength - DatCount;
	DAT_OPS_MoveData(&spLL_UART0->LL_Int.RX.Buff[DatCount],spNL_UART0->NL_Int.RX.Buff,
					 spNL_UART0->NL_Int.RX.Length,true);
	U0_ReceiverClerLinkLayerInterface();
	spNL_UART0->NL_Int.RX.E_Nr = 0;
	if (spNL_UART0->NL_Int.RX.RecipientAddress == spNL_UART0->NL.PeriphAddress) {
		spNL_UART0->NL_Int.TX.RecipientAddress = spNL_UART0->NL_Int.RX.SenderAddress;
		spNL_UART0->NL_Int.RX.Event = UART_NL_PRIVATE_MESS;
	}
	else if (spNL_UART0->NL_Int.RX.RecipientAddress == UART_BROADCAST_ADDRESS) {
		spNL_UART0->NL_Int.RX.Event = UART_NL_PUBLIC_MESS;
	}
	else if (spNL_UART0->NL_Int.RX.RecipientAddress == spNL_UART0->NL.SubBrdCst) {
		spNL_UART0->NL_Int.RX.Event = UART_NL_GROUP_MESS;
	}
	else {		
		spNL_UART0->NL_Int.RX.Event = UART_NL_FOREIGN_MESS;
	}
	if (spLL_UART0->LL.IsMasterPeriphery) {
		if (spNL_UART0->NL.PacketID_LastOut != PacketID) {
			spNL_UART0->NL_Int.RX.Event = UART_NL_ERROR_REC;
			spNL_UART0->NL_Int.RX.E_Nr = UART_E_NL_REC_PACKET_ID;
		}
	} 
	else {
		spNL_UART0->NL.PacketID_LastIn = PacketID;
	}
}

void U0_ReceiverClerLinkLayerInterface(void)
{
	spLL_UART0->LL_Int.RX.E_Nr = 0;
	spLL_UART0->LL_Int.RX.MissedRx = 0;
	spLL_UART0->LL_Int.RX.PacketLength = 0;
	spLL_UART0->LL_Int.RX.PacketReceived = false;
}

 // TX
void U0_TransmitterError(void)
{
	spNL_UART0->NL_Int.TX.E_Nr = spLL_UART0->LL_Int.TX.E_Nr;
	U0_TransmitterClerLinkLayerInterface();
	spNL_UART0->NL_Int.TX.Event = UART_NL_ERROR_TRANS; 
}

void U0_TransmitterMessSend(void)
{
	uint8_t DatCount = 0;
	// check length of mess
	if (spNL_UART0->NL_Int.TX.Length > UART_DATA_LEN_MAX) {
		spNL_UART0->NL_Int.TX.E_Nr = UART_E_NL_TRAN_BIG_MESS;
		spNL_UART0->NL_Int.TX.Event = UART_NL_ERROR_TRANS; 
		return;
	}
	spLL_UART0->LL_Int.TX.Buff[DatCount++] = spNL_UART0->NL_Int.TX.RecipientAddress;	// + TrgAdd
	spLL_UART0->LL_Int.TX.Buff[DatCount++] = spNL_UART0->NL_Int.TX.SenderAddress;		// + SrcAdd
	//spNL_UART1->NL_Int.TX.SenderAddress = spNL_UART1->NL.PeriphAddress;
	if (spLL_UART0->LL.IsMasterPeriphery) {
		spNL_UART0->NL.PacketID_LastOut++;
		spNL_UART0->NL.PacketID_LastOut &= 0b11111;
		spLL_UART0->LL_Int.TX.Buff[DatCount++] = (spNL_UART0->NL.PacketID_LastOut<<3);	// + PacketID
	} 
	else {
		spLL_UART0->LL_Int.TX.Buff[DatCount++] = (spNL_UART0->NL.PacketID_LastIn<<3);	// + PacketID
	}
	DAT_OPS_MoveData(spNL_UART0->NL_Int.TX.Buff,&spLL_UART0->LL_Int.TX.Buff[DatCount],spNL_UART0->NL_Int.TX.Length,true);
	spLL_UART0->LL_Int.TX.PacketLength = DatCount + spNL_UART0->NL_Int.TX.Length;
	spLL_UART0->LL_Int.TX.InitiateTransmition = true;
	spNL_UART0->NL_Int.TX.Length = 0;
	// setting time out for expecting message
	spLL_UART0->LL_Int.TX.ExpectRespond = spNL_UART0->NL_Int.TX.ExpectRespond;
	spNL_UART0->NL_Int.TX.ExpectRespond = false;
	spNL_UART0->NL_Int.TX.Event = UART_NL_TRANSMITTING;
}

void U0_TransmitterClerLinkLayerInterface(void)
{
	spLL_UART0->LL_Int.TX.E_Nr = 0;
	spLL_UART0->LL_Int.TX.PacketLength = 0;
	spLL_UART0->LL_Int.TX.PacketTransmitted = false;
}